본문으로 건너뛰기

Docker in Docker를 이용해 CI/CD 구축하기 (with jenkins, slack)

 · reading-time-plural

docker in docker 테크닉을 이용해 docker로 실행된 jenkins 환경에 또 docker를 이용해 웹 애플리케이션을 띄어보도록 하겠습니다.

jenkins 설치​

docker를 이용하여 jenkins를 설치합니다.

jenkins가 docker 컨테이너에서 돌아가고 빌드 유발시 컨테이너안에서 또 하나의 컨테이너가 생성되기 때문에 docker in docker 방식으로 구현됩니다.

Dockerfile 작성​

기본적으로 jenkins에는 docker 와 docker-compose 가 없습니다. 초기에 쉽게 설정할 수 있도록 Dockerfile 을 작성하도록 합니다.

Dockerfile
FROM jenkins/jenkins:lts

USER root

RUN apt-get update

# docker install
RUN curl -fsSL https://get.docker.com/ | sh

# docker-compose install
RUN curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \
chmod +x /usr/local/bin/docker-compose
jenkins docker image

jenkins 도 있지만 2.60.3 이후에 더 이상 업데이트가 종료되었습니다. jenkins/jenkins 는 최신 jenkins 버전을 지원합니다. jenkins/jenkins 는 Jenkins의 기본 이미지만을 제공하기 때문에, 추가적인 작업이 필요하다면, 따로 Dockerfile을 세팅해야 합니다.

jenkins 사용시 마운트 이유

/var/run/docker.sock 파일만 공유를 하면 Local에 설치된 Docker를 컨테이너 내부에서 사용할 수 있고, 또한 컨터에너 내부에 설치된 Docker를 다른 컨테이너 내부에서 사용이 가능해집니다. 덕분에, 젠킨스 파일을 모두 백업할 수 있습니다.

자세한 설명은 Docker in docker 를 참고허세요.

docker-compose 작성​

이미지 빌드 및 파라미터를 문서화 할 수 있도록 docker-compose 를 작성합니다.

docker-compose.yml
version: "3.8"
services:
jenkins:
build: .
image: jenkins/jenkins
restart: always
container_name: jenkins
user: root
ports:
- 8080:8080
volumes:
- ./jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
environment:
TZ: "Asia/Seoul"

실행​

docker-compose 의 파일 경로로 이동하여 docker-compose -p jenkins up -d 으로 실행하도록 합니다.

info

windows에서 설치하면 아래의 사진처럼 WSL이 가능하므로 Docker Desktop for Windows으로 설치하라고 많은 Warning message가 출력되는데 무시하고 좀 기달리면 정상적으로 설치됩니다.

파일 관리 전략

현재 jenkins 컨테이어의 볼륨은 호스트 디렉토리와 바인딩 되어있습니다.
앞으로 생길 docker resource를 쉽게 관리하기 위해 하나의 디렉토리에 Dockerfile , docker-compose , config 파일을 관리하도록 합니다.

// Ex

docker
└ jenkins
ㅤ└ Dockerfile
ㅤ└ docker-compose.yml
ㅤ└ jenkins_home
└ mysql
ㅤ└ Dockerfile
ㅤ└ docker-compose.yml
ㅤ└ config 파일

확인​

실행한 컨테이너로 들어가 docker 와 docker-compose version을 출력하여 정상적으로 설치된 것을 확인할 수 있습니다.

jenkins 접속​

호스트 PC에서 8080 으로 접속하도록 설정했음으로 http://{Server IP}:8080 으로 접속하도록 합니다.

그러면 비밀번호를 요구하는데 비밀번호는 docker-compose logs 혹은 해당 컨테이너 logs에 적혀있습니다.

필수 플러그인을 설치하도록 합니다.

admin 계정을 설정합니다.

jenkins의 TCP 포트를 앞으로 계속 같은 포트로 쓸 것인지 물어봅니다. 여기서 현재의 포트를 사용한다고 하면 jenkins 호출시 현재 포트번호로 호출해야합니다. 일단은 같은 포트를 사용할 예정이므로 Save하여 사용하도록 합니다.

