[Docker] Dockerfile 이미지 빌드

gununoo·2022년 8월 17일
2

Docker

목록 보기
2/8
post-thumbnail

OCI와 CRI

OCI(OPen Container Initiative)

  • 컨테이너 표준기술. chroot, cgroup, namespace에 대한 표준 제정
  • chroot: 일반 사용자가 컨테이너 내부로 들어갔을 경우 수퍼유저인 root 로 작업할 수 있도록해준다
  • cgroup: namespace 를 통해 구획이 나뉜 각 컨테이너별로 별도의 자원사용량을 제공하는 것(cpu, ram)
  • namespace: 각각의 컨테이너 별로 별도의 작업 공간을 제공하고 각 컨테이너 별로 서로 간에 영향을 끼치지 않도록 구획을 나누겠다.

CRI(Container Runtime Interface)

  • Kubelet이 컨테이너를 제어할 수 있도록 해주는 인터페이스.
일반 리눅스에서의 namespace 	 	httpd:ftp:nfs
도커(컨테이너)에서의 namespace		컨테이너(1111):컨테이너(1112):컨테이너(1113) 
k8s에서의 namespace				각 사용자별로 별도의 작업 공간을 제공 

쿠버네티스: 컨테이너 '오케스트레이션' 툴. 일반적으로 오케스트레이션은 컨테이너 '클러스터' 환경에서 이루어지게 된다.
애플리케이션은 '배포'한다.
시스템(서버, 네트워크, 볼륨)은 '프로비저닝' 한다.

배포와 프로비전은 일반적으로 여러 컨테이너, 서버, 네트워크, 볼륨 등을 연계하여 구성해야 하는 복잡한 과정이다. 하나의 작업을 수동으로 한 뒤 이를 묶는 작업은 복잡하므로 'IaC(Infrastructure as Code, 코드형 인프라)'를 도입하여 yml과 같은 파일 형태로 작성한 뒤 이를 활용하여 환경을 구성하는 형식으로 변화하고 있다.

docker-compose.yml: 컨테이너 환경
cloudformation: aws 에서 서버 인프라 환경
heat: openstack 에서 서버 인프라 환경
terraform

도커

docker 컨테이너의 일반적인 라이프사이클

출처: https://medium.com/better-programming/docker-for-front-end-developers-c758a44e622f

컨테이너의 모든 통신은 shim을 통해 이루어지게 되고 해당 내용은 shim에서 containerd와 통신을 통해 관리된다. shim은 컨테이너의 입출력, 로그를 d에게 전달한다.

rapa@rapa:~$ pstree -p | grep containerd
           |-containerd(835)-+-{containerd}(872)
           |                 |-{containerd}(873)
           |                 |-{containerd}(874)
           |                 |-{containerd}(877)
           |                 |-{containerd}(878)
           |                 |-{containerd}(930)
           |                 |-{containerd}(931)
           |                 `-{containerd}(983)
           |-containerd-shim(1465)-+-mysqld(1520)-+-{mysqld}(1657)
           |                       |-{containerd-shim}(1467)
           |                       |-{containerd-shim}(1468)
           |                       |-{containerd-shim}(1469)
           |                       |-{containerd-shim}(1472)
           |                       |-{containerd-shim}(1473)
           |                       |-{containerd-shim}(1474)
           |                       |-{containerd-shim}(1476)
           |                       |-{containerd-shim}(1480)
           |                       |-{containerd-shim}(1481)
           |                       |-{containerd-shim}(1857)
           |                       `-{containerd-shim}(2586)
           |-containerd-shim(1896)-+-mysqld(1929)-+-{mysqld}(2087)
           |                       |-{containerd-shim}(1897)
           |                       |-{containerd-shim}(1898)
           |                       |-{containerd-shim}(1899)
           |                       |-{containerd-shim}(1900)
           |                       |-{containerd-shim}(1901)
           |                       |-{containerd-shim}(1902)
           |                       |-{containerd-shim}(1903)
           |                       |-{containerd-shim}(1904)
           |                       |-{containerd-shim}(1905)
           |                       |-{containerd-shim}(1906)
           |                       `-{containerd-shim}(49446)
           |-containerd-shim(2702)-+-apache2(2722)-+-apache2(2801)
           |                       |-{containerd-shim}(2703)
           |                       |-{containerd-shim}(2704)
           |                       |-{containerd-shim}(2705)
           |                       |-{containerd-shim}(2706)
           |                       |-{containerd-shim}(2707)
           |                       |-{containerd-shim}(2708)
           |                       |-{containerd-shim}(2709)
           |                       |-{containerd-shim}(2710)
           |                       |-{containerd-shim}(2711)
           |                       |-{containerd-shim}(2742)
           |                       `-{containerd-shim}(3681)
           
