'docker'에 해당되는 글 5건

  1. 2018.11.01 docker container 활용 #5
  2. 2018.10.30 docker container 활용 #4
  3. 2018.10.29 docker container 활용 #3
  4. 2018.10.27 docker container 활용 #1
  5. 2016.04.17 CA 파일 생성하기 (TLS 사용)

이번에는 docker 이미지 최적화에 대해서 설명하겠습니다.


이미지 최적화를 위해서는 다음의 3가지를 잘 활용하면 됩니다.


1. 레이어를 줄이기 위해서 다중 RUN 명령어는 하나의 RUN 명령어로 구성
2. 파일 복사와 라이브러리 Install 은 순서가 중요
3. 컴파일과 같은 작업은 Multistep build 를 이용

 


alpine linux 로 nginx 를 실행시기 위한 방법으로 다음과 같은 docker 이미지를 만들 수 있습니다.


먼저, nginx.conf 파일을 로컬 컴퓨터에 생성합니다.

$ vi nginx.conf

user www;
worker_processes auto;

error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    sendfile on;
    access_log /var/log/nginx/access.log;
    keepalive_timeout 3000;
    server {
       listen 80;
       root /www;
       index index.html index.htm;
       server_name localhost;
       client_max_body_size 32m;
       error_page 500 502 503 504 /50x.html;
       location = /50x.html {
             root /var/lib/nginx/html;
       }
    }
}



다음은 간단한 index.html 입니다.

$ vi index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>HTML5</title>
</head>
<body>
    Server is online
</body>
</html>

 


이 두 파일을 활용한 Dockerfile 은 다음과 같습니다.

$ vi Dockerfile


FROM alpine:3.8
RUN apk update
RUN apk add --no-cache nginx
RUN adduser -D -g 'www' www
RUN mkdir /www
RUN chown -R www:www /var/lib/nginx
RUN chown -R www:www /www

COPY nginx.conf /etc/nginx/nginx.conf
COPY index.html /www/index.html

ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]

 


docker 이미지를 빌드하고 실행시키면 index.html 결과를 얻을 수 있습니다.


$ sudo docker build -t seungkyua/nginx-alpine .

$ docker run -d -p 30080:80 --name nginx-alpine seungkyua/nginx-alpine

$ curl http://localhost:30080

 

하나의 RUN 명령어로 구성

여기서 첫번째 이미지 최적화 포인트가 보입니다.


앞의 Dockerfile 에서 하나의 RUN 은 하나의 이미지 레이어가 되므로 이것을 하나로 다음과 같이 줄일 수 있습니다.

 

RUN apk update && \

    apk add --no-cache nginx && \

    adduser -D -g 'www' www && \

    mkdir /www && \

    chown -R www:www /var/lib/nginx && \

    chown -R www:www /www

 




이번에는 nodejs docker 이미지를 만들어 보겠습니다.

 

$ package.json
{
    "name": "docker_web_app",
    "version": "1.0.0",
    "description": "Node.js on Docker",
    "private": true,
    "author": "Seungkyu Ahn <seungkyua@gmail.com>",
    "main": "server.js",
    "scripts": {
       "start": "node server.js"
    },
    "dependencies": {
       "express": "^4.16.1"
    }
}



$ vi server.js

'use strict';

const express = require('express');

const PORT = 8080;

const HOST = '0.0.0.0';

const app = express();

app.get('/', (req, res) => {

  res.send('Hello world\n');

});

app.listen(PORT, HOST);

console.log(`Running on http://${HOST}:${PORT}`);

 


$ vi Dockerfile

FROM node:8

RUN mkdir -p /app

COPY package*.json /app/

WORKDIR /app

COPY . /app

RUN npm install --only=production

EXPOSE 8080

CMD [ "npm", "start" ]



파일 COPY 와 관련 라이브러리 설치 순서가 중요

위의 Dockerfile 의 경우 현재 디렉토리 소스를 COPY 한 후에 npm install 을 수행합니다.


docker 이미지는 변경된 레이어만 build 되지만 연관된 하위 레이어까지 build 됩니다.


여기서는 현재 디렉토리 소스가 변경되면 npm install 을 매번 다시 수행합니다.


그러므로 일단 package 설치를 먼저하고 COPY 를 나중에 하면 package 설치 내용이 변경되지 않는다면 npm install 은 캐시를 바로 사용하여 설치하지 않습니다.

 


