Katacoda를 이용한 Docker 공부 7일차 정리

이 포스트는 Korea Azure User Group에서 진행하는 Docker/Container 스터디 그룹에 참여하며 작성했습니다.

스터디를 진행한 Katacoda 강좌: Docker & Containers/Orchestration

진행한 강의 목록

  • Add Healthcheck for Containers
  • Deploy Swarm Services with Compose v3
  • Keeping Secrets with Docker Swarm
  • Create Encrypted Overlay Network

스터디는 Katacoda의 화면을 참조하되, 실습은 제 개인 PC에서 VM을 구성해서 진행했습니다. 따라해볼 수 있는 것만 별도로 정리했습니다.

구성환경

  • Windows 10 Pro 1809
  • Hyper-V
  • CentOS 7.6.1810 (Kernel 4.20.2-1.el7)

내용 정리

# 컨테이너의 상태 확인을 확인해보자.
[root@docker-master home]# vi Dockerfile  # Dockerfile 작성
FROM katacoda/docker-http-server:health
HEALTHCHECK --timeout=1s --interval=1s --retries=3 \
  CMD curl -s --fail http://localhost:80/ || exit 1
[root@docker-master home]# docker build -t http . # 이미지 빌드
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM katacoda/docker-http-server:health
health: Pulling from katacoda/docker-http-server
12b41071e6ce: Pull complete 
fb1cef6edba2: Pull complete 
1061ea2815dd: Pull complete 
Digest: sha256:fee2132b14b4148ded82aacd8f06bdcb9efa535b4dfd2f1d88518996f4b2fb1d
Status: Downloaded newer image for katacoda/docker-http-server:health
 ---> 7f16ea0c8bd8
Step 2/2 : HEALTHCHECK --timeout=1s --interval=1s --retries=3   CMD curl -s --fail http://localhost:80/ || exit 1
 ---> Running in 9b7a7fa9ad4c
Removing intermediate container 9b7a7fa9ad4c
 ---> a5ee862276bd
Successfully built a5ee862276bd
Successfully tagged http:latest
[root@docker-master home]# docker run -d -p 80:80 --name srv http # 컨테이너 배포
ab3e150b6ed3ef0c84b2d4c98d978b9e62b20303e94b9cd82087e236947fac5a
[root@docker-master home]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                   PORTS                NAMES
ab3e150b6ed3        http                "/app"              2 seconds ago       Up 2 seconds (healthy)   0.0.0.0:80->80/tcp   srv
[root@docker-master home]# curl localhost/unhealthy # unhealthy 입력
[root@docker-master home]# docker inspect --format "{{json .State.Health.Status}}" srv # health 확인시 unhealthy로 출력
"unhealthy"
[root@docker-master home]# curl localhost/healthy  # healthy 입력
[root@docker-master home]# docker inspect --format "{{json .State.Health.Status}}" srv # health 확인시 healthy로 출력
"healthy"
[root@docker-master home]# docker rm -f $(docker ps -qa) # 컨테이너 삭제
ab3e150b6ed3
[root@docker-master home]# docker service create --name http --replicas 2 -p 80:80 http # swarm으로 컨테이너 2개 배포
image http:latest could not be accessed on a registry to record
its digest. Each node will access http:latest independently,
possibly leading to different nodes running different
versions of the image.

7c530pawpqfr409xouxhfriia
overall progress: 2 out of 2 tasks 
1/2: running   
2/2: running   
verify: Service converged 
[root@docker-master home]# curl localhost/unhealthy # unhealthy 입력
[root@docker-master home]# curl localhost # 확인시 컨테이너 확인
<h1>A healthy request was processed by host: 4912d0761092</h1>
# Docker-compose v3 부터 추가된 swarm으로 배포하기
[root@docker-master home]# vi docker-compose.yml # compoase 파일 작성ㄱ
version: "3"
services:
  redis:
    image: redis:alpine
    volumes:
      - db-data:/data
    networks:
      appnet1:
        aliases:
          - db
    deploy:
      placement:
        constraints: [node.role == manager]
  web:
    image: katacoda/redis-node-docker-example
    networks:
      - appnet1
    depends_on:
      - redis
    deploy:
      mode: replicated
      replicas: 2
      labels: [APP=WEB]
      resources:
        limits:
          cpus: '0.25'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 512M
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: continue
        monitor: 60s
        max_failure_ratio: 0.3
      placement:
        constraints: [node.role == worker]

