[배포] 2.무중단 배포 nginx

1. Nginx

  1. nginx를 이용해 라우팅 할 컨테이너를 실행한다.

    $ docker run -p 8081:8080 --name myapp-container1 zkdlu/myapp:v1
    $ docker run -p 8082:8080 --name myapp-container2 zkdlu/myapp:v1
    
  2. nginx의 reverse-proxy를 이용해 해당 서비스로 라우팅 해준다.

    1. nginx.conf 작성

      worker_processes 4; 
            
      events { worker_connections 1024; } 
            
      http { 
        upstream my-app { 
          least_conn; 
      	server localhost:8081 weight=10 max_fails=3 fail_timeout=30s; 
      	server localhost:8082 weight=10 max_fails=3 fail_timeout=30s; 
        } 
            	
        server { 
      	listen 80; 
      	location / { 
      		proxy_pass http://my-app; 
      		proxy_http_version 1.1; 
      		proxy_set_header Upgrade $http_upgrade; 
      		proxy_set_header Connection 'upgrade'; 
      		proxy_set_header Host $host; 
      		proxy_cache_bypass $http_upgrade; 
      	} 
        }
      }
      

      nginx에 대한 공부는 차후 진행 할 예정

    2. 설치하기 싫으니까 nginx도 Docker를 이용한다.

      # Dockerfile
      FROM nginx 
      COPY nginx.conf /etc/nginx/nginx.conf
      RUN apt-get update
      RUN apt-get install vim
      
      $ docker build --tag nginx-image .
      

      실행

      $ docker run -p 80:80 --name nginx-container -v nginx.conf:/etc/nginx/nginx.conf  nginx-image
      

Rolling 배포

  1. 업데이트 할 서비스를 nginx에서 down 상태로 변경한다.

    worker_processes 4; 
       
    events { worker_connections 1024; } 
       
    http { 
      upstream my-app { 
        least_conn; 
        server localhost:8081 weight=10 max_fails=3 fail_timeout=30s; 
        server localhost:8082 weight=10 max_fails=3 fail_timeout=30s down; 
      } 
       
      server { 
        listen 80; 
        location / { 
            proxy_pass http://my-app; 
            proxy_http_version 1.1; 
            proxy_set_header Upgrade $http_upgrade; 
            proxy_set_header Connection 'upgrade'; 
            proxy_set_header Host $host; 
            proxy_cache_bypass $http_upgrade; 
        } 
      }
    }
    
  2. nginx를 reload 한다.

    $ docker exec -it nginx-container service nginx reload
    
  3. 기존 컨테이너를 제거 한 후 업데이트 된 컨테이너를 실행한다.

    $ docker run -p 8082:8080 --name myapp-container2 zkdlu/myapp:v2
    
  4. nginx의 설정을 서로 변경 후 위 과정을 반복한다.

    ...
     upstream my-app { 
        least_conn; 
        server localhost:8081 weight=10 max_fails=3 fail_timeout=30s down; 
        server localhost:8082 weight=10 max_fails=3 fail_timeout=30s; 
      } 
    ...
    

Blue/Green 배포

Nginx에서 Rolling 을 이용한 무중단 배포는 굉장히 번거로운 점이 있었다.

docker-compose를 이용하면 번거로운 작업을 줄일 수 있다.

  1. docker-compose 실행

    #docker-compose.yml
    version: '3'
    services:
      proxy:
        image: nginx:latest
        container_name: nginx_container
        ports: 
          - "80:80"
        volumes:
          - ./nginx.conf:/etc/nginx/nginx.conf
      myapp1:
        image: zkdlu/myapp:v1
        container_name: myapp-container1
        expose:
          - "8080"
      myapp2:
        image: zkdlu/myapp:v1
        container_name: myapp-container2
        expose:
          - "8080"
    
    $ docker-compose up -d
    
  2. nginx.conf 설정하기

    worker_processes 4; 
       
    events { worker_connections 1024; } 
       
    http { 
      upstream my-app { 
        server myapp-container1:8080 weight=10 max_fails=3 fail_timeout=30s; 
        server myapp-container2:8080 weight=10 max_fails=3 fail_timeout=30s; 
      } 
       	
      server { 
        listen 80; 
        location / { 
          proxy_pass http://my-app; 
          proxy_http_version 1.1; 
          proxy_set_header Upgrade $http_upgrade; 
          proxy_set_header Connection 'upgrade'; 
          proxy_set_header Host $host; 
          proxy_cache_bypass $http_upgrade; 
        } 
      }
    }
    

    docker network는 bridge에 속한 컨테이너가 서로 통신할 때 docker host에서 생성한 dns 서버를 이용하기 떄문에 컨테이너의 이름으로 설정이 가능하다.

  3. 실행하기

    $ docker-compose up -d
    
  4. docker-compose가 실행된 후에 업데이트를 진행한다.

  5. docker-compose.yml 에 새로운 버전의 서비스를 증설한다.

    ....
      myapp1:
        image: zkdlu/myapp:v1
        container_name: myapp-container1
        expose:
          - "8080"
      myapp2:
        image: zkdlu/myapp:v1
        container_name: myapp-container2
        expose:
          - "8080"
      myapp3:
        image: zkdlu/myapp:v2
        container_name: myapp-container3
        expose:
          - "8080"
      myapp4:
        image: zkdlu/myapp:v2
        container_name: myapp-container4
        expose:
          - "8080"      
    

    docker-compose를 실행하면 변경 된 사항만 추가된다.

    $ docker-compose up -d
    
  6. reverse proxy를 다시 설정하여 새로운 서비스로 라우팅 되도록 한다

    worker_processes 4; 
       
    events { worker_connections 1024; } 
       
    http { 
      upstream new-my-app { 
        server myapp-container3:8080 weight=10 max_fails=3 fail_timeout=30s; 
        server myapp-container4:8080 weight=10 max_fails=3 fail_timeout=30s; 
      } 	
           
      server { 
        listen 80; 
        location / { 
          proxy_pass http://new-my-app; 
          proxy_http_version 1.1; 
          proxy_set_header Upgrade $http_upgrade; 
          proxy_set_header Connection 'upgrade'; 
          proxy_set_header Host $host; 
          proxy_cache_bypass $http_upgrade; 
        } 
      }
    }
    
  7. nginx를 reload한다.

    $ docker exec nginx-container service nginx reload
    
  8. 업데이트가 완료 되었다면 docker-compose에서 기존의 서비스를 제거한다.

    docker-compose.yml 수정 후

    $ docker-compose up -d --remove-orphans