-
Notifications
You must be signed in to change notification settings - Fork 3
무중단 CI & CD (Jenkins & Nginx & Docker)
Zin0_0 edited this page Nov 4, 2020
·
1 revision
NCP를 이용한 Jenkins 서버 구축
- 서버 생성
- 이미지 타입에서 Application 선택 후, Jenkins 이미지 체크
- 인증키 설정
- 특이 사항은 없음
- ACG(방화벽) 설정
- 기존 ACG 설정이 있다면 이용해도 괜찮다.
- 이번 서버 구축에서는 필요한 주소만 추가하면서 여는 연습을 하기 위해 새로 생성
- Public IP 설정
- Jenkins 상태 확인 명령어
-
# Jenkins 프로세스 기동 및 중지 service jenkins start service jenkins stop service jenkins status
- 상태 확인 ~> 실행 중인 것을 확인할 수 있음
-
- 웹 브라우저로 Jenkins 접속
- 공인IP:18080
- 초기 접속화면으로 위와 같은 화면을 확인할 수 있다.
- 초기 패스워드는 터미널에서 확인할 수 있다.
-
cat /var/lib/jenkins/secrets/initialAdminPassword
-
- 초기 패스워드 이후, 젠킨스 install
- 좌측은 Jenkins 커뮤니티에서 가장 유용하다고 알려진 플러그인들을 설치해준다.
- Plugins 설치 오류 발생 시, Jenkins 커뮤니티에서 해결 가능하다 한다.
- 우측은 플러그인을 직접 선택해서 설치하는 방법
- NCP에서 제공하는 Jenkins 버전(작성 기준 2.73.2)에 호환되는 Plugins 직접 선택
- 우선은 설정 문제가 생겼을 때, 더 빠른 해결을 위해 좌측을 선택
- 좌측은 Jenkins 커뮤니티에서 가장 유용하다고 알려진 플러그인들을 설치해준다.
- 젠킨스 계정 설정
- 위의 설치가 끝나면, 젠킨스 계정을 설정하는 창이 나타난다.
- 젠킨스 URL 설정
- 계정 생성을 하고나면 URL을 설정하는 창이 나타난다
- 따로 URL을 지정해줄 수 있지만, default 값이 권장이기 때문에 그대로 진행
- 젠킨스 접속
- 예시와 다르게 Empty page가 나타났다. 그래서 putty로 서버에 접속해서 jenkins를 중지했다가 다시 키니까 아래와 같은 화면이 나왔다.
- 이후, 아이디와 패스워드를 입력해서 들어가니 초기화면이 나타났다.
Jenkins CI 환경 구축
- Jenkins 설정
- Jenkins는 기본적으로 보안 설정이 되어있지 않기 때문에, 보안 설정을 따로 해줘야한다.
- Jenkins url 접속 후 Configure Global Security 클릭
- 권한 설정
- Security Realm은 default 설정인 Jenkins' own user db로 설정한다.
- 인증은 Matrix-based security로 설정
- 사용자나 그룹에 권한을 부여할 수 있는 strategy
- 젠킨스를 공동 작업하는 팀원이 있다면, 위에서 사용자의 가입 허용을 체크하고 계정을 생성해서 권한을 부여하면 된다.
- 하지만, 젠킨스 관련한 작업은 우선 혼자 진행할 예정이기 때문에 모든 유저에 READ만, 작업자인는 나에게 모든 권한을 부여했다.
- 필요하다면 나중에 팀원 계정/그룹을 만들어서 권한을 추가하자
- 플러그인 관리
- Jenkins 관리 -> 플러그인 관리
- Github plugin => Jenkins와 Github 통합 (처음 설치 시 권장이라 이미 포함)
- Global Slack Notifier Plugin => Slack 연동(Job 알림 설정) ~> 추후 필요하면 사용
- Publish Over SSH => ssh로 빌드 파일 보내기
- Embeddable Build Status Plugin => Github 레포에 빌드 상태바 생성
- Manage Scripts => Node.js 기반의 서버를 배포하기 위한 Script
- Jenkins 관리 -> 플러그인 관리
- Jenkins Global 설정
- Jenkins 관리 -> 시스템 설정 -> GitHub Servers
- git api 주소를 설정해주고, 아래 Credentials에 git access token을 선택
- 현재 없는 상태기 때문에 옆에 Add버튼을 클릭하여 만들어준다.
- Credential 설정을 위해, 자신의 Github -> Settings -> Developer settings -> Personal access tokens로 들어가 repo와 admin:repo_hoot이 체크된 토큰을 발행한다
- 발행 후, 생성된 secret을 아래와 같이 Credential Secret에 입력
- Jenkins 관리 -> 시스템 설정 -> GitHub Servers
- 프로젝트 생성 및 설정
- 좌측 카테고리 네비게이션에서 새로운 Item -> Freestyle project 생성
- 소스코드 관리에서 Git 선택 후, URL 및 Credentials, build할 branch 설정
- user id와 pwd로 관리하는 것은 보안상 취약점 때문에 ssh키로 관리하기로 한다.
- ~> git의 clone 주소를 https가 아니라, ssh로 변경해서 주소를 입력해줘야한다.
- 위의 repo 주소는 사진의 주소로 입력해줘야한다.
- ssh 설치하기
- Jenkins 서버에 접속해서 ssh키를 생성해준다.
-
ssh-keygen -t rsa -f id_rsa
- 물어보는 대답에 대해서는 엔터로 넘어가준다.
- ls -al ~/.ssh/로 ssh파일이 생성된 것을 확인해준다고 하는데, 나의 경우에는 루프 디렉토리 아래 바로 퍼블릭키와 프라이빗 키가 생겼다.
- 그래서 mkdir을 통해 .ssh 디렉토리를 만들어주고, mv 명령어로 생성된 public/private 키를 옮겨줬다. (ssh키 관리를 위해)
- cat ~/.ssh/id_rsa 로 private key 확인, credentials private key에 입력(Kind에 SSH 선택)
- BEGIN RSA 부터 END까지 모두 복사해서 붙여넣는다.
- Username에는 현재 어떤 username이 들어가야하는지 잘 모르겠어서, 일단 임의로 넣어주었다.(CheckPoint) ~> username은 key 이름으로 나타나는 것으로 확인(별칭 같은 것)
- cat ~/.ssh/id_rsa.pub 로 public key를 확인, Git repo의 settings -> Deploy keys에 등록
- 이 과정까지 되면, Jenkins와 Github이 연동 되는 것까지 설정
- push 했을 때, Jenkins가 push 이벤트를 받을 수 있도록 설정
- git repo의 setting -> webhooks에서 jenkins 서버의 주소를 등록해준다
- 가려진 부분에 public ip를 입력해주고, 나머지 설정은 위와 같이 해준다
- webhook 등록 후, Recent Deliveries에 연결에 실패했다고 뜬다. payload에 public ip 설정할 때, jenkins port번호까지 함께 등록해주니까 연결에 성공했다.
- 여기까지 github repo 설정 및 연결이 끝났다.
- 빌드 유발에서 GitHub hook trigger for GITScm polling을 체크해줘서, push가 일어나면 Jenkins 프로젝트에 빌드가 시작되는 것을 확인하자
- 빌드가 정상적으로 완료돼서, Revision된 것을 확인하면, 여기까지 CI 설정이 끝났다!!!!!!
Jenkins 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
-
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"
-
- compose 파일에서 port:port 이 부분은 외부 port를 도커 컨테이너 내부 port로 바인딩해준다는 뜻이다.
- 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
- 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를 붙였다.
- 해결되었다.
-
- client
- client는 nginx를 통해 띄워주는 것으로 결정, build를 통해 webpack을 적용
- deploy.sh 작성
-
#!/bin/bash cd ./deploy npm install npm run build
-
-
컨테이너 생성하기
-
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 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를 접근할 권한을 부여해서 해결하는 방법이다.
- 기타
- 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
- https://docs.ncloud.com/ko/devtools/devtools-1-1.html
- https://docs.ncloud.com/ko/devtools/devtools-1-2.html
- https://velog.io/@doyuni/Jenkins-NAVER-Cloud-Platform-Docker%EB%A1%9C-CICD-%EB%AC%B4%EC%A4%91%EB%8B%A8-%EB%B0%B0%ED%8F%AC-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-1%ED%8E%B8-khk4w6hrm0
- https://velog.io/@doyuni/Jenkins-NAVER-Cloud-Platform-Docker%EB%A1%9C-CICD-%EB%AC%B4%EC%A4%91%EB%8B%A8-%EB%B0%B0%ED%8F%AC-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-2%ED%8E%B8-7rk4w9eynh#3-naver-cloud-%EC%84%9C%EB%B2%84%EC%97%90-docker-nginx-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0
- https://hiseon.me/linux/ubuntu/install-docker/
- https://itexpert.tips/ko/nginx-ko/%EC%9A%B0%EB%B6%84%ED%88%AC-%EB%A6%AC%EB%88%85%EC%8A%A4%EC%97%90-nginx-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0/
- https://docs.docker.com/compose/env-file/
- https://jeonghwan-kim.github.io/forever-and-docker/
- https://fishpoint.tistory.com/1406