반응형

 


 


설정 및 테스트한 날짜:  2023년 2월 7일

 

Harbor Registry  같은 private container image registry에 kubernetes가 접근하려면 kubernetes의 secret 리소스를 생성해줘야 한다.

kubernetes에 image registry의 credential(자격 증명)을 어떻게 등록하는지 알아보자~

 

 


설정에 관한 자세한 설명을 보고 싶다면, 아래 문서를 참고.
  참고 문서:   Private registry에서 image 받아오기

 

 

프라이빗 레지스트리에서 이미지 받아오기

이 페이지는 프라이빗 컨테이너 레지스트리나 리포지터리로부터 이미지를 받아오기 위해 시크릿(Secret)을 사용하는 파드를 생성하는 방법을 보여준다. 현재 많은 곳에서 프라이빗 레지스트리가

kubernetes.io

 

 

Harbor registry에 접근할 수 있는 credential을 등록하기 위해 아래의 예제를 따라서 실행한다. 

## regcred 라는 이름의 secret 리소스를 생성한다.

$  kubectl create secret docker-registry regcred --docker-server=registry.sejong.cluster --docker-username=myusername --docker-password=mypassword

## 위에서 생성한 regcred secret 리소스 내용을 확인한다.

$  kubectl get secret regcred --output=yaml

apiVersion: v1
kind: Secret
metadata:
  ...
  name: regcred
  ...
data:
  .dockerconfigjson: eyJodHRwczovL2luZGV4L ... J0QUl6RTIifX0=
type: kubernetes.io/dockerconfigjson

$

## 참고 정보:
##   - .dockerconfigjson 필드는 registry 자격 증명 값의 base64 인코딩한 결과이다.
##   - .dockerconfigjson 필드의 값을 눈으로 볼 수 있도록 base64 decoding한다. (아래와 같이)

$ kubectl get secret regcred --output="jsonpath={.data.\.dockerconfigjson}" | base64 --decode

{"auths":{"registry.sejong.cluster":{"username":"myusername","password":"mypassword","auth":"c3R...zE2"}}}

$

## 위 출력 내용 중에서 'auth' 값을 아래와 같이 base64 decoding한다.

$  echo "c3R...zE2" | base64 --decode

myusername:mypassword

$

 

Kubernetes master node, worker node에 Insecure registry를 등록한다.

만약, 10개의 node가 있다면 10개 모두 동일하게 작업해줘야 한다. (아~  귀찮아 ㅠㅠ)

참고로, OKD 또는 Red Hat OCP를 사용한다면 아래처럼 kubernetes node에 직접 접속해서 수작업으로 설정하지 않아도 된다.
$  vi /etc/crio/crio.conf

...

insecure_registries = [
"registry.sejong.cluster"
]

...

$  systemctl restart crio

$  systemctl status crio

 

 

설정 작업이 끝났으면, 테스트~

 

아래와 같은 예제 Pod를 구동하여 Image pulling이 잘 되는지 확인한다.

 

 

$  cat my-pod-example.yaml

apiVersion: v1
kind: Pod
metadata:
  name: almighty
  labels:
    app: almighty
spec:
  terminationGracePeriodSeconds: 3
  containers:
  - name: almighty
    image: registry.sejong.cluster/scope/almighty:0.2.4
       
$   kubectl apply -f my-pod-example.yaml

pod/almighty created

$  kubectl get pod

NAME           READY   STATUS    RESTARTS   AGE
pod/almighty   1/1     Running   0          3s

$

 

Great !!!  잘 동작한다.

 

 


 

블로그 작성자: sejong.jeonjo@gmail.com

 

반응형

`kubectl apply` 명령을 통해서 container image를 pull하려면, Docker 회사의 container image pulling에 대한 rate limit 정책 때문에 docker.io 또는 docker.com에서 image를 pulling하지 못하는 경우가 있다.

그래서 일반적으로 docker.com에 회원 가입하고, 무제한으로 image pulling 할 수 있도록 유료 서비스도 이용하는데, `docker login ....` 그리고 `docker image pull ...`하는 것은 잘 되지만, kubectl 명령으로 pod의 container image를 pulling하려면 rate limit제약이 있다. 바로 해당 Pod의 'imagePullSecret' 정보가 없이  때문이다. Pod가 생성될 때, Pod의 manifest에 있는 imagePullSecret 정보를 보고, Container Image Registry에 인증 요청을 하는 것인데 대부분 Pod manifest에 이 imagePullSecret 정보를 설정하지 않는다. (일부러 안 하는 것은 아니고, 이런 것이 있는 줄 모르니까 사용자들이 실수를 한다)

 

가장 흔한 Use Case가 namespace 마다 Docker Registry에 접속할 수 있는 secret을 등록하고, Pod manifest에 이 secret을 참조하도록 하는 것이다.  그런데 이것도 실제 사용하려면 문제가 있다. 내가 직접 작성한 Pod manifest라면, imagePullSecret을 추가하면 끝날 일이지만 istio처럼 istioctl 이라는 명령이 내부적으로 pod manifest를 생성해서 pod 생성을 시도하는 경우라면, imagePullSecret을 내 마음대로 추가하기 어렵다.

 

그래서~  나는 어떻게 이 문제를 풀어야 하지? ㅠㅠ

 

 

