<aside> 📌 아래 docker_install.sh의 도커 설치 스크립트는 라즈베리파이(arm)가 아닌 amd용이다.
</aside>
우리가 구성해볼 것은 docker 안에 docker를 띄우는 것이긴 하지만 "docker in docker" 방식처럼 독립적으로 띄우지는 않을 것이고, Host docker의 docker.sock을 공유해서 docker out of docker방식으로 띄워볼 것이다. docker in docker라는 것도 존재하지만 권장하는 방법이 아니기 때문에 우리는 docker out of docker로 실습을 진행해볼 것이다.
그렇다면 왜 docker in docker가 권장하지 않는 방법일까? 이유는 아래와 같다.
<aside> 👉 Docker in Docker(DinD)는 도커 안에 컨테이너 내부의 격리된 Docker 데몬을 실행하는 작업을 의미한다. 즉, 도커데몬이 2개가 뜨는 것이다. CI 측면에서 접근하자면 Task를 수행하는 Agent가 Docker Client와 Docker Daemon 역할까지 하게되어 도커 명령을 수행하는데 문제가 없어진다. 하지만 아주 큰 단점이 존재한다.
호스트 도커 컨테이너가 privilieged mode
로 실행되어야 한다.
docker run --privileged --name dind -d docker:1.8-dind
privilieged 플래그를 사용한다면 호스트 컨테이너가 호스트 머신에서 할 수 있는 거의 모든 작업을 할 수 있게 된다. 이는 컨테이너를 실행하는데 큰 보안 위험을 초래할 수 있다.
출저 : https://aidanbae.github.io/code/docker/dinddood/
</aside>
그렇다고, dood가 아예 단점이 없는 것은 아니다. 그 이유는 직접 띄워보면 알 수 있는 것이 jenkins container 내부에서 docker ps 명령을 날려보면 자기자신의 container가 떠있는 것이 목록에 보인다. 그 말은? 외부 호스트 도커에 떠있는 container에 접근이 가능하게 될 수도 있다는 것이다. 또한 docker.sock을 공유하기 위해 그만큼의 권한을 docker container에게 제공해야 한다. 조금씩 장단점이 있는 방법들인 것 같으니, 안전하게 사용하는 쪽이 좋은 방향인것 같다.
바로 실습에 들어간다. 우선 도커 엔진을 다운로드 받기 위한 스크립트를 파일로 작성하였다.
> 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
그리고 다음으로는 도커 이미지를 빌드하기 위한 Dockerfile이다.
#공식 젠킨스 이미지를 베이스로 한다.
FROM jenkins/jenkins:lts
#root 계정으로 변경(for docker install)
USER root
#DIND(docker in docker)를 위해 docker 안에서 docker를 설치
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 build -t 1223yys/jenkins-dind:latest .
docker push 1223yys/jenkins-dind
여기까지 크게 문제없이 따라왔다면 도커허브에 이미지가 push 되어 있을 것이다.
그 다음은 Jenkins를 띄울 서버에 방금 만든 이미지로 Jenkins를 띄워보자.
docker run -d --name jenkins -p 8080:8080 -p 50000:50000 \\
-v /home/deploy/jenkins_v:/var/jenkins_home \\
-v /var/run/docker.sock:/var/run/docker.sock \\
1223yys/jenkins-dind:latest
중요한 것은 우리가 처음 이야기했던 것처럼 Host의 docker.sock을 공유해서 사용할 것임으로 볼륨마운트가 필요하다. 이제 젠킨스 컨테이너에 들어가서 도커엔진이 잘 떠있는지 확인하자.
> docker exec -it jenkins bash
jenkins@20ff53d54e94:/$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
20ff53d54e94 1223yys/jenkins-dind:latest "/sbin/tini -- /usr/…" 35 minutes ago Up 35 minutes 0.0.0.0:8080->8080/tcp, 0.0.0.0:50000->50000/tcp jenkins
어? 나는 띄운 컨테이너가 없는데 떠있는 컨테이너가 하나 보인다 ! 그 이유는 앞에서도 간단히 이야기 한 것처럼 호스트 도커엔진과 공유하고 있기 때문이다 ! 우리가 실행시킨 젠킨스 컨테이너가 보인다. 만약 "docker.sock 볼륨마운트"에 관해 permission denied가 발생한다면 아래와 같이 호스트 머신에서 docker.sock에 접근할 수 있도록 권한을 부여하자.