Real World .NET Core on Kubernetes

Real World .NET Core on Kubernetes

1fe26e11357f3ba7250b6668ca61309f?s=128

Mayuki Sawatari

October 18, 2019
Tweet

Transcript

  1. 1.
  2. 6.
  3. 7.
  4. 9.

    Amazon EKS (Kuberentes) Amazon EC2 (Linux / EKS Optimized AMI)

    Application Load Balancer Aurora, ElastiCache (Redis), S3 など
  5. 10.
  6. 14.
  7. 25.

    apiVersion: extensions/v1beta1 kind: Ingress metadata: name: my-app annotations: kubernetes.io/ingress.class: alb

    略: ... # ロードバランサーに割り当てる DNS 名 external-dns.alpha.kubernetes.io/hostname: api.dev.example.com spec: rules: - http: paths: - path: /SubSystem/* backend: serviceName: my-api-subsystem servicePort: 80 - path: /* backend: serviceName: my-api servicePort: 80
  8. 26.

    apiVersion: extensions/v1beta1 kind: Ingress metadata: name: my-app annotations: kubernetes.io/ingress.class: alb

    略: ... # ロードバランサーに割り当てる DNS 名 external-dns.alpha.kubernetes.io/hostname: api-branch-feature-1.dev.example.com spec: rules: - http: ... hostnameを書き換えて別環境用に作成
  9. 29.

    # base/deployment.yaml apiVersion: apps/v1 kind: Deployment ... # base/ingress.yaml apiVersion:

    extensions/v1beta1 kind: Ingress metadata: name: my-app annotations: # ロードバランサーに割り当てる DNS 名 external-dns.alpha.kubernetes.io/hostname: dev.example.com ... # base/kustomization.yaml resources: - deployment.yaml - ingress.yaml
  10. 30.

    # overlay/branch/kustomization.yaml namespace: dev-branch-feature-1 commonAnnotations: k8s.example.com/gitBranch: dev-branch-feature-1 bases: - ../../base/

    patches: - ingress-patch.yaml # overlay/branch/ingress-patch.yaml - op: replace path: /metadata/annotations/external-dns.alpha.kubernetes.io~1hostname value: dev-branch-feature-1.example.com
  11. 31.

    # 完成品YAML namespace: dev-branch-feature-1 apiVersion: apps/v1 kind: Deployment metadata: annotations:

    k8s.example.com/gitBranch: dev-branch-feature-1 ... --- namespace: dev-branch-feature-1 apiVersion: extensions/v1beta1 kind: Ingress metadata: name: my-app annotations: k8s.example.com/gitBranch: dev-branch-feature-1 external-dns.alpha.kubernetes.io/hostname: dev-branch-feature-1.example.com ...
  12. 34.
  13. 43.
  14. 46.

    Microsoft.Extensions.Loggingのログプロバイダー https://github.com/mayuki/JsonStreamLogger 1 ログレコード、1 JSON行としてStreamに出力 logger.Log(LogLevel.Information, "[{Id}] is {Hello}", 12345,

    "Konnnichiwa"); logger.Log(LogLevel.Warning, new EventId(987, "NanikaEvent"), "[{Id}] is {Hello}", 67890, "Nya-n"); logger.LogError(ex, "[{Id}] is {ExceptionType}: {ExceptionMessage}", 77777, ex.GetType().FullName, ex.Message); {"Category":"Test","LogLevel":2,"EventId":{"Id":0,"Name":null},"State":{"Id":12345,"Hello":"Konnnichiwa"},"Exception":null,"Message" :"[12345] is Konnnichiwa"} {"Category":"Test","LogLevel":3,"EventId":{"Id":987,"Name":"NanikaEvent"},"State":{"Id":67890,"Hello":"Nya- n"},"Exception":null,"Message":"[67890] is Nya-n"} {"Category":"Test","LogLevel":4,"EventId":{"Id":0,"Name":null},"State":{"Id":77777,"ExceptionType":"System.Exception","ExceptionMess age":"Yabai"},"Exception":{"Name":"System.Exception","Message":"Yabai","StackTrace":"(snip)","InnerException":null}},"Message":"[777 77] is System.Exception: Yabai"}
  15. 48.

    ロガーはすべて登録しておいて設定で無効化 - Logging__Console__LogLevel__Default: None - Logging__JsonStream__LogLevel__Default: Trace { "Logging": {

    "Console": { "LogLevel": { "Default": "Debug“ } }, "JsonStream": { "LogLevel": { "Default": "None“ } } } }
  16. 52.
  17. 55.

    appsettings.jsonとConfigMap apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: -

    name: api envFrom: - configMapRef: name: aspnetcore-environment-variables volumeMounts: - name: app-secrets mountPath: /app/secrets readOnly: true apiVersion: v1 kind: ConfigMap metadata: name: aspnetcore-environment-variables data: # 開発環境 NETCORE_ENVIRONMENT: Development ASPNETCORE_ENVIRONMENT: Development
  18. 56.

    appsettings.jsonとSecret public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostContext, configure)

    => { configure // k8s 上では /app/secrets にシークレットをマウントするお気持ち .AddJsonFile($"secrets/appsettings.json", optional: true); }) apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: - name: api volumeMounts: - name: app-secrets mountPath: /app/secrets readOnly: true volumes: - name: lifebear-app-secrets secret: secretName: app-secrets optional: true
  19. 57.

    起動時に設定をログに出力しておく https://gist.github.com/mayuki/0d84d3d0b2bf8f089f69b042f4b650b8 ConnectionStrings:Default: server=Server;user id=User;password=<Secret Hash=1079a1>;database=MyDatabase MyApp:Hello: Konnichiwa! MyApp:Nantoka:Kantoka: True

    Application started. Press Ctrl+C to shut down. Hosting environment: Production { "MyApp": { "Hello": "Konnichiwa!", "Nantoka": { "Kantoka": true } }, "ConnectionStrings": { "Default": "server=Server;user id=User;password=NankaPassword;database=MyDatabase" } }
  20. 59.

    ロギングの口が提供されている ライフサイクルを扱える apiVersion: apps/v1 kind: Deployment spec: template: spec: #

    シャットダウン要求を受けてからアプリが kill されるまでの猶予時間(秒) terminationGracePeriodSeconds: 60
  21. 60.

    自身の名前やannotationなどを取得したいケース Downward API Kubernetes API Pripod apiVersion: v1 kind: Pod

    spec: containers: - name: test-container env: - name: MY_NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: MY_POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: MY_POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace
  22. 61.

    Podの情報を簡単に取得できるライブラリ https://github.com/mayuki/Pripod ラベルやアノテーションも取得できる Console.WriteLine($"Pod: {Pod.Current.Namespace}/{Pod.Current.Name} @ {Pod.Current.NodeName}"); Console.WriteLine("Labels:"); foreach (var

    keyValue in Pod.Current.Labels) { Console.WriteLine($" - {keyValue.Key}: {keyValue.Value}"); } IsRunningOnKubernetes: True Pod: default/consoleapp1-595b95b5f7-xsdjc @ docker-for-desktop Labels: - pod-template-hash: 1516516193 - run: consoleapp1 Deployment: default/consoleapp1
  23. 64.

    ASP .NET CoreにはHealth Check APIがある using Microsoft.Extensions.Diagnostics.HealthChecks; services.AddHealthChecks() .AddCheck("Readiness", ()

    => HealthCheckResult.Healthy()) .AddCheck<ApiHealthCheck>("Liveness"); ... app.UseHealthChecks("/health/readiness", new HealthCheckOptions { Predicate = check => check.Name == "Readiness", }); app.UseHealthChecks("/health/liveness", new HealthCheckOptions { Predicate = check => check.Name == "Liveness", });
  24. 65.

    ASP .NET CoreにはHealth Check APIがある public class ApiHealthCheck : IHealthCheck

    { public async Task<HealthCheckResult> CheckHealthAsync( HealthCheckContext context, CancellationToken cancellationToken = default ) { // 外部サービスへの接続性をチェックする var service = NantokaServiceClient.Instance; await service.GetNantokaKantokaAsync(); return HealthCheckResult.Healthy(); // ヨシ! } }
  25. 67.
  26. 70.
  27. 71.