한마디로, 도커 안의 도커가 있다는 것이다.
도커 바이너리를 설정하고 컨테이너 내부의 격리된 Docker 데몬을 실행하는 작업의 과정을 말한다.
CI 측면에서 접근한다면 job(task)을 수행하는 Executor(Agent)가 Docker Client와 Docker Daemon 역할까지 하게 되어 도커 명령을 수행하는데 문제가 없어진다.
실습할 DinD 를 그려보자면 다음과 같다.
이 구조의 아키텍쳐를 구축할려면 다음 과정을 따르자.
1) Docker 컨텐이너로 jenkins를 실행
2) 그 jenkins 컨테이너 안에 Docker를 또 다시 설치
# jenkins 컨테이너 os 확인, os 에 맞는 docker 설치 명령어를 쳐주면 된다!
cat /etc/*-release
3) jenkins 컨테이너 안에 docker 명령어는 외부 docker 컨텐이너와 연결되어야 한다.
-v 마운트 설정
필수!jenkins pipeline은 그전 Freestyle로 jenkins 프로젝트를 만드는 것보다 더 관리용의성이 편하기 때문에 많이 사용된곤 합니다.
별도의 pipeline 문법
으로 된 스크립트언어로 빌드 및 배포 흐름을 stage 별로 관리할 수 있습니다.
그리고 이를 하나의 문서
로 관리하고 싶다면, Jenkinsfile
스크립트 파일로 관리 수도 있습니다.
이번 실습은은 하나의 인스턴스
를 통해서 배포가 가능하게 할 것입니다.
원격으로 접속할 SSH서버가 따로 필요없습니다.(권장사항은 x)
젠킨스 파이프라인 첫번째 실습을 하기 위해선 DinD(Docker in Docker) 구조의 방식으로, jenkins 컨테이너 내에도 docker가 설치되어야 합니다.
https://velog.io/@mooh2jj/AWS-EC2-Docker-설치 편에서 실행한 방법입니다.
AWS EC2 인스턴스에 Docker를 설치했으면 이제, jenkins 이미지를 run 해봅시다.
docker run \
--name jenkins-docker \
-p 9000:8080 -p 50000:50000 \
-e TZ=Asia/Seoul \
-v /home/jenkins:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/bin/docker:/usr/bin/docker \
-u root \
-d \
--restart unless-stopped \
jenkins/jenkins:lts
이 위치 꼭 기억하자!
jenkins 내 project 이름의 폴더가 생기고 또 그 안에 git clone한 레포지토리 이름의 폴더 들어간다.
docker exec -it jenkins-docker bash
cd /var/jenkins_home/workspace/{jenkins project 이름}/{git clone한 git 레포지토리 이름}
실제 배포할 프로젝트 내용이 이 안에 있는 것입니다.
자, 이제 실행된 Jenkins 컨테이너에 다시 Docker와 Docker-compose를 깔아봅시다.
docker exec -it jenkins-docker bash
참고)
https://velog.io/@mooh2jj/AWS-EC2-Docker-설치
이런 방식도 있습니다.
jenkins Dockerfile
FROM jenkins/jenkins:jdk11
#도커를 실행하기 위한 root 계정으로 전환
USER root
#도커 설치
COPY docker_install.sh /docker_install.sh
RUN chmod +x /docker_install.sh
RUN /docker_install.sh
#설치 후 도커그룹의 jenkins 계정 생성 후 해당 계정으로 변경
RUN groupadd -f docker
RUN usermod -aG docker jenkins
USER jenkins
docker_install.sh
# jenkins 컨테이너 안에 docker 설치
#!/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
자 이제 설정 완료된 Jenkins 홈페이지에 들어가서 Item 설정 > Pipeline
프로젝트를 만들어줍니다.
배포할 Git 레포지토리를 등록해붑니다. 이 레포지토리는 public으로 credentials 설정이 필요없습니다.
private라면 credentials
설정을 꼭 해줍니다.
실습시, 아래와 같은 pipeline Script에 먼저 적어주시고 해주시는 게 하나씩 하나씩 파악하는 것을 추천드립니다!
자 이제 Pipeline 문서(Jenkinsfile
)를 가져와야 합니다. 밑에 Script Path
는 git 프로젝트 디렉토리 안에서 찾습니다. 저는 프로젝트 루트 바로 하위에 ForJenkins폴더를 하나 더 만들고 그안에 Jenkinsfile를 만들었습니다.
그래서 ForJenkins/Jenkinsfile
// Jenkinsfile (Declarative Pipeline)
pipeline {
agent any // 사용 가능한 에이전트에서 이 파이프라인 또는 해당 단계를 실행
stages {
stage('Checkout') {
steps {
sh 'echo git source 다운로드를 수행합니다. -> git clone'
}
}
stage('Build') {
steps {
sh 'echo "빌드" 단계와 관련된 몇 가지 단계를 수행합니다.'
}
}
stage('Deploy') {
steps {
sh 'echo "배포" 단계와 관련된 몇 가지 단계를 수행합니다.'
}
}
}
}
// Jenkinsfile(선언적 파이프라인)
pipeline {
agent any
options {
skipStagesAfterUnstable()
}
stages {
stage('Build') {
steps {
sh 'make'
}
}
stage('Test'){
steps {
sh 'make check'
junit 'reports/**/*.xml'
}
}
stage('Deploy') {
steps {
sh 'make publish'
}
}
}
}
pipeline {
agent any // 사용 가능한 에이전트에서 이 파이프라인 또는 해당 단계를 실행
stages {
stage('Checkout') {
steps {
git branch: 'master',
url: 'https://github.com/mooh2jj/docker-jenkins-pipeline-test2.git'
}
post {
success {
sh 'echo "Successfully Cloned Repository"'
}
failure {
sh 'echo "Fail Cloned Repository"'
}
}
}
stage('Build') {
steps {
// gralew이 있어야됨. git clone해서 project를 가져옴.
sh 'chmod +x gradlew'
sh './gradlew clean build'
sh 'ls -al ./build'
}
post {
success {
echo 'gradle build success'
}
failure {
echo 'gradle build failed'
}
}
}
stage('Test') {
steps {
echo '테스트 단계와 관련된 몇 가지 단계를 수행합니다.'
}
}
stage('Docker Rm') {
steps {
sh 'echo "Docker Rm Start, docker 컨테이너가 현재 돌아갈시 실행해야함"'
sh """
docker stop docker-jenkins-pipeline-test2
docker rm docker-jenkins-pipeline-test2
docker rmi -f mooh2jj/docker-jenkins-pipeline-test2
"""
}
post {
success {
sh 'echo "Docker Rm Success"'
}
failure {
sh 'echo "Docker Rm Fail"'
}
}
}
stage('Dockerizing'){
steps{
sh 'echo " Image Bulid Start"'
sh 'docker build . -t mooh2jj/docker-jenkins-pipeline-test2'
}
post {
success {
sh 'echo "Bulid Docker Image Success"'
}
failure {
sh 'echo "Bulid Docker Image Fail"'
}
}
}
stage('Deploy') {
steps {
sh 'docker run --name docker-jenkins-pipeline-test2 -d -p 8083:8083 mooh2jj/docker-jenkins-pipeline-test2'
}
post {
success {
echo 'success'
}
failure {
echo 'failed'
}
}
}
}
}
** 결과
(RDBMS가 연결되어 있으면 오류가 납니다.)
참고 : https://github.com/mooh2jj/board_vue_backend/blob/master/Jenkinsfile
jenkins 내부 컨테이너에서 docker-compose를 돌리기 때문에 docker-compose를 설치해주어야 한다.
pipeline {
agent any // 사용 가능한 에이전트에서 이 파이프라인 또는 해당 단계를 실행
# git 프로젝트 credentials 는 access token 으로 사용
stages {
stage('Prepare') {
steps {
git branch: 'master',
url: 'https://{git access token}@github.com/mooh2jj/board_vue_backend.git'
}
post {
success {
sh 'echo "Successfully Cloned Repository"'
}
failure {
sh 'echo "Fail Cloned Repository"'
}
}
}
stage('Build') {
steps {
// gralew이 있어야됨. git clone해서 project를 가져옴.
sh 'chmod +x gradlew'
sh './gradlew --warning-mode=all --stacktrace clean build -x test'
sh 'ls -al ./build'
}
post {
success {
echo 'gradle build success'
}
failure {
echo 'gradle build failed'
}
}
}
stage('Test') {
steps {
echo '테스트 단계와 관련된 몇 가지 단계를 수행합니다.'
}
}
stage('Prune Docker data') {
steps {
sh 'echo "Prune Docker data"'
sh 'docker system prune -a --volumes -f'
}
post {
success {
sh 'echo "Prune Docker data Success"'
}
failure {
sh 'echo "Prune Docker data Fail"'
}
}
}
stage('Docker Build'){
steps{
sh 'echo " Image Bulid Start"'
sh 'docker build . -t mooh2jj/board_vue_backend'
}
post {
success {
sh 'echo "Bulid Docker Image Success"'
}
failure {
sh 'echo "Bulid Docker Image Fail"'
}
}
}
stage('Docker Push') {
steps {
withCredentials([string(credentialsId: 'dockerHubPwd', variable: 'dockerHubPwd')]) {
sh "docker login -u mooh2jj -p ${dockerHubPwd}"
}
sh 'docker push mooh2jj/board_vue_backend'
}
post {
success {
echo 'Docker Push success'
}
failure {
echo 'Docker Push failed'
}
}
}
stage('Docker Deploy'){
steps{
sh 'docker-compose up -d --build'
sh 'docker-compose ps'
}
post {
success {
echo 'docker-compose success'
}
failure {
echo 'docker-compose failed'
}
}
}
}
}
이 상태에서 Build Now
를 하고 파이프라인이 실행됩니다.
이미지상 병렬적으로 실행된다는 것을 알 수 있습니다. 파이프라인 문법에서 stage
에 적힌 이름으로 각 job이 문제가 되는지 안되는지 편하게 확인할 수 있는 것이죠.
url 상 확인해보면 잘 되는 것을 확인할 수 있었습니다.