AWS(EC2 - Linux2) + Docker + Jenkins로 CI/CD 구성하기

개발하는 구황작물·2023년 3월 16일
1

개인 프로젝트

목록 보기
9/9
post-thumbnail

docker란? : Go 언어로 작성된 리눅스 컨테이너 기반으로 하는 오픈소스 가상화 플랫폼이다.
여기서 컨테이너는 다양한 프로그램, 실행환경을 컨테이너로 추상화하고 동일한 인터페이스를 제공하여 프로그램의 배포 및 관리를 단순하게 해준다.

개인 프로젝트에 docker를 사용한 이유 : 다양한 환경에서 구애받지 않고 실행이 가능하기 때문이다
...는 면접에서나 이야기 해야 하는 부분이고
언젠간 한번쯤 써보고 싶어서 사용하였다.

+) 이 글은 AWS EC2가 어느정도 세팅되었다는 전제 하에 작성되었습니다.

⚠️ 순서가 필자의 의식의 흐름대로 진행되고 있습니다.

Docker + Jenkins 로 CI/CD 구성하는 방법

  1. Docker를 설치한다.

  2. Docker에 Jenkins 이미지를 가져온다.
    docker pull jenkins/jenkins:jdk11

  3. usermod 사용해서 그룹에 사용자(ec2-user 를 추가한다.)
    sudo usermod -aG docker ec2-user

  4. jenkins 폴더 만들기
    mkdir jenkins

  5. 해당 폴더에 대해 권한 부여하기
    sudo chown -R 1000 ./jenkins

  6. jenkins 컨테이너를 실행시킨다.
    그냥 실행시키면 jenkins에서 작업시 docker명령어가 듣지 않으므로
    젠킨스에 도커 플러그인을 설치하거나(모든 도커 관련 명렁어 기능을 제공하지는 않는다고 함)
    도커 컨테이너 안에 도커 바이너리를 설정하고 도커 데몬을 실행하거나(DinD)
    Docker socket를 볼륨 세팅을 통해 공유하고 호스트의 도커 데몬을 이용해 내부에 도커 명령을 실행시키는 방법(DooD)을 사용해야 했다.
    결국 최종 명령어는
    sudo docker run -u 0 --privileged --name jenkins -d -p 9090:8080 -p 50000:50000 -v /var/run/docker.sock:/var/run/docker.sock -v $(which docker):/usr/bin/docker -v /home/jenkins:/var/jenkins_home jenkins/jenkins:jdk11

(혹시 이 명령어가 잘못되었다면 알려주시길 바랍니다.)
(+ 그리고 9090 포트 열어놓기)

그리고 EC2에 jenkins 내부에 Docker를 띄우기 위해 docker socket를 빌리기 위한 Dockerfile과 docker_install.sh 파일을 작성해야 한다.

Dockerfile

FROM jenkins/jenkins:jdk11

USER root

COPY docker_install.sh /docker_install.sh
RUN chmod +x /docker_install.sh
RUN /docker_install.sh

RUN usermod -aG docker jenkins
USER jenkins

docker_install.sh

#!/bin/sh
apt-get update && \
apt-get -y install apt-transport-https \
  ca-certificates \
    curl \
      gnupg2 \
        zip \
          unzip \
            software-properties-common && \
            curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg > /tmp/dkey; apt-key add /tmp/dkey && \
            add-apt-repository \
            "deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
            $(lsb_release -cs) \
            stable" && \
            apt-get update && \
            apt-get -y install docker-ce

이후 docker.sock의 파일의 권한을 변경해준다
sudo chmod 666 /var/run/docker.sock

  1. 이제 jenkins로 접속하면 비번 입력하라는 창이 뜰텐데
    docker exec -it jenkins /bin/bash로 젠킨스 컨테이너에 접근하고
    cat /var/jenkins_home/secrets/initialAdminPassword
    로 비번 알아오시면 됩니다.
    (+ 다시 컨테이너 밖으로 나가고 싶다면 ctrl + p + q)

  2. 이제 jenkins에 들어가서 추천하는 플러그인 설치한 후 아이디/비번 설정해주고 URL들어가면 초반 설정은 완료된다.

8-1. 그리고 Jenkins 관리에 들어가서 플러그인 관리에 들어간 후,

Avaliable plugin에서 gradle, github integration, post build task, publish over ssh를 설치한다. (만약 avaliable plugin에서 검색했는데 없다면 Installed plugin에 이미 설치되어 있을 수도 있다.)

  1. 이후 item 에서 freestyle 누른 후
  1. 깃허브 URL 적으면 된다.
  1. 이제 Credentials를 설정해야 한다.
    Dashboard -> Jenkins 관리 -> Manage Credentials 들어가서


위 사진의 add credentials 들어가서 credentials를 만들어야 한다.

깃허브 계정정보를 입력하면 된다. Username에 본인 깃허브 아이디 적고 password에는 비번 입력하면 된다.
(ID는 안적어도 됨)
똑같이 Dockerhub 계정도 등록해주면 된다.

  1. 이제 깃허브 webhook연동해주는 작업을 한다.
    본인의 깃허브 계정에 Settings 클릭해주고

Settings 쭉 내려가면 Developer Settings이 있는게 거기 들어가면 된다.

이제 Personal access tokens 들어가서 토큰 만들어주면 된다.

