PPAK

[CI/CD] Docker 에서 Jenkins 구동하기 본문

infra

[CI/CD] Docker 에서 Jenkins 구동하기

PPakSang 2022. 7. 16. 23:26

이번 팀 프로젝트를 준비하면서 CI/CD 환경 구축을 해봐야겠다고 마음을 먹었다.

 

우선은 Jenkins 이미지를 생성하고 컨테이너를 생성하는 과정에서 중요한 부분을 정리하고자 본 글을 작성한다.

 

들어가기에 앞서서, 쓰게될 글을 간단하게 요약을 하면

 

Local Machine (실제 배포과정에선 EC2 인스턴스?) 의 Docker 를 통해 Jenkins Image 를 생성하고 실행하는 것이 전부인데

 

그 과정에서

 

1. Jenkins Image 생성을 위한 Dockerfile 작성

2. DooD (Docker out of Docker) 방식 적용

3. 가상 tty 로 Container 에 접근해 파일 수정

 

을 수행할 예정이다.

Jenkins Image 생성을 위한 Dockerfile, Shell Script 작성

#https://hub.docker.com/r/jenkins/jenkins
#pull jenkins image
FROM jenkins/jenkins:jdk11

USER root

#컨테이너 내에서 필요한 도커 설치
COPY docker_install.sh /docker_install.sh
RUN chmod +x /docker_install.sh
RUN /docker_install.sh

#설치 후 docker 그룹의 jenkins 계정 생성 후 해당 계정으로 변경
RUN groupadd -f docker
RUN usermod -aG docker jenkins
USER jenkins

https://github.com/docker/docker-install

docker 설치를 위한 공식 shell script

 

 

GitHub - docker/docker-install: Docker installation script

Docker installation script. Contribute to docker/docker-install development by creating an account on GitHub.

github.com

curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh

 

Jenkins 이미지를 불러온 후 컨테이너 내부에서 Jenkins 의 command 에 포함될 docker 명령을 위해서 docker 를 설치한다.

 

docker 를 설치할 때는 지속적으로 설치가 가능하도록 shell script 를 불러와서 실행한다.

 

여기서 한 가지 의문이 들 수 있다.

 

docker 위에서 동작하는 컨테이너에서 다시 docker 를 설치한다?

 

컨테이너 내에서 docker 관련 명령을 수행하기 위해서(Jenkins 의 빌드 자동화 과정에서 docker build 명령어를 수행하는 등의) docker daemon 의 도움이 필요하다.

 

여기서 우리는 두 가지 선택이 가능한데

 

1. Docker 위에 Docker Container 를 생성한다. (Docker In Docker, DInD)

2. Local Machine 위에서 실행 중인 docker daemon 을 이용한다. (Docker out of Docker, DooD)

 

여기서 DInD 를 적용하기 위해서는 Docker Container 의 권한을 --privileged 로 설정해야하는데, 해당 권한이 Local Machine 의 대부분의 장치에 접근 가능하기 때문에 보안 상에 큰 단점이 존재하여 추천하지 않는 방식이라고 한다.

 

DooD 는 Local Machine 의 docker daemon 을 통해 docker 명령어를 수행하는 방식으로, 이 역시 100% 안전한 방식이라고는 할 수 없지만 권장되어 사용하는 방식이다.

 

Docker Build

jenkins image 를 생성할 준비가 완료되었으므로 build 를 실시한다.

 

docker build -t jenkins/test_jenkins:1.0 .

Docker Desktop 혹은 docker images 를 통해 확인 가능하다.

 

Docker Run (중요!!)

https://hub.docker.com/_/jenkins 에 따르면

 

모든 jenkins data 가 /var/jenkins_home 에 저장된다고 한다 -> container 의 마운팅 포인트

 

-v 옵션을 통해 컨테이너에서 생성된 jenkins data 를 영구 저장할 수 있도록 한다.

 

 

위를 바탕으로 작성한 docker run code 이다

docker run -d -p 9090:8080 --name=jenkinscicd \
-v ~/jenkins_home_sub:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
jenkins/test_jenkins

여기서 -v /var/run/docker.sock:/var/run/docker.sock 를 추가한 이유는

 

위의 DooD 를 적용하기 위해서 인데, Local Machine 의 Docker socket 을 Container 의 것과 공유하여, Local Machine Docker daemon 으로 명령어를 보낼 수 있게 한다.

 

하지만 여기까지 설정하고, 실제로 Jenkins 를 사용하다보면 docker 명령어에 대한 permission denied 가 뜰 수 있다.

 

현재까지의 상태를 나열해 보면

 

container 에서 docker 를 설치한 유저 : root

docker.sock 의 접근 권한 : root group level

현재 container 의 유저 : docker(usermod 명령어 참고)

 

따라서 container 의 권한을 변경할 수는 없으니 container 내부의 docker.sock 파일의 권한을 변경해주도록 한다.

 

Docker Container 는 일종의 프로세스로 여겨지면서도 가장 큰 차이점은 Container 만의 독립된 파일 시스템이 존재한다는 것인데

 

이를 통해 터미널로 Container에 접속하여 파일 수정이 가능하다는 것을 의미한다.

 

Container 접속

docker exec -it -u root [container_id] /bin/bash

docker exec 명령어를 통해 container 에 특정 명령어를 실행하는 것을 의미한다.

 

따라서 /bin/bash 명령어를 수행하고, -it 옵션은 STDIN 표준 입출력을 열고 가상 tty (pseudo-TTY) 를 통해 접속하겠다는 의미이다.

 

https://docs.docker.com/engine/reference/commandline/exec/ 참고

 

docker exec

docker exec: The `docker exec` command runs a new command in a running container. The command started using `docker exec` only runs while the container's primary process (`PID 1`) is...

docs.docker.com

 

이를 통해 /var/run 에서

chown root:docker /var/run/docker.sock

을 수행하고, jenkins container 를 재부팅하면 정상적으로 jenkins agent 가 동작하는 것을 확인할 수 있다.

 

잘못된 정보가 있다면 댓글로 알려주시면 감사하겠습니다!!

Comments