Ubuntu EC2, jenkins + docker 자동배포

가수왕·2022년 8월 15일
0

linux에서

목록 보기
1/3

1. 서론

WEBRTC 관련 프로젝트를 진행하면서 EC2서버 담당을 하게 되었다. 젠킨스를 이용해 자동배포를 하게 되었는데 이 때는 도커를 이용한 배포가 아니라 젠킨스 execute shell에 프론트엔드 코드를 빌드해서 nginx의 root 경로로 복사하고, 백엔드 코드를 빌드해서 이미 실행중이던 .jar를 kill하고 nohup을 이용해 실행하는 방법을 사용했다.
도커를 이용한 배포까지 도전해 보고 싶었으나, 프로젝트 일정상 그러지 못했다. 그러다 좋은 기회에 도커를 이용한 자동배포 과정에 대해 배우게 되어 그 내용을 정리해보려 한다.
gitlab, ubuntu, springboot, vue 프로젝트로 진행한 내용이다.

2. 흐름정리

일단 젠킨스를 이용한 자동 배포의 흐름은 이렇다.
젠킨스가 사용자가 지정한 브랜치에 발생하는 이벤트를 감지해 저장소를 pull 받고 사용자가 지정한 순서대로 명령어를 실행하게 된다. 이 명령어를 실행하는 부분에 프로젝트를 빌드하고 배포하라는 명령어를 지정해 주면 된다.
도커를 이용한 배포는 프로젝트를 도커 이미지화 해, run 시키라고 지정해 주면 된다는 말이다.
젠킨스에게 도커이미지를 만들어서 실행시켜! 라는 명령어를 적으려면 도커 이미지를 어떻게 생성하고 실행시켜야 하는지 알아야 한다.
그래서 도커 설치부터 도커 이미지 생성, 컨테이너 생성까지의 과정을 알아보자

3. 도커 설치

일단 도커를 이용하려면 도커가 설치 되어 있어야 한다.
아래의 명령어를 순서대로 실행하면 도커를 설치할 수 있다.

sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
sudo apt-get update && sudo apt-get install docker-ce docker-ce-cli containerd.io

4.도커 이미지화, 실행

도커 설치가 끝났다면 우리의 프로젝트를 이미지화 해서 실행시켜야 한다.
도커 이미지화 하기 위해서는 도커 파일에 우리 프로젝트에 대한 정보를 담아 주어야 한다.

4-1 백엔드 (maven project)

나에게 오늘 도커+젠킨스 자동배포에 대해 알려주신 분의 백엔드 도커파일이다.
이분은 maven으로 프로젝트를 구성했기 때문에 미리 빌드를 해놓고, 생성된 .jar파일을 이미지화 한것으로 보인다.
gradle을 이용한다면 프로젝트 내에 gradle프로젝트의 빌드 파일이 있어 도커에서 빌드가 가능할 것으로 추측하고 있다.

내가 도커파일 작성 문법에 대해 알지 못해 정확히 어떤 내용인지 적지는 못하겠지만, 추측한 내용을 정리해 보았다.

FROM openjdk:11-jdk //프로젝트의 jdk버전 명시

//미리 빌드해놓은 .jar파일의 경로를 JAR_FILE이라는 변수를 이용해 선언
ARG JAR_FILE=build/libs/demo1-0.0.1-SNAPSHOT.jar

//해당 jar파일을 현재 도커파일이 위치한 곳에 app.jar라는 이름으로 복사
COPY ${JAR_FILE} app.jar

//ENTRYPOINT에 명시된 내용을 실행해라?
ENTRYPOINT ["java","-jar","/app.jar"]

이렇게 작성한 도커 파일을 백엔드 프로젝트 최상위 폴더에 위치시킨다.

이후에 아래 명령어를 입력하면 도커 이미지를 생성할 수 있다.

sudo docker build -t [생성할 이미지 이름] .(도커파일 위치)

이렇게 생성한 이미지를 docker run 시키기만 하면 된다.

docker run -d --name [컨테이너이름] -p [portnum]:[portnum] [생성한 이미지 이름]
//-d 옵션은 background에서 실행하라는 뜻

이렇게 하면 백엔드 프로젝트의 도커화가 끝났다.

4-2 프론트엔드 (vue + nginx)

다음은 프론트엔드이다. 프론트엔드 도커 이미지에는 nginx를 포함시킬 것이다. nginx를 따로 분리해도 되지만 이렇게 하면 프론트엔드의 배포파일을 정적파일이기 때문에 nginx에서 읽기 위해 볼륨 설정을 해줘야 하는것으로 알고 있다. 도커 볼륨설정은 자신의 컨테이너 외부의 폴더를 사용하기 위해 하는 것으로 알고 있다.
백엔드와 과정이 비슷하다. 도커파일 작성 - 이미지 생성 - 이미지 실행 이 순서로 진행된다.
프론트엔드의 도커 파일이다.

