Container Orchestration/Kubernetes

Kubernetes 컨테이너 이미지 생성하기

Somaz 2022. 5. 10. 17:35
728x90
반응형

Overview

 

컨테이너 이미지를 만들자.

쿠버네티스를 이용해 서비스를 하려면 컨테이너화된 앱(컨테이너 이미지)가 필요하다.

여기선 간단히 hello + 서버의 호스트네임을 출력하는 웹앱 컨테이너 이미지를 만들 것이다.

호스트네임을 출력하는 이유는 차후 로드밸런싱이 잘 되는지(컨테이너가 바뀌면서 응답하는 건지) 확인하기 위해 위와 같이 만들기로 하였다.

  • 웹서버 : apache + CGI
  • 언어 : python
  • 로직 : hello + 서버의 hostname을 출력.

위와 같은 컨테이너 이미지를 만들자.

 

 

Docker

Docker CLI는 컨테이너 이미지를 만드는 기능을 지원한다.

우리가 사용하는 crictl은 컨테이너 이미지를 만드는 기능이 없다..

결론은 도커가 설치된 서버가 필요하다.

 

빌드머신

도커를 설치한 가상머신을 추가로 만들자.

이 머신은 컨테이너 이미지 빌드머신으로 사용한다.

  • hostname : d-img-build
  • ip : 192.168.xxx.241
  • os : debian bullseye

 

VM 생성하기(KVM)

 

qcow2 타입 디스크 생성

$ qemu-img create -f qcow2 d-img-build.qcow2 200G
Formatting 'd-img-build.qcow2', fmt=qcow2 size=214748364800 cluster_size=65536 lazy_refcounts=off refcount_bits=16

 

저번에 만들어놨던 k8s.sh 쉘을 이용하도록 하자.

$ vi k8s.sh

virt-install --virt-type kvm --name d-img-build \
  --ram 2096 \
  --cpu=host \
  --vcpus=2 \
  --os-type=debian \
  --os-variant=debianwheezy \
  --disk path=/data/dong/disk/d-img-build.qcow2,format=qcow2,bus=virtio \
  --cdrom=/data/dong/iso/debian-11.3.0-amd64-netinst.iso \
  --network bridge=mgmt,model=virtio --graphics vnc,listen=0.0.0.0

orchard@durant:/data/dong/shell$ ./k8s.sh

 

IP와 포트를 확인하자.

$ virsh dumpxml d-img-build | less
// vnc 포트확인

$ ip a | grep virbr0

 

vnc로 접속해서 설치를 완료해주자.

 

그리고 이제 도커를 설치하자.

 

apt가 HTTPS를 통해 저장소를 사용할 수 있도록 필수 패키지를 설치

$ sudo apt-get install \
     apt-transport-https \
     ca-certificates \
     curl \
     gnupg2 \
     software-properties-common

 

docker의 공식 GPG 키 추가

$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -

 

저장소 설정

$ sudo add-apt-repository \
> "deb [arch=amd64] https://download.docker.com/linux/debian \
> $(lsb_release -cs) \
> stable"

 

docekr ce 설치

$ sudo apt update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

 

docekr 작동확인

$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete 
Digest: sha256:10d7d58d5ebd2a652f4d93fdd86da8f265f5318c6a73cc5b6a9798ff6d2b2e67
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
  • 확인완료

 

 

Docker CLI를 이용하여 컨테이너 이미지를 만드는 방법은 2가지다.

  1. Dockerfile 로 만드는 방법
  2. 기존 이미지를 수정하여 commit 하는 방법

 

1번의 경우 모든 설정을 스크립트로 작성해야 하는데, 이것으로 해보도록 하자.

 

Dockerfile?

내가 만들 컨테이너 이미지를 Dockerfile에 잘 작성하면 도커는 Dockerfile을 토대로 컨테이너 이미지를 만들어 준다.

 

Dockerfile docs

 

Dockerfile reference

 

docs.docker.com

 

 

