Post

๐Ÿณ Docker ยท Jenkins ๋„์ž…์„ ํ†ตํ•œ CI ยท CD Pipeline ๊ตฌ์ถ•

๐Ÿณ Docker ยท Jenkins ๋„์ž…์„ ํ†ตํ•œ CI ยท CD Pipeline ๊ตฌ์ถ•

CI ยท CD Pipeline ๊ตฌ์ถ•์€ ์™œ ํ–ˆ๋‚˜?

  • ํ”„๋กœ์ ํŠธ ๊ฐœ๋ฐœ์„ ๋งˆ์น˜๊ณ  ์ƒˆ๋กœ์šด Release๊ฐ€ ์ƒ๊ธธ ๋•Œ๋งˆ๋‹ค ๋ฐฐํฌ๋ฅผ ํ•˜๋Š” ๊ฒƒ์€ ํšจ์œจ์ ์ด์ง€ ๋ชปํ•˜๋‹ค.
  • ์ฒ˜์Œ์œผ๋กœ ์ง„ํ–‰ํ•œ ํ”„๋กœ์ ํŠธ์—์„œ ๊ทธ๋ ‡๊ฒŒ ํ–ˆ์—ˆ๋Š”๋ฐ, ์ด๋ฒˆ์—๋Š” ํ”„๋กœ์ ํŠธ ๋ฐฐํฌ์— ์žˆ์–ด ํšจ์œจ์„ฑ ๋ฐ ์ผ๊ด€์„ฑ์„ ๊ฐ€์ ธ๊ฐ€๊ธฐ ์œ„ํ•ด ์ž๋™ํ™”๋ฅผ ํ•ด๋ณด๊ณ ์ž ํ•œ๋‹ค.

Infrastructure ๊ตฌ์กฐ

  • ์œ„ ๊ตฌ์กฐ๋กœ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ๋ฅผ ์œ„ํ•ด CI/CD Pipeline์„ ๊ตฌ์ถ•ํ–ˆ๋‹ค.

CI ยท CD Pipeline ๊ตฌ์ถ• ๊ณผ์ •

  1. Docker ์„ค์น˜
  2. Docker-compose ์„ค์น˜
  3. Jenkins ์„ค์น˜
  4. SSH Key ๋“ฑ๋ก
  5. GitHub Webhook ์„ค์ •
  6. Dockerfile, Docker-compose.yml, Jenkins Pipeline Script ํŒŒ์ผ ์ž‘์„ฑ
  7. application.yml ํŒŒ์ผ ์ž‘์„ฑ

โœ… Docker ์„ค์น˜

1
2
3
4
5
# Docker ์„ค์น˜
sudo apt update
sudo apt install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker

โœ… Docker-compose ์„ค์น˜

1
2
3
4
# ๋„์ปค ์ปดํฌ์ฆˆ ์„ค์น˜
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version

โœ… Jenkins ์„ค์น˜

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Jenkins ์ €์žฅ์†Œ ํ‚ค ๋ฐ ์ €์žฅ์†Œ ์ถ”๊ฐ€
wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null

# ํŒจํ‚ค์ง€ ๋ชฉ๋ก ๊ฐฑ์‹  ๋ฐ Jenkins ์„ค์น˜
sudo apt update && sudo apt install jenkins -y

# Jenkins ์„œ๋น„์Šค ์‹œ์ž‘ ๋ฐ ๋ถ€ํŒ… ์‹œ ์ž๋™ ์‹œ์ž‘ ์„ค์ •
sudo systemctl start jenkins
sudo systemctl enable jenkins

# UFW ๋ฐฉํ™”๋ฒฝ์—์„œ ํฌํŠธ 8080 ํ—ˆ์šฉ
sudo ufw allow 8080 && sudo ufw reload

# ์ดˆ๊ธฐ ๊ด€๋ฆฌ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ ์ถœ๋ ฅ (์›น ์‚ฌ์ดํŠธ์— ์ž…๋ ฅ)
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
  • Jenkins๋Š” Java ๊ธฐ๋ฐ˜์ด๊ธฐ ๋•Œ๋ฌธ์— JDK๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • http://์„œ๋ฒ„_IP:8080์— ์ดˆ๊ธฐ ๊ด€๋ฆฌ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๋œ๋‹ค.

โœ… SSH Key ๋“ฑ๋ก

1
2
3
4
5
# SSH Key ์ƒ์„ฑ
ssh-keygen -t rsa -b 4096

