Cloud/Docker

Docker In Action 2. 도커 컨테이너에 실행하기

로파이 2023. 10. 15. 21:28

도커 컨테이너에 실행하기


도커 명령어 

docker help

도커 명령어 리스트와 간단한 설명을 보여준다.

  • Common Commands : run, exec, ps, build, pull, push
  • Management Commands: builder, compose, container, image, network
  • Swarm Commands: swarm
  • Commands: attach, commit, cp, create, diff, kill, start, stop
docker help cp

자세한 명령어 사용법을 알 수 있다.

웹 사이트 모니터 구축 예제

웹 서버 nginx, 메일 전송 담당하는 mailer 그리고 이 두 어플리케이션을 모니터링하는 watcher 시스템을 구축해본다.


nginx 웹 서버 : 80 port를 사용하는 web server 실행

 

docker run --detach --name web nginx:latest

--detach flag로 백그라운드 동작으로 서비스를 실행한다. nginx는 Docker Hub에 등록된 trusted repository이다.

 

mailer : 웹 이메일을 전송하는 프로그램

docker run -d --name mailer dockerinaction/ch2_mailer

 

interactive 컨테이너 실행하기

컨테이너를 실행한 뒤에도 input stream을 연결하여 컨테이너에서 동작하는 shell 명령어를 실행 가능하도록 해준다.

docker run --interactive --tty --link web:web --name web_test busybox:latest /bin/bash

--interactive : 도커가 실행 이후에도 input stream을 컨테이너에서 받을 수 있도록 한다.

-- tty : virtual terminal을 컨테이너에 생성하여 container로 signal을 보낼 수 있도록 한다.

wget -O - http://web:80

web_test 컨테이너에서 web 컨테이너로 nginx 서버로의 http request를 테스트 가능하다.

 

- exit : 컨테이너 종료로 host로 돌아오기
- CTRL + P, Q로 컨테이너 종료 없이 host로 돌아오기

 

web 사이트 모니터 실행

docker run -it --name agent --link web:insideweb --link mailer:insidemailer dockerinaction/ch2_agent

모니터링 agent는 1초마다 두 컨테이너의 공개 포트로 test를 해보고 System up. 시스템 메시지를 출력한다.

 

자주 활용되는 도커 명령어

docker ps

 

실행되고 있는 컨테이너 리스트와 상태를 출력한다.

docker restart

도커 컨테이너 재실행하기

- docker restart web

- docker restart mailer

- docker restart agent

 

도커 컨테이너가 잘 동작하는 지 확인하기

docker logs web

해당 컨테이너의 로그들을 출력한다. agent가 1초마다 테스트를 하고 있었으므로 다음 로그들이 보여진다.

해당 컨테이너의 프로그램이 출력하는 stdout 혹은 stderr output stream이 로그에 기록된다. 이 로그는 rotate 혹은 truncated 되지 않으므로 실행 시간이 길어질 수록 점점 쌓인다.

 

PID namespace

같은 컨테이너에 다른 프로그램을 실행할 경우 PID namespace가 이용된다.

docker run -d --name namespaceA busybox:latest /bin/sh -c "sleep 30000"
docker exec namespaceA ps

docker exec 명령어는 추가 프로그램을 실행하고 있는 컨테이너에서 실행할 수 있게 한다.

다음 두 명령어로 시작한 프로그램이 같은 컨테이너 (namespaceA )에 존재하는 것을 확인할 수 있다.
- /bin/sh -c sleep 30000

- ps

컨테이너 이름(--name)이 PID namespace로 사용되었는데, 도커는 따로 지정하지 않고 docker run을 실행하여도 고유 namespace를 갖는 컨테이너를 만들고 프로그램을 실행하도록 한다.

 

docker run 옵션 중 --pid를 사용한다면 해당 PID namespace에 프로그램을 실행한다.

docker run –d --name webConflict nginx:latest
docker logs webConflict
docker exec webConflict nginx -g 'daemon off;'

위를 실행할 경우 webConflict 컨테이너에 "ngnix -g 'daemon off;'"를 실행하여 ngnix 웹 서버를 하나 더 실행하게 된다.