Dockerfile에 작성할 리스트를 정리하자.

  1. 필수 패키지를 설치한다.
  2. 아파치 설정파일을 수정한다.
  3. 파이썬 코드를 작성하고 실행권한을 준다.
  4. cgi 기능을 켠다.
  5. 아파치를 재시작한다.

위 작업 리스트를 Dockerfile로 정의하면 아래와 같다.

 

  • FROM : 베이스 이미지를 의미.
  • MAINTAINER : 관리자를 의미.
  • LABEL : 라벨의 의미.
  • USER : user를 의미. 아래 RUN 커맨드를 root로 실행함.
  • RUN : 이미지를 만드는 동안 실행할 명령.
  • COPY : 이미지 안에 넣을 파일을 복사.
  • EXPOSE : 컨테이너가 listen할 포트번호.
  • ENTRYPOINT 컨테이너가 실행될때 실행할 명령어.

Dockerfile의 ENTRYPOINT, CMD, RUN는 모두 커맨드를 실행하는데 이들의 차이가 있다.

 

 

Docker RUN vs CMD vs ENTRYPOINT

Some Docker instructions look similar and cause confusion among developers who just started using Docker or do it irregularly. In this post I will explain the difference between CMD, RUN, and ENTRYPOINT on examples. In a nutshell RUN executes command(s) in

codewithyury.com

 

000-default.conf 파일과 index.py 파일을 만들자.

$ cat 000-default.conf 
<VirtualHost *:80>

           ServerAdmin webmaster@localhost
           DocumentRoot /var/www/html
     
           <Directory /var/www/html>
               DirectoryIndex index.py
                       AddHandler cgi-script .py
                       Options ExecCGI
              </Directory>
    
          ErrorLog ${APACHE_LOG_DIR}/error.log
          CustomLog ${APACHE_LOG_DIR}/access.log combined
    
      </VirtualHost>

아파치 설정파일이다.

  • 6 ~ 10 라인을 추가했다.
  • DirectoryIndex index.py : index.html 대신 index.py를 도큐먼트루트에서 찾도록 수정했다.
  • 8 ~ 9 라인은 아파치 웹서버와 파이썬을 연동하기 위해 중간에 cgi(common gateway interface)가 실행되도록 하였다.

 

파이썬 코드를 작성한다.

$ cat index.py 
#!/usr/bin/python3

import socket

hostname = socket.gethostname()

print("content-type:text/html; charset=UTF-8\n")
print("hello!" + " " + hostname)

 

Dockerfile을 이미지로 빌드하자.

$ cat Dockerfile 
FROM       debian:latest
MAINTAINER DongHyung LEE <somaz@iorchard.co.kr>
LABEL      version="2.0"

