[AWS] Jenkins를 통한 Docker Compose + mysql+ Spring Boot 애플리케이션 빌드 및 자동 배포 🌟🌟🌟
0. 플로우
이 글을 참고했다.
원래는 github 올림
→ Jenkins에서 github에 올라와있는 springboot 프로젝트를 가져와서 빌드
→ 메인 서버에 .jar 형태로 파일을 전송
→ 실행
을 하고 싶다면 다음과 같은 방법을 써야하지만,
나는 springboot 서버를 docker 컨테이너에서 실행할 것이므로 아래과 같은 플로우로 가려고 한다.
github 올림
→ Jenkins에서 github에 올라와있는 springboot 프로젝트를 가져와서 빌드
→ jenkins 컨테이너에서 자동 빌드 및 docker-compose 명령어로 배포
목표:
- 우분투 인스턴스에서
Dockerfile
과docker-compose.yml
를 통해 젠킨스 구동하기 github webhook
을 이용해 Jenkins와 github 연동하기- Spring Boot 프로젝트에서
Dockerfile
과docker-compose.yml
을 이용해 mysql 컨테이너와 웹 컨테이너 구동하기 git push
를 통해 젠킨스에서 Spring Boot 애플리케이션 자동 빌드 & 배포 시스템 구축
1. 우분투 인스턴스 생성 및 swap file 할당
swap file 할당은 이 글을 참고했다.
인스턴스 볼륨은 넉넉하게 30G로 생성하자!! (프리티어는 최대 30G까지 무료이다.)
8G로 했다가 컨테이너 생성할 때 공간이 부족해서 에러 해결하는데 애먹었다..
2. Ubuntu에 Docker Engine 설치
공식 사이트를 참고했다.
Repository 설정
# apt-get 업데이트
$ sudo apt-get update
$ sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
$ sudo mkdir -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
Docker Engine 설치 및 실행
$ sudo apt-get update
# 설치
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 도커 실행
$ sudo service docker start
# 상태 확인
$ sudo service docker status
권한 설정
linux에서 root 권한이 아닌 상태로 docker를 실행하면 권한 문제가 발생할 수 있다.
[linux@localhost ]$ docker ps
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/containers/json: dial unix /var/run/docker.sock: connect: permi
ssion denied
이런 경우 매번 sudo로 커맨드를 실행해도 되지만, 번거롭기 때문에 docker group에 해당 유저를 추가해주면 해결할 수 있다.
# 보통은 docker group이 생겼을테지만, 만약 없으면 생성해준다.
$ sudo groupadd docker
# docker group에 해당 유저를 추가
$ sudo usermod -aG docker $USER
# 로그아웃 후 다시 로그인하거나 다음 명령어를 실행시켜야 적용이 된다.
$ newgrp docker
3. 도커 컴포즈 설치
$ sudo apt install docker-compose
$ docker-compose --version
💥 만약 위 방법으로 도커 컴포즈를 설치하고 버전을 확인했을 때 build unknown
이 나온다면?
이 글 참고
sudo apt remove docker-compose
커맨드로 이전에 설치한 docker-compose를 제거하고 아래 명령을 실행하자.
$ sudo curl -L "https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/bin/docker-compose
# 이 명령어는 외부에서 그대로 파일을 가져와서 현재의 시스템에 올려 놓는 것이다.
# 결과적으로 "/usr/bin/" 경로에 "docker-compose" 라는 이름의 파일로 다운된다.
# 참고) https://github.com/docker/compose/releases 에서 최신 버전 확인이 가능하다.
# 최신 버전을 설치하고 싶다면 위 명령어에 보이는 1.28.5 라는 버전 숫자를 바꿔주면 된다!
$ sudo chmod +x /usr/bin/docker-compose # chmod 를 통해서 실행이 가능하게 세팅
$ docker-compose --version
4. 젠킨스 설치 (with.Docker Compose)
1) 폴더 만들기
우분투 인스턴스에 접속해서 진행한다.
docker 폴더 생성 후 그 안에 jenkins 폴더를 만들고, 그 안에 home 폴더까지 만들어주자.
docker
⎿ jenkins
⎿ home
이제 home
디렉터리에 권한을 부여해야 한다.
$ chmod -R 777 home
🚨 주의
권한을 부여하지 않으면 아래 에러가 발생한다…touch: cannot touch '/var/jenkins_home/copy_reference_file.log': Permission denied Can not write to /var/jenkins_home/copy_reference_file.log. Wrong volume permissions?
2) Dockerfile
생성
이 글을 참고했다.
jenkins 폴더 안에 Dockerfile
을 생성할 것이다.
이제 폴더 구조는 아래처럼 된다.
docker
⎿ jenkins
⎿ home
⎿ Dockerfile
나중에 젠킨스 컨테이너 안에서 docker-compose up -d
커맨드를 실행할 것이기 때문에 docker 와 docker-compose를 설치해준다.
(젠킨스 컨테이너에 접속해서 직접 설치해도 되지만 그러면 컨테이너를 지우고 새로 만들때마다 매번 설치해주어야 해서 굉장히 번거롭다..)
FROM jenkins/jenkins:lts
USER root
# docker 설치
RUN 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
# docker-compose 설치
RUN curl -L "https://github.com/docker/compose/releases/download/1.28.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose && \
chmod +x /usr/local/bin/docker-compose && \
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
3) docker-compose.yml
생성
jenkins 폴더 안에 docker-compose.yml
을 생성할 것이다.
이제 폴더 구조는 아래처럼 된다.
docker
⎿ jenkins
⎿ home
⎿ Dockerfile
⎿ docker-compose.yml
docker-compose.yml
내용은 아래처럼 작성한다.
version: '3'
services:
jenkins:
build:
context: .
dockerfile: Dockerfile
container_name: 'jenkins'
image: 'jenkins/jenkins:lts'
restart: always
user: root
#privileged: true
ports:
- 9090:8080
- 50000:50000
volumes:
- /home/ubuntu/docker/jenkins/home:/var/jenkins_home
- /var/run:/var/run:ro # docker 실행 폴더 공유
- /var/run/docker.sock:/var/run/docker.sock # docker 소켓 파일 마운트
environment:
TZ: "Asiz/Seoul"
만약 Jenkins의 포트를 9090이 아닌 다른 포트를 쓰고 싶다면 “앞”의 포트를 9090이 아닌 다른 포트로 바꾼다.
뒤의 포트까지 바꾸면 Jenkins에 접속할 수 없다. 왜냐하면 Jenkins 내부에서 포트를 8080과 50000만 열어두었기 때문이다.
즉,9090:8080
은 접속할 수 있지만9090:9090
은 접속할 수 없다.
3) 젠킨스 컨테이너 실행
우분투 인스턴스의 jenkins 폴더 안에서 진행한다.
$ docker-compose up -d # permission denied가 발생하면 sudo를 붙이자!
# 만야 에러가 발생한다면 로그를 확인해보자
$ docker logs jenkins # 맨 마지막은 컨테이너 이름!
최종적으로 폴더 구조는 아래처럼 된다!
5. 젠킨스 설정
1) 젠킨스 접속 및 설정
이 글을 참고했다.
젠킨스 컨테이너를 실행한 후, 인스턴스의 public ip:9090
로 접속하면 다음과 같은 페이지가 나온다.
패스워드 입력
위 사진에 보이는 경로로 이동해 비밀번호를 확인해야하니 경로를 복사하자!
🌟 지금은 도커를 이용했기 때문에 도커 컨테이너에 접속해서 확인해야 한다!
$ docker exec -it jenkins /bin/bash # jenkins 자리는 젠킨스 컨테이너 이름!
# 혹은 docker exec -u 0 -it jenkins bash
# 젠킨스 컨테이너 접속 후 아래 커맨드 실행
$ cat ***/initialAdminPassword # 위에서 복사한 경로를 입력한다.
위의 빨간색으로 표시한 부분에 출력되는 값을 Administrator password 에 입력한다.
비밀번호를 제대로 입력했다면 어드민 설정페이지가 나온다.
어드민 설정페이지에서 설정한 아이디와 패스워드는 앞으로 사용해야하기 때문에 잊으면 안된다!
Trouble Shooting
처음에는 도커를 사용하지 않았을 때처럼 우분투에서 바로 cat ***/initialAdminPassword
커맨드를 실행하니 No such file or directory
에러가 떴다…
도커를 이용해 젠킨스를 구동했다면 젠킨스 컨테이너에 접속한 뒤에 해당 명령어를 실행해야 한다!
플러그인 설치 화면
패스워드를 입력 후 아래와 같이 플러그인 설치화면이 나오는데 특별히 설치할 플러그인이 필요없다면 install suggested plugins
를 선택한다.
그럼 아래처럼 Getting Started 페이지가 나올 것이다. 잠시 기다리자.
Admin 계정 생성
기다리면 이렇게 Admin 사용자를 생성하는 페이지가 나오는데, Admin 사용자를 생성하고 다음 화면을 누르면 Jenkins 화면이 보이는 것을 확인할 수 있다.
Instance Configuration
마지막으로 젠킨스의 TCP 포트를 앞으로도 계속 같은 포트를 쓸 것인지 물어본다.
이제 설정이 끝났다. Start using Jenkins를 누르자.
그럼 아래와 같은 대시보드가 나온다.
2) 젠킨스를 통한 자동 빌드 & 자동 배포 🌟
이 글을 참고했다.
Item 생성 및 기본 설정
젠킨스 대시보드에서 진행한다.
- 새로운 아이템 선택
- Freestyle project 선택 및 이름 작성
- 소스 코드 관리 -> Git 선택 -> Repository URL & Branch Specifier 작성
- 빌드 유발 ->
GitHub hook trigger for GITScm polling
선택
이 상태로 우선 저장한다.
3번에서 Credentials 는 나중에 생성한 뒤에 추가할 것이다.
ssh 키 발급
이 글을 참고했다.
$ docker exec -it [jenkins 컨테이너 이름] ssh-keygen
# 연속으로 엔터 세 번 입력하기
# Created directory 확인 !! 🌟
# 생성 된 Public SSH 키 검색
$ docker exec -it [jenkins 컨테이너 이름] cat [확인한 Created directory]/id_rsa.pub
# 예. docker exec -it jenkins cat /root/.ssh/id_rsa.pub
# 생성 된 Private SSH 키 검색
docker exec -it [jenkins 컨테이너 이름] cat /[확인한 Created directory]/id_rsa
# 예. docker exec -it jenkins cat /root/.ssh/id_rsa
비밀키와 공개키가 잘 생성되었는지 확인해보자
깃 deploy key 등록
이제 GitHub로 가서 Deploy Key를 등록해주자!
백엔드 레포지토리로 가서 Settings > Deploy keys > Add deploy key 를 클릭한다.
위 명령으로 공개키를 확인한 뒤, 복붙해주고 Add key
버튼을 누른다.
jenkins credentials 추가
다시 젠킨스 대시보드로 가서 Jenkins 관리 > Manage Credentials
로 이동해준다.
Stores scoped to Jenkins
에 있는 global
을 눌러 이동한다.
Add Credenials
를 눌러 키를 추가해준다.
Kind를 SSH Username with private Key
로 바꾸고 privateKey
의 Enter directly
를 활성화한뒤 Add를 통해 이번에는 젠킨스의 비밀키를 추가해준다.
위 명령으로 공개키를 확인한 뒤, 복붙해주고 아래처럼 붙여넣는다.
Username
은 원하는 이름으로 설정해주면 된다. 나는 deploy key
로 설정했다.
이제 Create
를 눌러준다.
Item에 생성한 credential 추가
이제 아까 만든 Item에 방금 생성한 credential(deploy key
)을 추가하자.
대시보드에서 아까 만든 Item 이름을 클릭한다.
왼쪽 사이드바에서 구성
을 클릭한다.
소스코드관리 > Credentials에 아까 만들어준 ssh키(deploy key
)를 설정해준다.
빌드 유발에는 깃허브 webhook 설정을 위해 GitHub hook trigger for GITScm polling
을 체크해준다.
Build 설정
이제 Build 설정을 하자.
Build Steps
항목에서 Execute shell
을 선택해주고 Github에 푸쉬가 되었을때 어떻게 작동할지를 적어준다.
나는 아래처럼 적었다.
echo "jar 파일 생성"
./gradlew build jar -x test
echo "도커 이미지 빌드"
docker-compose build --no-cache
echo "도커 컨테이너 생성 및 실행"
docker-compose up --force-recreate -d
# echo "도커 이미지 빌드 & 컨테이너 새로 만들기 & 컨테이너 백그라운드 실행"
# docker-compose up --build --force-recreate -d
sleep 5s
docker ps -a
이대로 돌리게 되면 sudo
를 사용할 수 없다는 에러가 뜬다. root 계정이 아니면 sudo
를 사용할 수가 없기 때문이다.
이를 해결하기 위해 젠킨스 계정이 sudo
를 사용할 수 있도록 설정 해주어야 한다.
(나는 위에 Execute shell
에서 sudo
를 사용하지는 않았지만 혹시 몰라서 아래 sudoers 설정까지 해주었다..!)
sudoers 설정
우분투 인스턴스에 접속한 상태로 진행한다.
$ sudo su
$ vi /etc/sudoers
# jenkins ALL=(ALL) NOPASSWD: ALL 추가
jenkins ALL=(ALL) NOPASSWD: ALL
는 jenkins에게 sudo 접근권한을 주는 명령어이다.
깃 web hook 설정
레포지토리의 세팅에 들어가 Webhooks를 선택한다.
Add webhook
을 누른 뒤, 아래처럼 payload URL
에 해당 젠킨스 주소를 적어주고 Content type
을 application/json
으로 설정해주면 된다.
이때, 꼭 보안그룹의 인바운드 규칙에 젠킨스 포트를 0.0.0.0
으로 퍼블릭으로 열어두어야 깃허브가 보낸 Webhook 요청을 받을 수 있다.
이제 푸쉬요청을 보내면, 젠킨스가 알아서 깃에서 푸쉬된 내용을 가져와 파일을 빌드하고 이를 도커 컨테이너로 빌드하여 실행하는 것을 확인할 수 있을 것이다.
6. Spring Boot 프로젝트 구성
로컬에 있는 Spring Boot 프로젝트의 최상위에 Dockerfile
과 docker-compose.yml
을 생성한다.
Dockerfile
부모 이미지는 이 글에서
3) Use Eclipse Temurin instead of JDK, if possible
을 참고해eclipse-temurin:11-jdk
로 했다.
eclipse-temurin
이미지의 다른 태그는 도커허브에서 확인할 수 있다.
FROM eclipse-temurin:11-jdk
#VOLUME /tmp
ARG JAR_FILE=./build/libs/jenkins-test-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
EXPOSE 8080
docker-compose.yml
version: '3'
services:
database:
container_name: my_mysql
image: mysql
environment:
- MYSQL_ROOT_PASSWORD=1234
- MYSQL_DATABASE=testdb
- MYSQL_ROOT_HOST=%
command: ['--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']
ports:
- '3306:3306'
volumes:
- ./docker/data:/var/lib/mysql
restart: always
networks:
- test_network
application:
container_name: my_app
build:
context: ./
dockerfile: Dockerfile
ports:
- '8080:8080'
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://database:3306/testdb?serverTimezone=UTC&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true
- SPRING_DATASOURCE_USERNAME=root
- SPRING_DATASOURCE_PASSWORD=1234
restart: always
depends_on:
- database
networks:
- test_network
networks:
test_network:
driver: bridge
이때 db 접속 정보를 입력해주었기 때문에 application.yml
에는 spring.datasource
정보를 작성할 필요가 없다!
7. env 파일이 있다면? -> Jenkins 빌드 시 매개변수 추가
이 빌드는 매개변수가 있습니다
-> String Parameter
로 매개변수를 추가해주자!
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${MYSQL_IP}:${MYSQL_PORT}/${MYSQL_NAME}?${MYSQL_OPT}
username: ${MYSQL_USERNAME}
password: ${MYSQL_PASSWORD}
...
마무리
이제 Spring Boot 코드를 깃헙에 푸시하면,
젠킨스가 webhook을 통해 가져와서 자동으로 build 하고, Execute shell
에 적은 docker-compose up -d
커맨드를 통해 배포까지 진행한다.
아래는 젠킨스에서 빌드 및 배포에 성공한 콘솔 출력이다!
Trouble Shooting
혹시나 빌드 시에 아래와 같은 에러가 발생한다면…
Dockerfile
에서 COPY
부분에서 문제가 발생한 것 같다…
이 글을 보고
.gitignore
의 문제임을 알았다.
Dockerfile에서 build/libs/jenkins-test-0.0.1-SNAPSHOT.jar
을 app.jar
로 COPY 해야하는데 build
디렉토리가 .gitignore
에 등록되어있었다.
그래서 build/libs
를 .gitignore
에서 제외했다.
변경 전 gitignore
...
build/
...
변경 후 gitignore
...
build/classes
build/generated
build/resources
build/tmp
build/bootJarMainClassName
...
이후 빌드해보니 에러가 해결되었다!!!
+) 추가
나중에 검색해보니 build/
파일은 용량이 커서 git에 올리지 않는게 좋은 것 같다.
COPY
명령어로 보내는게 맞을 것 같은데… 아직 하지 못하므로 나중에 시도해보자..
💛 개인 공부 기록용 블로그입니다. 👻