dotnet-container-deployment

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

dotnet-container-deployment

.NET容器部署

Deploying .NET containers to Kubernetes and local development environments. Covers Kubernetes Deployment + Service + probe YAML, Docker Compose for local dev workflows, and CI/CD integration for building and pushing container images.
将.NET容器部署到Kubernetes和本地开发环境。涵盖Kubernetes Deployment + Service +探针YAML配置、用于本地开发流程的Docker Compose,以及用于构建和推送容器镜像的CI/CD集成。

Scope

适用范围

  • Kubernetes Deployment, Service, and probe YAML for .NET apps
  • Docker Compose for local development workflows
  • CI/CD integration for building and pushing container images
  • 适用于.NET应用的Kubernetes Deployment、Service和探针YAML配置
  • 用于本地开发流程的Docker Compose
  • 用于构建和推送容器镜像的CI/CD集成

Out of scope

不适用范围

  • Dockerfile authoring, multi-stage builds, and base image selection -- see [skill:dotnet-containers]
  • Advanced CI/CD pipeline patterns (matrix builds, deploy pipelines) -- see [skill:dotnet-gha-deploy] and [skill:dotnet-ado-patterns]
  • DI and async patterns -- see [skill:dotnet-csharp-dependency-injection] and [skill:dotnet-csharp-async-patterns]
  • Testing container deployments -- see [skill:dotnet-integration-testing] and [skill:dotnet-playwright]
Cross-references: [skill:dotnet-containers] for Dockerfile and image best practices, [skill:dotnet-observability] for health check endpoint patterns used by Kubernetes probes.

  • Dockerfile编写、多阶段构建和基础镜像选择——详见[skill:dotnet-containers]
  • 高级CI/CD流水线模式(矩阵构建、部署流水线)——详见[skill:dotnet-gha-deploy]和[skill:dotnet-ado-patterns]
  • 依赖注入(DI)和异步模式——详见[skill:dotnet-csharp-dependency-injection]和[skill:dotnet-csharp-async-patterns]
  • 容器部署测试——详见[skill:dotnet-integration-testing]和[skill:dotnet-playwright]
交叉引用:[skill:dotnet-containers]提供Dockerfile和镜像最佳实践,[skill:dotnet-observability]介绍Kubernetes探针使用的健康检查端点模式。

Kubernetes Deployment

Kubernetes部署

Deployment Manifest

部署清单

A production-ready Kubernetes Deployment for a .NET API:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-api
  labels:
    app: order-api
    app.kubernetes.io/name: order-api
    app.kubernetes.io/version: "1.0.0"
    app.kubernetes.io/component: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-api
  template:
    metadata:
      labels:
        app: order-api
    spec:
      containers:
        - name: order-api
          image: ghcr.io/myorg/order-api:1.0.0
          ports:
            - containerPort: 8080
              protocol: TCP
          env:
            - name: ASPNETCORE_ENVIRONMENT
              value: "Production"
            - name: OTEL_EXPORTER_OTLP_ENDPOINT
              value: "http://otel-collector.monitoring:4317"
            - name: OTEL_SERVICE_NAME
              value: "order-api"
            - name: ConnectionStrings__DefaultConnection
              valueFrom:
                secretKeyRef:
                  name: order-api-secrets
                  key: connection-string
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"
          livenessProbe:
            httpGet:
              path: /health/live
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 15
            timeoutSeconds: 3
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /health/ready
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 3
          startupProbe:
            httpGet:
              path: /health/live
              port: 8080
            initialDelaySeconds: 0
            periodSeconds: 5
            failureThreshold: 30
      securityContext:
        runAsNonRoot: true
        runAsUser: 1654
        fsGroup: 1654
      terminationGracePeriodSeconds: 30
