도커 사용에 유용한
유틸리티와 팁
신명수 anarcher@gmail.com
2014-11-30
TOC
- 도커 설치
- 이미지 빌드
- 컨테이너 실행
도커 설치
그냥 도커 설치이라면 각 배포판의 패캐징을 사용하면 되지만...
여러 서버에 간단하게 설치하면 무언가 도구가 필요하다
서버 설정 관리 도구 (server configuration management tool)
- chef
- ansible
- puppet
- saltstack
- ...
Ansible을 이용한 Docker 설치
Ansible 특징
- 모듈을 만들것이 아니라면 서버 구성에 yaml만 알면 된다.
- ansible 모듈은 std in/out(JSON)이 되는 어떤 프로그램이라도 된다.
- chef-server community edition같은 것은 없고 사야하는 ansible tower가 있다. T_T
- http://deview.kr/2014/session?seq=15
(ansible 이해와 활용)
Ansible Docker 설치
$ansible-playbook -i hosts docker.yml
PLAY [cloudatcost] ************************************************************
GATHERING FACTS ***************************************************************
ok: [a]
...
TASK: [Add docker apt repository key] *****************************************
ok: [a]
...
TASK: [Add docker apt repository] *********************************************
ok: [a]
...
TASK: [Install latest docker via apt] *****************************************
changed: [a]
...
TASK: [Start docker on boot] **************************************************
ok: [a]
...
PLAY RECAP ********************************************************************
a : ok=6 changed=1 unreachable=0 failed=0
b : ok=6 changed=0 unreachable=0 failed=0
c : ok=6 changed=0 unreachable=0 failed=0
실행
docker.yml
tasks:
- include: debian.yml
when: "ansible_os_family == 'Debian'"
- name: Docker group
group: name=docker state=present
- name: Start docker on boot
service: name=docker state=started enabled=yes
debian.yml
- name: Add docker apt repository key
apt_key: url=https://get.docker.io/gpg state=present
- name: Add docker apt repository
apt_repository: repo='deb http://get.docker.io/ubuntu docker main' state=present
- name: Install latest docker via apt
apt: pkg=docker.io state=latest update_cache=yes
이미지 빌드
도커에서 이미지를 만드는 방법은 두가지
- 컨테이너에서 docker commit 하기
- Dockerfile로 이미지를 빌드하기 (추천)
Dockerfile
# Version: 0.0.1
FROM ubuntu:14.04
MAINTAINER anarcher "anarcher@gmail.com"
RUN apt-get update
RUN apt-get install -y nginx
RUN echo 'Hello container' > /usr/share/nginx/html/index.html
EXPOSE 80
$ sudo docker build -t="static_web" .
...
Step 2 : RUN apt-get update
---> Using cache
---> f1e96933a1b3
Step 3 : RUN apt-get install -y nginx
---> Using cache
---> f35da92bc69a
Step 4 : RUN echo 'Hello container2' >/usr/share/nginx/html/index.html
---> Running in 687148b94d31
---> 0f1b6efbb4ac
Removing intermediate container 687148b94d31
Step 5 : EXPOSE 80
---> Running in 07ece0129259
---> ded36d58c990
Removing intermediate container 07ece0129259
Successfully built ded36d58c990
Dockerfile
위에서 아래로 빌드
캐쉬가 무효화되면 그 시점부터 모든 캐쉬를 무효화된다
기본적으로 자주 안 변하고 오래 걸리는 것부터
자주 변하고 짧은 시간을 사용하는 것은 (환경변수 설정 등) 을 나중에
Step 3 : RUN apt-get install -y nginx
---> Using cache
---> f35da92bc69a
Step 4 : RUN echo 'Hello container2' >/usr/share/nginx/html/index.html
---> Running in 687148b94d31
---> 0f1b6efbb4ac
Removing intermediate container 687148b94d31
Step 5 : EXPOSE 80
---> Running in 07ece0129259
---> ded36d58c990
Removing intermediate container 07ece0129259
Successfully built ded36d58c990
Dockerfile
$docker history static_web
IMAGE CREATED CREATED BY SIZE
134455b6ba22 5 minutes ago /bin/sh -c #(nop) EXPOSE map[80/tcp:{}] 0 B
7814e0f4e451 5 minutes ago /bin/sh -c echo 'Hello container' >/usr/share 16 B
f35da92bc69a 5 minutes ago /bin/sh -c apt-get install -y nginx 18.46 MB
f1e96933a1b3 6 minutes ago /bin/sh -c apt-get update 20.65 MB
f2fb5e64006b 7 minutes ago /bin/sh -c #(nop) MAINTAINER anarcher "anarch 0 B
86ce37374f40 4 days ago /bin/sh -c #(nop) CMD [/bin/bash] 0 B
dc07507cef42 4 days ago /bin/sh -c apt-get update && apt-get dist-upg 0 B
78e82ee876a2 4 days ago /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/ 1.895 kB
3f45ca85fedc 4 days ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0 B
61cb619d86bc 4 days ago /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic 194.8 kB
5bc37dc2dfba 4 days ago /bin/sh -c #(nop) ADD file:d11cc4a4310c270539 192.5 MB
511136ea3c5a 17 months ago 0 B
build --no-cache
모든 캐쉬를 사용하지 않고 다시 빌드하려면 --no-cache 옵션 사용
하지만 빌드시에 시간이 많이 걸리는 부분(예: apt-get update)등을 선택적으로 캐쉬 사용하고 싶다면...
$ docker build --no-cache -t="static_web" .
선택적인 캐쉬 사용
# Version: 0.0.1
FROM ubuntu:14.04
MAINTAINER anarcher "anarcher@gmail.com"
ENV APT_UPDATED_AT 2014-11-30
RUN apt-get update
RUN apt-get install -y nginx=1.4.6-1ubuntu3.1
RUN echo 'Hello container' \
>/usr/share/nginx/html/index.html
EXPOSE 80
ENV APT_UPDATED_AT 2014-11-30
전체 패캐지 업데이트 하고 싶다면 날짜 변경
RUN apt-get install -y nginx=1.4.6-1ubuntu3.1
패캐지 버젼 명시하기
--no-cache 옵션을 사용하지 않고,
Base Image
여러 애플리케이션에서 쓰는 공통의 이미지
이미 언어별,플랫폼별 만들어서 공개된 이미지들이 많다
- Docker 공식 언어별 이미지:
http://blog.docker.com/2014/09/docker-hub-official-repos-announcing-language-stacks/ - Dockerfile 프로젝트: http://dockerfile.github.io
Build 실패했을 때
Step 3 : RUN apt-get update
---> Running in 85130977028d
---> 997485f46ec4
Step 4 : RUN apt-get install -y ngin
---> Running in ffca16d58fd8
Reading package lists...
Building dependency tree...
Reading state information...
E: Unable to locate package ngin
2014/06/04 18:41:11 The command [/bin/sh -c apt-get install -y
ngin] returned a non-zero code: 100
$ docker run -t -i --rm 997485f46ec4 /bin/bash
dcge12e59fe8:/# #DEBUG
사설 레지스트리 구성
https://hub.docker.com : docker inc에서 운영하는 레지스트리 서비스
레지스트리(Registry) 자체는 오픈소스 프로젝트
https://github.com/docker/docker-registry
많은 경우 Nginx + registry 으로 구성
docker container으로 사용가능
docker run \
-e SETTINGS_FLAVOR=s3 \
-e AWS_BUCKET=mybucket \
-e STORAGE_PATH=/registry \
-e AWS_KEY=myawskey \
-e AWS_SECRET=myawssecret \
-p 5000:5000 \
registry
컨테이너(Container) 실행
설정(Config)
환경변수
docker run \
-e SETTINGS_FLAVOR=s3 \
-e AWS_BUCKET=mybucket \
-e STORAGE_PATH=/registry \
-e AWS_KEY=myawskey \
-e AWS_SECRET=myawssecret \
-p 5000:5000 \
registry
설정 파일
sudo docker run -p 5000:5000 -v /home/me/myfolder:/registry-conf
-e DOCKER_REGISTRY_CONFIG=/registry-conf/mysuperconfig.yml registry
컨테이너 재시작 정책
도커 1.2에 추가된 기능 --restart
--restart always
--restart on-failure:5 #exit code 가 0이 아닌 경우
--restart no #default
docker run -d --restart always --name myredis redis
docker run -d --restart no --name myredis redis #default
docker run -d --restart on-failure:5 --name myredis redis
컨테이너 접속
docker exec 명령으로 실행중인 컨테이너에 커맨드를 실행
(>= 1.3)
docker exec -it anarcher/fluentd /bin/bash
#Output
aufs vs btrfs
file system corruption with devicemapper #7229
devicemapper와 aufs 둘다 발생하는 듯 (btrfs은 아님)
btrfs가 좀 더 잘 동작하는 것 같기도 (coreos은 btrfs 사용)
btrfs는 파티션을 따로 설정해야 함
$ mkfs.btrfs /dev/xvdb
$ mount /dev/xvdb /mnt
$ mkdir -p /mnt/docker
$ ln -sf /mnt/docker /var/lib/docker
$ sed -i -e '/DOCKER_OPTS/s/.*/DOCKER_OPTS="-s=btrfs"/' /etc/default/docker
$ restart docker
데이터 볼륨 컨테이너
Data only container , Data volume container
# Dockerfile
FROM busybox
VOLUME /var/lib/mysql
CMD /bin/sh
$docker build -t mysql_datastore
$docker run -i -t -name mysql_data mysql_datastore
$docker run -d -volumes-from mysql_data me/awesome_mysql_image
애플리케이션 컨테이너를 삭제하고 생성하더라도
데이터는 다른 컨테이너에서 유지된다
데이터 볼륨 백업
https://github.com/paimpozhil/docker-volume-backup
https://github.com/discordianfish/docker-backup
https://github.com/seapy/dock_trucker :
Dock Trucker is docker volume container auto backup and sync to cloud
$ docker run -d --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /your/host/backup/dir:/backup \
--volumes-from backup1 \
--volumes-from backup2 \
-e AWS_ACCESS_KEY_ID=yourkeyid \
-e AWS_SECRET_ACCESS_KEY=youraccesskey \
-e AWS_DEFAULT_REGION=us-east-1 \
-e S3_PATH=s3_bucketname_or_path \
-e OLDFILE_PRESERVE_DAYS=14 \
seapy/dock-trucker
컨테이너 로깅
도커(Docker)는 프로세스(Process)의 표준출력(stdout/err) 저장한다
docker logs stdout/err을 출력
docker logs -f --tail=0 fe24d # tail -f file.ext
stdout/err을 호스트 파일시스템에 저장해주기 때문에, 계속 쌓이기만 한다.
/var/lib/docker/containers/[containerID]/[containerID]-json.log
컨테이너 로깅
도커(Docker) 데몬(Daemon)에서 로깅 핸들링하도록 제안이 있는 상태
Proposal: Logging drivers #7195
docker -d --logging none
docker -d --logging default --logging-opt truncation=20mb
--logging-opt rotation=1gb
호스트에 logrotate 설정
#logrotate.conf
/var/lib/docker/containers/*/*-json.log {
daily
compress
rotate 5
size 10k
copytruncate
}
중앙 집중식 로깅(centralized logging)
호스트 머신에 쌓이는 컨테이너 로그를 로그 콜렉터로 수집
#fluentd
<source>
type tail
path /var/lib/docker/containers/*/*-json.log
pos_file /var/log/fluentd-docker.pos
time_format %Y-%m-%dT%H:%M:%S
tag docker.*
format json
</source>
<match docker.var.lib.docker.containers.*.*.log>
type record_reformer
container_id ${tag_parts[5]}
tag docker.all
</match>
<match docker.all>
type file
path /var/log/docker/*.log
format json
</match>
애플리케이션 로깅
Dockerized = stdout에만 쓴다?
많은 애플리케이션들이 파일에 로깅한다 예:/var/log/nginx/log
볼륨(volume)을 사용
docker run --name some-nginx -v <log-dir>:/var/log/nginx -d nginx
컨테이너 모니터링
docker run \
> --volume=/:/rootfs:ro \
> --volume=/var/run:/var/run:rw \
> --volume=/sys:/sys:ro \
> --volume=/var/lib/docker/:/var/lib/docker:ro \
> --publish=8080:8080 \
> --detach=true \
> --name=cadvisor \
> google/cadvisor:latest
컨테이너 모니터링
pharos : Distributed Docker Monitoring Tool
도커 네트워킹
컨테이너 링킹 (Container linking)
- 정적(static)이다
- 부모-자식 관계이다 (단방향)
- 호스트안의 컨테이너간에만 가능하다
- 컨테이너를 삭제하고 새로운 이미지로 컨테이너를 실행하면연결(Linking)은 깨진다
$ docker run -d --name db training/postgres
564cf1592267eccb013361cc14a0c413f2d5acd4f5f0ccc6a9473ca9faf9a4c1
$ docker run -d -P --name web --link db:db training/webapp python app.py
8aef00d59404f1ceb2cce74c75b738f0c7df12c6a31d27f1a7708404a4055eb6
$docker exec -it web env | grep DB
DB_PORT=tcp://172.17.0.42:5432
DB_PORT_5432_TCP=tcp://172.17.0.42:5432
DB_PORT_5432_TCP_ADDR=172.17.0.42
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_PROTO=tcp
DB_NAME=/web/db
DB_ENV_PG_VERSION=9.3
컨테이너 링킹
$ docker run -d --name db training/postgres
564cf1592267eccb013361cc14a0c413f2d5acd4f5f0ccc6a9473ca9faf9a4c1
$ docker run -d -P --name web --link db:db training/webapp python app.py
8aef00d59404f1ceb2cce74c75b738f0c7df12c6a31d27f1a7708404a4055eb6
$ docker exec -it db cat /etc/hosts
172.17.0.38 564cf1592267
$ docker exec -it web cat /etc/hosts | grep db
172.17.0.38 db
$ docker restart db
$ docker exec -it db cat /etc/hosts
172.17.0.40 564cf1592267
$ docker exec -it web cat /etc/hosts | grep db
172.17.0.40 db
$ docker rm -f db
$ docker run -d --name db training/postgres
db20aae037686ddc0efda400cceedf04c1e471e530b5dcfd5491a55bf9e99779
$ docker exec -it db cat /etc/hosts
172.17.0.41 db20aae03768
$ docker exec -it web cat /etc/hosts
172.17.0.40 db
컨테이너 네트웍 포트
도커 컨테이너의 네트웍 포트를 호스트 포트에 바인딩할수 있다.
$ docker run -d -p 5000:5000 -p 80 --name web training/webapp python app.py
3fe7e5cd9224f8ae56d73e8963943439d963d900f17d74d9d934b464d0d28ed0
$ docker port web
5000/tcp -> 0.0.0.0:5000
80/tcp -> 0.0.0.0:49164
고정 포트를 사용 할 때
새로운 이미지로 컨테이너를 실행하려면 기존의 컨테이너를
멈추고 시작해야 한다
프록시(Proxy) 사용하기
Automated Nginx Reverse Proxy for Docker
docker-gen 으로 컨테이너의 변화가 있을때 nginx 설정을 바꾸고 nginx reload을 실행
docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock jwilder/nginx-proxy
등록하고자 하는 컨테이너에 환경변수 VIRTUAL_HOST을 추가 해서 실행
docker run -e VIRTUAL_HOST=foo.bar.com ...
docker-gen -only-exposed -watch -notify "/etc/init.d/nginx reload"
templates/nginx.tmpl /etc/nginx/sites-enabled/default
Service discovery w/ Docker
synapse : AirBnB에 만든 Service discovery system
개발에서 도커 사용
fig.sh : Fast, isolated development environments using Docker.
- 기본적으로 한 호스트에서 있는 여러 컨테이너들을 yaml기반의 설정파일로 관리하는 도구.
- 특히 개발환경에서 여러 레이어(DB,APIServer,CacheServer 등등)를 하나의 호스트에서 사용할때 편리하다
web:
build: .
command: python app.py
links:
- db
ports:
- "8000:8000"
db:
image: postgres
Fig을 프로덕션에서?
- DOCKER_HOST=tcp://[ip]:[port] ; fig [command]
-
#527 : 각 서비스마다 다른 docker_host을 설정해서 여러 호스트에 띠울수 있도록 한 패치.
- 몇주째 머지되지 않았음
- 도커 핵데이 2014 우승작 : Enable Fig to deploy to multiple Docker servers #608
redis:
image: redis
docker_host: tcp://192.168.10.74:5555
redislocal:
image: redis
감사합니다!
docker-2014-11-30-springsprout
By Myoungsoo Shin
docker-2014-11-30-springsprout
- 5,403