토큰 이름 정해주고 repo, admin, admin:repo_hook를 선택하고 하단에 generate token 클릭해주면 된다.

이후 토큰 발급을 확인할 수 있다. 이때 토큰은 만든 당시에만 확인 가능하므로 어디 복사해 놓자

이제 연결하고 싶은 repository 들어가서 settings -> webhooks 클릭하고

payload url에 http://jenkinsEc2탄력적IP:젠킨스포트/github-webhook/ 형식으로 작성하면 된다.
(이때 url 마지막에 꼭! / 넣어야 한다.)

이후 Dashboard -> Jenkins 관리 -> Configure System으로 들어가서 쭉 아래로 내려가면 Github Servers가 있다. 여기서 Credentials에 add 누른 다음 kind는 secret text로 설정하고 Secret에다가 방금 발급받은 토큰을 입력하고 저장하면 된다.
이후 test Connection을 누르고 연결이 되는지 확인 한 후 저장을 누르면 된다.

이후 방금 화면에서 쭉 내려와 SSH Servers에서 추가를 눌러 설정을 해준다.

name : job에 표시될 이름
hostname : EC2 탄력적 IP 주소
Username : ssh 접근 계정
remote Directory : 업로드될 디렉토리

이후 고급을 눌러 use password authentication, or use different key를 눌러 Key에 본인 ec2에 접속시 사용하는 pem key를 입력하면 된다.

이후 빌드 유발에서 Github hook trigger for GITScm polling을 클릭하면 된다.

  1. Gradle 설정
    Jenkins 설정 -> Global Tool Configuration에 들어가서 Add Gradle 누른 후 사용하는 프로젝트의 Gradle 버전 선택한 후 저장하면 된다.

  2. 다시 작성했던 젠킨스 구성으로 돌아가서 빌드 환경에서 Use secret Text or file선택하고 Bindings의 add 클릭 한 후 Username and password(separated) 선택 후 각각 Username variable, Password variable 에 USERNAME, PASSWORD 선택 후 credentials를 전에 만든 dockerhub 계정을 선택한다.

사실 ec2를 하나만 사용하는 경우 도커 허브 없이 바로 이미지 빌드 후 바로 컨테이너를 ec2에 띄우면 된다. 그러나 배포용ec2, 운영용ec2 총 두개의 ec2를 사용하는 방식으로 진행 시 dockerhub에 push 후 운영용 ec2에서 pull 하는 방식으로 이루어져야 하므로 필자는 ec2가 두개 있다는 가정하에(실상은 비용 때문에 하나만 썼지만...) 진행되었다.

  1. Build 에서 Invoke Gradle script를 입력한다. 이후 Task에 clean build라고 명령어를 입력해준다

  2. Add build step에서 execute shell을 선택한 후
    빌드를 진행한 후 동작할 명령어를 입력한다.

docker build -t 도커본인계정/repository:tag .
docker push 도커본인계정/repository

  1. 빌드 후 조치 선택하고 send build artifacts over SSH를 선택한다.

빌드 후 수행할 동작들을 작성해준다.

sourse files : 본인 프로젝트에 위치한 deploy.sh 위치
remove prefix : 파일 앞부분 경로 제거
remote directory : 운영용 ec2에 업로드될 경로
exec command : 실행할 명령어

deploy.sh 전문

#!/bin/bash

sudo docker ps -a -q --filter "name=컨테이터이름" | grep -q . && docker stop 컨테이너이름 && docker rm 컨테이너이름 | true

# 기존 이미지 삭제
sudo docker rmi 도커계정이름/레포지토리:태그

# 도커허브 이미지 pull
sudo docker pull 도커계정이름/레포지토리:태그


# 도커 run
docker run -d -p 8080:8080 --name 컨테이너이름 도커계정이름/레포지토리:태그

# 사용하지 않는 불필요한 이미지 삭제 -> 현재 컨테이너가 물고 있는 이미지는 삭제되지 않습니다.
docker rmi -f $(docker images -f "dangling=true" -q) || true
  1. 수동으로 동작시켜보기
    이제 직접 작동시켜보면

    잘 되는 것을 볼 수 있다.

jenkins에서 sudo 사용이 안된다고 할 때

root 계정으로 로그인 한 후, visudo 명령어로 /etc/sudoers파일을 수정해주면 된다.

jenkins ALL=(ALL) NOPASSWD: ALL 추가


Docker + Jenkins로 CI/CD를 구성한 후 느낀점 :
이거 구성하는데 50번은 넘게 실패한 것 같다.
Docker에 대한 지식도 없이 냅다 시작하다보니 그렇게 된 것 같다.
특히 빌드는 다 되었는데 Docker 명령어가 먹히지 않아서 그 이후가 진행이 안 될 때 2차로 멘붕이 왔다.

이렇게 CI/CD 구성한 후, Nginx로 무중단 배포도 구축하고 싶었으나 실력 부족으로 결국 실패했다.
이거는 Docker와 Nginx에 대해 더 공부하고 시도를 해봐야 할 것 같다.

결론 : github Actions 쓰세요 여러분


reference : https://backtony.github.io/spring/aws/2021-08-08-spring-cicd-1/#7-%EC%A0%A0%ED%82%A8%EC%8A%A4-%EC%84%B8%ED%8C%85
https://postlude.github.io/2020/12/26/docker-in-docker/

profile
어쩌다보니 개발하게 된 구황작물

0개의 댓글