RUN npm install --only=production

COPY . /app

 




마지막으로, 컴파일 하는 소스의 docker 이미지를 살펴보겠습니다.

 

$ vi hello.c

#include <stdio.h>

int main () {

  printf ("Hello, world!\n");

  return 0;

}



$ vi Dockerfile

FROM alpine:3.8

RUN apk update && \

    apk add --update alpine-sdk

RUN mkdir -p /app

COPY . /tmp

WORKDIR /tmp

RUN gcc hello.c -o hello

ENTRYPOINT ["/tmp/hello"]


 

Multistep build 활용

위의 경우에 c 컴파일을 하기 위해 c 컴파일로가 들어있는 sdk 패키지를 설치하고 바이너리 파일로 컴파일을 하므로 이미지 사이즈가 커집니다.


여기서 build 단계를 활용하면 sdk 패키지는 제외하고 최종 바이너리 파일만 docker 이미지에 넣을 수 있습니다.

 

$ vi Dockerfile

FROM alpine:3.8 AS build

RUN apk update && \

    apk add --update alpine-sdk

RUN mkdir -p /app

COPY . /tmp

WORKDIR /tmp

RUN gcc hello.c -o hello


FROM alpine:3.8

COPY --from=build /tmp/hello /app/hello

ENTRYPOINT ["/app/hello"]

 




아래 이미지 사이즈는 build 스텝을 활용하지 않은 파일 사이즈와 활용한 사이즈의 차이입니다.



seungkyua/c-hello-world      176MB

 


seungkyua/c-hello-world      4.42MB


Posted by Kubernetes Korea co-leader seungkyua@gmail.com

docker 이미지가 어떻게 구성되는지 이해하기 위해서는 Copy-on-write 정책을 이해해야 합니다.


아래와 같은 Dockerfile 이 있고 이를 이미지로 만들었을 때 이미지가 차지하는 스토리지 구성은 다음과 같습니다.

(아래 Dockerfile 은 sample 파일로 make tool 까지 있다고 가정합니다.)

 

FROM ubuntu:15.04
COPY . /app
RUN make /app
CMD python /app/app.py

 

container-layers.jpg  

이미지 출처: https://docs.docker.com/v17.09/engine/userguide/storagedriver/images/container-layers.jpg

 

가장 아래 레이어 d3a1f33e8a5a 는 ubuntu:15.04 이미지 입니다.


그 다음 바로 위의 c22013c84729 는 현재 디렉토리의 이하의 모든 소스를 /app 디렉토리 아래 복사한 이미지 레이어입니다. (COPY . /app 명령에 의한)


d74508fb6632 는 RUN make /app 가 실행된 이미지 레이어이고, 마지막으로 91e54dfb1179 는 CMD python /app/app.py 이미지 레이어입니다.


Dockerfile 에서 하나의 명령어는 하나의 이미지 레이어 이며, 여기까지 이미지는 Read Only 이미지로 컨테이너가 실행되어도 바꿀 수 없습니다.

 

위의 Dockerfile 로 만든 이미지로 컨테이너가 실행되면 제일 상단의 Container Layer 로 Thin Read/Write 스토리지가 생기며, 여기에만 데이터 쓰기가 가능합니다.


같은 이미지로 컨테이너 인스턴스를 여러 개 실행시켜도 이미지는 공유하며 Container Layer 만 각 인스턴스별로 생겨 자신의 쓰기 스토리지가 생기는 구조이며, 기본적으로 컨테이너가 실행되면서 생긴 스토리지는 실행된 컨테이너가 삭제될 때 같이 삭제됩니다.  

 

위의 Dockerfile 에서 두번째 라인이 현재 디렉토리를 /app 아래로 복사는 명령어에서 현재 디렉토리에 있는 파일이 변경되었다고 가정해 봅시다.


다시 이미지를 만들 경우 맨아래 d74508fb6632 이미지 레이어는 링크로 그대로 활용되고, c22013c84729 이미지 레이어를 먼저 복사하고(copy), 수정된 파일들을 /app 디렉토리 아래로 복사하는(write) 부분이 일어나며 그 이후의 이미지 레이어들은 계속 실행됩니다.



Dockerfile 을 작성할 때 기본 예약 명령어는 다음과 같습니다.


FROM nginx:alpine


nginx 이미지의 alpine 태그를 Base 이미지로 사용합니다.