이미 webConfict 컨테이너에는 ngnix 웹 서버가 80번 포트로 실행되어 있으므로

새로 실행한 nginx 서버는 포트 충돌로 실행 실패를 하게 된다.

 

docker run -d --name webA nginx:latest
docker logs webA
docker run -d --name webB nginx:latest
docker logs webB

서로 다른 이름으로 실행한 컨테이너는 각 웹 서버를 실행하더라도 이제 포트 충돌과 같은 문제를 일으키지 않는다.이름을 다르게 지정하지 않더라도 기본으로 다른 이름을 가진 컨테이너로 실행하게 된다.

포트 중복외에도 같은 파일 시스템을 사용함, 공유 라이브러리, 같은 환경 변수 이름에 대한 다른 값 사용 등 서로 다른 프로그램 사이의 충돌을 야기하는 문제를 도커는 PID namespace로 해결한다.

 

유연한 컨테이너 identification

여러 웹 서버를 여러 컨테이너로 실행해야하는 website farm 시스템 구축을 해야한다고 하자.
website farm 구축하는데 앞서 metaconflicts를 생각해야한다.

docker run -d --name webid nginx
docker run -d --name webid nginx

같은 이름으로 실행하려는 두번째 컨테이너 실행은 실패하게 된다.

첫번째 컨테이너를 "docker rename webid webid-old"로 이름을 변경하면 이름 충돌을 피할 수 는 있다.

 

기본적으로 컨테이너를 detach 모드로 실행하게 되면 hex-encoded, 1024-bit numbers로 만들어진 id를 터미널 상으로 제공한다.

이 id를 컨테이너 이름 대신 사용 가능하다.

docker exec ba52fe38 ps
docker stop ba52fe38

 

컨테이너 실행 없이 만들기만 하고 할당된 id를 알 수 있는 명령어를 실행해도 된다.

docker create nginx

 

이 결과를 쉘 스크립트 변수로 사용가능 하다.

CID=$(docker create nginx:latest)
echo $CID

쉘 스크립트로 해당 id를 변수로 저장할 수 있다. 

 

이 방법은 터미널 세션에서만 유효하므로 전역으로 사용되어야 한다면 container ID file을 이용할 수 있다.

docker create --cidfile /tmp/web.cid nginx
cat /tmp/web.cid

 

혹은 컨테이너 실행 직후 라면 가장 최근 실행한 도커 컨테이너를 조사하여 id를 알아낼 수 있다.

CID=$(docker ps --latest --quiet)
echo $CID
CID=$(docker ps -l –q)
echo $CID

 

컨테이너 상태와 의존성

MAILER_CID=$(docker run -d dockerinaction/ch2_mailer) -- 미리 실행되어 있어야 한다.

WEB_CID=$(docker create nginx)

AGENT_CID=$(docker create --link $WEB_CID:insideweb \ --link $MAILER_CID:insidemailer \ dockerinaction/ch2_agent)

 

주요 컨테이너에 대한 CID를 변수로 저장한다.

 

docker ps는 실행 중 인 컨테이너의 목록을 보여주기 떄문에 ngnix와 agent에 대한 컨테이너는 포함하지 않는다.

컨테이너의 상태는 프로세스와 비슷하다.

도커 상태 변환

docker run는 새로운 컨테이너를 생성하고 시작 상태로 만든다. (created -> running)

docker stop는 실행중인 컨테이너를 중단한다. (running -> exited)

docker start는 중단한 컨테이너를 실행한다. (exited -> running)

 

 

ngnix와 agent 컨테이너의 상태는 종료 상태이라면 docker start로 컨테이너를 실행해야 한다.

docker start $WEB_CID
docker start $AGENT_CID

 

$AGENT_CID는 $WEB_CID를 필요로 하므로 $AGENT_CID를 나중에 실행해야한다.

--link 옵션은 IP 주소를 의존하는 컨테이너에 주입하기 때문에 실행 중이 아닌 컨테이너의 IP 주소를 주입할 수 없다.

 

항상 새 컨테이너를 실행할 수 있게하는 스크립트 최종본은 다음과 같다.