이로써 docker를 이용하여 jenkins 설치는 끝났습니다. 이제 ci/cd를 위한 소스코드를 작성하도록 하겠습니다.

소스코드 작성​

실습이 진행된 코드는 parkgang/helloworld-docker-cicd 에서 확인하실 수 있습니다.

Webhook 설정​

GitHub에서 소스코드 변화가 감지되면 알아서 빌드되도록 Webhook을 설정해야합니다.

info

GitHub에 Webhooks 설정​

jenkins item 생성​

~\jenkins_home\workspace 에 프로젝트 파일단위가 저장됩니다.

public repose이므로 GitHub 계정은 입력하지 않았습니다.

info

shell의 pwd는 /var/jenkins_home/workspace/~ 입니다.

Webhook 확인​

먼저 강제로 trigger으로 스트립트와 GitHub pull하는데 문제가 없는지 확인합니다.

tip

만약 GitHub repos가 권한이 필요한 경우 혹은 item이 잘못된 경우 Console Output을 통해 수정합니다.

문제가 없다면 소스 수정 후 GitHub에 Push하여 jenkins에서 자동으로 빌드가 유발되는지 확인합니다.

Webhook이외 원격 빌드​

token을 이용해서 API처럼 원격으로 빌드를 수행할 수 있습니다.

note

http://kyungeun.koreacentral.cloudapp.azure.com:8080/job/helloworld-docker-cicd/build?token=rebuild_token

소스코드 docker 컨테이너화​

이제 소스코드를 컨테이너화 시켜서 배포해보도록 하겠습니다. 소스코드는 Webbook때 사용한 코드와 동일합니다.

Execute shell에 추가​

아래의 shellscript를 jenkins item의 Execute shell에 추가합니다.

컨테이너를 종료하지 않으면 같은 이름의 컨테이너가 실행되지 않음으로 삭제하고 다시 이미지 빌드 후 컨테이너화 하는 script입니다.

docker rm -f tomcat-cicd || true

docker-compose -p jenkins-helloworld-docker-cicd up -d --build
info

위의 shellscript는 docker-compose 를 이용한 방법입니다. 아래의 script와 동일합니다.

docker rm -f tomcat-cicd || true

docker build -t tomcat-cicd-image:practice .
docker run -d --name tomcat-cicd -p 8888:8080 tomcat-cicd-image:practice

확인​

push후 정상적으로 컨테이너가 실행되는 것을 확인할 수 있습니다.

slack 연동​

  1. docker를 이용한 CI 구축 연습하기 (젠킨스, 슬랙)글을 참고합니다
  2. 해당 글으로 성공했습니다

docker in docker issue​

docker in docker으로 사용시 생기는 몇가지 문제점이 있습니다.

파일 마운트의 경로가 host pc으로 잡히는 문제가 있는 걸로 확인됩니다. 주의해서 사용바랍니다.

자세한 설명은 Docker in Docker cannot mount volume 를 참고하세요.

기타 빌드 도구 설정​

gradle​

jenkins에서 gradle shell 활성화

yarn​

note
  1. yarn plugin이 없어서 npm을 통해 설치 후 사용하는 것으로 확인됩니다.
  2. node script에 하면 안됩니다.
  1. gradle + yarn 설정
  2. job 설정 부분 참고함

NodeJS Plugin을 설치합니다.

설치 후 config에 들어갑니다.

node에 대한 이름과 버전을 선택합니다.

NodeJS script는 실제로 node.js로 js를 실행하기 위한 script만 가능한 것으로 확인됩니다.

아래의 체크박스를 선택 후 Execute shell 에 쉘을 작성합니다.

note

만약에 또 yarn: not found 출력된다면 node script만 실행가능한 item을 생성&실행을 통해서 강제로 yarn만을 설치하도록 합니다.

깔끔하지 않은 방법이며 이럴꺼면 처음 docker image에서 yarn을 추가하는 것이 깔끔해 보입니다.

추후 jenkins 재설치시 한번 더 확인하도록 합니다.