- 블록 : 괄호를 열고 닫은 구간, 시작과 끝이 있는 코드의 묶음
-> pipeline 블록으로 시작된다- 섹션 : 파이프라인 흐름 내에서 하나 이상의 지시문 또는 스텝의 묶음
- agent섹션 : 전체 파이프라인 또는 특정 단계가 실행되는 노드 지정 , 각 단계마다 실행되는 노드를 다르게 할 수 있다
- stages섹션 : 하나 이상의 순서가 있는 stage 묶음
- steps섹션 : stage 지시문에서 실행할 하나 이상의 작업
- post섹션 : stages 또는 stage의 마지막에 실행할 추가 작업
cron : 파이프라인이 트리거 되어야 하는 주기
triggers { cron('H */4 * * 1-5') }
pollSCM : 새 소스 변경 사항이 있는지 확인하는 주기
triggers { pollSCM('H */4 * * 1-5') }
upstream : 특정 파이프라인 잡이 실행되면, 후속으로 파이프라인 잡을 실행할 수 있음
triggers { upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS) }
githubPush : GitHub저장소의 웹훅(WebHook)에 의해 트리거
triggers { githubPush() }
branch : 특정 브랜치인 경우
when { branch 'master'}
environment : 환경 변수의 값과 일치하는 경우
when { environment name: 'DEPLOY_TO', value: 'production' }
expression : Groovy표현식이 참인 경우
when { expression { return params.DEBUG_BUILD } }
allOf : 여러 조건 모두 참인 경우(AND)
when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }
anyOf : 여러 조건 중 하나가 참인 경우(OR)
when { anyOf { branch 'master'; branch 'staging' } }
not : 조건이 거짓인 경우
when { not { branch 'master' } }
Jenkins에는 다양한 파이프라인을 쉽게 생성할 수 있도록 문서 기능이 웹에 내장되어 있고, 플러그인을 설치하면 내장 문서도 관련된 내용이 자동으로 업데이트 된다
새로운 item클릭
1 . Jenkinsfile을 이용한 간단한 war파일 배포
pipeline{
agent{
label 'jenkins-node'
}
stages{
stage('Checkout'){
steps{
git branch: 'main', url: 'https://github.com/suhwan12/abc.git'
}
}
stage('Build'){
steps{
sh 'mvn clean package'
}
}
stage('Deploy'){
steps{
sh 'scp /var/lib/jenkins/workspace/test_pipeline/target/hello-world.war ubuntu@172.31.45.89:/var/lib/tomcat9/webapps'
}
}
}
}
2 . github을 이용한 pipeline 생성
pipeline script from SCM 선택
git WorkDIR에서
vi Jenkinsfile
# 위의 코드를 붙여넣는다
git add .
git commit -m 'new pipeline'
git push
Jenkins에서 다시 빌드해보면 스크립트를 쓰지 않았는데도 불구하고
외부(git-bash...)에서Jenkinsfile생성과 commit 및 github에 push를 통해서 등록한 git주소에 해당하는 git repo에 Jenkinsfile이 올라와 해당 Jenkinsfile이 빌드된다
📒 Jenkinsfile을 작성할때 파이프라인 관련 내장문서 사이트를 이용하면 좀 더 쉽게 작성할 수 있다.
3 . 트리거와 파라미터, env 사용
pipeline{
agent{
label 'jenkins-node'
}
triggers {
pollSCM '* * * * *' # 트리거 사용
}
parameters { # 파라미터 사용
string defaultValue: '172.31.45.89', name: 'TOMCAT_IP'
string defaultValue: 'ubuntu', name: 'TOMCAT_LOGIN_USER'
string defaultValue: '/var/lib/tomcat9/webapps', name: 'TOMCAT_WEBAPP_DIR'
}
stages{
stage('Checkout'){
steps{
git branch: 'main', url: 'https://github.com/suhwan12/abc.git'
}
}
stage('Build'){
tools{ # global 도구 사용
jdk 'Java-11'
maven 'Maven-3'
}
steps{
sh 'mvn clean package'
}
}
stage('Deploy'){
steps{
sh "scp ${env.WORKSPACE}/target/*.war ${params.TOMCAT_LOGIN_USER}@${params.TOMCAT_IP}:${params.TOMCAT_WEBAPP_DIR}"
} # 설정한 param사용 , 큰 따옴표 사용
}
}
}
인스턴스 생성 (jenkins-docker)
ssh -i pem키 ubuntu@퍼블릭ip # 인스턴스 접속
sudo hostnamectl set-hostname jenkins-docker
exec bash # hostname 변경
sudo apt update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
sudo mkdir -m 0755 -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
#도커 설치
sudo usermod -aG docker $USER
exit
#현재사용자를 docker그룹에 포함
📒 install Jenkins with docker 참조
dokcer network create jenkins # 새로운 네트워크 생성
mkdir jenkins
cd jenkins
# jenkins디렉터리 생성 및 이동 (필수 x)
docker container run --name docker-dind --detach \
--privileged --network jenkins --network-alias docker \
--env DOCKER_TLS_CERTDIR=/certs \
--volume jenkins-docker-certs:/certs/client \
--volume jenkins-data:/var/jenkins_home \
--volume docker:/var/lib/docker \
--publish 2376:2376 \
--restart=always \
docker:dind --storage-driver overlay2
# docker container생성
vi Dockerfile # jenkins 이미지 생성하기 위한 Dockerfile 생성
FROM jenkins/jenkins:lts-jdk11
USER root
RUN apt-get update && apt-get install -y lsb-release
RUN curl -fsSLo /usr/share/keyrings/docker-archive-keyring.asc \
https://download.docker.com/linux/debian/gpg
RUN echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/usr/share/keyrings/docker-archive-keyring.asc] \
https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
RUN apt-get update && apt-get install -y docker-ce-cli
USER jenkins
RUN jenkins-plugin-cli --plugins "docker-plugin docker-workflow"
docker image build -t jenkins-docker:lts-jdk11 .
# jenkins image 생성
docker container run --name jenkins-docker \
--restart=always \
--detach \
--network jenkins \
--env DOCKER_HOST=tcp://docker:2376 \
--env DOCKER_CERT_PATH=/certs/client \
--env DOCKER_TLS_VERIFY=1 \
--publish 8080:8080 \
--publish 50000:50000 \
--volume jenkins-data:/var/jenkins_home \
--volume jenkins-docker-certs:/certs/client:ro \
jenkins-docker:lts-jdk11
# jenkins container 생성
docker container exec -it jenkins-docker bash
#jenkins컨테이너 접속
브라우저에 jenkins-docker 퍼블릭IP:8080입력
cat /var/jenkins_home/secrets/initialAdminPassword
# exec 명령으로 Jenkins컨테이너에 접속 후 암호를 찾아야 한다.
암호입력후 플러그인 설치 및 계정 설정 후 Jenkins 접속
노드관리 접속 후 아래 보이는 것처럼 Configure Clouds 클릭
node의 이름과 통신할 docker의 host URI를 설정
host URI는 docker container생성할 때 설정해주었다.
server credentials 클릭 후 x.509설정
아래와 같이 총 세개의 키를 등록해주어야 한다.
docker container exec jenkins-docker cat /certs/client/key.pem
# client key 복사 후 등록
docker container exec jenkins-docker cat /certs/client/cert.pem
# client certificate 복사 후 등록
docker container exec jenkins-docker cat /certs/client/ca.pem
# server ca certificate 복사 후 등록
1 . jenkinsfile-1
pipeline {
agent {
docker { image 'node:16-alpine' }
}
stages {
stage('Test') {
steps {
sh 'node --version'
}
}
}
}
#jenkinsfile-1의 내용
2 . jenkinsfile2
pipeline {
agent none
stages {
stage('Back-end') {
agent {
docker { image 'maven:3.8.1-adoptopenjdk-11' }
}
steps {
sh 'mvn --version'
}
}
stage('Front-end') {
agent {
docker { image 'node:16-alpine' }
}
steps {
sh 'node --version'
}
}
}
}
docker , 쿠버네티스를 사용하는 가장 큰 장점
- 이전에 가상머신을 이용해서 linux에서 jenkins를 사용했을 때는 노드를 생성하기 위해 VM(EC2)를 생성했었다. 컨트롤러가 작업이 있을 때 해당 노드에 작업을 시켜 수행하였다.
- 하지만 VM의 특성상 노드가 일을 하든 안하든 항상 띄워놔야 하기 때문에 리소스와 요금의 낭비가 심하다.
- dind 구조로 도커안에 jenkins를 설치한다면 비록 설치과정은 매우 어렵고 복잡하지만 jenkins가 작업을 수행하기 위한 노드를 VM이 아닌 컨테이너로 생성한다.
-> 도커안에 jenkins가 도커 명령을 사용할 수 있도록 설치과정에서 설정하였는데, 이것은 jenkins가 컨테이너를 생성하기 위해서 필수적이다.- 위의 1번 , 2번 실습에서 알 수 있다시피, Jenkins컨트롤러가 작업이 생긴다면 일시적으로 컨테이너(=노드)를 띄워서 작업을 수행 후 종료시킨다.
-> 컨테이너 특성 상 VM과 다르게 항상 띄워놓고 있지 않아도 된다
-> 따라서 불필요하게 노드 리소스를 띄워놓을 필요가 없다
📒 결론 : 도커나 쿠버네티스는 노드를 동적으로 생성해서 필요할때 생성, 필요하지 않으면 사용하지 않을 수 있다. 이것이 복잡하지만 굳이 도커나 쿠버네티스를 이용해 컨테이너로 작업을 하는 이유이다.
1 . dockerhub에 로그인하기 위한 인증
2 . Jenkinsfile
pipeline{
agent none
triggers{
pollSCM '* * * * *'
}
parameters {
string name: 'IMAGE_NAME' , defaultValue: 'hello-world'
string name: 'IMAGE_REGISTRY_ACCOUNT', defaultValue: 'suhwan11'
}
# 계정명과 이미지명 변수화
stages {
stage('SCM Checkout'){
agent any
steps{
git branch: 'main', url: 'https://github.com/suhwan12/abc.git'
}
}
stage('maven build project'){
agent{ docker { image 'maven:3-openjdk-8' }}
steps{
sh 'mvn clean package -DskipTests=true' # test는 따로하기 위해 스킵한다
}
}
stage('Test Maven Project'){
agent { docker { image 'maven:3-openjdk-8'} }
steps{
sh 'mvn test'
}
} # test는 따로 진행
stage('build docker image'){
agent any
steps{
sh "docker image build -t ${params.IMAGE_NAME} ."
}
}
stage('Tagging Docker Image'){
agent any
steps{
sh "docker image tag ${params.IMAGE_NAME} ${params.IMAGE_REGISTRY_ACCOUNT}/${params.IMAGE_NAME}"
}
}
stage('publishing Docker Image'){
agent any
steps{
withDockerRegistry(credentialsId: 'docker-hub-token', url: 'https://index.docker.io/v1/') {
sh "docker image push ${params.IMAGE_REGISTRY_ACCOUNT}/${params.IMAGE_NAME}"
# 1번에서 생성한 script 추가(= 로그인) 및 로그인후 수행할 명령어 작성
}
}
}
}
}
3 . Dockerfile
FROM tomcat:9-jre8
COPY target/hello-world.war /usr/local/tomcat/webapps/
4 . 프로젝트 빌드
git add .
git commit -m 'Add jenkinsfile & dockerfile'
git push
docker container exec jenkins-docker docker image ls
docker container run -d --name myweb -p 80:8080 suhwan11:hello-world
5 . 이미지 버전관리
- docker, kubernetes는 기본적으로 이미지를 풀링할때 풀링 정책(missing, always, never)이 있다
- default 정책(missing) : 로컬에 이미 이미지가 존재하면 풀링 x
- 따라서 버전을 바꾼 새로운 latest이미지를 생성하면 기존의 이미지와 해쉬값은 다르더라도 이미지의 이름이 똑같기 때문에 run 을 할때 버전이 바뀐 새로운 이미지를 풀링하지 않는다
docker container run -d --name myweb --pull always -p 80:8080 suhwan11/hello-world
docker container run -d --name myweb2 -p 80:8080 suhwan11/hello-world:60
📒 현업에서는 BUILD_NUMBER를 사용하지 않고 BUILD_TAG를 사용한 semantic versioning을 구현한다.