适用于.NET API的生产级Kubernetes Deployment:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-api
  labels:
    app: order-api
    app.kubernetes.io/name: order-api
    app.kubernetes.io/version: "1.0.0"
    app.kubernetes.io/component: api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-api
  template:
    metadata:
      labels:
        app: order-api
    spec:
      containers:
        - name: order-api
          image: ghcr.io/myorg/order-api:1.0.0
          ports:
            - containerPort: 8080
              protocol: TCP
          env:
            - name: ASPNETCORE_ENVIRONMENT
              value: "Production"
            - name: OTEL_EXPORTER_OTLP_ENDPOINT
              value: "http://otel-collector.monitoring:4317"
            - name: OTEL_SERVICE_NAME
              value: "order-api"
            - name: ConnectionStrings__DefaultConnection
              valueFrom:
                secretKeyRef:
                  name: order-api-secrets
                  key: connection-string
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"
          livenessProbe:
            httpGet:
              path: /health/live
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 15
            timeoutSeconds: 3
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /health/ready
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 3
          startupProbe:
            httpGet:
              path: /health/live
              port: 8080
            initialDelaySeconds: 0
            periodSeconds: 5
            failureThreshold: 30
      securityContext:
        runAsNonRoot: true
        runAsUser: 1654
        fsGroup: 1654
      terminationGracePeriodSeconds: 30

Service Manifest

服务清单

Expose the Deployment within the cluster:
yaml
apiVersion: v1
kind: Service
metadata:
  name: order-api
  labels:
    app: order-api
spec:
  type: ClusterIP
  selector:
    app: order-api
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http
在集群内部暴露Deployment:
yaml
apiVersion: v1
kind: Service
metadata:
  name: order-api
  labels:
    app: order-api
spec:
  type: ClusterIP
  selector:
    app: order-api
  ports:
    - port: 80
      targetPort: 8080
      protocol: TCP
      name: http

ConfigMap for Non-Sensitive Configuration

用于非敏感配置的ConfigMap

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: order-api-config
data:
  ASPNETCORE_ENVIRONMENT: "Production"
  Logging__LogLevel__Default: "Information"
  Logging__LogLevel__Microsoft.AspNetCore: "Warning"
Reference in the Deployment:
yaml
envFrom:
  - configMapRef:
      name: order-api-config
yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: order-api-config
data:
  ASPNETCORE_ENVIRONMENT: "Production"
  Logging__LogLevel__Default: "Information"
  Logging__LogLevel__Microsoft.AspNetCore: "Warning"
在Deployment中引用:
yaml
envFrom:
  - configMapRef:
      name: order-api-config

Secrets for Sensitive Configuration

用于敏感配置的Secrets

yaml
apiVersion: v1
kind: Secret
metadata:
  name: order-api-secrets
type: Opaque
stringData:
  connection-string: "Host=postgres;Database=orders;Username=app;Password=secret"
In production, use an external secrets operator (e.g., External Secrets Operator, Sealed Secrets) rather than plain Kubernetes Secrets stored in source control.

yaml
apiVersion: v1
kind: Secret
metadata:
  name: order-api-secrets
type: Opaque
stringData:
  connection-string: "Host=postgres;Database=orders;Username=app;Password=secret"
在生产环境中,请使用外部密钥管理器(如External Secrets Operator、Sealed Secrets),而非存储在源代码控制中的明文Kubernetes Secrets。

Kubernetes Probes

Kubernetes探针

Probes tell Kubernetes how to check application health. They map to the health check endpoints defined in your .NET application (see [skill:dotnet-observability]).
探针用于告知Kubernetes如何检查应用健康状态。它们与.NET应用中定义的健康检查端点相对应(详见[skill:dotnet-observability])。

Probe Types

探针类型