RUN mkdir -p /app


mkdir -p /app 명령을 실행합니다. shell 명령어를 쓸 때 사용합니다.



ADD source.tar /app/


source.tar 를 /app 디렉토리 아래에 풉니다.



ADD http://ahnseungkyu.com/release /data/


인터넷의 http://ahnseungkyu.com/release 파일을 /data 디렉토리 아래에 다운받습니다.



COPY . /app


현재 디렉토리의 모든 파일과 하위 디렉토리를 /app 디렉토리 아래로 복사합니다. 



COPY ./conf /app/conf


conf 디렉토리 아래의 모든 파일과 하위 디렉토리를 /app/conf 디렉토리 아래로 복사합니다.



COPY ./*.js /app/


현재 디렉토리으 모든 js 파일을 /app 디렉토리 아래로 복사합니다.




추가로 Dockerfile 을 작성할 때 가장 기본이 되는 CMD 와 ENTRYPOINT 의 차이에 대해서 알아보겠습니다.

Dockerifle 에서는 기본적으로 최소 하나의 CMD 혹은 ENTRYPOINT 가 있어야 하며, 둘 다 있을 수 도 있습니다.

즉, docker 를 실행할 때 CMD 로 호출하거나 ENTRYPOINT 로 호출 할 수 있습니다.

아래 alpine ping Dockerfile 을 예로 살펴보겠습니다.


From alpine:latest

RUN apk update && apk add --update iputils \

  && rm -rf /var/cache/apk/*

CMD ["ping", "-c", "3", "8.8.8.8"]



여기서는 CMD 를 사용하여 ping -c 3 8.8.8.8 명령어를 실행했습니다.

docker 이미지를 만들고 실행해보면 결과가 잘 나옵니다.


$ sudo docker build -t seungkyua/alpine-sample .


$ sudo docker run --name alipine-sample --rm -it seungkyua/alpine-sample



이것을 ENTRYPOINT 사용으로 바꾸면 다음과 같습니다.


From alpine:latest

RUN apk update && apk add --update iputils \

  && rm -rf /var/cache/apk/*

ENTRYPOINT ["ping", "-c", "3", "8.8.8.8"]



똑같이 결과가 나타납니다.


그럼 이 둘의 차이는 무엇일까요? 그건 둘 다 사용했을 때 알 수 있습니다. 다음과 같이 바꿔보겠습니다.


From alpine:latest

RUN apk update && apk add --update iputils \

  && rm -rf /var/cache/apk/*

ENTRYPOINT ["ping"]

CMD ["-c", "3", "8.8.8.8"]



결과가 똑같습니다. 하지만 여기서 아래와 같이 docker 를 실행할 때 8.8.8.8 을 맨 뒤에 추가하면 결과가 달라집니다.


$ sudo docker run --name alipine-sample --rm -it seungkyua/alpine-sample 8.8.8.8


마지막의 CMD 부분이 argument 로 처리 되는데 8.8.8.8 이라는 argument 가 override 되어 -c 3 8.8.8.8 부분이 8.8.8.8 로 되어 버립니다. 


결과적으로 ENTRYPOINT 와 CMD 를 함께 쓰는 경우는 CMD argument 를 override 하고 싶을 때 사용할 수 있기 때문에 가능하면 둘 다 사용하는 방법을 추천드립니다.






Posted by Kubernetes Korea co-leader seungkyua@gmail.com
TAG docker, Layer

PID namespace 외에 Network namespace 를 알아보겠습니다.

처음 글을 시작한 의도는 docker 를 잘 활용하자는 의미였는데 하다보니 아직 그 내용은 들어가 보지도 못했네요.


개발자나 운영자들은 잘 인식하지 못하지만 linux 의 Network 는 모두 namespace 구조하에 움직이고 있습니다.


기본적으로 host 기반으로 사용하는 network 의 namespace 는 1 입니다. 그리고 docker 가 실행되면 docker process 에 대해서 내부적인 network 를 사용합니다.


network namespace 와 network namespace 간의 연결은 virtual ethernet (veth) 를 사용하여 연결합니다. 즉, veth pair 를 만들어서 하나는 docker 내부에 다른 하나는 host 로 하여 서로 네트워크로 연결하고 host 에 있는 veth 는 host 의 bridge 로 연결하면 docker 내부에서 host 의 bridge 로 연결이 됩니다.

 

docker 컨테이너 (eth0)  <-> host veth  <->  host bridge (docker0)  <->  host network (ens2f0)

 


먼저, host veth 의 리스트를 보겠습니다.


$ sudo ip addr show


15479: vethf5fa5c1@if15478: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP

    link/ether 32:83:61:96:55:4a brd ff:ff:ff:ff:ff:ff link-netnsid 1

15481: veth4667f7d@if15480: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP

    link/ether 56:39:6e:41:3d:50 brd ff:ff:ff:ff:ff:ff link-netnsid 0

15483: vethd61c546@if15482: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP

    link/ether b2:4a:88:71:d0:03 brd ff:ff:ff:ff:ff:ff link-netnsid 2

15489: vethbe5dd5b@if15488: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker_gwbridge state UP

    link/ether fe:85:37:ac:ea:76 brd ff:ff:ff:ff:ff:ff link-netnsid 4

15493: veth66998b7@if15492: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP

    link/ether 42:5f:03:92:45:9d brd ff:ff:ff:ff:ff:ff link-netnsid 5

 


총 5개가 보이는데 이중 하나는 docker gateway bridge 로 연결되고 나머지 4개는 1:1 로 각각 docker 내부의 eth0 와 연결되어 있습니다.


이를 좀 쉽게 찾기 위해서 veth.sh 파일을 만들었습니다.


#!/bin/bash


VETHS=`ifconfig -a | grep veth | sed 's/ .*//g'`

