메인 콘텐츠로 이동하기
  1. Posts/

[K3s-03] K3s에서 Docker credentials를 주입하는 방법

·777 자

AWS의 관리형 쿠버네티스 클러스터인 EKS는 기본적으로 AWS ECR 권한을 가지고 있지만, 온프레미스 환경의 경우 Docker 권한을 직접 주입해야 합니다(프라이빗 Docker 레지스트리에서 이미지를 가져오기 위해). 기본 아이디어는 AWS에서 ECR 인증 토큰을 가져와 ‘regcred’라는 이름의 Secret(dockerconfigjson)을 생성하는 cronjob을 만드는 것입니다(이름은 ‘regcred’로 설정할 수 있습니다). 예제 네임스페이스로는 ‘practice’를 사용하겠습니다.

apiVersion: v1
kind: Secret
metadata:
  name: ecr-registry-helper-secrets
  namespace: practice
stringData:
  AWS_SECRET_ACCESS_KEY: "XXX" # Replace with your AWS secret access key
  AWS_ACCESS_KEY_ID: "XXX" # Replace with your AWS access key ID
  AWS_ACCOUNT: "XXX" # Replace with your AWS account ID
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ecr-registry-helper-cm
  namespace: practice
data:
  AWS_REGION: "ap-northeast-2" # Replace with your ECR region
  DOCKER_SECRET_NAME: regcred # Replace with your desired ECR token secret name
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-default
  namespace: default