ProbePurposeEndpointFailure Action
StartupHas the app finished initializing?
/health/live
Keep waiting (up to
failureThreshold * periodSeconds
)
LivenessIs the process healthy?
/health/live
Restart the pod
ReadinessCan the process serve traffic?
/health/ready
Remove from Service endpoints
探针用途端点失败动作
Startup(启动探针)应用是否完成初始化?
/health/live
持续等待(最长为
failureThreshold * periodSeconds
Liveness(存活探针)进程是否健康?
/health/live
重启Pod
Readiness(就绪探针)进程是否可以处理流量?
/health/ready
从Service端点中移除

Probe Configuration Guidelines

探针配置指南

yaml
undefined
yaml
undefined

Startup probe: give the app time to initialize

启动探针:为应用提供初始化时间

Total startup budget: failureThreshold * periodSeconds = 30 * 5 = 150s

总启动预算:failureThreshold * periodSeconds = 30 * 5 = 150s

startupProbe: httpGet: path: /health/live port: 8080 initialDelaySeconds: 0 periodSeconds: 5 failureThreshold: 30
startupProbe: httpGet: path: /health/live port: 8080 initialDelaySeconds: 0 periodSeconds: 5 failureThreshold: 30

Liveness probe: detect deadlocks and hangs

存活探针:检测死锁和挂起

Only runs after startup probe succeeds

仅在启动探针成功后运行

livenessProbe: httpGet: path: /health/live port: 8080 periodSeconds: 15 timeoutSeconds: 3 failureThreshold: 3
livenessProbe: httpGet: path: /health/live port: 8080 periodSeconds: 15 timeoutSeconds: 3 failureThreshold: 3

Readiness probe: control traffic routing

就绪探针:控制流量路由

readinessProbe: httpGet: path: /health/ready port: 8080 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3
undefined
readinessProbe: httpGet: path: /health/ready port: 8080 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3
undefined

Graceful Shutdown

优雅关闭

.NET responds to
SIGTERM
and begins graceful shutdown. Configure
terminationGracePeriodSeconds
to allow in-flight requests to complete:
yaml
spec:
  terminationGracePeriodSeconds: 30
In your application, use
IHostApplicationLifetime
to handle shutdown:
csharp
app.Lifetime.ApplicationStopping.Register(() =>
{
    // Perform cleanup: flush telemetry, close connections
    Log.CloseAndFlush();
});
Ensure the
Host.ShutdownTimeout
allows in-flight requests to complete:
csharp
builder.Host.ConfigureHostOptions(options =>
{
    options.ShutdownTimeout = TimeSpan.FromSeconds(25);
});
Set
ShutdownTimeout
to a value less than
terminationGracePeriodSeconds
to ensure the app shuts down before Kubernetes sends
SIGKILL
.

.NET会响应
SIGTERM
信号并开始优雅关闭。配置
terminationGracePeriodSeconds
以允许正在处理的请求完成:
yaml
spec:
  terminationGracePeriodSeconds: 30
在你的应用中,使用
IHostApplicationLifetime
处理关闭逻辑:
csharp
app.Lifetime.ApplicationStopping.Register(() =>
{
    // 执行清理操作:刷新遥测数据、关闭连接
    Log.CloseAndFlush();
});
确保
Host.ShutdownTimeout
允许正在处理的请求完成:
csharp
builder.Host.ConfigureHostOptions(options =>
{
    options.ShutdownTimeout = TimeSpan.FromSeconds(25);
});
ShutdownTimeout
设置为小于
terminationGracePeriodSeconds
的值,以确保应用在Kubernetes发送
SIGKILL
之前完成关闭。

Docker Compose for Local Development

用于本地开发的Docker Compose

Docker Compose provides a local development environment that mirrors production dependencies.
Docker Compose提供了与生产环境依赖一致的本地开发环境。

Basic Compose File

基础Compose文件

yaml
undefined
yaml
undefined

docker-compose.yml

docker-compose.yml

services: order-api: build: context: . dockerfile: src/OrderApi/Dockerfile ports: - "8080:8080" environment: - ASPNETCORE_ENVIRONMENT=Development - ConnectionStrings__DefaultConnection=Host=postgres;Database=orders;Username=app;Password=devpassword - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 depends_on: postgres: condition: service_healthy redis: condition: service_healthy # Note: CMD-SHELL + curl requires a base image with shell and curl installed. # Chiseled/distroless images lack both. For chiseled images, either use a # non-chiseled dev target in the Dockerfile or omit the healthcheck and rely # on depends_on ordering (acceptable for local dev). healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8080/health/live || exit 1"] interval: 10s timeout: 3s retries: 3 start_period: 10s
postgres: image: postgres:17 environment: POSTGRES_DB: orders POSTGRES_USER: app POSTGRES_PASSWORD: devpassword ports: - "5432:5432" volumes: - postgres-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U app -d orders"] interval: 5s timeout: 3s retries: 5
redis: image: redis:7-alpine ports: - "6379:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5
volumes: postgres-data:
undefined
services: order-api: build: context: . dockerfile: src/OrderApi/Dockerfile ports: - "8080:8080" environment: - ASPNETCORE_ENVIRONMENT=Development - ConnectionStrings__DefaultConnection=Host=postgres;Database=orders;Username=app;Password=devpassword - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 depends_on: postgres: condition: service_healthy redis: condition: service_healthy # 注意:CMD-SHELL + curl要求基础镜像包含shell和curl。 # 精简版/无操作系统镜像(chiseled/distroless)缺少这两者。对于精简版镜像,要么在Dockerfile中使用非精简版开发镜像,要么省略健康检查并依赖depends_on的顺序(本地开发中可接受)。 healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8080/health/live || exit 1"] interval: 10s timeout: 3s retries: 3 start_period: 10s
postgres: image: postgres:17 environment: POSTGRES_DB: orders POSTGRES_USER: app POSTGRES_PASSWORD: devpassword ports: - "5432:5432" volumes: - postgres-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U app -d orders"] interval: 5s timeout: 3s retries: 5
redis: image: redis:7-alpine ports: - "6379:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 5
volumes: postgres-data:
undefined

Development Override

开发环境覆盖配置

Use a separate override file for development-specific settings:
yaml
undefined
使用单独的覆盖文件设置开发特定的配置:
yaml
undefined

docker-compose.override.yml (auto-loaded by docker compose up)

docker-compose.override.yml(docker compose up会自动加载)

services: order-api: build: target: build # Stop at build stage for faster rebuilds volumes: - .:/src # Mount source for hot reload environment: - ASPNETCORE_ENVIRONMENT=Development - DOTNET_USE_POLLING_FILE_WATCHER=true command: ["dotnet", "watch", "run", "--project", "src/OrderApi/OrderApi.csproj"]
undefined
services: order-api: build: target: build # 停留在构建阶段以加快重建速度 volumes: - .:/src # 挂载源代码以实现热重载 environment: - ASPNETCORE_ENVIRONMENT=Development - DOTNET_USE_POLLING_FILE_WATCHER=true command: ["dotnet", "watch", "run", "--project", "src/OrderApi/OrderApi.csproj"]
undefined

Observability Stack

可观测性栈

Add an OpenTelemetry collector and Grafana for local observability:
yaml
undefined
添加OpenTelemetry收集器和Grafana以实现本地可观测性:
yaml
undefined

docker-compose.observability.yml

docker-compose.observability.yml

services: otel-collector: image: otel/opentelemetry-collector-contrib:latest command: ["--config=/etc/otelcol-config.yaml"] volumes: - ./infra/otelcol-config.yaml:/etc/otelcol-config.yaml ports: - "4317:4317" # OTLP gRPC - "4318:4318" # OTLP HTTP
grafana: image: grafana/grafana:latest ports: - "3000:3000" volumes: - grafana-data:/var/lib/grafana
volumes: grafana-data:

Run with the observability stack:

```bash
docker compose -f docker-compose.yml -f docker-compose.observability.yml up

services: otel-collector: image: otel/opentelemetry-collector-contrib:latest command: ["--config=/etc/otelcol-config.yaml"] volumes: - ./infra/otelcol-config.yaml:/etc/otelcol-config.yaml ports: - "4317:4317" # OTLP gRPC - "4318:4318" # OTLP HTTP
grafana: image: grafana/grafana:latest ports: - "3000:3000" volumes: - grafana-data:/var/lib/grafana
volumes: grafana-data:

启动包含可观测性栈的环境:

```bash
docker compose -f docker-compose.yml -f docker-compose.observability.yml up

CI/CD Integration

CI/CD集成

Basic CI/CD patterns for building and pushing .NET container images. Advanced CI patterns (matrix builds, environment promotion, deploy pipelines) -- see [skill:dotnet-gha-publish], [skill:dotnet-gha-deploy], and [skill:dotnet-ado-publish].
用于构建和推送.NET容器镜像的基础CI/CD模式。高级CI模式(矩阵构建、环境晋升、部署流水线)——详见[skill:dotnet-gha-publish], [skill:dotnet-gha-deploy], 和[skill:dotnet-ado-publish]。

GitHub Actions: Build and Push

GitHub Actions:构建和推送

yaml
undefined
yaml
undefined

.github/workflows/docker-publish.yml

.github/workflows/docker-publish.yml

name: Build and Push Container
on: push: branches: [main] tags: ["v*"]
env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }}
jobs: build-and-push: runs-on: ubuntu-latest permissions: contents: read packages: write
steps:
  - uses: actions/checkout@v4

  - name: Log in to container registry
    uses: docker/login-action@v3
    with:
      registry: ${{ env.REGISTRY }}
      username: ${{ github.actor }}
      password: ${{ secrets.GITHUB_TOKEN }}

  - name: Extract metadata
    id: meta
    uses: docker/metadata-action@v5
    with:
      images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
      tags: |
        type=ref,event=branch
        type=semver,pattern={{version}}
        type=semver,pattern={{major}}.{{minor}}
        type=sha

  - name: Build and push
    uses: docker/build-push-action@v6
    with:
      context: .
      push: true
      tags: ${{ steps.meta.outputs.tags }}
      labels: ${{ steps.meta.outputs.labels }}
      cache-from: type=gha
      cache-to: type=gha,mode=max