DOCKERS=$(docker ps -a | grep Up | awk '{print $1}')


for VETH in $VETHS

do

  PEER_IFINDEX=`ethtool -S $VETH 2>/dev/null | grep peer_ifindex | sed 's/ *peer_ifindex: *//g'`

  for DOCKER in $DOCKERS

  do

    PEER_IF=`docker exec $DOCKER ip link list 2>/dev/null | grep "^$PEER_IFINDEX:" | awk '{print $2}' | sed 's/:.*//g'`

    if [ -z "$PEER_IF" ]; then

      continue

    else

      printf "%-10s is paired with %-10s on %-20s\n" $VETH $PEER_IF $DOCKER

      break

    fi

  done

done



위 파일을 실행하면 아래와 같이 나옵니다.


veth4667f7d: is paired with eth0@if15481 on b75a945f84fa        

veth66998b7: is paired with eth0@if15493 on 67246d3e1c68        

vethd61c546: is paired with eth0@if15483 on 87faa6bacbba        

vethf5fa5c1: is paired with eth0@if15479 on 0b4bc5ba78f9

 

마지막에 보이는 것은 docker id 입니다.

 

host 의 docker0 bridge 가 어떻게 연결되어 있는 지는 brctl 로 알 수 있습니다. 


$ sudo yum install -y bridge-utils


$ sudo brctl show




docker0 bridge 가 어떻게 host 의 외부 네트워크로 나가는 지는 iptables 와 routing 을 보면 알 수 있습니다.


$ sudo iptables -t nat -S


-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

 


source 가 docker 내부 ip 대역이고 host 입장에서 패킷이 나가는 인터페이스가  docker0 가 아니면 jump 를 하고 host의 ip 로 변경해서 (masquerade) 나가라고 되어 있습니다. 

 


$ netstat -rn


Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface

0.0.0.0            192.168.30.1    0.0.0.0           UG        0 0          0 ens2f0

172.17.0.0        0.0.0.0            255.255.0.0     U         0 0          0 docker0

172.18.0.0        0.0.0.0            255.255.0.0     U         0 0          0 docker_gwbridge

 

그리고 위와 같이 외부로 나갈 때는 default gateway 로 외부로 나가게 됩니다.

 

 

Posted by Kubernetes Korea co-leader seungkyua@gmail.com

Kubernetes 는 여러 컨테이너를 관리할 수 있습니다. 그 이유는 kubernetes kubelet 과 컨테이너 데몬이 정해진 spec 에 따라 gRPC 통신을 하기 때문입니다.  Kubernetes 는 여러 컨테이너를 적용할 수 있는데 rkt, docker, CRI-O 등이 있습니다. 이중에서 가장 많이 사용하는 Docker 에 대해서 설명하고자 합니다.

앞서 kubespray 사용에 대해서 설명이 있는데, 여기를 보면 Production Level 로 사용 가능한 CentOS, RedHat, Ubuntu에 맞게 docker 를 쉽게 설치할 수 있습니다. 여기서는 Docker 를 이미 설치한 후에 어떻게 Docker 를 잘 활용할 수 있는지에 대해서 설명합니다.