networks:
  appnet1:

volumes:
  db-data:
[root@docker-master home]# docker stack deploy --compose-file docker-compose.yml myapp # stack 으로 배포
Creating network myapp_appnet1
Creating service myapp_redis
Creating service myapp_web

[root@docker-master home]# docker stack ls # stack 이름과 서비스 수량 등 확인
NAME                SERVICES            ORCHESTRATOR
myapp               2                   Swarm

[root@docker-master home]# docker stack services myapp # 서비스 배포 확인
ID                  NAME                MODE                REPLICAS            IMAGE                                       PORTS
2g9kla9ee58s        myapp_web           replicated          2/2                 katacoda/redis-node-docker-example:latest   
zfp56qncx34u        myapp_redis         replicated          1/1                 redis:alpine           

[root@docker-master home]# docker stack ps myapp # 컨테이너 확인
ID                  NAME                IMAGE                                       NODE                DESIRED STATE       CURRENT STATE           ERROR               PORTS
qv91fxfzfvaw        myapp_web.1         katacoda/redis-node-docker-example:latest   docker-node01       Running             Running 3 minutes ago                       
mjag86tngwr5        myapp_redis.1       redis:alpine                                docker-master       Running             Running 3 minutes ago                       
i196ixaxrk4a        myapp_web.2         katacoda/redis-node-docker-example:latest   docker-node01       Running             Running 3 minutes ago               

[root@docker-master home]# docker ps # 실제 컨테이너 확인
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
9cb8459bcb86        redis:alpine        "docker-entrypoint.s…"   4 minutes ago       Up 4 minutes        6379/tcp            myapp_redis.1.mjag86tngwr5fy5aw3tj1mce2
# 암호화된 정보로 컨테이너 배포하기
[root@docker-master home]# < /dev/urandom tr -dc A-Za-z0-9 | head -c64 > tokenfile # 랜덤 키 파일 생성
[root@docker-master home]# docker secret create deep_thought_answer_secure tokenfile # 토큰파일을 이용해서 swarm 에서 배포시 암호를 사용하도록 설정
kq5vdq9q44xzopjvt71g5drmn
[root@docker-master home]# echo "the_answer_is_42" | docker secret create lesssecure # 암호화 확인
Error response from daemon: rpc error: code = InvalidArgument desc = secret data must be larger than 0 and less than 512000 bytes
[root@docker-master home]# docker secret ls # 암호 목록 확인
ID                          NAME                         DRIVER              CREATED             UPDATED
kq5vdq9q44xzopjvt71g5drmn   deep_thought_answer_secure                       24 seconds ago      24 seconds ago
[root@docker-master home]# docker service create --name="redis" --secret="deep_thought_answer_secure" redis # redis를 암호화시켜 실행하기
d0zur8n1l7teo7ojbjecvmy6c
overall progress: 1 out of 1 tasks 
1/1: running   
verify: Service converged 
[root@docker-master home]# docker exec $(docker ps --filter name=redis -q) ls -l /run/secrets # redis 내부에 기록된 파일 확인
total 4
-r--r--r-- 1 root root 64 Mar 25 01:06 deep_thought_answer_secure
[root@docker-master home]# docker exec $(docker ps --filter name=redis -q) cat /run/secrets/deep_thought_answer_secure 
qOl6w2bo6cVt0LHWcNvLBMvDd0IiroEFoi1PrLwKinOYfeFbeA77CqvqCGfJsEFt

[root@docker-master home]# vi docker-compose.yml # composw로 배포하기
version: '3.1'
services:
    viewer:
        image: 'alpine'
        command: 'cat /run/secrets/deep_thought_answer_secure'
        secrets:
            - deep_thought_answer_secure

secrets:
    deep_thought_answer_secure:
        external: true

[root@docker-master home]# docker stack deploy -c docker-compose.yml secrets1 # compose를 읽어오도록 배포
Creating network secrets1_default
Creating service secrets1_viewer