undefined
name: Build and Push Container
on: push: branches: [main] tags: ["v*"]
env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }}
jobs: build-and-push: runs-on: ubuntu-latest permissions: contents: read packages: write
steps:
  - uses: actions/checkout@v4

  - name: Log in to container registry
    uses: docker/login-action@v3
    with:
      registry: ${{ env.REGISTRY }}
      username: ${{ github.actor }}
      password: ${{ secrets.GITHUB_TOKEN }}

  - name: Extract metadata
    id: meta
    uses: docker/metadata-action@v5
    with:
      images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
      tags: |
        type=ref,event=branch
        type=semver,pattern={{version}}
        type=semver,pattern={{major}}.{{minor}}
        type=sha

  - name: Build and push
    uses: docker/build-push-action@v6
    with:
      context: .
      push: true
      tags: ${{ steps.meta.outputs.tags }}
      labels: ${{ steps.meta.outputs.labels }}
      cache-from: type=gha
      cache-to: type=gha,mode=max
undefined

Image Tagging Strategy

镜像标签策略

Tag PatternExampleUse Case
latest
myapi:latest
Development only -- never use in production
Semver
myapi:1.2.3
Release versions -- immutable
Major.Minor
myapi:1.2
Floating tag for patch updates
SHA
myapi:sha-abc1234
Unique per commit -- traceability
Branch
myapi:main
CI builds -- latest from branch
标签模式示例使用场景
latest
myapi:latest
仅用于开发——生产环境切勿使用
语义化版本(Semver)
myapi:1.2.3
发布版本——不可变
主版本.次版本
myapi:1.2
用于补丁更新的浮动标签
SHA哈希
myapi:sha-abc1234
每个提交唯一——可追溯
分支名
myapi:main
CI构建——分支最新版本

