일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- saa-c03 #saa #aws certified solutions architect - associate
- aws-loadbalacner-controller
- docker
- Terraform
- aws ses #aws lambda
- IRSA
- 에이전트 구성
- instances failed to join cluster
- Amazon CloudWatch
- s3
- kubernetes
- Pipeline
- ingestion
- jenkins
- 클러스터 보안 그룹
- node group
- Gateway
- 코드커버리지
- fruition
- amazon sns
- 에이전트 유형
- helm_release
- assumerole
- httpasswd
- route53
- 추가 보안 그룹
- Service Account
- 테라폼
- NAT
- Docker0
- Today
- Total
cloudwithbass
[Jenkins] 트러블 슈팅: 젠킨스 도커인도커(DinD) 사용기 본문
목차
- 젠킨스 파이프라인을 빌드하던 도중 파이프라인 내에서 Docker 명령이 수행되지 않는 에러가 발생했습니다.
- 이번 포스팅에선 이 에러를 해결하려는 3일 동안의 과정을 담았습니다.
- 도커로 젠킨스 에이전트를 구성하는 방법은 두 가지가 있습니다.
- 영구 도커 에이전트 방법 (Node)
젠킨스 에이전트가 젠킨스 마스터 컨테이너에 영구적으로 연결된 상태로 유지됩니다. 에이전트가 한 번 설정되면 에이전트는 수동으로 조작하지 않는 한 계속해서 활성 상태로 유지됩니다. - 동적 프로비저닝 도커 에이전트 (Cloud)
파이프라인 빌드를 시작할 때 젠킨스 에이전트를 생성하고, 빌드가 끝나면 자동으로 에이전트를 삭제합니다.
- 영구 도커 에이전트 방법 (Node)
저는 첫 번째 구성 방법에선 이 에러를 해결했으나, 두 번째 방법에선 해결에 실패했습니다. 각각 3번, 4번 목차에서 확인하실 수 있습니다.
1. 에러 상황
Jenkins 파이프라인에서 docker 명령 실행 시 not found, Is the docker daemon running? 에러 발생
정확히는 아래 Jenkinsfile의 Docker build stage에서 발생합니다.
pipeline{
agent any
stages{
stage("Complie"){
//생략
}
stage("Unit test"){
//생략
}
stage("Code coverage"){
//생략
}
stage("Static code analysis"){
//생략
}
stage("Docker build"){
steps{
sh "docker build -t dminus251/calculator ."
}
}
}
}
2. 원인 탐색과 도커 인 도커(DinD, Docker in Docker)
- 이는 젠킨스 에이전트가 도커 명령어를 찾을 수 없어서 생기는 에러입니다.
- 젠킨스 에이전트 안에는 docker가 설치되어 있지 않기 때문에 docker 명령을 수행할 수 없습니다.
따라서 젠킨스 에이전트에서 도커를 이용해야 하고, 이를 도커 인 도커라고 합니다.
도커 인 도커를 구현하는 방법은 두 가지입니다.
- 에이전트에 도커를 설치
Docker 데몬이 컨테이너 내부에서 실행되므로 호스트 시스템과의 격리가 뛰어나지만, 시스템 성능 저하 문제가 발생합니다. - docker.sock을 마운트해서 호스트의 도커 명령 이용하기
별도의 Docker daemon을 실행하지 않으므로 컨테이너가 가볍지만, privileged 옵션이 필요하므로 보안 취약점이 생깁니다.
참고: Docker agent 사용을 위해 젠킨스에 Docker pipeline, Docker plugin 플러그인을 설치해야 합니다.
3. 영구 도커 에이전트에 DinD 환경 구성
3-1. 에이전트에 도커 설치
젠킨스의 Nodes에서 도커 노드를 생성합니다.
이때 이 에이전트를 사용하기 위해 label을 docker-node-agent로 지정합니다.
Jenkins 컨테이너에 들어가 위 사진의 Run from agent commind line을 복사 후 붙여넣기해서 에이전트 노드를 연결합니다.
다음으로 도커가 설치된 gradle 이미지를 빌드하고, 레지스트리에 푸시합니다.
젠킨스 에이전트가 이 도커 이미지를 에이전트로 사용하게 할 것입니다.
# dminus251/jenkins-docker-agent:latest
FROM gradle:jdk17
# Docker 클라이언트 설치
RUN apt-get update && \
apt-get install -y docker.io
# Jenkins가 Docker를 사용할 수 있도록 권한 설정
USER root
docker build -t your_registry_name/jenkins-docker-agent:latest .
docker push your_registry_name/jenkins-docker-agent
이제 Dockerfile 내용을 다음처럼 애플리케이션을 실행하도록 변경합니다.
이는 젠킨스 에이전트가 애플리케이션 Dockerfile을 빌드하기 위함입니다.
#Dockerfile for mdinus251/calculator:latest
FROM openjdk:17-slim
# JAR 파일을 이미지에 복사
COPY build/libs/calculator-0.0.1-SNAPSHOT.jar app.jar
# 컨테이너가 시작될 때 JAR 파일을 실행하도록 설정
ENTRYPOINT ["java", "-jar", "app.jar"]
이제 Jenkinsfile을 올바르게 구성해보겠습니다.
pipeline {
agent {
docker {
image 'dminus251/jenkins-docker-agent:latest'
label 'docker-node-agent'
}
}
stages {
stage('Check Docker Installation') {
steps {
script {
sh 'which docker'
sh 'docker --version'
}
}
}
stage('Compile') {
steps {
sh './gradlew compileJava'
}
}
stage('Unit Test') {
steps {
sh './gradlew test'
}
}
stage('Code Coverage') {
steps {
sh './gradlew jacocoTestReport'
sh './gradlew jacocoTestCoverageVerification'
}
}
stage('Static Code Analysis') {
steps {
sh './gradlew checkstyleMain'
}
}
stage('Build Jar') {
steps {
sh './gradlew build'
}
}
stage('Docker Build') {
steps {
script {
// Build Docker image
sh 'docker build -t dminus251/calculator:2 .'
}
}
}
}
}
성공적으로 파이프라인 빌드에 성공한 모습입니다.
3-2. DinD: docker.sock 마운트
dminus251/jenkins-docker-agent:latest 컨테이너에 들어가 확인해보니 파일의 그룹명이 1001로 나와있습니다.
따라서 해당 컨테이너의 Dockerfile을 다음과 같이 변경 후 다시 빌드, 푸시합니다.
그룹 1001을 newdocker 그룹으로 추가하고, newdocker 그룹에 root 사용자를 추가하는 명령을 추가했습니다.
이 작업을 하지 않으면 'Is the docker deamon running?' 에러가 발생합니다.
# Dockerfile for dminus251/jenkins-docker-agent:latest
FROM gradle:jdk17
# Docker 클라이언트 설치
RUN apt-get update && \
apt-get install -y docker.io
RUN groupadd -g 1001 newdocker && usermod -aG newdocker root
USER root
docker.sock을 마운트하더라도 docker cli를 사용해야 하기 때문에 여전히 docker.io 패키지를 설치해야 합니다.
새로 만든 이미지 dminus251/jenkins-docker-agent:using_socket를 통해 파이프라인 빌드에 성공한 모습입니다.
4. 의문점: 왜 동적 프로비저닝 도커 에이전트에선 빌드에 실패할까?
3번 과정에서 영구 도커 에이전트 유형(Node)에서 Docker 명령어를 잘 수행할 수 있는 것을 확인했습니다.
하지만 왜 동적 프로비저닝 도커 에이전트 유형(Cloud)에선 Docker가 설치된 이미지를 사용해도 docker not found 에러가 발생할까요?
동적 프로비저닝 도커 유형에선 젠킨스 에이전트가 dminus251/jenkins-docker-agent:latest 이미지가 아닌 jenkins/agent:latest를 pulling하는 것으로 확인했습니다.
Jenkinsfile에서 agent의 도커 이미지를 지정해도, 처음에는 에이전트 템플릿의 이미지를 사용하는 것 같습니다.
따라서 아래 사진처럼 템플릿의 이미지를 변경합니다.
템플릿 이미지에 도커가 설치되어 있으므로, 이제 도커 명령을 실행할 수 있을 것입니다.
템플릿 이미지를 수정 후 다시 파이프라인을 빌드했습니다.
이제 Docker not found 에러는 발생하지 않지만, Is the docker daemon running? 에러가 발생합니다.
도커 데몬과 통신이 원활하지 않아 생기는 에러입니다.
분명 Jenkinsfile에서 agent에 /var/run/docker.sock을 마운트 했고, privileged 권한까지 줬는데, 왜 이런 에러가 발생할까요?
아래는 제가 에러를 해결하려고 시도한 방법들입니다.
- 3-2와 마찬가지로 newdocker 그룹을 추가해서 roote 유저를 그룹에 추가
- Jenkinsfile의 agent에 args '--privileged -v /var/run/docker.sock:/var/run/docker.sock' 추가
agent 부분을 다음과 같이 변경했습니다.
docker-cloud-agent 레이블은 동적 프로비저닝 도커 에이전트의 레이블입니다.
agent { docker { image 'dminus251/gardle-agent:latest' args '--privileged -v /var/run/docker.sock:/var/run/docker.sock' #추가 label 'docker-cloud-agent' } }
- dminus251/jenkins-docker-agent:latest 컨테이너에 들어가 docker --version, docker ps 명령 수행
→ 수행 결과 도커 데몬과 통신할 수 있는 것을 확인함 - dminus251/jenkins-docker-agent:latest 이미지의 Dockerfile에서 docker.io 외에도 도커 관련 패키지들인 docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin을 모두 설치
혹시 이외에 더 시도해 볼만한 게 있을 경우 댓글로 알려주신다면 정말 감사드리겠습니다.
5. 후기
비록 의문점을 해결하진 못 했지만 도커, 젠키스 명령과 친해질 수 있는 기회가 되었습니다.
나중에 더 성장해서 이 의문점을 해결하게 된다면 꼭 포스팅을 올리겠습니다.
3일 동안 총 99번이나 빌드해준 젠킨스 에이전트에게 아주... 고맙습니다.
'Docker and Jenkins' 카테고리의 다른 글
[CI/CD] GitLab CI/CD 튜토리얼: 첫 파이프라인 생성하기 (0) | 2024.11.10 |
---|---|
[Jenkins] 젠킨스 파이프라인: 깃 푸시부터 인수 테스트까지 (3) | 2024.07.24 |
[Docker] https와 인증서를 이용해서 사설 도커 레지스트리 사용하기 (1) | 2024.07.20 |
[Jenkins] 코드 커버리지란?, JaCoCo와 Checkstyle (0) | 2024.07.17 |
[Jenkins] 파이프라인 구축하기 (2) | 2024.07.16 |