1. dockerd config option reload

대부분의 Linux 는 이제 systemd 를 활용하고 있습니다. 그렇기 때문에 docker 데몬 실행은 systemd 에 설치된 docker.service 를 보면 됩니다. 디렉토리는 둘 중에 하나를 찾아보면 됩니다.

/etc/systemd/system/multi-user.target.wants/docker.service

/etc/systemd/system/docker.service

 

제 환경은 CentOS 로 이렇게 정의가 되어 있습니다.

MountFlags=shared

EnvironmentFile=-/etc/sysconfig/docker

ExecStart=/usr/bin/dockerd $DOCKER_OPTS

ExecReload=/bin/kill -s HUP $MAINPID

 

dockerd 의 환경 파일로 /etc/sysconfig/docker 를 읽게 되어 있고 해당 파일은 아래 옵션으로 정의되어 있습니다.

DOCKER_OPTS="--storage-driver=overlay2 --insecure-registry docker-registry:5000 --insecure-registry oreo:5000"

 

이 경우 systemctl restart docker.service 를 하면 dockerd 가 restart 되는데 문제는 이미 실행되고 있는 docker 컨테이너가 영향을 받아 stop 으로 빠집니다. (kubernetes 의 deployment, daemonset, statefulset 혹은 docker 의 --restart=always 가 아닌 경우) 그러므로, docker 옵션만 reload 해야 기존의 실행되고 있는 컨테이너가 영향을 받지 않습니다.

docker option reload 는 SIGHUP 을 보내면 됩니다. 

$ sudo kill -SIGHUP $(pidof dockerd)

 

하지만, 지금의 세팅으로는 다시 올라오지 않습니다.

dockerd 로그를 보면 다음과 같습니다. 로그는 다음 명령어로 볼 수 있습니다.

$ sudo journalctl --no-pager -u docker.service

kube-deploy dockerd[16391]: time="2018-10-27T18:36:17.767207453+09:00" level=info msg="Got signal to reload configuration, reloading from: /etc/docker/daemon.json"

kube-deploy dockerd[16391]: time="2018-10-27T18:36:17.767283042+09:00" level=error msg="open /etc/docker/daemon.json: no such file or directory"

 

디폴트로 dockerd 옵션은 /etc/docker/daemon.json 파일을 읽기 때문에 옵션  reload  가 안되는 문제가 있습니다.

이를 해결하기 위해서 다음과 같이 변경해 보겠습니다.

docker.service 에 정의된 EnvironmentFile 의 변수를 daemon.json 으로 옮기겠습니다.

/etc/systemd/system/multi-user.target.wants/docker.service

EnvironmentFile=-

 

$ sudo mkdir -p /etc/docker

$ sudo vi /etc/docker/daemon.json

{

    "storage-driver": "overlay2",

    "insecure-registries": ["docker-registry:5000", "oreo:5000"]

}

 

docker.service 를 바꿨으니 어쩔 수 없이 한 번의 docker restart 는 해야 합니다.

$ sudo systemctl daemon-reload

$ systemctl restart docker.service

 

이제 현재의 dockerd option 이 어떤지 보겠습니다.

$ sudo docker system info

 

Storage Driver: overlay2

Insecure Registries:

  docker-registry:5000

  oreo:5000

  127.0.0.0/8

 

Insecure Registries 의 oreo:5000 을 제거하고 싶다면 다음과 같이 daemon.json 에서 변경하면 됩니다.

{

    "storage-driver": "overlay2",

    "insecure-registries": ["docker-registry:5000"]

}

 

그리고 SIGHUP 을 보내서 option reload 를 하면 새로운 옵션이 적용됩니다.

$ sudo kill -SIGHUP $(pidof dockerd)

 

dockerd 옵션에 oreo:5000 이 Insecure Registries 에서 빠져 있는 것을 볼 수 있습니다.

$ sudo docker system info

 

Storage Driver: overlay2

Insecure Registries:

  docker-registry:5000

  127.0.0.0/8

 

 

Posted by Kubernetes Korea co-leader seungkyua@gmail.com

ca-key.pem -> ca.pem

server-key.pem -> server.csr -> server.csr + (ca-key.pem + ca.pem) -> server.cert