[root@docker-master home]# echo "my-super-secure-cert" > secret.crt
[root@docker-master home]# vi docker-compose.yml
version: '3.1'
services:
    test:
        image: 'alpine'
        command: 'cat /run/secrets/secretcert'
        secrets:
            - secretcert

secrets:
    secretcert:
        file: ./secret.crt

[root@docker-master home]# docker stack deploy -c docker-compose.yml secrets2
Creating network secrets2_default
Creating secret secrets2_secretcert
Creating service secrets2_test

[root@docker-master home]# docker logs $(docker ps -aqn1 -f name=secrets2 -f status=exited)
my-super-secure-cert
# swarm으로 배포시 이용하는 overlay 네트워크에 대해 암호화를 해보자.
# 2번째 노드에는 사전에 tcpdump를 설치한다.
[root@docker-node01 ~]# yum install tcpdump -y
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
epel/x86_64/metalink                                                                                                                                    | 8.2 kB  00:00:00     
 * base: centos.mirror.cdnetworks.com
 * elrepo: dfw.mirror.rackspace.com
 * epel: ftp.cuhk.edu.hk
 * extras: centos.mirror.cdnetworks.com
 * updates: centos.mirror.moack.net
base                                                                                                                                                    | 3.6 kB  00:00:00     
docker-ce-stable                                                                                                                                        | 3.5 kB  00:00:00     
elrepo                                                                                                                                                  | 2.9 kB  00:00:00     
extras                                                                                                                                                  | 3.4 kB  00:00:00     
updates                                                                                                                                                 | 3.4 kB  00:00:00     
Resolving Dependencies
--> Running transaction check
---> Package tcpdump.x86_64 14:4.9.2-3.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

===============================================================================================================================================================================
 Package                                  Arch                                    Version                                          Repository                             Size
===============================================================================================================================================================================
Installing:
 tcpdump                                  x86_64                                  14:4.9.2-3.el7                                   base                                  421 k

Transaction Summary
===============================================================================================================================================================================
Install  1 Package

Total download size: 421 k
Installed size: 1.0 M
Downloading packages:
tcpdump-4.9.2-3.el7.x86_64.rpm                                                                                                                          | 421 kB  00:00:00     
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : 14:tcpdump-4.9.2-3.el7.x86_64                                                                                                                               1/1 
  Verifying  : 14:tcpdump-4.9.2-3.el7.x86_64                                                                                                                               1/1 

Installed:
  tcpdump.x86_64 14:4.9.2-3.el7                                                                                                                                                

Complete!

[root@docker-master home]# docker network create -d overlay app1-network  # 비암호화 overlay 네트워크 생성
stkvwxbp8ay7vz8ou3k1fx305
[root@docker-master home]# docker service create --name redis --network app1-network redis:alpine # 앞서 생성한 네트워크에 서비스 배포
  --network app1-network -p 80:3000 \
  --replicas 1 --name app1-web \
  katacoda/redis-node-docker-example
7mn34bf8oxdgqoccelha8caqy
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged 
[root@docker-master home]# docker service create \
>   --network app1-network -p 80:3000 \
>   --replicas 1 --name app1-web \
>   katacoda/redis-node-docker-example
wajhlj7csql6s0eabfu7rzul4
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged 

[root@docker-master home]# docker service ls # 서비스 실행 확인
ID                  NAME                MODE                REPLICAS            IMAGE                                       PORTS
wajhlj7csql6        app1-web            replicated          1/1                 katacoda/redis-node-docker-example:latest   *:80->3000/tcp
7mn34bf8oxdg        redis               replicated          1/1                 redis:alpine            

[root@docker-master home]# curl localhost # 서비스 호출
This page was generated after talking to redis.

Application Build: 1

Total requests: 1

IP count: 
    ::ffff:10.255.0.2: 1

# 2번째 노드에선 미리 tcpdump를 실행해둔다.
# master 노드에서 서비스 호출시 2번째 노드에 실행해둔 tcpdump에 암호화되지 않은 내용이 나오게 된다.
[root@docker-node01 ~]# tcpdump -s 1500 -A -i eth1 port 4789
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 1500 bytes
10:35:56.720049 IP docker-master.48187 > docker-node01.4789: VXLAN, flags [I] (0x08), vni 4096
IP 10.255.0.2.40488 > 10.255.0.21.http: Flags [S], seq 4078274696, win 65495, options [mss 65495,sackOK,TS val 3760921752 ecr 0,nop,wscale 7], length 0
E..n.m..@...