# authorized_keys ํŒŒ์ผ์— ๊ณต๊ฐœํ‚ค ๋“ฑ๋ก
echo id_rsa.pub_๋‚ด์šฉ >> ~/.ssh/authorized_keys
  • SSH Key๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ~/.ssh/id_rsa ๋น„๋ฐ€ํ‚ค ํŒŒ์ผ๊ณผ ~/.ssh/id_rsa.pub ๊ณต๊ฐœํ‚ค ํŒŒ์ผ์ด ๋งŒ๋“ค์–ด ์ง„๋‹ค.
  • authorized_keys ํŒŒ์ผ์— ๊ณต๊ฐœํ‚ค ๋“ฑ๋ก์„ ํ•˜๊ณ ์„œ, ๋น„๋ฐ€ํ‚ค๋Š” Jenkins Pipeline์ด๋‚˜ job์—์„œ SSH ์ ‘์†ํ•  ๋•Œ์˜ ์ธ์ฆ์„ ์œ„ํ•ด Jenkins ์ž๊ฒฉ ์ฆ๋ช…์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

โœ… GitHub Webhook ์„ค์ •

  1. GitHub ํ”„๋กœ์ ํŠธ Repository Settings > Webhooks > Add Webhook
  2. Payload URL(Ubuntu ์„œ๋ฒ„ URL), Content type ์ž…๋ ฅ
  3. Enable SSL verification ์ฒดํฌ
  4. Just theย pushย event ์ฒดํฌ

โœ… Dockerfile ์ž‘์„ฑ

  1. spring-app Dockerfile
1
2
3
4
5
6
7
8
9
10
11
FROM gradle:8.8-jdk17 as build
WORKDIR /app
COPY . .
RUN gradle clean build --no-daemon

FROM openjdk:17-jdk-slim
WORKDIR /usr/local/app
COPY --from=build /app/build/libs/ํ”„๋กœ์ ํŠธ_jar_ํŒŒ์ผ๋ช… /usr/local/app/ํ”„๋กœ์ ํŠธ_JAR_ํŒŒ์ผ๋ช….jar
ENTRYPOINT ["java", "-jar", "/usr/local/app/ํ”„๋กœ์ ํŠธ_jar_ํŒŒ์ผ๋ช….jar"]

EXPOSE 18080
  • JAR ํŒŒ์ผ์„ ๋นŒ๋“œํ•  ๋•Œ๋Š” Daemon์„ ์„ค์ •ํ•˜์ง€ ์•Š๋Š” ๊ฒŒ ์ข‹๋‹ค๊ณ  ํ•œ๋‹ค.
  • ์ปจํ…Œ์ด๋„ˆ๋Š” ์ƒ๋ช… ์ฃผ๊ธฐ๊ฐ€ ์งง๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ๋ง๊ฐ€์ง€๋Š” ๊ฒŒ ๋‹น์—ฐํ•œ Resource์ด๊ณ , ๊ทธ๋•Œ๋งˆ๋‹ค ์ปจํ…Œ์ด๋„ˆ ์ž์›์„ ํ•ด์ œํ•˜๊ณ  ์žฌ์ƒ์„ฑ ํ•ด์•ผ ํ•œ๋‹ค.
  • ๊ทธ๋Ÿฐ๋ฐ Daemon์ด ์„ค์ •๋˜์–ด ์žˆ๋‹ค๋ฉด ํ•ด์ œ๋˜์ง€ ์•Š๋Š” ์ž์›์ด ์ƒ๊ธธ ์ˆ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.
    1. react-app Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
FROM node:18-alpine AS build

WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

โœ… Docker-compose.yml ์ž‘์„ฑ

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
services:
  oracle-db:
    container_name: oracle-db
    image: gvenzl/oracle-xe:11-slim
    ports:
      - "1521:1521"
    environment:
        ORACLE_PASSWORD: ํŒจ์Šค์›Œ๋“œ
    volumes:
      - oracle-data:/opt/oracle/oradata
    networks:
      - app-network

  spring-app:
    container_name: spring-app
    image: spring-app
    build: ./spring-app
    ports:
      - "18080:18080"
    volumes:
      - ./logs:/usr/local/app/logs
    depends_on:
      - oracle-db
    restart: on-failure
    networks:
      - app-network

  react-app:
    container_name: react-app
    build: ./react-app
    image: react-app
    ports:
      - "3000:80"
    volumes:
      - ./react-app:/app
    networks:
      - app-network

  networks:
    app-network:
      name: app-network
      driver: bridge
  
volumes:
  oracle-data:
    driver: local

