🐳 Docker를 이용한 배포

Dockerizing

Application 을 Docker Image로 Wrapping

FROM node:10

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000
CMD [ "node", "index.js" ]

Docker Registry

Docker Image에 대한 저장소

기본적으로 Docker Hub를 사용

Application 배포시에는 Private Registry를 사용

version: "3"
services:
  registry:
    container_name: registry
    image: registry:2.6
    ports:
      - 5000:5000
    volumes:
      - "./registry-data:/var/lib/registry"

Docker Image로 제공

ECR, Quay.io ...

Docker Registry

# docker image build
docker build -t test-server .

# docker image tagging
docker tag test-server localhost:5000/test-server

# docker image push
docker push localhost:5000/test-server

Docker Image Push 과정

docker tag <옵션> <이미지 이름>:<태그> <저장소 주소, 사용자명>/<이미지 이름>:<태그>

Docker Tag 형식

이제 배포

다른 머신에 배포하려면 ?

App Dockerizing & Build

Image Registry Push

Image Pull & Run

Node-01

Node-02

Docker Daemon

- Container를 관리하는 Background 프로세스

Docker Socket

- 실행시 옵션을 받거나 혹은 daemon.json 파일을 통해서 관리

- Docker Daemon 은 Docker Engine API를 요청해서 사용

- Docker Engine API는 unix, tcp, fd 세가지 Socket을 사용 가능

$ sudo dockerd -H unix:///var/run/docker.sock -H tcp://192.168.59.106 -H tcp://10.10.10.2

example

DOCKER_HOST 환경 변수

Docker Remote API 를 요청하는 소켓을 지정할 수 있음

$ export DOCKER_HOST="tcp://0.0.0.0:2375"

Node01

Node02

192.168.0.1

192.168.0.2

DOCKER_HOST=192.168.0.1

$ docker run echo -d

echo

Shell Script를 통한 Deploy

LOCAL_IMAGE=test-server
REMOTE_IMAGE=registry:5000/test-server

echo "Build Image"
docker build -t ${LOCAL_IMAGE} .
docker tag ${LOCAL_IMAGE} ${REMOTE_IMAGE} 
docker push ${REMOTE_IMAGE} 

echo "Deploy node02"
export DOCKER_HOST="tcp://node02:3000"
docker pull ${REMOTE_IMAGE} 
docker rm -f test-server || true 
docker run -p 4000:3000 --name test-server -d ${REMOTE_IMAGE} 

Node 1번에서 2번으로 배포하는 스크립트

Blue - Green 배포

Load Balancer를 이용해서 무중단 배포 

Nginx load balancing config

http {
 upstream app {
    server localhost:4000;
    server localhost:4001;
  }

  server {
    listen 80;

    location / {
      proxy_pass http://app;
    }
  }

}

Helth check를 통해서 살아있는 쪽으로 트래픽 전달

컨테이너를 순차적으로 업데이트 가능

Blue-Green Script

#!/bin/sh
export DOCKER_HOST=...

if [ $(docker ps -f name=blue -q) ]
then
    ENV="green"
    PORT=4000
    OLD="blue"
else
    ENV="blue"
    PORT=4001
    OLD="green"
fi

echo "Starting "$ENV" container"
PORT=${PORT} docker-compose --project-name=$ENV up -d

echo "Waiting..."
sleep 5s

echo "Stopping "$OLD" container"
docker-compose --project-name=$OLD down

Nginx load balancing 단점

물리 노드가 추가될시 자동으로 인식 불가능 (설정파일 수정)

고정적인 IP & Port

Docker Swarm

Docker 에 기본적으로 내장된 컨테이너 오케스트레이션 툴

오케스트레이션 ?

컨테이너 스케쥴링 

클러스터링

서비스 디스커버리

멀티 호스트 네트워크 지원 (Overlay)

매니저 노드와 워커 노드

스웜 클러스터 상태 관리를 위한 노드

$ docker swarm init

초기에 스웜을 initialize 한 노드가 매니저 노드

$ docker swarm join <token>

매니저 노드에 조인한 다른 노드들 

워커 노드

서비스

스웜 모드에서의 기본적인 배포 단위

Compose와 비슷하지만 Multi Host에 배포가 가능하고 Scale 설정

$ docker service create --replicas 1 --publish 8000:8000 --name echo registry/echo

replicas 는 배포될 container 개수를 의미

service scale 명령을 통해 추후에 scale 조정 가능

Ingress Network

서비스가 publish 한 port를 모든 Host가 해당 port를 open

현재 살아있는 node에 알아서 전달

Rolling Update

$ docker service update --image <최신이미지> ip-server

docker swarm이 알아서 순차적으로 이미지를 업데이트

상황에따라서 중단될수도 그렇지 않을수도 있음

스택

하나의 이상의 서비스를 그룹으로 묶은 단위

version: "3"
services:
  nginx:
    image: gihyodocker/nginx-proxy:latest
    deploy:
      replicas: 3
      placement:
        constraints: [node.role != manager]
    environment:
      SERVICE_PORTS: 80
      BACKEND_HOST: echo_api:8080
    depends_on:
      - api
    networks:
      - ch03
  api:
    image: registry:5000/example/echo:latest
    deploy:
      replicas: 3
      placement:
        constraints: [node.role != manager]
    networks:
      - ch03

Reverse Proxy 이용하기(traefik)

Swarm mode traefik

version: "3.3"
services:
  traefik:
    image: traefik
    command: --web \
      --docker \
      --docker.swarmmode \
      --docker.domain=test.com \
      --docker.watch \
      --logLevel=DEBUG
    ports:
      - "80:80"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - ch03
    deploy:
      placement:
        constraints: [node.role==manager]
networks:
  ch03:
    external: true

Docker Event 감시 host 추가되면 도메인 연결

 Jenkins를 이용한 CI / CD

Jenkins Setup

Dockerfile

FROM jenkinsci/jenkins:latest

USER root
RUN apt-get update -qq
RUN apt-get install -qqy apt-transport-https ca-certificates
RUN apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
RUN echo deb https://apt.dockerproject.org/repo debian-jessie main > /etc/apt/sources.list.d/docker.list
RUN apt-get update -qq
RUN apt-get install -qqy docker-engine

USER jenkins

Jenkins 이미지 내부에서 Docker 사용을 위해 Docker-Engine 셋업

Jenkins Setup

귀찮다면 추천 플러그인 모두 설치 

Docker를 이용한 배포

By y0c

Docker를 이용한 배포

  • 580