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가지다.
- Dockerfile 로 만드는 방법
- 기존 이미지를 수정하여 commit 하는 방법
1번의 경우 모든 설정을 스크립트로 작성해야 하는데, 이것으로 해보도록 하자.
Dockerfile?
내가 만들 컨테이너 이미지를 Dockerfile에 잘 작성하면 도커는 Dockerfile을 토대로 컨테이너 이미지를 만들어 준다.
Dockerfile docs
Dockerfile에 작성할 리스트를 정리하자.
- 필수 패키지를 설치한다.
- 아파치 설정파일을 수정한다.
- 파이썬 코드를 작성하고 실행권한을 준다.
- cgi 기능을 켠다.
- 아파치를 재시작한다.
위 작업 리스트를 Dockerfile로 정의하면 아래와 같다.
- FROM : 베이스 이미지를 의미.
- MAINTAINER : 관리자를 의미.
- LABEL : 라벨의 의미.
- USER : user를 의미. 아래 RUN 커맨드를 root로 실행함.
- RUN : 이미지를 만드는 동안 실행할 명령.
- COPY : 이미지 안에 넣을 파일을 복사.
- EXPOSE : 컨테이너가 listen할 포트번호.
- ENTRYPOINT 컨테이너가 실행될때 실행할 명령어.
Dockerfile의 ENTRYPOINT, CMD, RUN는 모두 커맨드를 실행하는데 이들의 차이가 있다.
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 해야 한다.
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 모두 같은 표현이다.
$ 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
- 잘 저장되었다!
이제 컨테이너 이미지는 준비되었으니, 쿠버네티스로 배포하자.!
배포는 다음 문서에서 진행하도록 하겠다.
이상입니다.
'Container Orchestration > Kubernetes' 카테고리의 다른 글
Kubernetes Probe (Liveness, Readiness, Startup) (0) | 2022.07.15 |
---|---|
Kubernetes 어피니티 (0) | 2022.05.13 |
Kubernetes 클러스터 구축하기(kubespray) (0) | 2022.05.10 |
Kubernetes 클러스터 구축하기(kubeadm) (0) | 2022.05.03 |
쿠버네티스 배포 도구 : Kubeadm vs Kubespray vs Kops (0) | 2022.05.03 |