Use Docker in Jenkins Docker

Docker로 기동한 Jenkins에서 Docker를 실행하는 방법을 정리합니다.

Introduction

Synology에서 여러 응용 프로그램을 설치해서 사용하기 위해서 Docker를 애용합니다.
Docker로 Jenkins 를 사용중인데, Jenkins에서도 Docker를 사용해야하는 상황이 생겨 진행하게 되었습니다.
Synology가 아닌 다른 Machine에서도 비슷하게 진행되지만, 이번 설명은 Synology를 기준으로 설명하겠습니다.

설명한 방법은 Host의 docker sock을 공유하는 방법입니다.

Prerequisite

  • Jenkins Container Using Official Image

Progress

생각보다 어렵지 않습니다. 차근차근히 진행하면 쉽습니다.
DSM 7.2로 업데이트한 후에 진행한 작업이라, 캡처한 이미지가 차이가 있을 수 있습니다.

1. Docker sock 공유

Synology에 설치해준 Docker sock과 container에서 사용할 Docker sock을 binding 하는 작업을 해야합니다.
아래의 명령어대로 설정해 주면 됩니다.

1
2
3
4
docker run -p ${webPort}:8080 -p ${agentPort}:50000 -d -v /var/run/docker.sock:/var/run/docker.sock -v ${hostJenkinsDir}:/var/jenkins_home jenkins/jenkins:lts

# 예시로 들면 아래와 같습니다.
docker run -p 8080:8080 -p 50000:50000 -d -v /var/run/docker.sock:/var/run/docker.sock -v /docker/jenkins/home:/var/jenkins_home jenkins/jenkins:lts

하지만 Synology에서는 / directory 설정할 수 없기떄문에, SSH로 접속해서 설정해주어야합니다.
SSH로 접속해서 Docker command를 사용할 준비를 합니다.

update_command_in_host

저의 경우에는 위의 이미지처럼 container의 volume을 update할 수 있는 설정이 있습니다.
그래서 아래의 명령어를 사용해서 volume binding 하였습니다.

1
docker container update -v /var/run/docker.sock:/var/run/docker.sock -v /docker/jenkins/home:/var/jenkins_home ${containerId}

이렇게 변경한 volume binding은 synology web ui상에서는 보이지 않기 때문에, 명령어를 통해 잘 변경되었는지 확인해야합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
docker container inspect ${containerId}
{
          ...,
          "Mounts": [
            {
                "Type": "bind",
                "Source": "/volume1/docker/jenkins/home",
                "Destination": "/var/jenkins_home",
                "Mode": "rw",
                "RW": true,
                "Propagation": "rprivate"
            },
            {
                "Type": "bind",
                "Source": "/var/run/docker.sock",
                "Destination": "/var/run/docker.sock",
                "Mode": "rw",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],
        ...
}

위처럼 docker.sock이 추가되었다면, 정상적으로 된 것입니다.
혹시 docker container update 명령어를 통해 volume binding을 할 수 없다면, 새로 container를 만드는것이 편하겠습니다.
직접 하진않았지만 아래의 명령어처럼 입력하면 되지않을까 싶습니다.

1
2
3
4
docker run --restart ${policy} --name ${jenkins} -p ${webPort}:8080 -p ${agentPort}:50000 -d -v /var/run/docker.sock:/var/run/docker.sock -v ${hostJenkinsDir}:/var/jenkins_home jenkins/jenkins:lts

# 예시로 들면 아래와 같습니다.
docker run --restart always --name jenkins -p 8080:8080 -p 50000:50000 -d -v /var/run/docker.sock:/var/run/docker.sock -v /docker/jenkins/home:/var/jenkins_home jenkins/jenkins:lts

항상 재시작 하는 옵션을 공식문서를 참고하였습니다.
본인의 필요에 따라 설정해주세요.

2. Jenkins에 Docker 설치

Dockerfile을 새로 만들어, Docker를 설치하는 스크립트를 입력해주는 방법도 있습니다. 하지만 새로 이미지를 만들고 관리하는건 번거롭기도하고, volume binding을 해서 데이터가 유지되는 상황이니 설치 스크립트를 저장해두는게 좋다고 생각이 들었습니다.
(Jenkins를 업그레이드하거나 Container가 삭제된다면, 설치스크립트를 새로 실행해주긴 해야하지만요.)

아래의 내용의 스크립트를 host의 /docker/jenkins/home/install_jenkins.sh로 만들어 주었습니다.

1
2
3
#!/bin/bash
curl https://get.docker.com/ > dockerinstall && chmod 777 dockerinstall && ./dockerinstall
chmod 666 /var/run/docker.sock

설치하는데 조금 시간이 걸리긴합니다. 기다리면, 설치가 완료된것을 보실 수 있습니다.

3. 동작 확인

Jenkins Container와 Web UI에서 Docker command가 잘 되는지 확인해보겠습니다.
우선은 Container에서 확인해보겠습니다.

1
2
3
4
5
6
7
docker exec -it ${containerId} /bin/bash
# 예시
docker exec -it f0f5398c9a62 /bin/bash

---

docker container ls --all

위의 명령어들을 실행하면 Container에 접속하였고, 시놀로지에서 구동중인 Container 리스트를 확인할 수 있게됩니다.
구동중인 Container가 없을 수는 없지만, 에러는 발생해서는 안됩니다.

위에까지만 확인해도 문제는 없을텐데, 저는 혹시나 싶어 더 확인해보았습니다.
아래처럼 Jenkins pipeline으로 실행해보았습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
pipeline {
    agent any
    stages {
        stage('Run Container') {
            steps {
                script {
                    // Docker 컨테이너 실행
                    docker.image("hello-world:latest").run()
                }
            }
        }
    }
}

console_job 위의 결과까지 나오면, jenkins에서도 docker를 마음껏 사용하실 수 있습니다.

Conclusion

Docker로 구동한 Jenkins에서 Docker를 실행할 수 있도록 해보았습니다.
Container로 만들어진 Jenkins에서 Host의 Docker에 접근할 수 있게 만든다는게, 편리하긴 하지만 보안상으로는 좋지않아 보입니다.
사용하신다면 Container와 Host의 보안을 좀 더 신경 써서 사용해주시면, 안전할 것 같습니다.

다른 분들에게 도움이 되면 좋겠네요. 감사합니다.

Reference

Hugo로 만듦
JimmyStack 테마 사용 중