우선 즉흥적으로 생각나는 대로 메모를 해보면,  (깊게 생각한다고 풀릴 문제는 아닌 듯...)

  • Cluster 전체에서 공용으로 imagePullSecret을 사용할 수 있도록 설정하는 기능이 있는지 확인한다.
  • ServiceAccount에 Secret을 등록하고, 항상 이 ServiceAccount로 생성되는 Pod에 imagePullSecret을 사용할 수 있도록 한다.
  • istioctl 같은 별개의 deployment 관리 명령이 있는 경우라면, istioctl option 중에서 imagePullSecret을 설정하는 parameter가 있는지 찾아본다.

Web Docs를 잘 찾아보니까, 고맙게도 kubernetes.io의 Web Docs에 내가 고민하고 있는 내용을 잘 설명해주고 있다.

https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry

 

Images

A container image represents binary data that encapsulates an application and all its software dependencies. Container images are executable software bundles that can run standalone and that make very well defined assumptions about their runtime environmen

kubernetes.io

 

 

위 Web Docs에서는 아래의 4 가지 답안을 줬는데, 가장 사람 손을 덜 타는 (A) 방법으로 문제를 풀어봤다.

 

(A) Configuring Nodes to Authenticate to a Private Registry      ## 내가 선택한 해결 방법
    - all pods can read any configured private registries
    - requires node configuration by cluster administrator

(B) Pre-pulled Images
    - all pods can use any images cached on a node
    - requires root access to all nodes to setup

(C) Specifying ImagePullSecrets on a Pod
    - only pods which provide own keys can access the private registry

(D) Vendor-specific or local extensions
    - if you're using a custom node configuration,
       you (or your cloud provider) can implement your mechanism for authenticating the node to the container registry.

 

 

그래서 위 (A) 방법대로 문제를 해결했다~  자세한 절차는 아래 Web Docs에 있다.  단순하게 따라하면 잘 동작한다.


https://kubernetes.io/docs/concepts/containers/images/#configuring-nodes-to-authenticate-to-a-private-registry

위 원문을 조금 요약해보자면 아래와 같다.

##
## If you run Docker on your nodes, 
## you can configure the Docker container runtime to authenticate to a private container registry.
## This approach is suitable if you can control node configuration.

## Here are the recommended steps to configuring your nodes to use a private registry. 
## In this example, run these on your desktop/laptop PC:

##   1. Run docker login "docker.io" for each set of credentials you want to use. 
##      This updates $HOME/.docker/config.json on your PC.
##   2. View $HOME/.docker/config.json in an editor to ensure it contains only the credentials you want to use.
##   3. Get a list of your nodes; for example:
##     - if you want the names: 
##       nodes=$( kubectl get nodes -o jsonpath='{range.items[*].metadata}{.name} {end}' )
##     - if you want to get the IP addresses: 
##       nodes=$( kubectl get nodes -o jsonpath='{range .items[*].status.addresses[?(@.type=="ExternalIP")]}{.address} {end}' )
##   4. Copy your local .docker/config.json to one of the search paths list above.
##     - for example, to test this out: 
##       for n in $nodes; do scp ~/.docker/config.json root@"$n":/var/lib/kubelet/config.json; done
##

위 설명대로 /root/.docker/config.json 파일을 모든 master node, worker node의 /var/lib/kubelet/config.json 경로에 복사한 후에 아래와 같이 Pod를 deploy하면서  docker.io에서 rate limit이 걸리지 않고 container image를 pulling 할 수 있는지 확인한다. 

 

$  kubectl  apply -f -  <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: busybox-sleep
spec:
  containers:
  - name: busybox
    image: busybox
    imagePullPolicy: Always
    args:
    - sleep
    - "1000000"
EOF

pod/busybox-sleep created

$ kubectl get pod
NAME            READY   STATUS    RESTARTS   AGE
busybox-sleep   1/1     Running   0          7s
$

 

주의:
나는 docker.io 유료 가입자이다.  이 글을 읽는 분도 본인이 사용하는 kubernetes cluster가 container image pulling rate limit 없이 동작하게 하려면 꼭 docker.io에 유료 가입해야 한다)

 

 

참고:

가장 일반적인 Use Case는 아래와 같이 namespace에 secret을 생성하고, 이 regcred 라는 secret을 Pod manifest에서 참조하도록 한다. 그런데, 모든 Pod의 manifest를 수정해야 하는 노동력이 추가되므로 이 방법을 권장하지 않는다.

(아마 imagePullSecret 정보를 자동으로 patch해주는 Mutating Admission Controller / WebHook Server를 만들어서 나의 Kubernetes Cluster에 추가해주면 사람이 개입할 일은 없겠지만, Webhook Server를 작성하는 것도 일인지라... ㅠㅠ)

 

$  kubectl create  -n ${MY-NS}  secret docker-registry  regcred  --docker-server=docker.io  --docker-username=${MYID}  --docker-password=${MYPW}

 

 

참고:

이 container image pulling rate limit 해결 방법은 순정 kubernetes cluster에서만 유효하고, Red Hat Openshift(OCP)는 Docker Registry 인증 문제를 해결하는 방식이 다르다. (결론만 말하자면, Red Hat OCP 쪽이 더 명령이 간단하고 쉽게 해결된다)

Red Hat에 비용을 내고 기술 지원 서비스를 받으면, Red Hat 직원이 알아서 해결해줬기 때문에 굳이 남의 밥벌이 영역의 일을 이렇게 공개된 글에 올리는 것은 예의가 아닌 것 같아서, Red Hat OCP에서의 Docker Registry 인증 문제에 대한 해결 방법은 언급하진 않겠다.

 

+ Recent posts