FROM node:lts-alpine as build-stage //vue 프로젝트의 실행환경 선언?
WORKDIR /app //작업 공간 변경? 혹은 생성?
COPY package*.json ./   //package로시작하는 json파일을 복사

RUN npm install //모듈들 설치
COPY . . //설치된 모듈을 복사하기 위함?
RUN npm run build //빌드

//-----------여기까지가 vue 프로젝트 빌드과정

FROM nginx:stable-alpine as production-stage //nginx 실행환경?
RUN rm /etc/nginx/conf.d/default.conf //존재하던 nginx의 설정파일 제거
COPY ./nginx/test.conf /etc/nginx/conf.d/test.conf //내가 만든 nginx 설정파일 복사

//nginx에서 지정한 root에 존재하던 vue 배포폴더 삭제
RUN rm -rf /usr/share/nginx/html/* 
//새롭게 생성된 vue 배포폴더 nginx 설정파일에 지정한 root위치로 이동
COPY --from=build-stage /app/dist /usr/share/nginx/html 


EXPOSE 80 //nginx 사용포트 지정?
CMD ["nginx", "-g", "daemon off;"] //이 명령어 실행해!

이후에 도커 이미지를 생성해준다.

sudo docker build -t [생성할 이미지 이름] .(도커파일 위치)

그리고 실행해 준다.

docker run -d --name [컨테이너이름] -p [portnum]:[portnum] [생성한 이미지 이름]

아래에 있는건 nginx 설정파일 즉 test.conf의 내용이다.

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    index index.html;

    server_name _;

    location / {
        root /usr/share/nginx/html;
        try_files $uri $uri/ /index.html;
    }

    location /test { #/test로 들어온 요청 리다이렉트
        proxy_pass 도메인:8081;
    }
}

여기에 특별한 점이 있다. 나는 리다이렉트를 할때 localhost를 사용했지만 현재 nignx는 컨테이너라는 독립된 환경에서 실행되기 때문에 우리 도메인으로 다시 요청을 보낸다는 것이다.
이게 굉장히 안좋은 방법이라고 한다. 실제로 요청이 여러 과정을 통해 우리 서버로 들어온다.
이후 nginx가 /test로 들어온 요청을 다시 외부로 요청을 보내 험난한 과정을 거쳐 우리 8081포트로 들어오는 것이다. 하지만 나는 다른 방법을 모르기에 이렇게 진행하겠다.

여기까지 도커 이미지를 생성하고 컨테이너를 생성해 실행하는 것까지 해본것이다. 이제 남은 과정은 젠킨스를 설치하고 git 저장소에 webhook을 연결하고 젠킨스에게 도커 이미지 생성하고 실행해! 라는 명령을 내려주면 된다.

5.젠킨스

먼저 젠킨스를 설치해야한다. 젠킨스를 사용하는 방법은 도커컨테이너를 사용하는 방법과 설치를 통해 사용하는 방법이 있는데 나는 프로젝트를 진행할때 설치를 통해 젠킨스를 사용했기 때문에 이번에는 도커를 이용한 사용방법을 설명하겠다.
굉장히 간단하다. 그냥 아래 명령어를 사용하면 된다.

sudo docker run -d --name jenkins -u root --privileged \
-p '9090:8080' \
-v '/home/ubuntu/docker-volume/jenkins:/var/jenkins_home' \
-v '/var/run/docker.sock:/var/run/docker.sock' \
-v '/usr/bin/docker:/usr/bin/docker' \
jenkins/jenkins

-p 옵션은 젠킨스가 사용할 포트번호, -v 옵션은 젠킨스 컨테이너 외부에 존재하는 폴더를 사용하겠다는 뜻이 된다.
젠킨스 컨테이너 내부에도 도커가 설치되어있어야 한다.

# 컨테이너 내부 bash 접근
sudo docker exec -it jenkins bash

# Docker 확인
docker -v

이후에 자신의 도메인:젠킨스할당 포트번호 로 접속하면 젠킨스 페이지로 입장이 가능하다.
처음 접속하면 젠킨스 초기 비밀번호를 입력하라고 나온다. 친절하게 어느 위치에 있는지 알려주기 때문에 아래 명령어를 이용해 확인이 가능하다.

sudo vi /젠킨스 초기비밀번호 위치

젠킨스 git 연동

  1. 이렇게 초기 비밀번호를 입력하면 계정생성을 하라고 한다.
    아이디와 비밀번호를 생성하고 잊지않게 어딘가에 기록해두자...
    나는 실제로 아이디를 까먹었다가 로그인 없이 접속해서 anonymous계정으로 로그아웃이 되질 않아 지웠다 다시 설치했다.

  2. 이후에 플러그인들을 설치하면 된다.

  3. 무사히 플러그인 설치가 끝났다면 아래와 같은 화면을 만날 수 있다.
    동그라미 친 새로운 Item을 눌러 프로젝트를 추가해 주면 된다. 그전에 자신의 git저장소와 연동해야 한다.

  4. Jenkins관리에 Manage Credential 탭으로 이동해 자신의 git저장소와 연결해 준다. git 저장소의 주소 (clone 할때 사용하는 https주소), git저장소에서 생성된 AccessToken등을 이용해 연결이 가능하다(git 에서 생성된 AccessToken을 잘 기억하자 나중에 비밀번호로 사용된다). 자신의 git 계정과 비밀번호등이 필요하다.

  5. 지난 프로젝트때는 freestyle 프로젝트로 생성해 execute shell에 명령어를 입력했지만 이번에는 pipeline프로젝트로 생성해 보겠다.

  6. 깃 저장소 연결후에 빌드 트리거를 깃랩에 변화가 생겼을때로 지정한다. 여기에 적힌 URL을 잘 기억하자 git에서 Webhook설정할 때 필요하다.
    빌드 트리거를 선택하고 아래쪽에 보면 고급이 있다. 그걸 누르면 새로운 항목이 주루룩 나오는데 가장 아래쪽에 secret token항목이 있다. generate를 눌러 토큰 생성을 해주자 이것도 Webhook설정할 때 필요하다.

  7. pipeline의 definition을 pipeline script from SCM으로 변경 -> 미리 있는 파일을 이용해 파이프 라인을 구축하겠다는 뜻
    Repositories에 git 저장소의 주소를 입력해준다. credential은 아까 생성했던거 선택해 주면 된다.

  1. 깃 저장소 주소를 입력했을때 아래와 같은 에러가 발생하는건 정상이다. Credentials를 지정해주면 된다. 물론 Credentials를 지정했는데도 아래 오류가 나면 자신의 깃 저장소에 접근이 거부된것이니 주소나, Credential을 잘 확인해보자!!!
  2. 아래 사진은 젠킨스가 빌드할 브랜치를 지정해 주는 곳이다. 배포용 브랜치를 하나 만들어 지정하는걸 추천한다.

여기까지 하고 저장하자!!! 일단 젠킨스에서의 설정은 끝났다. 이제 남은 건 git에서 웹 훅을 걸어주고 Jenkins 파이프라인 파일만 작성해 주면 된다.

git Webhook설정

Settings메뉴에 Webhook탭이 있다.
여기서 URL과 SecretToken은 젠킨스 설정 6번에서 기억하라고 했던 URL과 토큰이다. 트리거는 어떤 이벤트가 발생했을때 젠킨스를 실행시킬건지 지정하는 거다. push event에 머지 이벤트도 포함되는것 같다.
push event 하단에 input박스에 특정 브랜치를 입력하면 해당브랜치에 push이벤트가 발생했을때만 젠킨스가 일한다.

젠킨스 파일 입력

빌드 과정을 작성한 젠킨스 파일을 프로젝트 최상단에 위치시키면 된다.
솔직히 제킨스파일 문법은 뭐가 뭔지 잘 모른다. 하지만 pipeline안에 stage들로 구성되어 있고 각 stage는 task별로 나누면 되는거 같다.
해당 파일을 추가하고 push하면 젠킨스가 알아서 push이벤트를 감지하고
아래 있는 빌드 과정을 수행하게 된다.

pipeline { 
        agent none
        stages {
                stage('Docker build') {
                        agent any
                        steps {
                                sh 'echo hello2'
                        }
                }
                stage('Docker run') {
                        agent any
                        steps {
                                sh 'echo hello'
                        }
                }
        }

}

파이프라인으로 빌드 하면 아래와 같이 스테이지별로 결과와 소요시간을 확인할 수 있다.

6. 후기

아직 공부할게 굉장히 많긴하다. 이 방법이 가장 좋은 방법이 아닐 수도있다. 하지만 이번에 이런 방법을 배우면서 도커에대해 조금은 알게 됐고, 젠킨스의 파이프라인에 대해서도 조금은 알게됐다. 하지만 지금은 조금 쓸 수 있다 정도이기 때문에, 도커에 대해서도 공부해 봐야하고 파이프라인이 뭔지, 문법은 어떻게 작성해야하는지도 공부해봐야 할듯하다.

0개의 댓글