.


...;...Z...........B
....B
.....E..<..@.?.1.
...
....(.P............!..........
.+..........
10:35:56.720180 IP docker-node01.37479 > docker-master.4789: VXLAN, flags [I] (0x08), vni 4096
IP 10.255.0.21.http > 10.255.0.2.40488: Flags [S.], seq 3671223879, ack 4078274697, win 27960, options [mss 1410,sackOK,TS val 5536316 ecr 3760921752,nop,wscale 7], length 0
E..n1...@.4.

..

.
.g...Z...........B
....B
.....E..<..@.@.$.
...
....P.(..nG......m8.N.........
.Tz<.+......
10:35:56.720429 IP docker-master.48187 > docker-node01.4789: VXLAN, flags [I] (0x08), vni 4096
IP 10.255.0.2.40488 > 10.255.0.21.http: Flags [.], ack 1, win 512, options [nop,nop,TS val 3760921753 ecr 5536316], length 0
E..f.n..@...

.

......

.


...;...R...........B
....B
.....E..4..@.?.1.
...
....(.P......o^...........
.+...Tz@

# 암호화된 overlay 네트워크를 위해 앞서 생성한 서비스와 네트워크 삭제
[root@docker-master home]# docker service rm redis app1-web && docker network rm app1-network
redis
app1-web
app1-network

# 암호화된 overlay 네트워크 생성
[root@docker-master home]# docker network create -d overlay --opt encrypted app1-network
zggptayjp4wbdzn2k5j38k5m5

# 암호화된 overlay 네트워크로 서비스 배포
[root@docker-master home]# docker service create --name redis --network app1-network redis:alpine 
docker service create \
  --network app1-network -p 80:3000 \
  --replicas 1 --name app1-web \
  katacoda/redis-node-docker-example
pzaeni5zsymu5a1dx51un4pxu
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged 
[root@docker-master home]# docker service create \
>   --network app1-network -p 80:3000 \
>   --replicas 1 --name app1-web \
>   katacoda/redis-node-docker-example
552ro33ut4thbcl60d5vahijf
overall progress: 1 out of 1 tasks 
1/1: running   [==================================================>] 
verify: Service converged 

[root@docker-master home]# curl localhost # 서비스 호출
This page was generated after talking to redis.

Application Build: 1

Total requests: 1

IP count: 
    ::ffff:10.255.0.2: 1

# 앞서 마찬가지로 2번째 노드에는 tcpdump를 실행해둔다.
# master 노드에서 서비스 호출시 비암호화된 overlay 네트워크와 암호화된 overlay 네트워크간 나오는 정보의 양이 약 100여라인이 차이가 나게된다.
# 암호화된 overlay 네트워크에서 나오는 양이 100여라인이 더 적다.
[root@docker-node01 ~]# tcpdump -s 1500 -A -i eth1 port 4789
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 1500 bytes
10:39:22.478343 IP docker-master.52579 > docker-node01.4789: VXLAN, flags [I] (0x08), vni 4096
IP 10.255.0.2.40548 > 10.255.0.23.http: Flags [S], seq 4215025776, win 65495, options [mss 65495,sackOK,TS val 3761127511 ecr 0,nop,wscale 7], length 0
E..nO...@...

.


...c...Z...........B
....B
.....E..<.y@.?.v,
...
....d.P.<0p........M..........
..@W........
10:39:22.478481 IP docker-node01.39339 > docker-master.4789: VXLAN, flags [I] (0x08), vni 4096
IP 10.255.0.23.http > 10.255.0.2.40548: Flags [S.], seq 2836227324, ack 4215025777, win 27960, options [mss 1410,sackOK,TS val 5742074 ecr 3761127511,nop,wscale 7], length 0
E..n.c..@...

..

....

.


...c...R...........B
....B
.....E..4..@.?.v.
...
....d.P.<0...f............
..@\.W..