dotnet publish Container in CI

CI中使用dotnet publish构建容器

For projects using
dotnet publish /t:PublishContainer
instead of Dockerfiles:
yaml
steps:
  - uses: actions/checkout@v4

  - uses: actions/setup-dotnet@v4
    with:
      dotnet-version: "10.0.x"

  - name: Publish container image
    run: |
      dotnet publish src/OrderApi/OrderApi.csproj \
        --os linux --arch x64 \
        /t:PublishContainer \
        -p:ContainerRegistry=${{ env.REGISTRY }} \
        -p:ContainerRepository=${{ env.IMAGE_NAME }} \
        -p:ContainerImageTag=${{ github.sha }}

对于使用
dotnet publish /t:PublishContainer
而非Dockerfile的项目:
yaml
steps:
  - uses: actions/checkout@v4

  - uses: actions/setup-dotnet@v4
    with:
      dotnet-version: "10.0.x"

  - name: Publish container image
    run: |
      dotnet publish src/OrderApi/OrderApi.csproj \
        --os linux --arch x64 \
        /t:PublishContainer \
        -p:ContainerRegistry=${{ env.REGISTRY }} \
        -p:ContainerRepository=${{ env.IMAGE_NAME }} \
        -p:ContainerImageTag=${{ github.sha }}

