Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Real World .NET Core on Kubernetes

Real World .NET Core on Kubernetes

Mayuki Sawatari

October 18, 2019
Tweet

More Decks by Mayuki Sawatari

Other Decks in Programming

Transcript

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

    Application Load Balancer Aurora, ElastiCache (Redis), S3 など
  2. 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
  3. 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を書き換えて別環境用に作成
  4. # 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
  5. # 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
  6. # 完成品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 ...
  7. 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"}
  8. ロガーはすべて登録しておいて設定で無効化 - Logging__Console__LogLevel__Default: None - Logging__JsonStream__LogLevel__Default: Trace { "Logging": {

    "Console": { "LogLevel": { "Default": "Debug“ } }, "JsonStream": { "LogLevel": { "Default": "None“ } } } }
  9. 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
  10. 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
  11. 起動時に設定をログに出力しておく 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" } }
  12. ロギングの口が提供されている ライフサイクルを扱える apiVersion: apps/v1 kind: Deployment spec: template: spec: #

    シャットダウン要求を受けてからアプリが kill されるまでの猶予時間(秒) terminationGracePeriodSeconds: 60
  13. 自身の名前や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
  14. 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
  15. 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", });
  16. 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(); // ヨシ! } }