ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Kubernetes] private docker registry Pod 설치
    인프라/Kubernetes 2020. 12. 2. 10:32

    Docker Registry

     

    Configuring a registry

     

    docs.docker.com

     

    # vi docker-registry.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: docker-registry
      namespace: infra
      labels:
        app: docker-registry #label
    spec:
      #nodeName: kube-node2 #node를 지정해도되고 안해도됨
      #nodeSelector: // node labels를 지정해도 됨
        #kubernetes.io/hostname: kube-node2
      containers:
      - name: docker-registry
        image: registry:2.7.1
        ports:
        - containerPort: 5000 #registry 기본 port
        volumeMounts:
        - mountPath: /var/lib/registry #container directory
          name: host-path #아래에 volumes name
      volumes: #host pc volume생성
      - name: host-path
        hostPath:
          path: /docker-registry
          type: DirectoryOrCreate
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: docker-registry
      namespace: infra
    spec:
      type: NodePort
      selector:
        app: docker-registry
      ports:
        - protocol: TCP
          port: 5000
          targetPort: 5000
          nodePort: 30500

    registry를 kubernetes Pod로 띄우고 외부에서 30500포트로 접근하기위해 yaml을 작성해준다. (1개의 Pdo만 띄우기 위해서 Deployment를 통해 생성하지 않았다.)

    spec.containers.image: registry:2.7.1 은 docker-hub에 있는 official registry container 이다.

    Pod가 생성될 Node에 volumeMounts를 설정했는데 registry 기본 config.yml을 보면

    version: 0.1
    log:
      fields:
        service: registry
    storage:
      cache:
        blobdescriptor: inmemory
      filesystem:
        rootdirectory: /var/lib/registry
    http:
      addr: :5000
      headers:
        X-Content-Type-Options: [nosniff]
    health:
      storagedriver:
        enabled: true
        interval: 10s
        threshold: 3

    storage.filesystem.rootdirectory의 경로에 images들이 저장된다.

     

    # kubectl get pods -n infra -o wide
    NAME              READY   STATUS    RESTARTS   AGE    IP             NODE         NOMINATED NODE   READINESS GATES
    docker-registry   1/1     Running   1          136m   172.16.0.107   kube-node2   <none>           <none>

    생성된 Node를 찾아가 보면 volume hostPath type DirectoryOrCreate 로 인해서 자동생성된 directory를 볼 수 있다.

    # ls -l / | grep docker-registry
    drwxr-xr-x.   3 root root   20 12월  1 14:26 docker-registry

    생성할 수 있는 자세한 volume 유형은 여기를 참조

     

    {hostip}:30500 로 api를 날려서 정상 실행여부를 확인해보자

    curl -v 192.168.5.1:30500/v2
    * About to connect() to 192.168.5.1 port 30500 (#0)
    *   Trying 192.168.5.1...
    * Connected to 192.168.5.1 (192.168.5.1) port 30500 (#0)
    > GET /v2 HTTP/1.1
    > User-Agent: curl/7.29.0
    > Host: 192.168.5.1:30500
    > Accept: */*
    >
    < HTTP/1.1 301 Moved Permanently
    < Content-Type: text/html; charset=utf-8
    < Docker-Distribution-Api-Version: registry/2.0
    < Location: /v2/
    < Date: Tue, 01 Dec 2020 08:00:49 GMT
    < Content-Length: 39
    <
    <a href="/v2/">Moved Permanently</a>.
    
    * Connection #0 to host 192.168.5.1 left intact

    이렇게 나온다면 정상적으로 registry가 떠있다는 것이다.

     

    그럼 이제 image를 push해보자.

    # vi Dockerfile
    FROM ubuntu:12.04
    RUN mkdir /test

    테스트용으로 ubuntu에 /test 디렉로리만 생성한 image를 생성해보자

    # docker build -t 192.168.5.1:30500/test:v1.0 .
    Sending build context to Docker daemon  4.608kB
    Step 1/2 : FROM ubuntu:12.04
     ---> 5b117edd0b76
    Step 2/2 : RUN mkdir /test
     ---> Running in 2ad98801e2c4
    Removing intermediate container 2ad98801e2c4
     ---> b924a4ba8074
    Successfully built b924a4ba8074
    Successfully tagged 192.168.5.1:30500/test:v1.0
    

    -t 옵션으로 REPOSITORY경로ImageName:Tag로 Dockerfile을 build하자

    # docker images
    REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
    192.168.5.1:30500/test               v1.0                b924a4ba8074        50 seconds ago      104MB

    제대로 생성된것을 확인하고 push를 해보자

    # docker push 192.168.5.1:30500/test:v1.0
    The push refers to repository [192.168.5.1:30500/test]
    Get https://192.168.5.1:30500/v2/: http: server gave HTTP response to HTTPS client

    server gave HTTP response to HTTPS client라는 오류가 뜨면서 실패한다.

    이는 docker push나 pull이 https로 동작하기 때문인데, 우리가 설치한 registry가 http로만 현재 동작하고 있기 때문이라고 한다. 그래서 push나, pull을 할 때 보안이 적용되지 않도록 insecure 설정을 해주어야한다.

     

    [Kubernetes] 쿠버네티스 설치하기 (1) - Container runtimes 를 통해 docker를 설치하였다면 /etc/docker/daemon.json 를 통해 dockerd의 설정을 하였을 것이다. 이부분야 insecure 설정을 추가해주자.

    # vi /etc/docker/daemon.json
    {
      "exec-opts": ["native.cgroupdriver=systemd"],
      "log-driver": "json-file",
      "log-opts": {
        "max-size": "100m"
      },
      "storage-driver": "overlay2",
      "storage-opts": [
        "overlay2.override_kernel_check=true"
      ],
      "insecure-registries" : ["docker-registry.com:30500"]
    }

     

    ip로 설정하지않고 domain name (docker-registry.com) 으로 설정해 놓았다. /etc/hosts파일에 설정해놓고 사용하면 ip가 바뀌어도 아무런 영향이 없기 때문에 위와같이 설정하겠다.

    "insecure-registries" 설정을 통해 docker 에서 우리가 만든 private docker registry의 ip:port로의 통신은 보안을 무시하게 해준다. (docs.docker.com/registry/insecure/)를 살펴보면

    • If HTTPS is available but the certificate is invalid, ignore the error about the certificate.
    • If HTTPS is not available, fall back to HTTP.

    증명서 무시, https가 불가능하면 http로 변경해서 보내게 해준다고 한다.

     

    # vi /etc/hosts
    192.168.5.1 docker-registry.com

    위와같이 hosts 파일에 본인의 host ip를 설정해주자. 그리고 restart!

     

    systemctl restart docker

     

    # docker rmi 192.168.5.1:30500/test:v1.0
    Untagged: 192.168.5.1:30500/test:v1.0
    Deleted: sha256:b924a4ba807463d9301c2bf30ccb65d3032e7aa03ce751efe765b02a820dc039
    Deleted: sha256:8aca5f5c3a1ec66b0b06ab11b2b33847edc180d125407053391edf8aec6f0b35

    ip로 설정되어있던 image를 삭제 후

     

    # docker build -t docker-registry.com:30500/test:v1.0 .
    Sending build context to Docker daemon  4.608kB
    Step 1/2 : FROM ubuntu:12.04
     ---> 5b117edd0b76
    Step 2/2 : RUN mkdir /test
     ---> Running in 2f706b4beb8d
    Removing intermediate container 2f706b4beb8d
     ---> 00c57a0e17c4
    Successfully built 00c57a0e17c4
    Successfully tagged docker-registry.com:30500/test:v1.0

    domain name을 사용하여 새로 만들어주자.

    # docker images
    REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
    docker-registry.com:30500/test       v1.0                00c57a0e17c4        29 seconds ago      104MB

     

    # docker push docker-registry.com:30500/test:v1.0

    그리고 다시한번 push를 실행해보자! ip를 domain name으로 변경하였다.

    # docker push docker-registry.com:30500/test:v1.0
    The push refers to repository [docker-registry.com:30500/test]
    4756cb421d70: Pushed
    3efd1f7c01f6: Layer already exists
    73b4683e66e8: Layer already exists
    ee60293db08f: Layer already exists
    9dc188d975fd: Layer already exists
    58bcc73dcf40: Layer already exists
    v1.0: digest: sha256:18dfa93ff7781705b7a917ba9d5ae0d2972a181b7fcb0c2f827d15e1cd71fb91 size: 1566

    pushed가 성공하였다! (Layer already exists는 이전에 같은걸 넣어놔서 뜬것이므로 무시해도 된다)

     

    # curl docker-registry.com:30500/v2/_catalog
    {"repositories":["test"]}

    curl을 통해 등록된 repositories를 확인해보면 정상적으로 들어가 있는것을 확인할 수 있다.

    # curl docker-registry.com:30500/v2/test/tags/list
    {"name":"test","tags":["v1.0"]}

    test image의 tags도 확인

     

    # kubectl exec docker-registry -n infra -- ls -l /var/lib/registry/docker/registry/v2/repositories/test/_manifests/tags/
    total 0
    drwxr-xr-x    4 root     root            34 Dec  1 07:06 v1.0

    이렇게 실제 Pod 안에 reposoitories 를 살펴봐도 test가 생성되어 있는것을 확인할 수 있다.

     

    # ll /docker-registry/docker/registry/v2/repositories/test/_manifests/tags/
    합계 0
    drwxr-xr-x. 4 root root 34 12월  1 16:06 v1.0
    

    volumeMount 했던 Node에서도 생성되어 있는것을 확인할 수 있다.

    Pod 내부에 application을 확인해보니 시간이 안맞다 ... 이 부분도 나중에 확인해야할 듯 싶다.

     

    # docker rmi docker-registry.com:30500/test:v1.0
    Untagged: docker-registry.com:30500/test:v1.0
    Untagged: docker-registry.com:30500/test@sha256:18dfa93ff7781705b7a917ba9d5ae0d2972a181b7fcb0c2f827d15e1cd71fb91
    Deleted: sha256:00c57a0e17c409690e0073e6a033935fce8fb04e8b680b80a78c03fa04bbb5fd
    Deleted: sha256:3b290c2dffe58dd36be164bf08a5940285405daf2f4bc994857e47b65ba6d0b2

    지우고 다시 pull도 받아보자

    # docker pull docker-registry.com:30500/test:v1.0
    v1.0: Pulling from test
    396e9d6ee8c9: Already exists
    403b0fc2e6f1: Already exists
    7124ef1a91d2: Already exists
    f47441d15565: Already exists
    588e8920e707: Already exists
    6dbaa51c9a68: Pull complete
    Digest: sha256:18dfa93ff7781705b7a917ba9d5ae0d2972a181b7fcb0c2f827d15e1cd71fb91
    Status: Downloaded newer image for docker-registry.com:30500/test:v1.0
    docker-registry.com:30500/test:v1.0
    # docker images
    REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
    docker-registry.com:30500/test       v1.0                00c57a0e17c4        22 minutes ago      104MB

    잘 동작한다.

     

    자 push를 통해서 image를 생성하였으니 이젠 해당 image를 Pod로 띄워보자!

    # vi test.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: test
      labels:
        app: test #label
    spec:
      nodeName: kube-node2
      containers:
      - name: test
        image: docker-registry.com:30500/test:v1.0
        ports:
        - containerPort: 80
        command: ["/bin/sh"]
        args: ["-c", "while true; do echo hello; sleep 5;done"]

     

    test로 띄울 Pod yaml을 생성 nodeName으로 난 특정 Node에 띄우도록 하였다.

    그리고 image가 아무것도 실행하고 있지않아 container가 바로 종료하는것을 방지하기위해 command, args를 이용하여 shellscript를 실행하였다.

     

    # kubectl apply -f test.yaml
    pod/test created
    # kubectl get pods -o wide
    NAME       READY   STATUS             RESTARTS   AGE   IP             NODE         NOMINATED NODE   READINESS GATES
    test       0/1     ImagePullBackOff   0          83s   172.16.0.109   kube-node2   <none>           <none>
    

     

    그러나 위와같이 ImagePullBackOff 상태가 되면서 실패할 것이다!

    # kubectl describe pods/test
    .
    .
    .
    Events:
      Type     Reason   Age                From     Message
      ----     ------   ----               ----     -------
      Normal   Pulling  12s (x3 over 53s)  kubelet  Pulling image "docker-registry.com:30500/test:v1.0"
      Warning  Failed   12s (x3 over 53s)  kubelet  Failed to pull image "docker-registry.com:30500/test:v1.0": rpc error: code = Unknown desc = Error response from daemon: Get https://docker-registry.com:30500/v2/: dial tcp: lookup docker-registry.com on 192.168.5.254:53: no such host
      Warning  Failed   12s (x3 over 53s)  kubelet  Error: ErrImagePull
      Normal   BackOff  1s (x4 over 53s)   kubelet  Back-off pulling image "docker-registry.com:30500/test:v1.0"
      Warning  Failed   1s (x4 over 53s)   kubelet  Error: ImagePullBackOff
    

    docker-registry.com을 찾지못해서 pull에 실패하였다.

    해당 node에도 /etc/hosts에 docker-registry.com을 추가하여주자.

    # kubectl delete -f test.yaml
    pod "test" deleted
    # kubectl apply -f test.yaml
    pod/test created

    삭제했다가 다시 생성

    # kubectl describe pods/test
    Events:
      Type     Reason          Age                From     Message
      ----     ------          ----               ----     -------
      Normal   Pulling         14s                kubelet  Pulling image "docker-registry.com:30500/test:v1.0"
      Warning  Failed          14s                kubelet  Failed to pull image "docker-registry.com:30500/test:v1.0": rpc error: code = Unknown desc = Error response from daemon: Get https://docker-registry.com:30500/v2/: http: server gave HTTP response to HTTPS client
      Warning  Failed          14s                kubelet  Error: ErrImagePull
      Normal   SandboxChanged  13s                kubelet  Pod sandbox changed, it will be killed and re-created.
      Normal   BackOff         11s (x3 over 12s)  kubelet  Back-off pulling image "docker-registry.com:30500/test:v1.0"
      Warning  Failed          11s (x3 over 12s)  kubelet  Error: ImagePullBackOff

    docker-registry.com은 찾았으나, 여전히 실패할 것이다.

    위에서 docker push 했을 때와 같은 오류가 발생할 것이다.

    이는 해당 Node의 docker를 이용해서 pull을 받는 것이기 때문에 Node에 daemon.json 설정에도 insecure을 설정해 주어야한다. /etc/docker/daemon.json에 위처럼 insecure를 추가후 docker를 재시작 해주자!

    그리고 다시 생성하면 그제서야 정상적으로 생성이된다!

    Events:
      Type    Reason   Age   From     Message
      ----    ------   ----  ----     -------
      Normal  Pulled   11s   kubelet  Container image "docker-registry.com:30500/test:v1.0" already present on machine
      Normal  Created  11s   kubelet  Created container test
      Normal  Started  11s   kubelet  Started container test
    # kubectl get pods/test -o wide
    NAME   READY   STATUS    RESTARTS   AGE     IP             NODE         NOMINATED NODE   READINESS GATES
    test   1/1     Running   0          6m33s   172.16.0.115   kube-node2   <none>           <none>
    # kubectl exec test -- ls / | grep test
    test

    container내부에 /test 디렉토리가 있는것도 확인

     

    [root@kube-node2 ~]# docker ps
    CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS               NAMES
    970114cc25e3        00c57a0e17c4           "/bin/sh -c 'while t…"   7 minutes ago       Up 7 minutes                            k8s_test_test_default_8e825cfd-a8c3-4438-ad3d-8659d42065b5_0
    ed0c2fd23ad2        k8s.gcr.io/pause:3.2   "/pause"                 7 minutes ago       Up 7 minutes                            k8s_POD_test_default_8e825cfd-a8c3-4438-ad3d-8659d42065b5_0

    실제 생성된 kube-node2에도 확인

     

    마지막으로 docker registry pod를 삭제했다가 다시 생성해도 volume설정이 제대로 동작하는지 보자

    # kubectl delete -f docker-registry.yaml
    pod "docker-registry" deleted
    service "docker-registry" deleted
    # kubectl get pods -n infra
    No resources found in infra namespace.
    # kubectl apply -f docker-registry.yaml
    pod/docker-registry created
    service/docker-registry created
    # kubectl get pods -n infra
    NAME              READY   STATUS    RESTARTS   AGE
    docker-registry   1/1     Running   0          105s
    # curl docker-registry.com:30500/v2/_catalog
    {"repositories":["test"]}

    확인 완료!

     


    앞으로 진행될 image들은 모두 private docker registry를 이용하여 저장하면 될 것 같다.

    그리고 모든 Node의 docker daemon.json 설정파일에 insecure-registries 설정을 전부 해주도록 하자

    댓글

Designed by Tistory.