Key Principles

核心原则

  • Use startup probes to decouple initialization time from liveness detection -- without a startup probe, slow-starting apps get killed before they are ready
  • Separate liveness from readiness -- liveness checks should not include dependency health (see [skill:dotnet-observability] for endpoint patterns)
  • Set resource requests and limits -- without them, pods can starve other workloads or get OOM-killed unpredictably
  • Run as non-root -- set
    runAsNonRoot: true
    in the pod security context and use chiseled images (see [skill:dotnet-containers])
  • Use
    depends_on
    with health checks
    in Docker Compose -- prevents app startup before dependencies are ready
  • Keep secrets out of manifests -- use Kubernetes Secrets with external secrets operators, not plain values in source control
  • Match ShutdownTimeout to terminationGracePeriodSeconds -- ensure the app finishes cleanup before Kubernetes sends SIGKILL

  • 使用启动探针:将初始化时间与存活检测解耦——如果没有启动探针,启动缓慢的应用会在准备就绪前被杀死
  • 区分存活探针与就绪探针:存活检查不应包含依赖健康状态(详见[skill:dotnet-observability]中的端点模式)
  • 设置资源请求与限制:如果不设置,Pod可能会抢占其他工作负载的资源或被随机OOM杀死
  • 以非root用户运行:在Pod安全上下文中设置
    runAsNonRoot: true
    并使用精简版镜像(详见[skill:dotnet-containers])
  • 在Docker Compose中使用带健康检查的
    depends_on
    :防止应用在依赖服务就绪前启动
  • 不要将密钥放入清单文件:使用Kubernetes Secrets或ConfigMaps,通过
    secretKeyRef
    /
    configMapRef
    引用
  • 匹配ShutdownTimeout与terminationGracePeriodSeconds:确保应用在Kubernetes发送SIGKILL前完成清理

Agent Gotchas

常见陷阱

  1. Do not omit the startup probe -- without it, the liveness probe runs during initialization and may restart slow-starting apps. Calculate startup budget as
    failureThreshold * periodSeconds
    .
  2. Do not include dependency checks in liveness probes -- a database outage should not restart your app. Liveness endpoints must only check the process itself. See [skill:dotnet-observability] for the liveness vs readiness pattern.
  3. Do not use
    latest
    tag in Kubernetes manifests
    --
    latest
    is mutable and
    imagePullPolicy: IfNotPresent
    may serve stale images. Use immutable tags (semver or SHA).
  4. Do not hardcode connection strings in Kubernetes manifests -- use Secrets or ConfigMaps referenced via
    secretKeyRef
    /
    configMapRef
    .
  5. Do not set
    terminationGracePeriodSeconds
    lower than
    Host.ShutdownTimeout
    -- the app needs time to drain in-flight requests before Kubernetes sends SIGKILL.
  6. Do not forget
    condition: service_healthy
    in Docker Compose
    depends_on
    -- without the condition, Compose starts dependent services immediately without waiting for health checks.

  1. 切勿省略启动探针:如果没有启动探针,存活探针会在初始化阶段运行,可能会重启启动缓慢的应用。启动预算计算方式为
    failureThreshold * periodSeconds
  2. 切勿在存活探针中包含依赖检查:数据库故障不应导致应用重启。存活端点应仅检查进程本身。详见[skill:dotnet-observability]中的存活与就绪探针模式。
  3. 在Kubernetes清单中切勿使用
    latest
    标签
    latest
    是可变的,
    imagePullPolicy: IfNotPresent
    可能会提供过时的镜像。使用不可变标签(语义化版本或SHA哈希)。
  4. 切勿在Kubernetes清单中硬编码连接字符串:使用通过
    secretKeyRef
    /
    configMapRef
    引用的Secrets或ConfigMaps。
  5. 切勿将
    terminationGracePeriodSeconds
    设置为小于
    Host.ShutdownTimeout
    :应用需要时间处理完正在进行的请求,然后Kubernetes才会发送SIGKILL。
  6. 在Docker Compose的
    depends_on
    中切勿忘记
    condition: service_healthy
    :如果没有该条件,Compose会立即启动依赖服务,而不等待健康检查完成。

References

参考资料