# Kubernetes Deployment - Detailed Reference Detailed configurations và examples cho Kubernetes deployment trong GoodGo. ## Table of Contents 1. [Complete Deployment Example](#complete-deployment-example) 2. [Helm Chart Templates](#helm-chart-templates) 3. [Kustomize Configuration](#kustomize-configuration) 4. [CI/CD Integration](#cicd-integration) 5. [Production Configurations](#production-configurations) --- ## Complete Deployment Example ### Namespace ```yaml # k8s/base/namespace.yaml apiVersion: v1 kind: Namespace metadata: name: goodgo labels: name: goodgo environment: production ``` ### Complete Service Deployment ```yaml # k8s/base/iam-service/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: iam-service namespace: goodgo labels: app.kubernetes.io/name: iam-service app.kubernetes.io/part-of: goodgo app.kubernetes.io/version: "1.0.0" spec: replicas: 3 revisionHistoryLimit: 5 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 selector: matchLabels: app.kubernetes.io/name: iam-service template: metadata: labels: app.kubernetes.io/name: iam-service annotations: prometheus.io/scrape: "true" prometheus.io/port: "8080" prometheus.io/path: "/metrics" spec: serviceAccountName: iam-service securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 containers: - name: iam-service image: goodgo/iam-service:1.0.0 imagePullPolicy: IfNotPresent securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL ports: - name: http containerPort: 8080 protocol: TCP envFrom: - configMapRef: name: iam-config env: - name: ConnectionStrings__DefaultConnection valueFrom: secretKeyRef: name: iam-secrets key: database-url - name: Jwt__SecretKey valueFrom: secretKeyRef: name: iam-secrets key: jwt-secret resources: requests: memory: "256Mi" cpu: "100m" limits: memory: "512Mi" cpu: "500m" livenessProbe: httpGet: path: /health/live port: http initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /health/ready port: http initialDelaySeconds: 5 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3 startupProbe: httpGet: path: /health/startup port: http initialDelaySeconds: 5 periodSeconds: 5 failureThreshold: 30 volumeMounts: - name: tmp mountPath: /tmp volumes: - name: tmp emptyDir: {} affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app.kubernetes.io/name: iam-service topologyKey: kubernetes.io/hostname topologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app.kubernetes.io/name: iam-service ``` ### Service Account ```yaml # k8s/base/iam-service/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: name: iam-service namespace: goodgo --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: iam-service-role namespace: goodgo rules: - apiGroups: [""] resources: ["configmaps", "secrets"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: iam-service-rolebinding namespace: goodgo subjects: - kind: ServiceAccount name: iam-service roleRef: kind: Role name: iam-service-role apiGroup: rbac.authorization.k8s.io ``` ### PodDisruptionBudget ```yaml # k8s/base/iam-service/pdb.yaml apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: iam-service-pdb namespace: goodgo spec: minAvailable: 2 selector: matchLabels: app.kubernetes.io/name: iam-service ``` --- ## Helm Chart Templates ### Chart.yaml ```yaml # charts/goodgo-service/Chart.yaml apiVersion: v2 name: goodgo-service description: A Helm chart for GoodGo microservices type: application version: 1.0.0 appVersion: "1.0.0" maintainers: - name: GoodGo Team email: team@goodgo.vn ``` ### Deployment Template ```yaml # charts/goodgo-service/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "goodgo-service.fullname" . }} labels: {{- include "goodgo-service.labels" . | nindent 4 }} spec: {{- if not .Values.autoscaling.enabled }} replicas: {{ .Values.replicaCount }} {{- end }} selector: matchLabels: {{- include "goodgo-service.selectorLabels" . | nindent 6 }} template: metadata: annotations: checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} {{- with .Values.podAnnotations }} {{- toYaml . | nindent 8 }} {{- end }} labels: {{- include "goodgo-service.selectorLabels" . | nindent 8 }} spec: serviceAccountName: {{ include "goodgo-service.serviceAccountName" . }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: - name: {{ .Chart.Name }} securityContext: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: http containerPort: {{ .Values.service.targetPort }} protocol: TCP {{- if .Values.env }} env: {{- toYaml .Values.env | nindent 12 }} {{- end }} {{- if .Values.envFromSecret }} envFrom: - secretRef: name: {{ include "goodgo-service.fullname" . }}-secrets {{- end }} livenessProbe: httpGet: path: {{ .Values.probes.liveness.path }} port: http initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }} periodSeconds: {{ .Values.probes.liveness.periodSeconds }} readinessProbe: httpGet: path: {{ .Values.probes.readiness.path }} port: http initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }} periodSeconds: {{ .Values.probes.readiness.periodSeconds }} resources: {{- toYaml .Values.resources | nindent 12 }} ``` ### Helpers Template ```yaml # charts/goodgo-service/templates/_helpers.tpl {{/* Expand the name of the chart. */}} {{- define "goodgo-service.name" -}} {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} {{- end }} {{/* Create a default fully qualified app name. */}} {{- define "goodgo-service.fullname" -}} {{- if .Values.fullnameOverride }} {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} {{- else }} {{- $name := default .Chart.Name .Values.nameOverride }} {{- if contains $name .Release.Name }} {{- .Release.Name | trunc 63 | trimSuffix "-" }} {{- else }} {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} {{- end }} {{- end }} {{- end }} {{/* Common labels */}} {{- define "goodgo-service.labels" -}} helm.sh/chart: {{ include "goodgo-service.chart" . }} {{ include "goodgo-service.selectorLabels" . }} app.kubernetes.io/version: {{ .Values.image.tag | default .Chart.AppVersion | quote }} app.kubernetes.io/managed-by: {{ .Release.Service }} {{- end }} {{/* Selector labels */}} {{- define "goodgo-service.selectorLabels" -}} app.kubernetes.io/name: {{ include "goodgo-service.name" . }} app.kubernetes.io/instance: {{ .Release.Name }} {{- end }} ``` ### Production Values ```yaml # charts/goodgo-service/values/production.yaml replicaCount: 3 image: repository: gcr.io/goodgo/iam-service tag: "1.0.0" pullPolicy: IfNotPresent resources: requests: memory: "512Mi" cpu: "250m" limits: memory: "1Gi" cpu: "1000m" autoscaling: enabled: true minReplicas: 3 maxReplicas: 20 targetCPUUtilizationPercentage: 70 targetMemoryUtilizationPercentage: 80 ingress: enabled: true className: nginx annotations: nginx.ingress.kubernetes.io/rate-limit: "100" nginx.ingress.kubernetes.io/rate-limit-window: "1m" hosts: - host: api.goodgo.vn paths: - path: /api/v1/iam pathType: Prefix tls: - secretName: goodgo-tls hosts: - api.goodgo.vn probes: liveness: path: /health/live initialDelaySeconds: 10 periodSeconds: 10 readiness: path: /health/ready initialDelaySeconds: 5 periodSeconds: 5 ``` --- ## CI/CD Integration ### GitHub Actions Deploy ```yaml # .github/workflows/deploy.yml name: Deploy to Kubernetes on: push: branches: [main] tags: ['v*'] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to GCR uses: docker/login-action@v3 with: registry: gcr.io username: _json_key password: ${{ secrets.GCP_SA_KEY }} - name: Build and push uses: docker/build-push-action@v5 with: context: ./services/iam-service-net push: true tags: gcr.io/goodgo/iam-service:${{ github.sha }} cache-from: type=gha cache-to: type=gha,mode=max - name: Set up kubectl uses: azure/setup-kubectl@v3 - name: Set up Helm uses: azure/setup-helm@v3 - name: Deploy to Kubernetes run: | helm upgrade --install iam-service ./charts/goodgo-service \ --namespace goodgo \ --create-namespace \ --values ./charts/goodgo-service/values/production.yaml \ --set image.tag=${{ github.sha }} \ --wait ``` --- ## Resources / Tài Nguyên - [Kubernetes Documentation](https://kubernetes.io/docs/) - [Helm Documentation](https://helm.sh/docs/) - [Kustomize Documentation](https://kustomize.io/) - [NGINX Ingress Controller](https://kubernetes.github.io/ingress-nginx/)