MAILER_CID=$(docker run -d dockerinaction/ch2_mailer
WEB_CID=$(docker run -d nginx) AGENT_CID=$(docker run -d \ --link $WEB_CID:insideweb \ --link $MAILER_CID:insidemailer \ dockerinaction/ch2_agent)

환경에 독립적인 시스템 구축

도커는 다음 요소에 대해 환경 독립적인 시스템을 구축하도록 해준다.

- Read-Only 파일 시스템

- 환경 변수 주입

- Volumes 볼륨

 

Read-only 파일 시스템

파일 시스템을 변경하지 않는 컨테이너를 실행할 수 있게 한다.

 

docker run -d --name wpdb -e MYSQL_ROOT_PASSWORD=ch2demo mysql:5

docker run -d --name wp --link wpdb:mysql -p 80 --read-only  wordpress:4

docker inspect --format "{{.State.Running}}" wp

 

wp 컨테이너를 실행하고 State가 Running인 지 알아보자.

해당 결과는 false를 주는데 docker logs wp로 로그를 살펴보면 파일 시스템에 write를 할 수 없다는 에러가 발생했다는 것을 알 수 있다.

 

따라서 write가 발생하는 파일 경로는 볼륨을 이용해 컨테이너 외부의 파일 시스템으로부터 맵핑을 해야한다.

 

docker run -d --name wp --link wpdb:mysql -p 80 \ -v /run/lock/apache2/ -v /run/apache2/ --read-only wordpress:4

 

환경 변수 주입

프로그램 실행의 Configuration을  key-value 형식으로 주입할 수 있는 방법을 도커에서 제공한다.

 

-- env 옵션

docker run --env MY_ENVIRONMENT_VAR="this is a test" busybox:latest env

이전 경우 MySQL의 user, password에 대한 config를 주입할 수 있게 된다.

docker create --env WORDPRESS_DB_HOST=<db_host> wordpress:4

 

신뢰성 있는 컨테이너

서비스가 failure로 인한 중지가 발생했을 때 재빨리 재시작하는 것이 중요하다. 중지된 컨테이너의 상태는 exited 가 된다.

 

-- restart 옵션

해당 옵션은 컨테이너가 중지했을 때 어떻게 할 것인가에 대한 옵션이다.

- never restart

- failure가 감지되었을 때 재시작

- failure가 감지되었을 때 대기 이후 재시작

- 조건없이 항상 재시작

 

Maintaining supervised container and start. Supervisor 프로세스와 시작하는 컨테이너 

supervisor process는 프로세스를 시작하고 여러 프로세스의 상태를 유지하는 프로세스 이다.

리눅스에서는 PID #1에 해당하는 init process가 그러한 프로세스 이고 모든 시스템 프로세스의 시작과 실패시의 재시작을 중재한다.

 

컨테이너에서도 supervisor process를 사용할 수 있는데, init, systemd, runit, upstart 그리고 supervisord가 있다.

tutum company는 LAMP(Linux, Apach, MySQL, PHP)를 한 컨테이너에 제공한다.

 

docker run -d -p 80:80 --name lamp-test tutum/lamp

 

docker exec lamp-test ps

 

컨테이너에 실행된 프로세스 리스트를 확인해보면, supervisord가 같이 실행되고 있다는 것을 확인할 수 있다.

docker exec lamp-test kill <PID>

위 명령어로 apach2에 해당하는 프로세스를 kill 하면 다음과 같이 supervisord 프로세스가 apache2를 recovery 하는 것을 확인할 수 있다.

 

 Cleaning up 종료 및 삭제

docker ps -a 로 컨테이너 ID를 확인한다.

docker rm {CID or CONTAINERNAME} 로 컨테이너를 삭제한다.

 

컨테이너를 삭제하기 전에 중지하기 위해서는 docker stop을 먼저 사용하자.

dcoker rm -f 로 강제 삭제를 할 때는 컨테이너에 SIG_KILL 시그널을 사용하고 docker stop의 경우 SIG_HUP을 사용한다.

finalization과 종료 과정을 수행하기 위해서는 docker stop을 사용한다.

참고 : Docker In Action, 2nd Edition by Nickoloff Kuenzli