โœ… Jenkins Pipeline Script

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
32
pipeline {
	agent any
	stages {
		stage('Checkout') {
			steps {
				git branch: '๋ธŒ๋žœ์น˜๋ช…', url: '๊นƒํ—ˆ๋ธŒ_ํ”„๋กœ์ ํŠธ_์ฃผ์†Œ'
			}
		}
		
		stage('Prepare') {
			steps {
				sshagent(['์  ํ‚จ์Šค_์ž๊ฒฉ์ฆ๋ช…_ํ‚ค']) {
					sh 'mkdir -p ${WORKSPACE}/ํ”„๋กœ์ ํŠธ/src/main/resources'
 
					sh 'scp -o StrictHostKeyChecking=no ์‚ฌ์šฉ์ž๋ช…@์„œ๋ฒ„๋„๋ฉ”์ธ:/home/ubuntu/application.yml ${WORKSPACE}/ํ”„๋กœ์ ํŠธ/src/main/resources/application.yml'
				}
			}
		}
		
		stage('Build and Deploy with Docker Compose') {
			steps {
				sh 'docker-compose -f ${WORKSPACE}/docker-compose.yml up --build -d'
			}
		}
	}
	
	post {
		failure {
			echo 'Deployment failed.'
		}
	}
}
  • GitHub Webhook์„ ํ†ตํ•ด Push Event๋ฅผ ๊ฐ์ง€ํ•ด์„œ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ${WORKSPACE}๋กœ ๊ฐ€์ ธ์˜จ๋‹ค.ย 
  • ์„œ๋ฒ„์—์„œ ์ง์ ‘ ์†Œ์Šค ์ฝ”๋“œ์˜ resources ๊ฒฝ๋กœ๋กœ ์ฃผ์ž…ํ•ด ์ค€๋‹ค.
  • Docker-compose.yml ํŒŒ์ผ์„ ๋นŒ๋“œํ•˜๋ฉด ๋„คํŠธ์›Œํฌ๊ฐ€ ์ƒ์„ฑ๋˜๊ณ , ๊ทธ ์•ˆ์—์„œ Docker Container๋“ค์ด ์ƒ์„ฑ๋˜๊ณ  ์‹คํ–‰๋œ๋‹ค.

โœ… application.yml ํŒŒ์ผ ์ž‘์„ฑ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
spring:
  datasource:
    url: jdbc:oracle:thin:@oracle-db:1521:xe?oracle.jdbc.timezoneAsRegion=false
    username: ์‚ฌ์šฉ์ž๋ช…
    password: ๋น„๋ฐ€๋ฒˆํ˜ธ
    driver-class-name: oracle.jdbc.OracleDriver
  jpa:
    database-platform: org.hibernate.dialect.OracleDialect
    hibernate:
      ddl-auto: update

logging:
  level:
    org.hibernate.SQL: debug
    org.hibernate.orm.jdbc.bind: trace
    ์ตœ์ƒ์œ„_๋„๋ฉ”์ธ.2์ฐจ_๋„๋ฉ”์ธ.ํ”„๋กœ์ ํŠธ๋ช…: debug
  file:
    name: /usr/local/app/logs/app.log

jwt:
  secret-key: ๋ฌธ์ž์—ด

server:
  port: 18080

ํ”„๋กœ์ ํŠธ ๋นŒ๋“œ

  • GitHub์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ Pushํ•˜๊ฑฐ๋‚˜, Jenkins Console์—์„œ โ€œ์ง€๊ธˆ ๋นŒ๋“œโ€ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋œ๋‹ค.
  • Pipeline ์‹คํ–‰์ด ์„ฑ๊ณตํ•˜๋ฉด ์œ„ ์ด๋ฏธ์ง€์ฒ˜๋Ÿผ Docker Container๊ฐ€ ๋ชจ๋‘ ์˜ฌ๋ผ์™€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.ย 

ํšŒ๊ณ 

  • Jenkins Pipeline Script๋ฅผ 101๋ฒˆ์ด๋‚˜ ์‚ฝ์งˆํ•˜๋ฉด์„œ ๋ช‡ ๊ฐ€์ง€ ๋А๋‚€ ์ ์ด ์žˆ๋‹ค.
    1. ์ดˆ๊ธฐ Pipeline ๊ตฌ์ถ• ์‹œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ๋„ˆ๋ฌด ์˜ค๋žœ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋ฏ€๋กœ ์ œ์™ธํ•˜๊ณ  ๋นŒ๋“œ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
    2. application.yml ํŒŒ์ผ์€ ํ”„๋กœ์ ํŠธ ๋‚ด์— ํฌํ•จํ•˜๋˜, ์•ˆ์˜ ๋‚ด์šฉ์€ .env๋ฅผ ํ†ตํ•ด ์™ธ๋ถ€์—์„œ ๊ด€๋ฆฌํ•˜๊ณ  ์ฃผ์ž…ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  • ํ˜น์ž๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ•˜๊ณ  ์ ์€ ํšŸ์ˆ˜๋ฅผ ์‹œ๋„ํ•ด์„œ ์„ฑ๊ณตํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๊ณ  ์ƒ๊ฐ ํ•  ์ˆ˜ ์žˆ๊ณ , ๊ทธ๊ฒŒ ๋งž์„ ์ˆ˜๋„ ์žˆ๋‹ค.
  • ๊ทธ๋Ÿฐ๋ฐ ํ•„์ž๋Š” ๋งŽ์€ ์‹œ๋„์—์„œ ๊ฒช๋Š” Trouble-shooting ๊ณผ์ •์—์„œ๋„ ์–ป์„ ๊ฒŒ ๋งŽ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— 101๋ฒˆ์˜ ์‹œ๋„๊ฐ€ ์˜๋ฏธ๊ฐ€ ์žˆ์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.
This post is licensed under CC BY 4.0 by the author.