USER       root
RUN    apt-get update && \
       apt-get upgrade -y && \
       apt-get install -y apt-utils apache2 python3 && \
       apt-get clean && \
       rm -fr /var/lib/apt/lists/*

COPY       000-default.conf /etc/apache2/sites-available/
COPY       index.py /var/www/html/

EXPOSE     80
ENTRYPOINT chmod a+x /var/www/html/index.py && \
       a2enmod cgid && \
       apache2ctl -D FOREGROUND

 

$ sudo docker build -t webapp:2.0 .
Sending build context to Docker daemon  19.97kB
Step 1/9 : FROM       debian:latest
 ---> a11311205db1
Step 2/9 : MAINTAINER DongHyung LEE <somaz@iorchard.co.kr>
 ---> Running in dae4e0098b21
Removing intermediate container dae4e0098b21
 ---> 0931e098c835
Step 3/9 : LABEL      version="2.0"
 ---> Running in 0a4ebab501d5
Removing intermediate container 0a4ebab501d5
 ---> f4de83e0ae7f
Step 4/9 : USER       root
 ---> Running in 12530a3ebbad
Removing intermediate container 12530a3ebbad
 ---> b4d5b2eec9fb
Step 5/9 : RUN    apt-get update &&        apt-get upgrade -y &&        apt-get install -y apt-utils apache2 python3 &&        apt-get clean &&        rm -fr /var/lib/apt/lists/*
 ---> Running in 32b63228c278
Get:1 http://security.debian.org/debian-security bullseye-security InRelease [44.1 kB]
Get:2 http://deb.debian.org/debian bullseye InRelease [116 kB]
Get:3 http://deb.debian.org/debian bullseye-updates InRelease [39.4 kB]
Get:4 http://security.debian.org/debian-security bullseye-security/main amd64 Packages [127 kB]
Get:5 http://deb.debian.org/debian bullseye/main amd64 Packages [8182 kB]
Get:6 http://deb.debian.org/debian bullseye-updates/main amd64 Packages [2596 B]
...
Removing intermediate container 32b63228c278
 ---> 78f956b41057
Step 6/9 : COPY       000-default.conf /etc/apache2/sites-available/
 ---> 9bf585c9a0e4
Step 7/9 : COPY       index.py /var/www/html/
 ---> bfe927a3636a
Step 8/9 : EXPOSE     80
 ---> Running in 898ed21c353b
Removing intermediate container 898ed21c353b
 ---> d3bc82af3c27
Step 9/9 : ENTRYPOINT chmod a+x /var/www/html/index.py &&        a2enmod cgid &&        apache2ctl -D FOREGROUND
 ---> Running in 3d487e0aed98
Removing intermediate container 3d487e0aed98
 ---> e4de4ea12351
Successfully built e4de4ea12351
Successfully tagged webapp:2.0
  • step 1 ~ 9 를 진행하며, 컨테이너 이미지가 완성된다.
  • 내부적으로는 임시 컨테이너를 띄우고 Dockerfile 내의 라인을 하나씩 수행한다.
  • 즉, Dockerfile 내의 라인의 순서가 의미가 있다는 것이니 고려하여 잘 작성해야 한다.

 

이제 webapp:2.0 이미지로부터 컨테이너를 만들고 잘 작동하는지 확인한다.

$ sudo docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
webapp        2.0       e4de4ea12351   4 minutes ago   263MB
debian        latest    a11311205db1   2 weeks ago     124MB
hello-world   latest    feb5d9fea6a5   7 months ago    13.3kB
orchard@d-img-build:~$ sudo docker run -d -p 9999:80 webapp:2.0
3c0bdfd3089e754026fe48206d9b34ae0706192b2c51fc38f7fccfa27a5c5101
orchard@d-img-build:~$ curl http://localhost:9999
hello! 3c0bdfd3089e
orchard@d-img-build:~$ sudo docker ps -a | grep 3c0bdfd3089e
3c0bdfd3089e   webapp:2.0    "/bin/sh -c 'chmod a…"   22 seconds ago   Up 21 seconds               0.0.0.0:9999->80/tcp, :::9999->80/tcp   dazzling_spence
  • 방금만든 3c0bdfd3089e 컨테이너가 HTTP request에 대한 응답을 잘 했다.

 

이제 이 이미지(webapp:2.0)를 쿠버네티스로 배포하자.

그런데 이 이미지를 가져다 쓰려면 이미지 저장소(registry)에 push 해야 한다.

 

Docker registry

docker registry의 자세한 설명은 아래 docs를 참조하자.

 

Docker Registry

 

docs.docker.com

 

 

registry?

Docker 레지스트리는 Docker 이미지를 저장하는 저장소다.

예들들어 비교하자면 Git Hub와 비슷하다. 깃 허브에 저장소를 만들어 소스를 push, pull 하는 것 처럼, docker 이미지를 저장(docker push) 하여 필요할때 가져다 쓴다.(docker pull)

docker registry는 공개 저장소인 Docker Hub에 저장할 수도 있고, private 저장소를 만들어 사용할 수도 있다.

Docker Hub

먼저 Docker Hub에 push 하도록 하는 방법을 알아보자.

  • Docker Hub 에 이미지를 push 하려면 Docker Hub 계정이 있어야 한다.
  • Docker Hub에 이미지를 올리려면 이미지 이름을 아래와 같은 형식으로 만들어야 한다.
    • [Registry RUL]/[사용자 ID]/[이미지 이름]:[Tag]
    • Registry RUL은 기본값으로 DockerHub를 바라보고 있다.
    • 사용자 ID를 지정하지 않으면 기본값(library)가 사용된다.
    • 따라서 debian = library/debian = docker.io/library/debian 모두 같은 표현이다.

 

1.) Docker Hub 에 접속하여 아이디를 만든다.

 

2.) Docker 계정으로 로그인한다.

$ sudo docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: somaz94
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

 

3.) 이미지 태그

이미지를 태그하자 docker tag명령으로 위에서 만든 이미지에 계정정보와 버전을 추가할 수 있다.

  • docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] 와 같은 형식으로 지정한다.

 

 

태그를 만들자.

$ sudo docker tag webapp:2.0 somaz94/webapp:2.0
$ sudo docker images
REPOSITORY       TAG       IMAGE ID       CREATED          SIZE
webapp           2.0       e4de4ea12351   25 minutes ago   263MB
somaz94/webapp   2.0       e4de4ea12351   25 minutes ago   263MB
debian           latest    a11311205db1   2 weeks ago      124MB
hello-world      latest    feb5d9fea6a5   7 months ago     13.3kB
  • 기존 webapp:2.0이미지에 somaz94(계정아이디), webapp(이미지 이름), tag(2.0)을 추가하였다.

 

4.) push

이제 이미지를 Docker Hub에 있는 나의 repo 에 푸쉬한다.

$ sudo docker push somaz94/webapp:2.0
The push refers to repository [docker.io/somaz94/webapp]
e3938a4f31a9: Pushed 
493f14571f73: Pushed 
dea8e891a387: Pushed 
a13c519c6361: Mounted from library/debian 
2.0: digest: sha256:547a6c5e81ae4214c18b6b1d585c6dd8c2cc219b5b848e439bb51feb671e2331 size: 1155
  • 이렇게 하면 Docker Hub의 내 계정에 로그인하면 webapp 이라는 repo가 생성되고 그 안에 이미지가 저장된다.

이제 어디서든 나의 webapp:2.0 컨테이너 이미지를 사용할 수 있게 되었다.

 

 

Private Docker Registry

Docker Hub 에 비공개로 이미지를 저장하려면 돈을 내야 한다.

그래도 많은 기능을 제공해주니 감사하다.

그리고 사설 Docker Registry는 도커를 이용하여 쉽게 만들 수 있다. 폐쇄망 환경에서 유용하게 사용하면 되겠다.

도커 레지스트리를 만들자.

$ sudo docker run -d \
> -v /data/registry:/var/lib/registry \
> -p 5000:5000 \
> distribution/registry
Unable to find image 'distribution/registry:latest' locally
latest: Pulling from distribution/registry
90f4dba627d6: Pull complete 
6ca70669e0c7: Pull complete 
8afccc587e11: Pull complete 
5d5d4c33684a: Pull complete 
6865c91bf9e0: Pull complete 
24ec77c4f34d: Pull complete 
d998fd3ae604: Pull complete 
9ae2aa709472: Pull complete 
dfbbb717df56: Pull complete 
9f9a21385c8d: Pull complete 
30cb17477211: Pull complete 
Digest: sha256:910528144c2dcbfbf1ee85b9b3c8b8312ef4222e61e7d6282b0b17d6e363611c
Status: Downloaded newer image for distribution/registry:latest
5b919677c19b7253e4b313b6db1be4c73ebb0721358471a719e365a3d42db754

 

도커 이미지를 저장할 레지스트리 정보를 포함하여 Tag를 부여하자.

$ sudo docker tag webapp:2.0 localhost:5000/somaz94/webapp:2.0

$ sudo docker images
REPOSITORY                      TAG       IMAGE ID       CREATED          SIZE
webapp                          2.0       e4de4ea12351   31 minutes ago   263MB
somaz94/webapp                  2.0       e4de4ea12351   31 minutes ago   263MB
localhost:5000/somaz94/webapp   2.0       e4de4ea12351   32 minutes ago   263MB
debian                          latest    a11311205db1   2 weeks ago      124MB
hello-world                     latest    feb5d9fea6a5   7 months ago     13.3kB
distribution/registry           latest    71b9fde93b3f   3 years ago      299MB

 

이제 이미지를 사설 레지스트리로 푸쉬하자.

$ sudo docker push localhost:5000/somaz94/webapp:2.0
The push refers to repository [localhost:5000/somaz94/webapp]
e3938a4f31a9: Pushed 
493f14571f73: Pushed 
dea8e891a387: Pushed 
a13c519c6361: Pushed 
2.0: digest: sha256:547a6c5e81ae4214c18b6b1d585c6dd8c2cc219b5b848e439bb51feb671e2331 size: 1155

 

  • 성공!

레지스트리 디렉토리에 잘 저장 되었는지 살펴보자.

orchard@d-img-build:~$ sudo apt install tree

orchard@d-img-build:~$ sudo tree /data/registry/
/data/registry/
`-- docker
    `-- registry
        `-- v2
            |-- blobs
            |   `-- sha256
            |       |-- 07
            |       |   `-- 07d8d21ad875e9b0848254744495a7cd2f78db7cac5948586bf84a36e4038c76
            |       |       `-- data
            |       |-- 14
            |       |   `-- 1480138896cc1ac68e70b6018ef04145a1824ae9e9607c1109e384c1003dccf7
            |       |       `-- data
            |       |-- 54
            |       |   `-- 547a6c5e81ae4214c18b6b1d585c6dd8c2cc219b5b848e439bb51feb671e2331
            |       |       `-- data
            |       |-- 6a
            |       |   `-- 6aefca2dc61dcbcd268b8a9861e552f9cdb69e57242faec64ac120d2355a9c1a
            |       |       `-- data
            |       |-- b1
            |       |   `-- b1d18bc9fff044687b23a411dd7079364f773cf91625822b8a44ec84fdf14641
            |       |       `-- data
            |       `-- e4
            |           `-- e4de4ea123515a0870c98884b890779eed81495f99b7bedf6c1492d800c57b8f
            |               `-- data
            `-- repositories
                `-- somaz94
                    `-- webapp
                        |-- _layers
                        |   `-- sha256
                        |       |-- 07d8d21ad875e9b0848254744495a7cd2f78db7cac5948586bf84a36e4038c76
                        |       |   `-- link
                        |       |-- 1480138896cc1ac68e70b6018ef04145a1824ae9e9607c1109e384c1003dccf7
                        |       |   `-- link
                        |       |-- 6aefca2dc61dcbcd268b8a9861e552f9cdb69e57242faec64ac120d2355a9c1a
                        |       |   `-- link
                        |       |-- b1d18bc9fff044687b23a411dd7079364f773cf91625822b8a44ec84fdf14641
                        |       |   `-- link
                        |       `-- e4de4ea123515a0870c98884b890779eed81495f99b7bedf6c1492d800c57b8f
                        |           `-- link
                        |-- _manifests
                        |   |-- revisions
                        |   |   `-- sha256
                        |   |       `-- 547a6c5e81ae4214c18b6b1d585c6dd8c2cc219b5b848e439bb51feb671e2331
                        |   |           `-- link
                        |   `-- tags
                        |       `-- 2.0
                        |           |-- current
                        |           |   `-- link
                        |           `-- index
                        |               `-- sha256
                        |                   `-- 547a6c5e81ae4214c18b6b1d585c6dd8c2cc219b5b848e439bb51feb671e2331
                        |                       `-- link
                        `-- _uploads

38 directories, 14 files

 

  • 잘 저장되었다!

이제 컨테이너 이미지는 준비되었으니, 쿠버네티스로 배포하자.!

 

배포는 다음 문서에서 진행하도록 하겠다.

 

이상입니다. 

728x90
반응형