client-key.pem -> client.csr -> client.csr + (ca-key.pem + ca.pem) -> client.cert



[ CA 생성 ]


1. ca-key.pem => ca.pem    (ca.crt: client ca 파일)

$ sudo mkdir -p /etc/docker

$ cd /etc/docker

$ echo 01 | sudo tee ca.srl


$ sudo openssl genrsa -des3 -out ca-key.pem

Enter pass phrase for ca-key.pem:

Verifying - Enter pass phrase for ca-key.pem:


$ sudo openssl req -new -days 365 -key ca-key.pem -out ca.pem

Enter pass phrase for ca-key.pem:

...

Common Name (e.g. server FQDN or Your name) []: *         (ex : www.ahnseungkyu.com)



[ Server Cert 생성 ]


1. server-key.pem => server.csr    (Common Name : e.g. server FQDN 이 중요)

$ sudo openssl genrsa -des3 -out server-key.pem

Enter pass phrase for server-key.pem:

Verifying - Enter pass phrase for server-key.pem:


$ sudo openssl req -new -key server-key.pem -out server.csr

Enter pass phrase for server-key.pem:

...

Common Name (e.g. server FQDN or Your name) []: *         (ex : www.ahnseungkyu.com)


2. ca-key.pem + ca.pem + server.csr => server-cert.pem (server.cert: 서버 cert 파일)

$ sudo openssl x509 -req -days 365 -in server.csr -CA ca.pem -CAkey ca-key.pem -out server-cert.pem

Enter pass phrase for ca-key.pem:


3. server-key.pem 의 phrase 를 삭제 (server.key: 서버 private key 파일)

$ sudo openssl rsa -in server-key.pem -out server-key.pem

Enter pass phrase for server-key.pem:

writing RSA key


4. 퍼미션 수정

$ sudo chmod 600 /etc/docker/server-key.pem /etc/docker/server-cert.pem /etc/docker/ca-key.pem /etc/docker/ca.pem




[ Docker 데몬 설정 ]


Ubuntu, Debian : /etc/default/docker

RHEL, Fedora    : /etc/sysconfig/docker

systemd 버전     : /usr/lib/systemd/system/docker.service




[ systemd Docker Server 실행 ]


ExecStart=/usr/bin/docker -d -H tcp://0.0.0.0.2376 --tlsverify --tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server-cert.pem --tlskey=/etc/docker/server-key.pem


[ Docker 데몬 reload 및 재시작 필요 ]

$ sudo systemctl --system daemon-reload




[ Client Cert 생성 ]


1. client-key.pem => client.csr

$ sudo openssl genrsa -des3 -out client-key.pem

Enter pass phrase for client-key.pem:

Verifying - Enter pass phrase for client-key.pem:


sudo openssl req -new -key client-key.pem -out client.csr

Enter pass phrase for client-key.pem:

...

Common Name (e.g. server FQDN or Your name) []:



2. Client 인증 속성 추가

$ echo extendedKeyUsage = clientAuth > extfile.cnf



3. ca-key.pem + ca.pem + client.csr => client-cert.pem

$ sudo openssl x509 -req -days 365 -in client.csr -CA ca.pem -CAkey ca-key.pem -out client-cert.pem -extfile extfile.cnf

Enter pass phrase for ca-key.pem:



4. client-key 의 phrase 를 삭제

$ sudo openssl rsa -in client-key.pem -out client-key.pem

Enter pass phrase for client-key.pem:

writing RSA key




[ Docker 클라이언트에 ssl 설정 ]


$ mkdir -p ~/.docker

$ cp ca.pem ~/.docker/ca.pem

$ ca client-key.pem ~/.docker/key.pem

$ ca client-cert.pem ~/.docker/cert.pem

$ chmod 600 ~/.docker/key.pem ~/.docker/cert.pem


# docker 연결 테스트

$ sudo docker -H=docker.example.com:2376 --tlsverify info



# server

# sudo docker -d --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem \

--tlskey=server-key.pem -H=0.0.0.0:4243


# client -- note that this uses --tls instead of --tlsverify, which I had trouble with 

# docker --tls --tlscacert=ca.pem --tlscert=client-cert.pem --tlskey=client-key.pem \

-H=dns-name-of-docker-host:4243









Posted by Kubernetes Korea co-leader seungkyua@gmail.com
TAG ca, CERT, docker, SSL, TLS