ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • NCP(Naver Cloud Platform)와 Jenkins -3) CD 환경 구축
    기술 이야기/CI&CD 2020. 11. 2. 16:24
    반응형

    Jenkins, Nginx, docker를 활용한 무중단 CD

    • 보통은 Jenkins 서버와 배포하는 서버를 따로 두지만, NCP에서는 Jenkins가 탑재된 Server를 생성할 수 있고 프로젝트의 규모가 크지 않기 때문에, 하나의 서버에서 진행하는 것으로 전제한다.

    • Docker 설치

      • 패키지 저장소 추가 (도커의 공식 GPG 키와 저장소를 추가)
      •           sudo apt-get update && sudo apt-get install \
                sudo apt-transport-https \
                sudo ca-certificates \
                curl \
                sudo software-properties-common
      • sudo: unable to resolve host라는 값이 console에 찍힌다면, /etc/hostname이 /etc/hosts에 등록되어있지 않아서 그렇다.
      • /etc/hosts에 hostname을 등록해주자
      •    [/etc/hosts]
           127.0.1.1    host_name
      • docker 패키지가 검색되는지 확인하기
      • sudo apt-get update && sudo apt-cache search docker-ce
        • docker-ce - Docker: the open-source application container engine 이렇게 표시된다면 설치패키지가 검색된다는 의미
      • 도커 CE 설치 (무료버전)
      • sudo apt-get update && sudo apt-get install docker-ce
    • Nginx 설치

      • apt-get install nginx 명령어로 Nginx서버 설치
      • Nginx 웹 서버 수동으로 재실행하고 상태 확인하기
      •      service nginx restart
         service nginx status
        • image
    • Dockerfile 작성

      • /home/docker-image에서 작업. server와 client를 구분하여 server만 도커 이미지화 해준다.

      • server 디렉토리 아래 작업

        • vi Dockerfile로 Dockerfile 생성 및 내부를 설정하기

        •       FROM node:12.19.0
          
              MAINTAINER zin0
          
              VOLUME /deploy/issue-tracker/server
          
              RUN mkdir -p /app
          
              WORKDIR /app
          
              COPY ./deploy/ /app
          
              RUN npm install
          
              CMD npm start
      • docker image build -t 도커이미지이름 . 으로 이미지를 빌드한다.

        • docker image build -t issue-tracker-server .
        • .은 현재 path를 의미
      • docker-compose 작성 (blue, green)

        • docker-compose.blue.yml 작성

        • version: '2'

          services:
          issue-tracker-server:

          image: issue-tracker-server-docker-image
          volumes:
              - ./deploy:/deploy/issue-tracker/server
          ports:
              - "3001:3000"
      • docker-compose.green.yml 작성

        • version: '2'

          services:
          issue-tracker-server:

          image: issue-tracker-server-docker-image
          volumes:
              - ./deploy:/deploy/issue-tracker/server
          ports:
              - "3002:3000"
      • deploy.sh 작성

        •      #!/bin/bash
          
             DOCKER_APP_NAME=issue-tracker-server
          
             EXIST_BLUE=$(sudo docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml ps | grep Up)
          
             if [ -z "$EXIST_BLUE" ]; then
                 echo "blue up"
                 sudo docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml up -d
          
                 sleep 10
          
                 sudo docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml down
             else
                 echo "green up"
                 sudo docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml up -d
          
                 sleep 10
          
                 sudo docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml down
             fi
        • deploy.sh에 권한 추가

          • chmod 755 ./deploy.sh
      • client

        • client는 nginx를 통해 띄워주는 것으로 결정, build를 통해 webpack을 적용

        •       deploy.sh 작성
             #!/bin/bash
          
             cd ./deploy
          
             npm install
          
             npm run build
      • compose 파일에서 port:port 이 부분은 외부 port를 도커 컨테이너 내부 port로 바인딩해준다는 뜻이다.

      • Couldn't connect to Docker daemon at http+docker://localunixsocket - is it running? 에러

        • 검색 결과, docker가 정상적으로 실행되는지에 대한 에러라고 한다.

        • 그래서 docker socket을 이용하는 권한추가 sudo chown $USER /var/run/docker.sock나 docker 그룹에 유저를 추가하는 sudo usermod -aG docker $USER나 여러가지 방법을 해봤지만 똑같았다. 마지막으로, docker 컨테이너를 띄울 때, 권한 문제가 있지 않을까 싶어서 deploy.sh의 명령어에 sudo를 붙였다.

        •       #!/bin/bash
          
              DOCKER_APP_NAME=issue-tracker-server
          
              EXIST_BLUE=$(sudo docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml ps | grep Up)
          
              if [ -z "$EXIST_BLUE" ]; then
                  echo "blue up"
                  sudo docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml up -d
          
                  sleep 10
          
                  sudo docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml down
              else
                  echo "green up"
                  sudo docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yml up -d
          
                  sleep 10
          
                  sudo docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml down
              fi
        • 해결되었다.

    • 컨테이너 생성하기

      • docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yml up -d
      • docker-compose가 없다는 메세지가 출력돼서, apt install docker-compose를 통해 설치했다.
      • yaml.scanner.ScannerError: while scanning for the next token found character '\t' that cannot start any token 에러가 뜬다면, yaml 파일에서는 탭('\t')을 지원하지 않는다는 에러다. 따라서, tab으로 작성을 한 부분을 space(' ')로 변경해줘야한다.
      • docker ps -a로 컨테이너가 정상 작동 중인지 확인해준다.
    • Nginx 설정하기

      • Nginx로 blue와 green의 로드밸런싱을 설정
      • vi /etc/nginx/sites-available/issue-tracker-server로 서버 로드밸런싱 설정
      •       # Load Balancing
            upstream issue-tracker-server {
                    least_conn;
                    server 127.0.0.1:3001 weight=5 max_fails=3 fail_timeout=10s;
                    server 127.0.0.1:3002 weight=10 max_fails=3 fail_timeout=10s;
            }
            server {
              listen 3000;
              server_name Naver Cloud 주소;
              location / {
                proxy_pass http://issue-tracker-server;
              }
            }
      • vi /etc/nginx/sites-available/issue-tracker-client로 클라이언트 배포 설정
      •           server {
              listen 80;
              location / {
                root /home/docker-image/client/deploy/dist;
                autoindex on;
                set $fallback_file /index.html;
                if ($http_accept !~ text/html) {
                    set $fallback_file /null;
                }
                if ($uri ~ /$) {
                    set $fallback_file /null;
                }
                index index.html
                server_name $url
                try_files $uri /index.html;
              }
              error_page 404 /index.html;
            }
      • nginx 기본 설정 값들을 삭제해준다.
      •       $ sudo rm /etc/nginx/sites-available/default
            $ sudo rm /etc/nginx/sites-enabled/default
      • 그런 다음 아래 명령어로 이 파일을 /etc/nginx/sites-enabled 디렉터리에 링크
      •       sudo ln -fs /etc/nginx/sites-available/issue-tracker-server /etc/nginx/sites-enabled/
            sudo ln -fs /etc/nginx/sites-available/issue-tracker-client /etc/nginx/sites-enabled/
      • sudo nginx -t 명령어로 문법 이상 유무를 체크해주고, successful이 뜨면 됐다.
      • systemctl stop nginx, systemctl start nginx로 재실행을 해준다.
    • ACG 설정하기

      • 1024 포트(Nginx)를 열어준다.
      • Nginx는 1024포트를 통해 로드 밸런싱을 하기 때문(설정을 1024로 했음)
    • Jenkins Script 작성

      •       #!/bin/sh
            ## docker container image를 만들 디렉토리를 비운다.
            sudo rm -rf /home/docker-image/server/deploy/*
            sudo rm -rf /home/docker-image/client/deploy/*
        
            ## jenkins에서 받아온 파일을 docker image 작업 디렉토리에 복사
            sudo cp -r /var/lib/jenkins/workspace/issue-tracker/server/* /home/docker-image/server/deploy/
            sudo cp -r /var/lib/jenkins/workspace/issue-tracker/client/* /home/docker-image/client/deploy/
        
            ## server 단에서, config를 구성하는 파일이 필요하기 때문에, 미리 저장해둔 파일 복사
            sudo mkdir /home/docker-image/server/deploy/config
            sudo cp /home/docker-image/server/config.json /home/docker-image/server/deploy/config/
        
            #!/bin/sh
            cd /home/docker-image/server
            sudo docker image build -t issue-tracker-server-docker-image .
            ./deploy.sh    
        
            #!/bin/sh
            cd /home/docker-image/client
            ./deploy.sh    
            exit
            EOF
      • 하나의 서버에서 작업하기 때문에, ssh 접속이 필요가 없었다.

      • 대신, deploy 스크립트를 실행할 때 권한 문제가 생겨서 권한을 주가해줬다.

      • chmod +x deploy.sh

      • server와 client를 각각 docker를 띄워 nginx로 로드 밸런싱해준다.

      • server에 config 디렉토리와 json 파일이 필요하기 때문에, 서버에 저장해뒀다가 docker를 image화 하는 디렉토리 아래 복사해주는 명령어를 추가했다.

    • sequilze connection error

      • GRANT ALL PRIVILEGES ON . TO root@'ip주소' IDENTIFIED BY '비밀번호'' WITH GRANT OPTION;
      • DB 접근 권한이 없기 때문에 localhost로는 접근이 가능하지만, 다른 ip로 접근했을 때 나오는 오류다. HOST에게 DB를 접근할 권한을 부여해서 해결하는 방법이다.
    • [nginx에서 세부 경로를 조회했을 때 React Router로 넘어가지 않는 오류](https://github.com/boostcamp-2020/IssueTracker-35/issues/10)
      • react는 SPA형식으로 index.html만을 사용하지만, nginx의 경우는 URL에 맞는 html파일을 찾으려고 하는 문제가 원인.
      • 설정 파일의 location 하단에 `server_name $url` 설정 파일에 url로 호스트를 설정해줘서 해결
      • 에러메세지는 사라졌는데 왜일까..? 파일을 찾는게 아닌, spa 내에서 처리하게 되는걸까??

    • 기타
    • NodeJS 설치
      • PPA 추가
      • curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
      • NodeJS 설치
      • sudo apt-get install -y nodejs
      • build-essential 설치
      • sudo apt-get install build-essential
        • PPA를 통해서 NodeJS를 설치하면 npm도 함께 설치가 되는데, npm install시 에러가 발생하는 것을 방지하기 위해 build-essential을 설치해준다.
      • 설치가 완료되면 node -v로 버전을 확인해준다.
    • server forever 구동
      • forever start는 background 명령이기 때문에 도커 컨테이너가 계속 죽음 ~> forever app.js로 도커 컨테이너가 죽지 않도록 설정

    • 문제점
      • 동일 서버에서 클라이언트 배포, API 서버 배포, docker image화 및 jenkins, nginx를 한번에 돌리기 때문에 메모리 부하 및 용량이 걱정된다.
      • 하지만, 토이 프로젝트기 때문에 큰 문제가 없을 것으로 판단되고 서버당 요금이 무시할 수준은 아니기 때문에 하나에서 진행
      • 지원받는 크레딧이 있긴 하지만, 12월 까지 다른 프로젝트도 돌려야하므로 서버 한대로 진행하기로 결정했다.

    Reference

    반응형

    댓글

Designed by Tistory.