docker

DooD (docker-outside-of-docker) 를 통해 Jenkins 컨테이너에서 docker 사용하기

빛가닥 2021. 9. 6. 20:55
반응형

Jenkins 를 docker 를 통해 컨테이너로 띄우는 것이 아주 편해져서 이제는 docker 로 운영하고 있다.

그런데, Jenkins 상에서 Docker 관련 작업이 필요하여 단순하게 컨테이너 내부에서 설치를 하려고 했는데, 내부에서 docker 를 띄우는 것과 관련하여 이것저것 이슈가 있다고 한다. (https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/)

관련해서 좀 더 찾아보았는데, 내부에서 Docker 를 전부 띄우지 말고 외부(호스트 환경) 의 Docker 와 소켓을 공유하여 사용하는 것이 그나만 나은 방법이라고 한다.

이를 기존의 방식인 Docker-in-docker 와 대비하여 Docker-outside-of-docker 라고 부르는 것 같다. 완전히 정착된 이름은 아닌 것 같지만 이 글에서는 이 이름을 사용하겠다.

 

공식 Jenkins 이미지: https://hub.docker.com/r/jenkins/jenkins

공식 Docker 이미지: https://hub.docker.com/_/docker (여기도 Docker-in-docker 를 추천하지 않는다고 쓰여있다.)


환경

  • 호스트 서버
    • CentOS 7.9
    • Docker server: 20.10.8
    • 사용자는 docker 그룹에 포함되어 있다. (sudo 없이 docker 명령어 입력 가능)
  • Jenkins 컨테이너
    • 기본 이미지: 2.289.3-jdk11
      • 내부에서 Docker 를 사용해야 하기 때문에 이를 베이스로 새로 이미지를 만들 것이다.
    • Docker client: 20.10.8


1. Jenkins 이미지 만들기

컨테이너 내부에서 외부(호스트) 도커와 통신해야 하기 때문에 추가로 설치할 것이 있다. 기본 이미지는 현시점 (2021-09-06) 에서 가장 최신의 lts 버전이고, jdk11 이 들어 있는 버전인 2.289.3-jdk11 을 택한다.

젠킨스 이미지: https://hub.docker.com/r/jenkins/jenkins/tags?page=1&ordering=last_updated&name=2.289.3-jdk11 

 

Docker client 가 필요하기 때문에 Dockerfile 를 통해 설치하고 이미지를 만든다. 베이스 이미지가 Debian 기반이기 때문에 Debian 환경에 Docker 설치를 위한 가이드를 참고한다.

공식 가이드: https://docs.docker.com/engine/install/debian/

 

Dockerfile 은 아래와 같다.

FROM jenkins/jenkins:2.289.3-jdk11

USER root

RUN apt-get update \
 && apt-get -y install lsb-release \
 && curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \
 && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
 && apt-get update \
 && apt-get -y install docker-ce docker-ce-cli containerd.io
RUN usermod -u {{호스트의사용자아이디}} jenkins && \
    groupmod -g {{호스트의도커그룹아이디}} docker && \
    usermod -aG docker jenkins

USER jenkins

 

  • 사이트에서 요구하는 패키지들이 있는데, 대부분 이미 설치되어 있고, lsb-release 만 추가로 설치하면 된다.
  • 외부(호스트) 도커 서버를 사용할거라서 docker-ce-cli 만 설치해도 되기는 하지만, docker-ce 를 설치해야 docker 그룹이 생긴다. 괜히 건드렸다가 꼬일 것 같아서 그냥 가이드대로 다 설치했다.
  • 컨테이너 내부 사용자 (jenkins) 가 호스트의 파일에 접근이 가능 가능하도록 호스트 사용자 아이디와 동일하도록 맞춰준다. (위 Dockerfile 에서 {{호스트의사용자아이디}})
    • 사용자 아이디는 호스트의 /etc/passwd 에서 확인한다.
  • 컨테이너의 도커 그룹 아이디를 호스트의 도커 그룹 아이디와 동일하게 맞춘다. (위 Dockerfile 에서 {{호스트의도커그룹아이디}})
    • 도커 그룹 아이디는 호스트의 /etc/group 에서 확인한다.

이미지를 만든다.

docker build -t my-jenkins:0.1 .

확인

[user@host ~]$ docker image ls
REPOSITORY                 TAG             IMAGE ID       CREATED         SIZE
my-jenkins                 0.1             df9c3ec43a7c   4 minutes ago   1.15GB
jenkins/jenkins            2.289.3-jdk11   ea470c80c15d   5 weeks ago     680MB

2. volume 만들기

jenkins 설정 및 히스토리를 저장하고 재시작시에도 유지되도록 volume 을 만든다.

docker volume create jenkins

확인

[user@host ~]$ docker volume ls
DRIVER    VOLUME NAME
local     jenkins

3. Jenkins 컨테이너 실행

docker run -d --name jenkins \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v jenkins:/var/jenkins_home \
    -p 8080:8080 my-jenkins:0.1
  • 핵심은 docker.sock 을 마운트 하는 것이다. 이를 통해 컨테니어 내부에서 외부(호스트) 의 docker 서버에 접근할 수 있다.
  • volume 을 마운트하고, 접근 포트를 열어준다.

컨테이너가 잘 떴는지 확인해 보자

[user@host ~]$ docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS        PORTS                               NAMES
d57073d5fec2   my-jenkins:0.1   "/sbin/tini -- /usr/…"   3 seconds ago   Up 1 second   0.0.0.0:8080->8080/tcp, 50000/tcp   jenkins

jenkins 컨테이너 내부에서도 호스트의 docker 에 접근이 가능한지 내부에서 호출하여 확인해 보자

[user@host ~]$ docker exec jenkins docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                               NAMES
d57073d5fec2   my-jenkins:0.1   "/sbin/tini -- /usr/…"   2 minutes ago   Up 2 minutes   0.0.0.0:8080->8080/tcp, 50000/tcp   jenkins

호스트의 도커 서버를 공유하고 있기 때문에 같은 결과가 나온다.

반응형