rapa@rapa:~$ pstree -p | grep dockerd
           |-dockerd(982)-+-docker-proxy(1406)-+-{docker-proxy}(1415)
           |              |-{dockerd}(1011)
           |              |-{dockerd}(1013)
           |              |-{dockerd}(1014)
           |              |-{dockerd}(1016)
           |              |-{dockerd}(1047)
           |              |-{dockerd}(1079)
           |              |-{dockerd}(1085)
           |              |-{dockerd}(1443)
           |              |-{dockerd}(1445)
           |              `-{dockerd}(2187)

컨테이너는 이미지로부터 배포된다. 이미지는 iso 파일과 같이 정적인 파일이다. 따라서 추가 작성된 내용은 기본적으로 저장되지 않는다. 이를 해결하기 위해서는 별도의 볼륨을 사용해야 한다.

볼륨의 종류

  • nfs(binding): 호스트의 특정 디렉토리와 컨테이너의 특정 디렉토리를 마운트
/root/test:/var/www/html 
  • iSCSI(volume): 별도의 볼륨을 생성하고 해당 볼륨을 컨테이너의 특정 디스크로 활용하는 방법
testvolume:/root 

/root는 /dev/sda3과 같이 특정 파티션이 된다.

  • tmpfs: 디스크/스토리지의 특정 공간을 사용하는 것이 아니라 메모리를 사용하는 방법이다. 속도가 빠른 대신 영구 보관은 불가능하다.

이미지의 저장소

  • pulblic registry: docker hub. 불특정 다수가 접속할 수 있는 공간
  • private registry: 특정 사용자나 그룹 사용자가 접속할 수 있는 공간
  • local registry: 도커 데몬이 동작하는 내 컴퓨터

관리를 위한 명령들

  • docker container ls --all: 동작/중지 중인 모든 컨테이너 리스트 확인
  • docker image ls: 로컬 저장소에 있는 이미지들의 리스트 확인
  • docker container run: 생성 + 시작
  • docker container stop: 중지
  • docker container rm -f: 강제 삭제

컨테이너 실행을 위한 옵션들

  • -i: 대화식으로 컨테이너에게 명령 전달 가능
  • -t: ssh와 같은 연결 방법을 제공한다.
    컨테이너에 직접 들어가지 않고 외부(호스트)에서 명령을 전달하고 결과값도 호스트에서 받고 싶다면
docker container exec [ctname] [command] 
  • -d: 컨테이너를 백그라운드에서 동작시킨다.
  • --restart=always: 데몬 실행과 함꼐 자동으로 컨테이너가 실행된다.
  • --restart=on-failure: 처음 컨테이너 시작 시 또는 생성 시 정상 실행이 되지 않거나 정상 생성이 되지 않는 경우 계속해서 실행을 시도할 수 있다.
  • -v: 볼륨 제공, 비슷한 옵션으로 --mount도 사용 가능하다. mount는 과거에는 compose에서만 사용이 가능했으나 17버전 이후부터는 container run에서도 사용이 가능하게 되었다.
  • -h(--hostname): 컨테이너 내에서 사용하는 호스트명
  • --name: 관리를 위한 목적으로 컨테이너의 이름을 지정할 수 있다.
  • -p: 호스트의 특정 포트와 컨테이너의 특정 포트를 매핑
  • -P: 호스트의 랜덤 포트와 컨테이너의 특정 포트를 매핑
  • --link: 두 개 이상의 컨테이너를 연결하는 방법으로 IP가 아닌 이름으로 연결할 수 있다.
    link 옵션은 compose에서는 더 이상 사용하지 않는다.
--link dbctn:mysql 

컨테이너의 종류

  • os 컨테이너: centos, fedora, ubuntu 등
  • 애플리케이션 컨테이너: httpd, node, python 등

모든 컨테이너 삭제하기

rapa@rapa:~$ docker container ls --all -q
ded23beec1eaf
ee334749beb7
1c8382045175

rapa@rapa:~$ docker container rm -f $(docker container ls --all -q)
ed23beec1eaf
ee334749beb7
1c8382045175

rapa@rapa:~$ docker container ls --all 
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

centos7 컨테이너 배포

rapa@rapa:~$ docker container run -it \
> --name centos1 \
> --hostname test \
> centos:7 \
> /bin/bash

[root@test /]# hostname 
test

[root@test /]# cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2      test

# 호스트(우분투)의 커널을 사용 중
[root@test /]# uname -a
Linux test 5.15.0-46-generic #49~20.04.1-Ubuntu SMP Thu Aug 4 19:15:44 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

# ctrl + p, q 눌러서 호스트(우분투)로 빠져나오기 
[root@test /]# rapa@rapa:~$ 

# centos1 컨테이너가 종료되지 않고 실행 중임 
rapa@rapa:~$ docker container ls
CONTAINER ID   IMAGE      COMMAND       CREATED              STATUS              PORTS     NAMES
abbbbef3ef3d   centos:7   "/bin/bash"   About a minute ago   Up About a minute             centos1

볼륨 삭제

rapa@rapa:~$ docker volume ls -q
1931215e79c48a93df85bb4312dc400850b5f8236e875d39397cb7d4dbeb7b92
cea6d051284adc616cb33f95fc5bcdeb82a7956266c7ffd40bb3bd8e9467e771
e382fc7aeafdf4e741bdd92673f0c2347ae5a7d028fd1ff0de036bb8eaed3427
f1fe96aab7edffd26795998469821081c242ec858bfc33b51c6a89cc6bf35354

rapa@rapa:~$ docker volume rm $(docker volume ls -q) 
1931215e79c48a93df85bb4312dc400850b5f8236e875d39397cb7d4dbeb7b92
cea6d051284adc616cb33f95fc5bcdeb82a7956266c7ffd40bb3bd8e9467e771
e382fc7aeafdf4e741bdd92673f0c2347ae5a7d028fd1ff0de036bb8eaed3427
f1fe96aab7edffd26795998469821081c242ec858bfc33b51c6a89cc6bf35354

볼륨

  • 볼륨 생성
rapa@rapa:~$ docker volume create testvol1
testvol1
  • 볼륨 마운트 된 컨테이너 배포
rapa@rapa:~$ docker container run -it \
> --name centos01 \
> -v testvol1:/root \
> centos:7 /bin/bash 

[root@0a7fa257afd2 /]# df -h | grep /root
/dev/sda5        20G   10G  8.1G  56% /root
[root@0a7fa257afd2 /]#   

20GB 중에서 10GB 사용 중
20GB는 호스트(우분투)의 전체 저장공간이다. 이 저장 공간은 flexible하다.
만약 볼륨의 크기를 지정하여 사용하고 싶다면 외부 플러그인을 활용해야 한다.

  • 볼륨 확인하기
[root@0a7fa257afd2 /]# touch /root/test.txt
[root@0a7fa257afd2 /]# ls /root
anaconda-ks.cfg  test.txt
[root@0a7fa257afd2 /]# exit
exit

rapa@rapa:~$ docker container ls --all
CONTAINER ID   IMAGE      COMMAND       CREATED         STATUS                      PORTS     NAMES
0a7fa257afd2   centos:7   "/bin/bash"   4 minutes ago   Exited (0) 16 seconds ago             centos01

rapa@rapa:~$ docker volume ls
DRIVER    VOLUME NAME
local     testvol1
  • 컨테이너를 삭제해도 볼륨이 남아있음
rapa@rapa:~$ docker container rm centos01
centos01

rapa@rapa:~$ docker volume ls
DRIVER    VOLUME NAME
local     testvol1
  • 기존 볼륨을 새로운 컨테이너(centos02)에 연결
rapa@rapa:~$ docker container run -it \
> --name centos02 \
> -v testvol1:/root \
> centos:7 /bin/bash
  • 기존 컨테이너에서 생성했던 파일을 여전히 볼 수 있음
[root@6d9132fb36fc /]# ls /root
anaconda-ks.cfg  test.txt

[root@6d9132fb36fc /]# df -h | grep root
/dev/sda5        20G   10G  8.1G  56% /root
  • 이미지 inspect
rapa@rapa:~$ docker container inspect centos02
            "Labels": {
                "org.label-schema.build-date": "20201113",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS",
                "org.opencontainers.image.created": "2020-11-13 00:00:00+00:00",
                "org.opencontainers.image.licenses": "GPL-2.0-only",
                "org.opencontainers.image.title": "CentOS Base Image",
                "org.opencontainers.image.vendor": "CentOS"
            }

Label

  • label을 부여하여 이미지 배포 -> color=blue
rapa@rapa:~$ docker container run -it \
> --name centos03 \
> --label color=blue \
> centos:7 /bin/bash
[root@c5fd36fc4cb0 /]# 
  • inspcet해서 label 확인
rapa@rapa:~$ docker container inspect centos03
		...
        "Config": {
        ...
            "Labels": {
                "color": "blue",
                "org.label-schema.build-date": "20201113",
                "org.label-schema.license": "GPLv2",
                "org.label-schema.name": "CentOS Base Image",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.vendor": "CentOS",
                "org.opencontainers.image.created": "2020-11-13 00:00:00+00:00",
                "org.opencontainers.image.licenses": "GPL-2.0-only",
                "org.opencontainers.image.title": "CentOS Base Image",
                "org.opencontainers.image.vendor": "CentOS"
            }
        },
        ...
  • format 옵션으로 label 확인
rapa@rapa:~$ docker container inspect centos03 -f "{{.Config.Labels.color}}"
blue

도커 네트워크

  • format 옵션으로 ip주소 확인
rapa@rapa:~$ docker container inspect centos03 -f "{{.NetworkSettings.IPAddress}}"
172.17.0.3
  • docker0의 ip 확인
rapa@rapa:~$ ifconfig docker0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        inet6 fe80::42:8aff:fe84:b19b  prefixlen 64  scopeid 0x20<link>
        ether 02:42:8a:84:b1:9b  txqueuelen 0  (Ethernet)
        RX packets 1549  bytes 3350197 (3.3 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1453  bytes 1890942 (1.8 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

docker0는 도커가 설치되면 자동으로 생성되는 네트워크 브릿지이며 NAT를 통해 컨테이너를 외부와 연결시켜준다.

  • 도커 네트워크: bridge, host, null
    • bridge: NAT를 통해 외부와 연결한다.
    • host: 호스트의 주소를 컨테이너와 동일하게 취급한다.
    • null: 네트워크를 사용하지 않는다.
rapa@rapa:~$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
060582ca6c67   bridge    bridge    local
3ead376f089f   host      host      local
39430d1f4412   none      null      local

swarm과 같은 클러스터 환경에서는 'overlay' 드라이버가 생성된다. 이는 kvm과 같은 환경에서 터널을 구성했던 작업이 생략된다.

실습 - mysql, 워드프레스 배포

워드프레스 구축하기

  • 실제 환경에서는 php 설치, apache 설치, mariadb(mysql) 설치, wordpress 소스코드가 필요하다. 하지만 컨테이너를 이용하게 되면 이를 두 개의 컨테이너에 구성할 수 있다.
  1. mysql 이미지 -> 배포 -> DB 컨테이너
  2. wordpress 이미지 -> 배포 -> WP 컨테이너
  • mysql 컨테이너(wpdb) 배포
rapa@rapa:~$ docker container run -d \
> --name wpdb \
> -v wpdbvol:/var/lib/mysql \
> --restart=always \
> -e MSYQL_ROOT_PASSWORD=test123 \
> -e MYSQL_DATABASE=wordpress \
> mysql:5.7
9873794e595e7191cab4d272ede90eafeaf2441df0a5064b6e46fe712676b24a
  • wordpress 컨테이너(wp) 배포
rapa@rapa:~$ docker container run -d \
> --restart=always \
> -p 8080:80 \
> --name wp \
> -e WORDPRESS_DB_PASSWORD=test123 \
> -e WORDPRESS_DB_NAME=wordpress \
> -e WORDPRESS_DB_USER=root \
> --link wpdb:mysql \
> -v wpvol:/var/www/html \
> wordpress
43c48c907ef964a08322120e7bf597cb8c407942605384e71b08a800f3253b3c

--link wpdb:mysql
mysql 컨테이너(wpdb)와 링크 설정

윈도우에서 211.183.3.137:8080 접속
-> 워드프레스가 성공적으로 배포되었다.

rapa@rapa:~$ sudo ls /var/lib/docker 
buildkit  containers  image  network  overlay2  plugins  runtimes  swarm  tmp  trust  volumes

rapa@rapa:~$ sudo ls /var/lib/docker/containers
43c48c907ef964a08322120e7bf597cb8c407942605384e71b08a800f3253b3c  9873794e595e7191cab4d272ede90eafeaf2441df0a5064b6e46fe712676b24a
6d9132fb36fcd968036777f6f575153b29648b1790be4b5fad9f1be440b1afe4  c5fd36fc4cb0f5b38f43da7a0fec86ee5d9bfd9a459da3ce34b813f1f607e826

rapa@rapa:~$ sudo ls /var/lib/docker/volumes
backingFsBlockDev  metadata.db  testvol1  wpdbvol  wpvol

실습 - cAdvisor 배포

  • 컨테이너 모니터링 도구 cAdvisor 배포
rapa@rapa:~$ docker container run -d \
> -v /:/rootfs:ro \
> -v /var/run:/var/run:rw \
> -v /sys:/sys:ro \
> -v /var/lib/docker/:/var/lib/docker:ro \
> -p 9559:8080 \
> --name cadvisor \
> google/cadvisor:latest

Unable to find image 'google/cadvisor:latest' locally
latest: Pulling from google/cadvisor
ff3a5c916c92: Pull complete 
44a45bb65cdf: Pull complete 
0bbe1a2fe2a6: Pull complete 
Digest: sha256:815386ebbe9a3490f38785ab11bda34ec8dacf4634af77b8912832d4f85dca04
Status: Downloaded newer image for google/cadvisor:latest
14399e870de93f7d51820b616ea68a79e842a0cf91fc4369dce263fa156660c6


쿠버네티스

컨테이너나 서비스를 직접 만드는 도구는 아니다. 컨테이너, 네트워크, 볼륨 등을 관리(오케스트레이션)하는 도구이다. 실제 컨테이너를 만드는 역할은 runtime이 수행하게 된다. 이 runtime으로 docker(containerd), cri-o, podman, rocket 등을 사용할 수 있고, 쿠버네티스는 모든 런타임과 통신이 가능하다. 이로 인해 사실상 컨테이너 오케스트레이션의 표준으로 불린다.

볼륨의 경우 도커에서는 현재 로컬에 있는 볼륨을 사용하고 있다. 클라우드 환경에서는 외부에 있는 별도의 스토리지의 볼륨을 마운트하여 사용해야 영구적으로 볼륨을 사용할 수 있다. 이러한 볼륨을 영구 볼륨(Persistent Volume)이라 부른다.

개발자가 요청하는 볼륨을 IP정보나 마운트 타입에 관계 없이 조건만 부합한다면 자동으로 마운트 될 수 있는 방법을 제공해야 한다. 이를 Kubernetes에서는 PVC(Persistent Volume Claim)라고 한다.
개발자(PVC) ---> 스토리지(PV)
필요할 때마다 그때 그때 볼륨을 제공하는 방법은 storage class라는 방법을 사용하면 편리하다.


  • 활용되지 않고 있는 자원 삭제하기
rapa@rapa:~$ docker network prune
WARNING! This will remove all custom networks not used by at least one container.
Are you sure you want to continue? [y/N] y 

rapa@rapa:~$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

rapa@rapa:~$ docker system prune 
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all dangling images
  - all dangling build cache

Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

도커 이미지 만들기

  1. 동작 중인 컨테이너를 이미지로 변환 -> commit
  2. tar 파일을 이용하여 내용을 이미지로 전송하는 방식으로 새로운 이미지 만들기 -> image save
    3⭐. Dockerfile 이용하여 이미지 생성하기 -> 일종의 명세서를 작성하는 방법
  • Dockerfile 생성
rapa@rapa:~/0818$ vi Dockerfile 
  • Dockerfile 작성
FROM centos:7
  • 도커 build
rapa@rapa:~/0818$ docker build -t test:1.0 .
Sending build context to Docker daemon  2.048kB
Step 1/1 : FROM centos:7
 ---> eeb6ee3f44bd
Successfully built eeb6ee3f44bd
Successfully tagged test:1.0

-> 두 파일의 id는 같다

  • 하나의 이미지를 둘이 같이 쓰고 있다.
rapa@rapa:~/0818$ docker image inspect test:1.0 
        "RepoTags": [
            "centos:7",
            "test:1.0"
        ],
  • Env: 환경 변수 지정
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
            ],
  • Cmd: 컨테이너로 실행할 때 실행하는 명령
            "Cmd": [
                "/bin/bash"
            ],
  • Entrypoint: 컨테이너로 실행할 때 실행하는 명령. cmd와 유사하지만 인자 값을 사용하는 경우에 사용.
            "Entrypoint": null,

자주 사용하는 옵션들

RUN

  • 명령어 작성, 이미지에 패키지 설치, 업데이트 등의 명령을 실행하고자 하는 경우 작성한다. 여러 번 사용할 수 있음

[쉘 형식]

FROM centos:7

RUN yum -y update
RUN yum -y install httpd 

[exec 형식]

RUN ["echo", "이것은 테스트입니다"]

-> 리스트 형식으로 작성

CMD

  • 컨테이너로 배포될 때 실행할 명령어
    ex) nginx
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ",
                "CMD [\"nginx\" \"-g\" \"daemon off;\"]"
            ],
CMD nginx -g 'daemon off;'

또는

CMD ["nginx", "-g", "Daemon off;"]

ex) httpd

            "Cmd": [
                "httpd-foreground"
            ],

ENTRYPOINT

  • 컨테이너로 배포될 때 사용하는 명령어
ENTRYPOINT nginx -g 'daemon off,'

CMD와 ENTRYPOINT

  • 둘 다 Dockerfile 내에서 한 번만 사용해야 한다. 여러 번 사용하면 마지막 라인만 처리된다.

ex) test:1.0

FROM ubuntu
ENTRYPOINT ["top"]
CMD ["-d", "10"]

-> top: cpu 확인
-> -d 10: 10초마다 갱신

docker container run -it test:1.0 -d 2 

CMD와 ENTRYPOINT에서 실행하는 명령어가 docker container run에서 실행하는 옵션과 동일한 경우 ENTRYPOINT 모두 처리한다. 하지만 CMD는 동일 옵션이 있는 경우 docker container run에 있는 옵션만들 처리한다. ENTRYPOINT는 고정적으로 실행할 명령을 작성하고 CMD는 변경될 가능성이 있는 매개변수, 옵션 등에 대하여 지정할 떄 주로 사용한다.

추가적으로 만약 컨테이너로 배포될 때 실행해야할 명령어가 ENTRYPOINT, CMD 두 개로 너무 부족한 경우에는 shell 파일을 만들고 CMD나 ENTRYPOINT를 이용하여 해당 쉘을 실행하도록 설정한다.

COPY

호스트 환경의 파일, 디렉토리를 이미지 안에 복사하는 경우 작성한다.

FROM centos:7

RUN yum -y install httpd 
COPY index.html /var/www/html 

ADD

"COPY"를 포함한다. URL에 있는 파일을 붙여넣기 하는 것도 가능하다. 또한 패키지, 압축파일의 경우에는 이를 해제하여 내용물만 붙여넣기 할 수 있다.
단, URL 상의 tar 파일 등은 해제되지 않은 상태에서 붙여넣기 된다.

Volume

이미지에 볼륨을 할당하고자 할 때 사용한다.

VOLUME /var/log 

또는

VOLUME ["/var/log"]

EXPOSE

마치 방화벽에서 몇 번 포트를 열어놓을지 지정하는 것

FROM centos:7

RUN yum -y install httpd 
EXPOSE 80
EXPOSE 8080 

ONBUILD

ONBUILD는 이를 이용하여 베이스 이미지를 만들 때에는 필요하지 않지만 생성된 이미지를 베이스 이미지로 활용할 경우에는 사용되는 명령

WORKDIR

컨테이너 내에서 작업할 경로 설정

WORKDIR /var/www
WORKDIR /root 

USER

USER는 작업 사용자 지정하기

ARG

컨테이너가 아니라 이미지에서 사용하는 변수 지정

실습 - ONBUILD

웹 개발 팀장이 팀원들 중에 /blog를 만드는 팀에게 아래와 같이 지시했다.
www.test.com/blog
www.test.com/shop
www.test.con/news
"제가 index.html 파일을 만들테니까 blog 팀은 개발된 파일, 디렉토리를 blog.tar로 만들어서 빌드하세요."

팀장 이미지 구성(webbase)

  • 팀장 웹페이지 작성 (index.html)
rapa@rapa:~/0818$ touch index.html
rapa@rapa:~/0818$ echo "<h2>TEAM MANAGER<h2>" > index.html
rapa@rapa:~/0818$ tree
.
└── index.html
  • 팀장 Dockerfile 작성
vi Dockerfile 
FROM centos:7
RUN yum -y install httpd
EXPOSE 80
ADD index.html /var/www/html/index.html
ONBUILD ADD blog.tar /var/www/html/

CMD httpd -D FOREGROUND
rapa@rapa:~/0818$ tree
.
├── Dockerfile
└── index.html
  • 팀장 이미지(webbase) 빌드
rapa@rapa:~/0818$ docker build -t webbase:1.0 .
Sending build context to Docker daemon  3.072kB
Step 1/6 : FROM centos:7
 ---> eeb6ee3f44bd
Step 2/6 : RUN yum -y install httpd
 ---> Running in 6c92adea75f6
 Removing intermediate container 6c92adea75f6
 ---> 0e364cb2ed15
 Step 3/6 : EXPOSE 80
 ---> Running in 58e07310ee70
Removing intermediate container 58e07310ee70
 ---> f2123cc62fbc
Step 4/6 : ADD index.html /var/www/html/index.html
 ---> c1d6967b052b
Step 5/6 : ONBUILD ADD blog.tar /var/www/html/
 ---> Running in 549e6a754e1e
Removing intermediate container 549e6a754e1e
 ---> 15b4d7b4dd27
Step 6/6 : CMD httpd -D FOREGROUND
 ---> Running in 710a94b707bb
Removing intermediate container 710a94b707bb
 ---> 56a51820953a
Successfully built 56a51820953a
Successfully tagged webbase:1.0

블로그 팀원 이미지 구성(webbase:blog)

  • 블로그 팀원 웹페이지 생성 (blog.html)
rapa@rapa:~/0818$ mkdir blogdev
rapa@rapa:~/0818$ cd blogdev/
rapa@rapa:~/0818/blogdev$ mkdir blog
rapa@rapa:~/0818/blogdev$ cd blog/
rapa@rapa:~/0818/blogdev/blog$ touch blog.html
rapa@rapa:~/0818/blogdev/blog$ echo "<h2>BLOG TEAM MEMBER<h2>" > blog.html 
rapa@rapa:~/0818$ tree
.
├── blogdev
│   └── blog
│       └── blog.html
├── Dockerfile
└── index.html
  • 블로그 팀원 tar 파일 생성
rapa@rapa:~/0818/blogdev/blog$ cd ..
rapa@rapa:~/0818/blogdev$ ls
blog 
rapa@rapa:~/0818/blogdev$ tar cf blog.tar blog/*
rapa@rapa:~/0818/blogdev$ ls
blog  blog.tar
rapa@rapa:~/0818$ tree
.
├── blogdev
│   ├── blog
│   │   └── blog.html
│   └── blog.tar
├── Dockerfile
└── index.html
  • 블로그 팀원의 Dockerfile 작성
rapa@rapa:~/0818/blogdev$ touch Dockerfile
rapa@rapa:~/0818/blogdev$ vi Dockerfile 
FROM webbase:1.0
rapa@rapa:~/0818$ tree
.
├── blogdev
│   ├── blog
│   │   └── blog.html
│   ├── blog.tar
│   └── Dockerfile
├── Dockerfile
└── index.html
  • 블로그 팀원 이미지(webbase:blog) 빌드
rapa@rapa:~/0818/blogdev$ docker build -t webbase:blog .
Sending build context to Docker daemon  14.34kB
Step 1/1 : FROM webbase:1.0
# Executing 1 build trigger
 ---> c69cbc539f19
Successfully built c69cbc539f19
Successfully tagged webbase:blog
rapa@rapa:~/0818/blogdev$ docker container run -d \
> -p 8888:80 \
> webbase:blog
e137d3dd8db85d35c4414a5c686f0579020f492f38dd9631429923abbe027109

211.183.3.137:8888 접속 -> 팀장 페이지가 보임

211.183.3.137:8888/blog/blog.html -> 블로그 팀원 페이지가 보임

"ONBUILD"가 작성된 파일을 베이스 이미지로 하는 별도의 Dockerfile에서 동작하는 옵션이다.

Quiz 1 - ubuntu, nginx 배포

ubuntu 18.04 이미지를 베이스이미지로 하여 nginx를 설치하고 해당 nginx에서는 개발자가 작성한 index.html 파일이 보이도록 설정한다.
외부에서 접속 시 해당 컨테이너의 웹페이지가 보여야 하며 포트번호는 8881을 이용하여 접속할 수 있어야 한다.
단, 위의 실습 전 각 ubuntu의 ip 주소는 192.168.1.116으로 설정해야 한다.

VMnet0으로 변경하기

  • netplan 파일 설정 변경
rapa@rapa:~$ sudo vi /etc/netplan/01-network-manager-all.yaml 
  • 아래와 같이 네트워크 설정 변경 -> ip: 192.168.1.116
# Let NetworkManager manage all devices on this system
network:
  ethernets:
    ens32:
      addresses: [192.168.1.116/24]
      gateway4: 192.168.1.1
      nameservers:
        addresses: [8.8.8.8, 168.126.63.1]
      dhcp4: no
  version: 2
#  renderer: NetworkManager
  • netplan 변경 적용
rapa@rapa:~$ sudo netplan apply
  • ip 변경 확인
rapa@rapa:~$ ifconfig ens32
ens32: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.116  netmask 255.255.255.0  broadcast 192.168.1.255
        ether 00:0c:29:16:8d:3f  txqueuelen 1000  (Ethernet)
        RX packets 384329  bytes 468567019 (468.5 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 234807  bytes 207681523 (207.6 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
  • 통신 확인
rapa@rapa:~$ ping www.google.com -c 3
PING www.google.com (172.217.174.100) 56(84) bytes of data.
64 bytes from nrt12s28-in-f4.1e100.net (172.217.174.100): icmp_seq=1 ttl=111 time=32.9 ms
64 bytes from nrt12s28-in-f4.1e100.net (172.217.174.100): icmp_seq=2 ttl=111 time=31.7 ms
64 bytes from nrt12s28-in-f4.1e100.net (172.217.174.100): icmp_seq=3 ttl=111 time=32.4 ms

--- www.google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 31.718/32.312/32.866/0.469 ms

웹서비스를 위한 컨터이너의 기본 홈 디렉토리

base image 		home dir 
centos/ubuntu	/var/www/html 
httpd 			/usr/local/apache2/htdocs
nginx 			/usr/share/nginx/html 
  • Dockerfile 작성
rapa@rapa:~/0818$ vi Dockerfile 
FROM ubuntu:18.04
RUN apt-get update
RUN apt-get -y install nginx
EXPOSE 8881
ADD index.html /var/www/html/index.html

CMD nginx -g 'daemon off;'
  • 컨테이너 이미지 빌드
rapa@rapa:~/0818$ docker build -t ubuntunginx:1.0 .
Sending build context to Docker daemon   16.9kB
Step 1/6 : FROM ubuntu:18.04
 ---> 8d5df41c547b
Step 2/6 : RUN apt-get update
 ---> Using cache
 ---> ed639c80424a
Step 3/6 : RUN apt-get -y install nginx
 ---> Using cache
 ---> 0270c5c781db
Step 4/6 : EXPOSE 8881
 ---> Using cache
 ---> b94b24a98072
Step 5/6 : ADD index.html /var/www/html/index.html
 ---> Using cache
 ---> f9cb1a97131c
Step 6/6 : CMD nginx -g 'daemon off;'
 ---> Running in 3648d6ac7956
Removing intermediate container 3648d6ac7956
 ---> b26e017b5678
Successfully built b26e017b5678
Successfully tagged ubuntunginx:1.0
  • 컨테이너 배포
rapa@rapa:~/0818$ docker container run -d \
> --name ubuntunginx \
> -p 8881:80 \
> --restart=always \
> ubuntunginx:1.0

192.168.1.116:8881 접속

Quiz 2 - 컨테이너 호스팅

다음의 조건을 활용하여 배포된 컨테이너는 접속 즉시 설치 페이지에서 설치 후 게시판을 사용할 수 있어야 한다.
참고: https://missio1227.tistory.com/26

이미지												컨테이너  
centos:7을 base로 하여 xe:1.0 이미지를 만들어야 함    xe 컨테이너(xe01)
mysql 5.7 										  db 컨테이너(db01)
xe01 --(link)-- db01 
(80)			(3306)
 |
8888
  • db01 배포
rapa@rapa:~/0818$ docker container run -d \
> --name db01 \
> --restart=always \
> -e MYSQL_ROOT_PASSWORD=test123 \
> -e MYSQL_DATABASE=xeDB \
> mysql:5.7
df637eb6cbd5098412fac809002f98aa4cd4ff0a78aa9d5d758a188d6801a0e0
  • xe01용 Dockerfile 생성
rapa@rapa:~/0818$ vi Dockerfile 
FROM centos:7
EXPOSE 80

RUN yum -y install wget
RUN yum -y install unzip
RUN wget http://download.xpressengine.com/download/18325662/22756225
RUN unzip 22756225
RUN mv ./xe/* /var/www/html/
RUN chmod 777 /var/www/html/*
RUN mkdir /var/www/html/files
RUN chmod 707 /var/www/html/files

CMD httpd -D FOREGROUND
  • xe01 이미지 빌드
rapa@rapa:~/0818$ docker build -t xe01:1.0 .
  • xe01 배포
rapa@rapa:~/0818$ docker container run -it -d \
--name xe01 \
--link db01:mysql \
-p 8888:80 \
xe01:1.0 

db 호스트네임: dbcontainer의 이름 (wpdb)

요약

도커 명령어

  • docker container attach: 컨테이너로 직접 들어간다(-it 옵션을 주고 생성된 컨테이너)

  • docker container exec: 컨테이너로 직접 들어가지 않고 외부에서 컨테이너로 명령을 전달하고 결과값을 밖에서 전달받는다.

  • docker container start: 중지된 컨테이너를 실행

  • docker container run(docker run) -> 컨테이너 생성 + 실행
    1) 이미지를 로컬 저장소에서 찾는다. 없다면 기본적으로 도커 허브로 접속하여 검색한다.
    2) pull된 이미지를 이용하여 컨테이너 생성하고 실행시킨다. 실행 시 문제가 있다면 exit 상태가 된다.

    • -it: it 옵션은 일반적으로 함꼐 실행한다. 생성된 컨테이너와 직접 통신이 된다.
      ex) centos:7 /bin/bash 또는 centos:7 /bin/sh를 주로 사용한다.

    • -d: 컨테이너를 백그라운드에서 실행시킨다.

    • --name: 관리를 위한 목적으로 사용한다. 컨테이너 생성되면 각 컨테이너 별로 id, name이 할당된다. 하지만 별도로 관리의 편의를 위해 이름을 직접 지정할 수 있다. 다수의 컨테이너를 관리할 때에는 별도의 이름을 입력하는 것이 불필요한 작업이 될 것이다. 이 때에는 작성하지 않는다.

    • --restart: 처음 생성 시, 호스트 재부팅 시 컨테이너를 어떻게 실행할 것인가? 웹서버나 DB와 같이 상시 동작해야하는 컨테어너의 경우에는 초기 생성 시 --restart==always로 하여 실행에 문제가 있더라도 계속해서 실행을 시도하도록 설정해주는 것이 좋다.

    • -e(--env): 시스템 환경 변수를 견테이너에 작성한다.
      ex) -e MYSQL_DATABASE=testdb
      ex) -e PYTHON=/usr/lib/python2
      ex) -e PY3=/usr/lib/python3.4

    • -v(--volume): 볼륨 지정. 절대 경로를 쓴다면 nfs 방식으로, 상대 경로를 쓴다면 볼륨 방식으로 마운트함.

      docker container run -d \
      --name db1 \
      -v /testvolume1:/var/lib/mysql mysql:5.7

      -> nfs 마운트

      docker container run -d \
      --name db1 \
      -v testvolume1:/var/lib/mysql:ro mysql:5.7

      -> 볼륨 마운트
      :ro 옵션: read only

    • -p: 호스트의 포트와 매핑하기
      ex) -p 80:80 httpd01

    • --link

  • mysql 배포 (wpdb1)

rapa@rapa:~/0818/board$ docker container run -d \
> --name wpdb1 \
> -e MYSQL_ROOT_PASSWORD=test123 \
> -e MYSQL_DATABASE=wordpress \
> -v wpdb1:/var/lib/mysql \
> mysql:5.7
7b5b7df898e438d56dd62c788dd7a3d76370fa538e30903c1a4011b47fd8e1cd
  • wp 배포 (wp1)
rapa@rapa:~/0818/board$ docker container run -d \
> --name wp1 \
> -e WORDPRESS_DB_PASSWORD=test123 \
> -e WORDPRESS_DB_USER=root \
> -e WORDPRESS_DB_NAME=wordpress \
> -p 8001:80 \
> --link wpdb1:db1 \
> wordpress
0332b2486fc0d5281f312cdd4775975ad5c63e939c58d54cd106a78c30470f8d

--link wpdb1:db1을 통해 mysql 컨테이너와 연결함

  • wp의 hosts 정보 확인
rapa@rapa:~/0818/board$ docker container exec wp1 cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.3      db1 7b5b7df898e4 wpdb1
172.17.0.2      0332b2486fc0
172.17.0.3      db1 7b5b7df898e4 wpdb1 <--- link된 컨테이너의 ID, 이름, alias명을 IP주소와 함께 등록 
172.17.0.2      0332b2486fc0 <--- 자신의 ID와 IP 주소를 등록 

Dockerfile

  • 컨테이너(linux의 cgroup, namespace)는 이미지를 통해 배포된다.
  • 이미지를 생성하는 대표적인 방법
  1. commit은 동작 중인 컨테이너를 이미지화
  2. Dockerfile을 이용하여 build하게 되면 새로운 이미지가 생성된다.
    build할 때에는 기본적으로 Dockerfile을 인식하게 되는데 만약 다른 이름을 사용한다면?
docker build -t myimg:1.0 -f dockerfile1

일반적으로는 두 개 이상의 이미지를 생성하고자 한다면 별도의 디렉토리를 만들고 각 디렉토리에서 별도의 Dockerfile을 생성하는 형식으로 이미지를 만들게 된다.

FROM: Dockerfile의 제일 상단에는 무조건 FROM을 위치시킨다. base image를 지정하는 것이다.

MAINTAINER: 작성자 정보를 간략히 입력해 둔다. 최근에는 잘 사용하지 않고, 대신 LABEL을 쓴다.

LABEL:

LABEL author=goyangyee
LABEL email=goyangyee@test.com 
LABEL version=1.0 
LABEL desc="I love cats"

RUN: 컨테이너가 아닌 베이스 이미지 자체에 전달하는 명령어. RUN은 여러 번 사용 가능하다. 가장 많이 사용하는 명령이다.

FROM centos:7 
RUN yum -y install vim # 베이스 이미지 centos:7에게 vim을 설치한다. 

CMD: 컨테이너가 배포될 때 실행할 명령어. 가령, web서버 컨테이너를 실행시키고 싶다면 RUN으로 베이스 이미지에 웹서버를 설치하고 컨테이너가 실행될 때 웹서버 데몬이 동작해야 하므로 CMD를 이용하여 데몬 실행 명령을 전달한다.

ENTRYPOINT: 컨테이너가 배포될 떄 실행할 명령어.

CMD vs ENTRYPOINT: 한 번만 사용 가능하다.

FROM centos:7 
ENTRYPOINT top # 무조건 실행 
CMD -d 10 	   # docker run과 겹치는 옵션이면 무시됨 

위의 구성을 통해 컨테이너가 배포된다면 각 컨테이너는 컨테이너의 CPU 정보를 10초 마다 한 번 씩 갱신하여 보여준다.

docker container run -d \
-d 2 # 2초 마다 갱신한다. 

CMD는 이미지 내에 있는 정보와 docker container run에서 작성한 정보가 동일한 옵션인 경우 이미지 내에 있는 옵션은 무시된다.

만약 컨테이너로 실핼될 때 컨테이너가 동작시켜야 할 데몬이 많고 해야할 일이 많다면? shell 파일을 만들고 CMD나 ENTRYPOINT를 이용하여 해당 쉘을 실행하도록 설정한다.

ADD a.sh /root/a.sh 
CMD bash a.sh 

또는

ADD a.sh /root/a.sh 
CMD ["/bin/bash", "/root/a.sh"] 

COPY: 호스트에 있는 파일 또는 디렉토리를 이미지에 붙여넣기 한다.

ADD: COPY의 모든 기능을 포함하고 추가적으로 URL을 통해 파일을 붙여넣기 하는 것 가능하다.

ADD http://www.test.com/main.jsp /var/www/html/index.jsp 

또한

ADD website.tar.gz /var/www/html 

디렉토리를 패키지로 묶은(tar) 후 압축(gz)

ENV: 시스템 환경 변수 선언

EXPOSE: 포트 오픈. 마치 방화벽으로 포트를 여는 것과 같은 효과가 있다.

EXPOSE 80 8080 

VOLUME: docker container run -v와 동일하다.

VOLUME /var/log # 컨테이너의 /var/log를 호스트에 있는 볼륨과 연결해 준다. 

만약 볼륨 이름을 지정한다면?

VOLUME testvol1:/var/log 

ctn1이 testvol1과 연결
ctn2도 testvol1과 연결
좋은 방법이 아니기 때문에 쓰지 말 것!

만약 컨테이너의 여러 디렉토리를 볼륨과 연결하고 싶다면?

VOLUME /var/log /var/www/html /var/lib/mysql 

WORKDIR: 작업 경로 지정

WORKDIR /var/www 
...
WORKDIR /var/www/html 
... 

해당 디렉토리에서 작업이 수행됨
RUN cd [디렉토리] 명령어를 사용한다면 바로 root 경로로 돌아와버리기 때문에 해당 디렉토리에서 작업이 수행될 수 없다.

RUN cd /var/www
RUN cd /var/www/html 

yaml
key: value
value가 한 개인 경우에는 바로 옆에 띄어쓰기 후 작성
value 가 여러개인 경우 아래와 같이 리스트 형태로 작성

key:
  - value1
  - value2
profile
take a look

0개의 댓글

관련 채용 정보