컨테이너 통신
1. 컨테이너의 네트워크는 기본적으로 외부와 통신이 불가능하다.
2. 외부통신을 원하면 외부로 노출할 Port를 지정해야 한다.
3. docker run -p 옵션 사용시 외부 노출할 포트를 지정 가능하다.
예) # docker run -d -p 8080:80 --name con1 httpd
외부에서 호스트서버의 8080 포트로 요청이 들어오면 con1 컨테이너의 80 포트로 해당 요청을 포워딩한다.
EXPOSE 사용
1. EXPOSE <포트 번호>
2. EXPOSE 하나로 포트 번호를 여러 개 설정 가능하다.
3. EXPOSE는 호스트와 연결할 컨테이너의 포트 번호를 설정한다.
4. docker run --expose 옵션과 같다.
5. EXPOSE 80, EXPOSE 443 또는EXPOSE 80 443
6. Dockerfile의 EXPOSE로 포트를 설정해도 외부에 연결을 위해서는 'docker run -p' 옵션으로 포트를 셋팅 해야 컨테이너의 포트가 호스트 운영체제에 공개될 수 있다.
7. EXPOSE 구문으로 명시한 포트는 컨테이너 생성시 ‘docker run -p’을 이용해서 호스트 서버와 컨테이너로 바인딩할 포트번호를 사용자가 직접 부여한다.
8. EXPOSE 구문으로 명시한 포트는 컨테이너 생성시 'docker run -P(대문자)'을 이용해서 호스트 운영체제로 오픈 된다. 이때, 호스트 운영체제의 랜덤 포트 번호가 컨테이너의 EXPOSE 구문으로 명시한 모든 포트에 매핑 된다.
9. 컨테이너는 포트를 0번부터 65535번까지 가지고 있다.
- 실습
[root@cent1 ~]# cd lab
[root@cent1 lab]# cat Dockerfile
FROM ubuntu:14.04
MAINTAINER suye <a@b.com>
RUN apt-get update
RUN apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
RUN chown -R www-data:www-data /var/lib/nginx
VOLUME ["/data", "/etc/nginx/site-enabled", "/var/log/nginx"]
WORKDIR /etc/nginx
CMD ["nginx"]
EXPOSE 80
EXPOSE 443
[root@cent1 lab]# docker build -t codemonkyuimage:1.1 .
#컨테이너 생성과 포트지정 -p옵션 사용
[root@cent1 lab]# docker run --name test-nginx -d -p 80:80 -v /root/data:/data codemonkyuimage:1.1
#컨테이너에서 포트가 열려 있는지 확인 docker port <컨테이너 이름, ID> <포트>
[root@cent1 lab]# docker port test-nginx
#연결 테스트하기
리눅스 호스트 서버에서 웹브라우저 띄워 http://localhost:80 포트로 호스트 서버에 접근하면 컨테이너 80번 포트와 연결된다.
컨테이너 생성과 포트 지정 -P(대문자) 옵션 테스트-3
[root@cent1 lab]# docker run --name test-nginx -d -P -v /root/data:/data codemonkyuimage:1.1
58937620ca0e372b6a81c545db190d262a829b237bc6e677654ae92caee9560c
[root@cent1 lab]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
58937620ca0e codemonkyuimage:1.1 "nginx" 10 seconds ago Up 9 seconds 0.0.0.0:32769->80/tcp, 0.0.0.0:32768->443/tcp suye-nginx3
-nginx
[root@cent1 lab]# docker port test-nginx3
443/tcp -> 0.0.0.0:32768
80/tcp -> 0.0.0.0:32769
[root@cent1 lab]# docker port test-nginx3 80
0.0.0.0:32769
[root@cent1 lab]# docker port test-nginx3 443
0.0.0.0:32768
#연결 테스트하기
웹 브라우저에서 호스트서버:32768 로 연결 테스트하기
기본 브릿지 드라이버를 이용하는 컨테이너 관리
기본 브릿지 드라이버 타입의 네트워크에서는 모든 컨테이너는 서로 통신이 가능하다. (cat /etc/hosts 명령어로 서로의 ip주소를 확인, 통신 가능) 하지만 이러한 ip 구성은 영구적이지 않기 때무에 자주 통신하는 컨테이너간의 구성에는 좋지않다.(만약 컨테이너에 에러가 나서 정지되고 다시 작동시킨다면 다른ip가 할당될수도있기 때문이다.)
해결책으로 브리지타입의 네트워크를 수동으로 만들고 각각의 컨테이너와 이어주는 것을 권장한다. (컨테이너의 이름을 지정하여 특정 네트워크에 연결해주면 ip에 상관없이 관리하기 편해진다.)
- 실습 (web 서버와 db서버를 서로 항상 상호통신이 가능하도록 네트워크에 연결하여 사용해보자)
네트워크 리스트 확인
[root@cent1 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
ba1a762e4235 bridge bridge local
728ea5d39364 host host local
91a85949d047 none null local
#네트워크 testnet을 만든다.
[root@cent1 ~]# docker network create testnet
#testdb 컨테이너를 testnet 네트워크에 만든다.
[root@cent1 ~]# docker run -it -d --name testdb --network testnet ubuntu:14.04 /bin/bash
#suyeweb 컨테이너를 suyenet 네트워크에 만든다.
[root@cent1 ~]# docker run -it -d --name testweb --network testnet ubuntu:14.04 /bin/bash
#첫번째 터미널을 띄우고 testweb컨테이너에 접속한다.
[root@cent1 ~]# docker exec -it testweb /bin/bash
root@4af263fd10ab:/# hostname
4af263fd10ab
root@4af263fd10ab:/# 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.18.0.3 4af263fd10ab
중요: 호스트 이름으로 ping 테스트가 가능하다.
이유: testnet 네트워크 구성원으로 생성된 2개의 컨테이너는 상호 통신에 host명을 사용할 수 있다.
이렇게 같은 네트워크에 속한 컨테이너끼리는 컨테이너 이름으로 접속할 수 있다.
#testdb 컨테이너의 이름으로 ping 테스트를 해본다.
root@4af263fd10ab:/# ping testdb
#2번째 터미널을 띄우고 testdb 컨테이너에 접속한다.
[root@cent1 ~]# docker exec -it testdb /bin/bash
root@a928963037ce:/# hostname
a928963037ce
root@a928963037ce:/# 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.18.0.2 a928963037ce
#testweb 컨테이너 이름으로 ping테스트를 해본다.
root@a928963037ce:/# ping testweb
#2개의 터미널에서 각 컨테이너를 나온다.
exit명령어 사용
root@a928963037ce:/# exit
exit
root@4af263fd10ab:/# exit
exit
#계속 실행중인 2개의 컨테이너를 확인한다.
[root@cent1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4af263fd10ab ubuntu:14.04 "/bin/bash" 9 minutes ago Up 9 minutes testweb
a928963037ce ubuntu:14.04 "/bin/bash" 14 minutes ago Up 14 minutes testdb
#testnet 네트워크 구성 정보 상세히 출력
#컨테이너 이름 확인
[root@cent1 ~]# docker network inspect testnet
"Containers": {
"4af263fd10abcb4a680e7a689536ee68e19fb79ee339cf30098626df914f050f": {
"Name": "testweb",
"EndpointID": "eaf0ccffa1c34b1278ecb0044d58dcc6d1442095accbd08c93e24436b4049167",
"MacAddress": "02:42:ac:12:00:03",
"IPv4Address": "172.18.0.3/16",
"IPv6Address": ""
},
"a928963037ce8d2ed232a3f9a1e491393a28d155ce92c549417875829a2eb303": {
"Name": "testdb",
"EndpointID": "d56a91470e5c060f33b611a69aadc86c82b4f14fa799e3ff4ef91b33817fe051",
"MacAddress": "02:42:ac:12:00:02",
"IPv4Address": "172.18.0.2/16",
"IPv6Address": ""
}
도커 이미지 빌드(docker build) 분석
1. 하나의 Dockerfile을 이용해 만든 2개의 이미지를 분석하기
2. 이미 생성된 첫번째 이미지가 같은 내용을 사용하는 2번째 이미지를 생성시 이미 존재하는 cache를 사용한다. (실습)
- 실습
[root@cent1 ~]# cd
[root@cent1 ~]# cd lab1
#도커파일생성
[root@cent1 lab1]# cat Dockerfile
FROM ubuntu:14.04
RUN mkdir -p /lab
RUN touch /lab/file1
[root@cent1 lab1]# docker build -t codemonkyuimage:1.1 .
Sending build context to Docker daemon 3.072 kB
Step 1/3 : FROM ubuntu:14.04
---> 13b66b487594
Step 2/3 : RUN mkdir -p /lab
---> Running in 24afa1a01475
---> 0bf7053e1251
Removing intermediate container 24afa1a01475
Step 3/3 : RUN touch /lab/file1
---> Running in 04c00c83faaf
---> d9ef52ce5b0c
Removing intermediate container 04c00c83faaf
Successfully built d9ef52ce5b0c
[root@cent1 lab1]# docker build -t codemonkyuimage:1.2 .
Sending build context to Docker daemon 3.072 kB
Step 1/3 : FROM ubuntu:14.04
---> 13b66b487594
Step 2/3 : RUN mkdir -p /lab
---> Using cache
---> 0bf7053e1251
Step 3/3 : RUN touch /lab/file1
---> Using cache
---> d9ef52ce5b0c
Successfully built d9ef52ce5b0c
두 이미지 생성시 이미 존재하는 캐시 된 이미지 레이어를 그대로 사용함을 확인할 수 있다.
결과:
1. 도커 허브와 같은 레지스트리에서 최신 버전이 있는지 확인하고 빌드해야 하므로 속도가 느리다.
실무에서는 latest보다는 정확한 버전을 지정하는 방식인 태그를 사용하여 베이스 이미지를 사용하기를 권장한다.
2. 이미지 캐시사용: Docker는 이미지를 build할 때 자동으로 캐시를 생성하고 다른 이미지를 build할 때 내부의 캐시를 사용하여 build의 속도를 높일 수 있다.
Docker 사용법 (심화)
-컨테이너 생성(docker create)
-컨테이너 생성과 시작 (docker run)
-컨테이너 상태를 항상 자동으로 재시작 하도록 설정: (docker run –-restart=always)
-컨테이너 생성(docker create)
1. docker create <옵션> 이미지명 <명령어> <인자> 또는
또는 docker container create <옵션> 이미지명 <명령어> <인자>
2. Docker Container create 명령을 통해 이미지를 기반으로 컨테이너를 단순히 생성만 하고 시작은 하지 않는다. 보통은 docker run 명령어로 컨테이너 생성과 start를 함께 지원하는 명령어를 주로 사용한다.
3. 컨테이너 생성시 기본 #docker container create만 사용하면 표준 입출력이 데스크탑의 키보드와 화면에 대해 열려 있지 않다. 그래서 /bin/bash나 /bin/cal 같은 명령을 실행하고 그 입력이나 출력을 보려면 interactive 모드 (-it)옵션을 꼭 붙여줘야 한다.
EX)
# docker create -it --name testcon1 ubuntu:14.04 /bin/bash
-컨테이너 생성과 시작 (docker run)
1. docker run <옵션> 이미지명 <명령어> <인자> 또는
또는 docker container run <옵션> 이미지명 <명령어> <인자>
2. Docker run 명령어를 통해 이미지를 기반으로 컨테이너 생성 후 바로 시작을 할 수 있다.
3. docker run --name 옵션을 사용해 컨테이너 이름을 지정할 수 있다. 컨테이너 관리를 간편하게 할 수 있으나 보통 --name옵션을 사용하지 않고 자동 이름 생성기능을 주로 사용한다. 이유: 수많은 컨테이너 이름을 일일이 부여하기도 힘들 수 있다.
4. docker run -it <이미지명> <실행할 쉘 경로> 명령어로 컨테이너 생성과 시작을 할 경우 쉘로 접속하여 사용된다. 이때 컨테이너에서 exit 명령어 입력 시 컨테이너가 stop된다.
5. 접속 중인 컨테이너를 start상태로 유지하고 나오고 싶을 경우 ^P ^Q키를 순서 것 눌러 나온다. (백그라운드 모드로 전환된다.)
6. docker run -d : 컨테이너를 백그라운드 모드로 실행한다.
-컨테이너 상태를 항상 자동으로 재시작 하도록 설정: (docker run –-restart=always)
# docker run -it --restart=always --name suyecon1 ubuntu:14.04 /bin/bash
# exit
# docker ps #도커가 자동으로 start 중인것을 확인할 수 있다.
컨테이너 CPU/Memory 자원을 제한
1. --cpu-shares, -c : CPU 사용 비율, Default로 1024이다. 두배의 값을 사용하고 싶으면 -c 2048로 설정한다.
2. --memory, -m : 메모리 제한, 최소 4Mbyte이며 사용할 최대 메모리 양을 지정한다.
3. #docker run, #docker create명령어에서 컨테이너의 리소스 할당량을 지정할 수 있다.
4. 기존에 만들어져 있는 컨테이너에 대해 자원 제한을 변경하려면 #docker update 명령 사용
#docker update <resource limit> <컨테이너명>
5. docker inspect 컨테이너명: 컨테이너의 상세 정보 출력으로 자원 제한 정보 확인가능
Docker 리소스 사용량 관찰
1. docker stats: 각 컨테이너의 cpu, memory, storage, network 사용량 실시간 표시
2. 메모리 열에는 컨테이너에 구성된 라이브 메모리 사용량과 메모리 제한이 표시되고, 제한이 설정되어 있지 않으면 호스트에서 사용 가능한 RAM 양이 표시된다.
3. 마지막 칼럼: PIDS는 컨테이너에 의해 시작된 프로세스 수이다.
4. docker stats명령어나 docker top 명령어로 관찰
ex)
[root@cent1 ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
df58f4881116 testcon3 0.00% 728KiB / 200MiB 0.36% 656B / 0B 344kB / 0B 1
51aa3c92b9da testcon2 0.00% 2.578MiB / 100MiB 2.58% 656B / 0B 4.46MB / 0B 1
82a3d2a1800e testcon1 0.00% 3.891MiB / 1.795GiB 0.21% 656B / 0B 7.05MB / 0B 1
- 메모리 사용 제한 량을 모니터링 할 수 있다.
- ð suyecon1: 호스트 서버의 메모리 량과 같다.
- suyecon2: 제한 값 100m 확인
- suyecon3: 제한 값 200m 확인
CONTAINER: 컨테이너 ID 이름
CPU %: 컨테이너가 사용중인 cpu 사용 백분률율
MEM USAGE / LIMIT: 컨테이너가 사용중인 메모리 사용량 / 컨테이너에서 사용할 수 있는 메모리 제한.
MEM %: 컨테이너가 사용중인 메모리 사용 백분율
NET I/O: 컨테이너가 사용중인 네트워크 i/o 량
BLOCK I/O: 컨테이너가 호스트의 블록 장치에서 read/write 한 데이터 량
PIDS : 컨테이너가 생성한 프로세스, 스레드 개수
1. CPU 부하
# stress -c <코어 수>
grep -c processor /proc/cpuinfo 명령어를 통해 CPU 코어 전체 개수를 확인할 수 있습니다.
stress 툴에 코어 수를 지정하면 해당 코어는 100%를 사용하게 됩니다.
2. Memory 부하
# stress --vm <프로세스 수> –vm-bytes <사용할 크기>
예 : stress --vm 3 --vm-bytes 1024m
Container CPU 제한 (--cpu-shares)
1. 기본적으로 호스트 시스템의 컴퓨팅 성능에 대한 액세스는 무제한이다.
--cpus옵션을 사용하여 CPU 제한을 설정할 수 있다.
예)최대 2개의 cpu 사용 제한 설정
$ docker run --cpus=2 .......................................
2. --cpu-shares 옵션: 컨테이너의 가중치를 설정해 해당 컨테이너가 CPU를 상대적으로 얼마나 사용할 수 있는지 나타낸다. 즉, CPU의 개수를 할당하는 것이 아닌 CPU를 나누는 비중을 정의하여 상대적으로 얼마나 나누어 사용할 수 있는지 설정한다.
상대적인 값이므로 cpu-share 설정을 처음 컨테이너에 할당하는 CPU 비중은 100%로 본다.
아무런 설정을 하지 않았을 때 설정 값은 1024로 기본 셋팅된다.
예) docker run -it --name suyecon1 --cpu-shares 512 ubuntu:14.04
3. CPU 할당의 우선 순위를 지정할 수도 있다. 숫자가 높을수록 우선 순위가 높다.
cpu-shares옵션 사용은 컴퓨팅 성능이 부족하고 경쟁 프로세스 간에 분할되어야 할 때 좋다.
*실습 (hewon16/stress는 제가 듣는 수업에서 강사님이 docker hub수업에 올려놓은 자료입니다.)
2번째 터미널에서 작업 (suyecon1) --cpu-shares=512
[root@cent1 ~]# docker run -it --name suyecon1 --cpu-shares 512 hewon16/stress /bin/bash
3번째 터미널에서 작업 (suyecon2) --cpu-shares 1024
[root@cent1 ~]# docker run -it --name suyecon2 --cpu-shares 1024 hewon16/stress /bin/bash
4번째 터미널에서 작업 (suyecon3) --cpu-shares 2048
[root@cent1 ~]# docker run -it --name suyecon3 --cpu-shares 2048 hewon16/stress /bin/bash
5번째 터미널에서 작업 (suyecon4) --cpu-shares 4096
[root@cent1 ~]# docker run -it --name suyecon4 --cpu-shares 4096 hewon16/stress /bin/bash
6번째 터미널에서 작업 (suyecon5) --cpu-shares 셋팅 하지 않고 기본값으로 사용(1024)
docker inspect suyecon5로 출력 시 1024라고 나오지는 않는다.
[root@cent1 ~]# docker run -it --name suyecon5 hewon16/stress /bin/bash
첫번째 터미널 (모니터링 터미널)
[root@cent1 ~]#docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
1cf5ed6fbd6d suyecon1 0.00% 540KiB / 1.795GiB 0.03% 656B / 0B 0B / 0B 1
83fc87139a6a suyecon2 0.00% 536KiB / 1.795GiB 0.03% 656B / 0B 0B / 0B 1
48b8456e59ea suyecon3 0.00% 532KiB / 1.795GiB 0.03% 656B / 0B 0B / 0B 1
4fcc193de918 suyecon4 0.00% 536KiB / 1.795GiB 0.03% 656B / 0B 0B / 0B 1
3d21b3d292ef suyecon5 0.00% 540KiB / 1.795GiB 0.03% 656B / 0B 0B / 0B 1
=> 실시간 모니터링을 위해 계속 띄워 두고 작업한다.
5번째 터미널의 컨테이너에 stress 명령어 실행하자. (--cpu-shares 4096을 준 곳)
#stress -c 2
stress 명령어로 cpu 코어 2개를 사용하도록 하여 스트레스 주고 모니터링하기
모니터링 터미널에서 작업
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
1cf5ed6fbd6d suyecon1 12.27% 680KiB / 1.795GiB 0.04% 656B / 0B 0B / 0B 4
83fc87139a6a suyecon2 20.81% 672KiB / 1.795GiB 0.04% 656B / 0B 0B / 0B 4
48b8456e59ea suyecon3 45.96% 672KiB / 1.795GiB 0.04% 656B / 0B 0B / 0B 4
4fcc193de918 suyecon4 99.44% 676KiB / 1.795GiB 0.04% 656B / 0B 0B / 0B 4
3d21b3d292ef suyecon5 23.10% 676KiB / 1.795GiB 0.04% 656B / 0B 0B / 0B 4
실행중인 컨테이너 리소스 재설정(docker update)
1. 이미 실행중인 컨테이너의 리소스 설정을 변경할 때에는 docker update 명령을 사용한다.
2. docker update <리소스 설정> <컨테이너이름> => 부분만 업데이트 가능
- 실습
[root@cent1 ~]# docker run -itd --name suyecon1 --cpu-shares=2048 hewon16/stress /bin/bash
e3cf25f836cf1e356f21ba262992fb6436cfa839ff4bda162682e068a1282e22
[root@cent1 ~]# docker inspect suyecon1 | grep -i cpu
"CpuShares": 2048,
"NanoCpus": 0,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
[root@cent1 ~]# docker update --cpu-shares=1024 suyecon1
suyecon1
[root@cent1 ~]# docker inspect suyecon1 | grep -i cpu
"CpuShares": 1024, # 새로운 설정으로 update 된것을 확인
"NanoCpus": 0,
.....
주의: 컨테이너내부에서 시스템 정보
컨테이너에서 /proc/meminfo에서는 해당 컨테이너가 아닌 해당 호스트 서버의 정보가 나온다.
ex) 커너버전, cpu개수 등
[root@cent1 ~]# docker exec -it suyecon1 /bin/bash
[root@f56096cdd879 /]# cat /proc/meminfo
MemTotal: 1881984 kB
MemFree: 96404 kB
MemAvailable: 1004892 kB
Buffers: 0 kB
Cached: 1028840 kB
.........................
[root@f56096cdd879 /]# exit
컨테이너에서 발생한 로그 확인 (docker logs 컨테이너명)
1. 컨테이너의 표준입력, 표준출력, 표준 에러출력의 로그를 별도의 메타데이터 파일에 저장되고 이를 확인하기 위해 명령어 docker logs를 사용한다.
2. 로그의 내용은 현재 실행중인 컨테이너에서 표준 입력한 모든 명령어와 표준 출력이 기록된다.
3. –tail: 마지막 로그부터 지정한 라인까지 출력
4. –since: 입력 받은 유닉스 시간 이후의 로그를 출력 (40m, 2h 처럼)
5. –until: 특정 타임스탬프 이전의 로그만 출력 (40m, 2h 처럼)
6. -t 옵션: 로그의 내용에 타임스탬프도 함께 출력
7. -f 옵션: 실시간 모티터링 가능하다. 마치 tail -f 옵션 사용과 비슷하다.
^C키처럼 인터럽트로 취소한다.
8. --details: 로그의 추가적인 세부정보를 출력한다.
- 실습 (실시간 로그 모니터링: docker logs -f 사용)
터미널을 2개 동시에 띄우고 실습한다.
첫번째 터미널에서 작업하기
새 컨테이너 tescon1을 실행하고 접속한다.
[root@cent1 ~]# docker run -it --name tescon1 ubuntu:14.04 /bin/bash
2번째 터미널에서 작업하기
컨테이너 tescon1의 로그를 실시간 모니터링하자.
[root@cent1 ~]# docker logs -f tescon1
2개의 터미널을 동시에 띄워 두고 첫번째 터미널에서 작업을 한다.
명령어를 여러 개 실행하여 2번째 터미널에 입력한 명령어와 출력들이 모두 나오는지 확인한다.
실시간 모니터링 가능
* 주의: 한번 실행된 컨테이너 로그 관찰을 하다가 컨테이너가 stop 되고 다시start 하더라도 log가 연속적으로 append 되지 않는다.
* 로그가 더이상 쌓이지 않는다.
- 실습 (실시간 모니터링 : docker events 사용)
(2개의 터미널을 이용한다.)
1. 첫번째 터미널에서는 이벤트를 실시간 모니터링
2. 2번째 터미널에서는 컨테이너를 start, 명령어 실행, stop 등의 작업을 통해 이벤트를 발생시킨다.
이벤트 출력을 1번째 터미널에서 모니터링을 해보면 컨테이너 stop, start등의 이벤트를 보여주고 접속상태에서 실행하는 유닉스 명령어들을 이벤트로 보내지는 않는다.
만약 실행 컨테이너의 유닉스 입출력 명령어들을 모니터링 하려면 #docker logs <컨테이너명> 명령어를 사용해야한다.
docker events 명령어는 현재 시점부터 발생하는 이벤트를 모니터링한다. 지난 이벤트는 --since 옵션을 사용해 관찰해야 한다. event 관찰을 위해 실행한 컨테이너의 상태를 실시간 모니터링한다.
docker save/load 와 docker export/import 를 이용해서
도커 이미지를 tar아카이브 파일로 백업과 복원하기
1. docker save/load: 도커 이미지를 tar 아카이브 파일로 백업과 복구하는 용도로 사용할 수 있다.
- 원본 이미지와 똑같이 복구된 이미지를 사용할 수 있다. (재사용성)
2. docker export/import: 도커 컨테이너를 tar 아카이브 파일로 백업과 복구가 가능하다.
- 원본 이미지를 tar 아카이브로 만들어 하나의 layer로만 저장된 백업용 이미지를 생성한다.
- 백업된 이미지를 복구 시 반드시 컨테이너로 진입할 엔트리포인트(명령어)가 필요하다.
(컨테이너 내부에서 실행할 명령어)
- 실습 ( docker save/load 이미지)(hewon16/stress는 내가 듣는 교육에서 강사님이 교육용으로 올려놓은 이미지이다.)
실습에 사용할 이미지 받기
[root@cent1 ~]# docker pull hewon16/stress
..............
#이미지 id 확인하기[root@cent1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/hewon16/stress latest ad6aeea895c4 9 months ago 291 MB
docker.io/ubuntu 14.04 13b66b487594 10 months ago 197 MB
이미지를 tar아카이브로 추출하기
[root@cent1 ~]# docker save -o teststress.tar hewon16/stress
이미지 원본을 삭제하여 tar파일을 이용해 복구해보자.
[root@cent1 ~]# docker rmi ad6aeea895c4
Untagged: docker.io/hewon16/stress:latest
........
[root@cent1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/ubuntu 14.04 13b66b487594 10 months ago 197 MB
삭제된 원본의 이미지 ID ad6aeea895c4 와 같은 이미지로 복구된다.
[root@cent1 ~]# docker load < teststress.tar
...................
[root@cent1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/hewon16/stress latest ad6aeea895c4 9 months ago 291 MB
docker.io/ubuntu 14.04 13b66b487594 10 months ago 197 MB
- 실습2 (docker export/import 컨테이너)
컨테이너 리스트 확인
[root@cent1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
백업에 사용할 새 컨테이너 testcon1을 생성하고 start 시킨다. (접속은 하지 않는다.)
[root@cent1 ~]# docker run -d -it --name testcon1 ubuntu:14.04
5d1ba893d9d6527c289d5f6be975ba41cd14e72ecbdce804a47f202bddfd6a4d
컨테이너 리스트 확인
[root@cent1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5d1ba893d9d6 ubuntu:14.04 "/bin/bash" 4 seconds ago Up 3 seconds testcon1
suyecon1 컨테이너를 tar 아카이브로 백업한다.
[root@cent1 ~]# docker export testcon1 > testcon1back
[root@cent1 ~]# docker ps #컨테이너 id확인한다.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5d1ba893d9d6 ubuntu:14.04 "/bin/bash" 3 minutes ago Up 3 minutes testcon1
원본 컨테이너를 삭제한다. (tar로 백업해둔 testcon1back 파일을 이용해 복구할 계획)
[root@cent1 ~]# docker rm -f 5d1ba893d9d6
5d1ba893d9d6
[root@cent1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
#export로 백업해둔 파일 확인
[root@cent1 ~]# file testcon1back
testcon1back: POSIX tar archive
#tar로 백업해둔 파일 체크
[root@cent1 ~]# ls -l testcon1back
-rw-r--r-- 1 root root 206149632 1월 28 09:36 testcon1back
#복구하기 docker import <tar 파일> <이미지이름>
[root@cent1 ~]# docker import testcon1back testimage:14.04
sha256:dc8b07a39a28853591ee29baa8406521dc6c2b670ce005fbb7770e030e5d64ba
#import로 복구한 경우 새 이미지가 만들어진다.
[root@cent1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
testimage 14.04 dc8b07a39a28 8 seconds ago 196 MB
docker.io/ubuntu 14.04 13b66b487594 10 months ago 197 MB
#import로 복구한 이미지는 한개의 이미지로 구성됨을 확인한다.
[root@cent1 ~]# docker image history testimage:14.04
IMAGE CREATED CREATED BY SIZE COMMENT
2d2670f2c84c 6 minutes ago 196MB Imported from –
=> 하나의 이미지로만 구성된 이미지
베이스 이미지 우분투는 여러 개의 이미지로 구성됨을 확인할 수 있다.
[root@cent1 ~]# docker image history ubuntu:14.04
IMAGE CREATED CREATED BY SIZE COMMENT
13b66b487594 11 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 11 months ago /bin/sh -c mkdir -p /run/systemd && echo 'do… 7B
<missing> 11 months ago /bin/sh -c [ -z "$(apt-get indextargets)" ] 0B
<missing> 11 months ago /bin/sh -c set -xe && echo '#!/bin/sh' > /… 195kB
<missing> 11 months ago /bin/sh -c #(nop) ADD file:276b5d943a4d284f8… 196MB
[*중요한에러]
[root@cent1 ~]# docker run -it --name testcon1 testimage:14.04
/usr/bin/docker-current: Error response from daemon: No command specified.
See '/usr/bin/docker-current run --help'.
=> 에러발생 이유: 컨테이너의 파일 시스템을 tar아카이브 하고 다시 이미지로 만든 것이므로 Docker는 해당
이미지의 ENTRYPOINT(런타임에 실행할 명령어)를 인식하지 못한다.
따라서
1.새로 만든 이미지를 실행할 때 엔트리포인트(실행 명령어:/bin/bash같은 쉘)를 직접 지정만 하면 된다.
2.진입지점을 인식하기 위한 단순 명령어를 지정하면 컨테이너가 작동한다.
[root@cent1 ~]# docker run -it --name testncon1 testimage:14.04 /bin/bash
root@310cc32714cb:/# id
uid=0(root) gid=0(root) groups=0(root)
root@310cc32714cb:/# exit
exit
[root@cent1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
310cc32714cb testimage:14.04 "/bin/bash" 29 seconds ago Exited (0) 14 seconds ago testcon1
또는 --entrypoint 옵션을 사용한다.
[root@cent1 ~]# docker run -it -d --name testcon2 --entrypoint /bin/bash testimage:14.04
136e767277f5c31c49fc3ef5fdde2f18ffe937478225b1343044022e99be4d77
[root@cent1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
136e767277f5 testimage:14.04 "/bin/bash" 7 seconds ago Up 6 seconds testcon2
도커 보안 (capabilities)
1. Container는 Default로 Unprivileged이다. 이는 시스템의 주요 자원에 접근할 수 있는 권한이 제한되어 있다.
즉, 도커 컨테이너를 실행하면 Network interface의 enable/disabe이나 ipv4, ipv6의 주소 변경 등이 불가능하다.
마운트 작업이 거부된다. 새 장치 노드 생성, 파일 소유자 변경 등을 거부할 수 있다.
2. Docker는 옵션(privileged)으로 호스트 서버의 주요자원에 접근 가능한 Privileged Container를 생성할 수 있다.
3. --privileged 옵션은 컨테이너에 모든 device 기능을 제공하고 cgroup 컨트롤러가 적용하는 모든 제한도 해제한다. 즉, 컨테이너는 호스트가 할 수 있는 거의 모든 작업을 수행할 수 있다.
4. Docker는 컨테이너 내 root 사용자의 기능을 제한하는 기능을 제공한다. 컨테이너 내부의 프로세스가 호스트의 root 사용자가 할 수 있는 작업을 수행하면 안전하지 않으므로 Docker는 Linux의 Capabilities를 이용하여 컨테이너 내 사용자에게 권한을 제한한다.
5. 권한 부여: docker run --cap-add <CAPABILITY> <IMAGE>
권한 해지: docker run --cap-drop <CAPABILITY> <IMAGE>
6. 모든 권한 부여
#docker run --cap-add ALL ubuntu 또는 #docker run --privileged ubuntu
7. 권한 종류
CAP_SYS_ADMIN : sysadmin 작업 수행
CAP_SYS_TIME : 시스템 시간 변경
CAP_CHOWN : 파일의 uid/gid 변경
등등…….
예)
docker run --cap-add=ALL --cap-drop=MKNOD : MKNOD를 제외한 모든 기능을 사용할 수 있다.
docker run --cap-add=SYS_ADMIN 또는 docker run --cap-add=CAP_SYS_ADMIN
docker run --cap-add=NET_ADMIN
- 실습
랩1
-기본 컨테이너 (Unprivileged)에서 네트워크 장치의 ip 주소 변경이 불가능하다.
즉 호스트 서버의 네임스페이스 네트워크에 접근할 권한이 없다.
[root@cent1 ~]# docker run -it --name suyecon1 ubuntu:14.04 /bin/bash
root@7194cd123f41:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02
inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:6 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:516 (516.0 B) TX bytes:516 (516.0 B)
...........
root@7194cd123f41:/# ifconfig eth0 192.168.56.150
SIOCSIFADDR: Operation not permitted
=> 권한이 없어 에러
마운트 테스트
root@7194cd123f41:/# mount -t tmpfs none /mnt
mount: permission denied
=> 권한이 없어 에러
root@7194cd123f41:/#exit
exit
랩2
- privileged 권한이 부여된 컨테이너에서 eth0 네트워크 장치의 IP주소를 변경 가능하다.
즉, Privilged 컨테이너는 호스트 서버의 자원을 접근하고 변경할 수 있다.
[root@cent1 ~]# docker run --privileged -it --name suyecon2 ubuntu:14.04 /bin/bash
root@936b1af5beb3:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:03
inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:7 errors:0 dropped:0 overruns:0 frame:0
TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:586 (586.0 B) TX bytes:586 (586.0 B)
............
# 이제 ip 변경이 가능하다.
root@936b1af5beb3:/# ifconfig eth0 192.168.56.150
root@936b1af5beb3:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:03
inet addr:192.168.56.150 Bcast:192.168.56.255 Mask:255.255.255.0
inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:656 (656.0 B) TX bytes:656 (656.0 B)
............
파일시스템 마운트가 가능하다.
root@936b1af5beb3:/# mount -t tmpfs none /mnt
root@936b1af5beb3:/# df -h | grep mnt
none 919M 0 919M 0% /mnt
- 실습2 (--cap-add , drop 사용하기)
랩1(
--cat-add=”NET_ADMIN”: 네트워크 구성을 변경할 수 있는 권한을 설정하여 컨테이너의 ip를 변경하자.)
네트워크 구성을 권한 부여한 컨테이너 실행과 접속
[root@cent1 ~]# docker run -it --cap-add="NET_ADMIN" --name suyecon1 ubuntu:14.04 /bin/bash
네트워크 확인
root@67beba62b2d3:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02
inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:6 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:516 (516.0 B) TX bytes:516 (516.0 B)
1. 네트워크 ip 변경하기 (권한이 부여되어 변경이 가능하다.)
root@67beba62b2d3:/# ifconfig eth0 192.168.56.150
root@67beba62b2d3:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02
inet addr:192.168.56.150 Bcast:192.168.56.255 Mask:255.255.255.0
inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:656 (656.0 B) TX bytes:656 (656.0 B)
2. 기본 권한에 없는 mount 명령어를 사용해 파일시스템을 마운트 테스트하자.
# 마운트 테스트하면 권한이 없어 에러 난다.
root@67beba62b2d3:/# mount -t tmpfs none /mnt
mount: permission denied
# 시스템 디렉토리 /etc 를 chown 명령어로 소유권 변경을 테스트하기
# 기본 권한이 chown명령어를 컨테이너의 root가 사용할 수 있도록 허가되어 있다.
# 따라서 시스템 디렉토리인 /etc는 소유권 변경이 된다.
root@67beba62b2d3:/# ls -ld /etc
drwxr-xr-x 1 root root 66 Feb 1 14:47 /etc
root@67beba62b2d3:/# chown -R nobody /etc
root@67beba62b2d3:/# ls -ld /etc
drwxr-xr-x 1 nobody root 4096 Feb 1 14:47 /etc
root@67beba62b2d3:/#exit
exit
랩2 (기본 권한 중 CHOWN 권한을 drop하자)
--cap-drop=”CHOWN” 옵션을 설정하여 chown 명령어로 시스템 파일이나 디렉토리에 소유권 변경을 할 수 없도록 보안 설정을 한다.
권한이 drop된 컨테이너 생성과 접속하기
[root@cent1 ~]# docker run -it --cap-drop="CHOWN" --name suyecon2 ubuntu:14.04 /bin/bash
네트워크 구성을 출력하고 변경시켜보자. (기본 권한이 없어 네트워크 변경이 불가능하다.)
root@b0ea82d74636:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:03
inet addr:172.17.0.3 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe11:3/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:7 errors:0 dropped:0 overruns:0 frame:0
TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:586 (586.0 B) TX bytes:586 (586.0 B)
#네트워크 ip변경 권한이 없다.
root@b0ea82d74636:/# ifconfig eth0 192.168.56.150
SIOCSIFADDR: Operation not permitted
시스템 디렉토리 /etc/ 소유권 확인
root@b0ea82d74636:/# ls -ld /etc
drwxr-xr-x 1 root root 66 Feb 1 14:54 /etc
소유권 변경 시도 (권한이 drop 되어 안된다.)
root@b0ea82d74636:/# chown -R nobody /etc
chown: changing ownership of '/etc/.pwd.lock': Operation not permitted
..............에러발생 (권한 없음)
root@b0ea82d74636:/# exit
exit
[root@cent1 ~]# docker rm -f suyecon2
suyecon2
랩3
모든 권한을 drop하고 일부 권한 네트워크 설정권한 (NET_ADMIN)만 허가 하기위한 컨테이너 생성과 접속
[root@cent1 ~]# docker run -it --cap-drop=ALL --cap-add="NET_ADMIN" --name suyecon3 ubuntu:14.04 /bin/bash
#소유권 변경을 위한 /etc 디렉토리 리스트 확인
root@8f0f3e409939:/# ls -ld /etc
drwxr-xr-x 1 root root 66 Feb 1 15:09 /etc
#/etc 디렉토리 소유권 변경 (기본 권한을 drop시켰기 때문에 불가능하다.)
root@8f0f3e409939:/# chown nobody /etc
chown: changing ownership of '/etc': Operation not permitted
#ip 구성 변경하기 (네트워크 변경 권한을 추가했기 때문에 잘된다.)
root@8f0f3e409939:/# ifconfig eth0 192.168.56.150
root@8f0f3e409939:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:04
inet addr:192.168.56.150 Bcast:192.168.56.255 Mask:255.255.255.0
inet6 addr: fe80::42:acff:fe11:4/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:656 (656.0 B) TX bytes:656 (656.0 B)
root@8f0f3e409939:/# exit
exit
[root@cent1 ~]# docker rm -f suyecon3
suyecon3
HEALTHCHECK 명령으로 Docker 이미지 생성
1. 컨테이너의 HEALTHCHECK를 사용하여 컨테이너의 프로세스 상태를 체크할 수 있고, 두가지 사용 방법이 있다.
2. HEALTHCHECK <OPTIONS> CMD <명령어>
3. 컨테이너 내부에서 명령 실행하여 컨테이너 상태 확인, 이 방법을 통해 웹페이지 등을 확인할 수 있다.
4. Dockerfile에서 HEALTHCHECK는 하나의 명령만이 유효하고, 만약 여러 개가 있다면 가장 마지막에 선언된 HEALTHCHECK가 적용된다.
5. 옵션
--interval=간격 헬스 체크 간격 기본값 30s => 30초 마다
--timeout=기간 타임 아웃 기본값 30s => 30초 이상이 소요되고
--retries=횟수 타임 아웃 횟수 기본값 3회 => 3회 재시도
6. HEALTHCHECK의 처음 상태는 starting이고, HEALTHCHECK가 통과될 때 마다 healthy (이전 상태와 상관없이)상태이다. 그리고 옵션에 정한 일정 횟수가 실패된다면 unhealthy 상태로 된다.
7. EXIT CODE
0: success 컨테이너가 정상적이고 사용 가능한 상태
1: unhealthy 컨테이너가 올바르게 작동하지 않는 상태
2: starting 예약된 코드
8. 헬스 체크 상태는 docker container inspect [컨테이너명] 또는 docker container ls (docker ps -a)에서 확인할 수 있다.
- 실습
랩1)
# pwd로 돌아가기
[root@cent1 lab18]# cd
[root@cent1 ~]# mkdir lab20
[root@cent1 ~]# cd lab20
[root@cent1 lab20]# cat Dockerfile
FROM ubuntu:14.04
RUN mkdir /lab
COPY test.sh /lab/
RUN chmod +x /lab/test.sh
HEALTHCHECK --interval=10s --timeout=3s CMD /lab/test.sh red || exit 1
=> 10초 마다 기본값 총 3번의 헬스체크
=> 3초 이상이 소요되면서 3번의 재시도 (기본값3회)가 실패하면 unhealthy가 된다.
[root@cent1 lab20]# cat test.sh
#!/bin/bash
echo test dockerfile
echo "arg1 => $1"
echo "bye bye!!!!!!!!!!!!!!!!!!!!"
[root@cent1 lab20]# docker build -t suyeimage:1.1 .
Sending build context to Docker daemon 3.072 kB
.....
Successfully built e6d91764c966
[root@cent1 lab20]# docker run -it -d --name suyecon1 suyeimage:1.1
2d70ded3730ffb1af597f062c112c40b9dceb67961f55623ac4ae166e080c43f
[root@cent1 lab20]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2d70ded3730f suyeimage:1.1 "/bin/bash" About an hour ago Up About an hour (health: starting) suyecon1
-> 10초 간격으로 총 3번 헬스체크 시작
[root@cent1 lab20]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2d70ded3730f suyeimage:1.1 "/bin/bash" About an hour ago Up About an hour (healthy) suyecon1
-> 10초 간격으로 총 3번 헬스체크를 하여 healthy 상태로 정해짐
[root@cent1 lab20]# docker inspect suyecon1 |more
"Path": "/bin/bash",
"Args": [],
"Pid": 21843,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-02-02T00:51:25.547431283Z",
"FinishedAt": "0001-01-01T00:00:00Z",
"Health": {
"Status": "healthy",
"FailingStreak": 0, #실패횟수 0
"Log": [
{
"Start": "2022-02-02T09:51:35.561172614+09:00",
"End": "2022-02-02T09:51:35.61380597+09:00",
"ExitCode": 0, #성공 리턴코드
"Output": "test dockerfile\narg1 => red\narg2 => \narg
...........................
"Cmd": [
"/bin/bash"
],
"Healthcheck": {
"Test": [
"CMD-SHELL",
"/lab/test.sh red || exit 1"
],
"Interval": 10000000000 #10초간격
"Timeout": 3000000000 #3초간 유지
},
......................
강의를 들으면서 내가 중요하다고 생각하는 docker사용법에 대한 것을 정리하다 보니까 글이 길어졌다.
다음 포스팅에서 나머지 docker 사용법과 명령에서 쓰이는
특수문자 등을 정리하며 docekr 에 대한 포스팅은 끝내도록 해야겠다.
지금은 kubernetes를 배우고 있는데 어서 빨리 docker 포스팅을 마무리하고 kubernetes도 정리해야겠다.
댓글