이제 ‘CronJob’에게 시크릿을 삭제하고 생성할 수 있는 권한을 부여하는 RoleRoleBinding을 생성합니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: practice
  name: role-full-access-to-secrets
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    resourceNames: ["regcred"] # 원하는 ECR 토큰 시크릿 이름으로 교체
    verbs: ["delete"]
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["create"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: default-role-binding
  namespace: practice
subjects:
  - kind: ServiceAccount
    name: sa-default # serviceaccount 이름이 다르면 해당 이름으로 교체
    namespace: practice
    apiGroup: ""
roleRef:
  kind: Role
  name: role-full-access-to-secrets # role 이름이 다르면 교체
  apiGroup: ""

마지막으로 CronJob을 생성합니다. 이미지 omarxs/awskctl은 컨테이너 내에서 AWS 커맨드라인을 사용하도록 구성되어 있습니다. 네임스페이스 또한 꼭 설정해주세요.

apiVersion: batch/v1
kind: CronJob
metadata:
  name: ecr-registry-helper
  namespace: default
spec:
  schedule: "0 */10 * * *" # 원하는 스케줄로 교체
  successfulJobsHistoryLimit: 2
  suspend: false
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: sa-default # serviceaccount 이름이 다르면 교체
          containers:
            - name: ecr-registry-helper
              image: omarxs/awskctl:v1.0
              imagePullPolicy: IfNotPresent
              envFrom:
                - secretRef:
                    name: ecr-registry-helper-secrets # secret 이름이 다르면 교체
                - configMapRef:
                    name: ecr-registry-helper-cm # configmap 이름이 다르면 교체
              command:
                - /bin/bash
                - -c
                - |-
                  ECR_TOKEN="$(aws ecr get-login-password --region ${AWS_REGION})"
                  NAMESPACE_NAME=practice # 원하는 namespace로 교체
                  kubectl delete secret --ignore-not-found $DOCKER_SECRET_NAME -n $NAMESPACE_NAME
                  kubectl create secret docker-registry $DOCKER_SECRET_NAME --docker-server=https://${AWS_ACCOUNT}.dkr.ecr.${AWS_REGION}.amazonaws.com --docker-username=AWS --docker-password=${ECR_TOKEN} --namespace=$NAMESPACE_NAME
                  echo "Secret was successfully updated at $(date)"                  
          restartPolicy: Never

이 cronjob은 10시간마다 실행됩니다. AWS ECR 토큰은 12시간 동안 유효하므로, 만료되기 전에 새로고침됩니다. 추가로, cronjob을 수동으로 실행하는 방법은 다음과 같습니다.

kubectl create job --from=cronjob/ecr-registry-helper ecr-registry-helper-manual -n practice
# CronJob 이름이 다르면 교체

Check whether it shows this kind of message when looking at the logs: Secret was successfully updated at Sat Jan 1 00:00:00 UTC 2023

# Manual Job 삭제
kubectl delete job ecr-registry-helper-manual -n practice # Job 이름과 Namespace가 다르면 교체

Now, all you need to do is put imagePullSecrets on the Pod spec.

# 예제 Pod
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
  namespace: practice
spec:
  containers:
  - name: test-container
    image: <your-account>.dkr.ecr.<your-region>.amazonaws.com/<your-image>:<your-tag> # ECR 이미지로 교체
    imagePullPolicy: Always
  imagePullSecrets:
  - name: regcred # secret 이름이 다르면 교체

TL;DR #

apiVersion: v1
kind: Secret
metadata:
  name: ecr-registry-helper-secrets
  namespace: default
stringData:
  AWS_SECRET_ACCESS_KEY: "" # AWS 비밀 액세스 키로 교체
  AWS_ACCESS_KEY_ID: "" # AWS 액세스 키 ID로 교체
  AWS_ACCOUNT: "" # AWS 계정 ID로 교체
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ecr-registry-helper-cm
  namespace: default
data:
  AWS_REGION: "eu-central-1" # ECR 리전으로 교체
  DOCKER_SECRET_NAME: regcred # 원하는 ECR 토큰 시크릿 이름으로 교체
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: sa-default
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: role-full-access-to-secrets
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    resourceNames: ["regcred"] # 원하는 ECR 토큰 시크릿 이름으로 교체
    verbs: ["delete"]
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["create"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: default-role-binding
  namespace: default
subjects:
  - kind: ServiceAccount
    name: sa-default # serviceaccount 이름이 다르면 교체
    namespace: default
    apiGroup: ""
roleRef:
  kind: Role
  name: role-full-access-to-secrets # Role 이름이 다르면 교체
  apiGroup: ""
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: ecr-registry-helper
  namespace: default
spec:
  schedule: "0 */10 * * *" # 원하는 스케줄로 교체
  successfulJobsHistoryLimit: 2
  suspend: false
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: sa-default # serviceaccount 이름이 다르면 교체
          containers:
            - name: ecr-registry-helper
              image: omarxs/awskctl:v1.0
              imagePullPolicy: IfNotPresent
              envFrom:
                - secretRef:
                    name: ecr-registry-helper-secrets # secret 이름이 다르면 교체
                - configMapRef:
                    name: ecr-registry-helper-cm # configmap 이름이 다르면 교체
              command:
                - /bin/bash
                - -c
                - |-
                  ECR_TOKEN="$(aws ecr get-login-password --region ${AWS_REGION})"
                  NAMESPACE_NAME=default # 원하는 namespace로 교체
                  kubectl delete secret --ignore-not-found $DOCKER_SECRET_NAME -n $NAMESPACE_NAME
                  kubectl create secret docker-registry $DOCKER_SECRET_NAME --docker-server=https://${AWS_ACCOUNT}.dkr.ecr.${AWS_REGION}.amazonaws.com --docker-username=AWS --docker-password=${ECR_TOKEN} --namespace=$NAMESPACE_NAME
                  echo "Secret was successfully updated at $(date)"                  
          restartPolicy: Never

registries.yaml #

K3s의 경우 추가적인 프라이빗 레지스트리 구성을 지원합니다. 시작할 때, K3s는 /etc/rancher/k3s/registries.yaml이 존재하는지 확인합니다. 해당 파일에 포함된 레지스트리 구성이 컨테이너 구성을 생성할 때 사용됩니다.

따라서 yaml 파일에 자격 증명이 올바르게 구성되어 있으면 Kubernetes의 배포에서 imagePullSecrets를 추가할 필요가 없습니다.

mirrors:
  <REGISTRY>:
    endpoint:
      - https://<REGISTRY>/v2
configs:
  <REGISTRY>:
    auth:
      username: <BASIC AUTH USERNAME>
      password: <BASIC AUTH PASSWORD>
      token: <BEARER TOKEN>
    tls:
      ca_file: <PATH TO SERVER CA>
      cert_file: <PATH TO CLIENT CERT>
      key_file: <PATH TO CLIENT KEY>
      insecure_skip_verify: <SKIP TLS CERT VERIFICATION BOOLEAN>

Reference #