티스토리 뷰
목차
시작하기 전에, 이 글은
위 글을 사실상 그대로 베낀 것이다.
몇 번이고 젠킨스+도커로 배포를 하면서 수없이 많이 읽었고 도움을 많이 받았으나,
이러다 해당 글이 삭제라도 되는 날엔 내가 길을 잃을 것 같아 아카이빙 + 최신버전 반영 차원에서 작성한다.
Stacks
이번 구현에서 내가 사용하고 있는 기술 스택이다.
- M1 MacBook Air
- Spring WebFlux
- Gradle 8.1.1
- EC2 두 대(젠킨스 용, 배포 용)
- Java 17
- Jenkins
- Docker
- IntelliJ
- DockerHub private Repository
- Github private Repository
Flow
워크플로우를 간략하게 정리하면 아래와 같다.
- GitHub 레포지토리로 코드를 푸시한다.
- Webhooks를 이용해 Jenkins에서 코드를 가져온다.
- 이어서 젠킨스 내부에서 다음과 같은 과정을 거친다.
- 가져온 코드를 빌드(및 테스트)한다.
- 미리 작성한 Dockerfile을 이용해 이미지를 빌드하고 준비된 Docker Hub에 푸시한다.
- 역시 미리 작성한 deploy.sh 파일을 배포용 EC2로 전송한 뒤 실행한다.
- deploy.sh 내부에는 기존 Docker 이미지 삭제 및 새로운 이미지 풀 및 실행 코드가 담겨있다.
- 운영용 EC2에서 도커 이미지를 이용해 Spring WebFlux 프로젝트를 실행시킨다.
Preparation
위에 적혀있는 <미리 작성한> 파일들을 준비한다.
실제로 띄울 스프링 프로젝트는 이미 준비되었다고 가정한다.
Dockerfile
도커파일은 프로젝트를 도커 이미지로 빌드하는 역할을 한다.
# JDK17 이미지 사용
FROM openjdk:17-jdk
VOLUME /tmp
# JAR_FILE 변수에 값을 저장
ARG JAR_FILE=./build/libs/basic-0.0.1-SNAPSHOT.jar
# 변수에 저장된 것을 컨테이너 실행시 이름을 app.jar파일로 변경하여 컨테이너에 저장
COPY ${JAR_FILE} app.jar
# 빌드된 이미지가 run될 때 실행할 명령어
ENTRYPOINT ["java","-jar","app.jar"]
해당 도커 파일의 경로는 메인 프로젝트와 같은 위치이다.
deploy.sh
# 가동중인 astarcorp 도커 중단 및 삭제
sudo docker ps -a -q --filter "name=astarcorp" | grep -q . && docker stop astarcorp && docker rm astarcorp | true
# 기존 이미지 삭제
sudo docker rmi astarcorp/copykleb2b:1.0
# 도커허브 이미지 pull
sudo docker pull astarcorp/copykleb2b:1.0
# 도커 run
docker run -d -p 8080:8080 --name astarcorp astarcorp/copykleb2b:1.0
# 사용하지 않는 불필요한 이미지 삭제 -> 현재 컨테이너가 물고 있는 이미지는 삭제되지 않음
docker rmi -f $(docker images -f "dangling=true" -q) || true
위에 적었듯이 이 파일은 마지막에 배포용 EC2에서 실행할 스크립트를 담은 파일이다.
지금은 하나의 이미지만 다루고 있지만 Redis와 같은 여러 이미지도 한 번에 처리하도록 구성할 수도 있다.
해당 파일의 위치는 아래와 같다.
Create EC2 instances
계속해서 젠킨스용, 배포용 두 개의 EC2 인스턴스를 만들자.
EC2 for Jenkins
AWS에 접속해 EC2 서비스로 이동한 뒤에 인스턴스 시작을 누른다.
운영체제는 프리티어로 사용 가능한 Amazon Linux 2 AMI를 선택한다.
이어서 인스턴스 유형을 프리티어 t2.micro로 골라준다.
다음은 SSH 접근을 위한 키 페어 생성이다.
키 페어 생성을 누르면 만들어지는 .pem파일은 잘 보관해야 한다.
이어서 보안그룹을 선택하거나 새로 만든다. 여기선 새로 만드는 것으로 하겠다.
SSH 트래픽을 내 아이피로 지정한다. HTTPS와 HTTP는 전체로 열어두고 필요하면 추후에 제한한다.
EC2 프리티어는 무료 용량을 30GB까지 설정할 수 있다. 최대로 설정해 주자.
나머지 설정은 건드릴 필요 없이 인스턴스 시작 버튼을 눌러준다.
이어서 생성된 EC2 인스턴스를 누르고 보안 > 보안그룹을 누른 뒤 인바운드 규칙 편집을 눌러준다.
여기서 TCP 소스를 내 아이피로 바꿔준다. SSH 소스는 이미 내 IP가 들어가 있다는 전제다.
EC2 for Deployment
배포용 EC2도 위와 동일하게 만들어주면 된다.
차이점이 있다면 프로젝트의 규모에 따라 인스턴스 유형을 조절해야 하고,
HTTP, HTTPS 포트를 위와 다르게 둘 다 전체로 열어주어야 한다.
Elastic IP
이어서 생성한 EC2 인스턴스에 탄력적 IP 주소를 할당하자.
이는 인스턴스의 재부팅 시 일어나는 IP 재할당을 막기 위함이다.
위와 같이 접근해 탄력적 IP 주소를 두 개 할당하자. 따로 설정할 것 없이 기본으로 만들면 된다.
만들어진 탄력적 IP 주소에 위에서 생성한 EC2 인스턴스를 연결하면 EC2 생성과정은 끝이다.
EC2 Initial Setup
생성 및 탄력적 IP 할당을 마친 EC2의 초기 세팅이다.
먼저 위에서 생성한 두 개의 .pem 파일이 있는 위치에서 터미널을 열고 다음 명령어를 입력해 권한을 변경한다.
chmod 600 파일명.pem
이어서 아래와 같이 입력하면 해당 EC2에 접속할 수 있게 된다.
ssh -i 파일명.pem ec2-user@<탄력적 IP 주소>
EC2에 접속하면 hostname과 시간대를 변경해 주도록 하자.
hostname은 딱히 변경하지 않아도 상관없으나 알아보기 쉽게 바꾸는 것을 추천한다.
sudo hostnamectl set-hostname <원하는 hostname>
sudo reboot #EC2 인스턴스 재부팅
다음은 시간대 변경이다.
sudo rm /etc/localtime
sudo ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime
위와 같이 입력한 뒤에
date
를 입력하면 변경된 시간대가 나오는 것을 확인할 수 있다.
EC2 for Jenkins
계속해서 젠킨스용 EC2 인스턴스의 기본 세팅을 하자.
기본적으로 프리티어 유형에서는 이 글에서 원하는 플로우를 구현하기엔 메모리가 모자라다.
따라서 인스턴스의 하드디스크를 가상 메모리로 스왑해 공간을 확보해야 한다.
순서는 아래와 같다.
sudo dd if=/dev/zero of=/swapfile bs=128M count=16
- dd 명령어로 루트 파일 시스템에 스왑 파일을 생성한다. bs는 블록의 크기, count는 개수를 가리킨다.
- 여기서 지정한 블록의 크기는 인스턴스의 메모리보다 작아야 한다. 그렇지 않으면 memory exhauted 에러가 발생한다.
- 위 코드대로라면 128MB * 16 = 2GB의 메모리가 확보된다.
이어서 다음과 같이 입력한다.
#스왑 파일 권한 업데이트하기
sudo chmod 600 /swapfile
#Linux 스왑 영역 설정
sudo mkswap /swapfile
#스왑 공간에 스왑 파일을 추가하여 스왑 파일을 즉시 사용할 수 있도록 설정
sudo swapon /swapfile
#절차 성공여부 확인
sudo swapon -s
#/etc/fstab 파일을 편집하여 부팅 시 스왑 파일을 활성화
sudo vi /etc/fstab
#파일 가장 마지막에 다음을 추가하고 :wq로 저장 및 종료
/swapfile swap swap defaults 0 0
#메모리 확인
free
과정이 제대로 끝났다면 아래와 같은 출력을 만날 수 있다.
다음은 도커 설치이다. 아래와 같이 쭉쭉 입력하면 된다.
#패키지 업데이트
sudo yum -y upgrade
#도커 설치
sudo yum -y install docker
#도커 설치 작업이 잘 되었는지 버전 확인
docker -v
#도커 시작
sudo service docker start
#도커 그룹에 사용자 추가 -> docker가 그룹명, ec2-user가 사용자명
sudo usermod -aG docker ec2-user
현재 사용자명을 모른다면
echo $USER
를 입력하면 된다.
이어서 젠킨스용 EC2 내부에도 Dockerfile, 그리고 docker_install.sh 파일을 구성한다.
도커로 띄운 젠킨스 안에서 도커를 사용하기 위한 방법이라고 보면 된다.
#Dockerfile 생성
sudo vim Dockerfile
#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
# 도커 그룹에 사용자 추가
RUN usermod -aG docker jenkins
USER jenkins
#입력 완료 후 저장 및 종료
:wq
위 파일에서 사용할 docker_install.sh를 구성하자. 도커 파일 내부에 도커를 설치하기 위한 스크립트다.
#docker_install.sh 파일 생성
sudo vim docker_install.sh
#docker_install.sh 파일 작성 시작
#!/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
#저장 후 종료
:wq
이어서 다음과 같이 권한변경 후 젠킨스 이미지를 빌드한다.
sudo chmod 666 /var/run/docker.sock
docker build -t jenkins .
- -t: 태그를 주는 옵션. 여기서는 jenkins가 된다.
- .: 현재 위치에 있는 Dockerfile을 가리킨다.
빌드한 이미지를 컨테이너로 띄우기 전에 마운트 폴더를 작성한다.
이는 컨테이너 재부팅 시 데이터와 설정을 유지하기 위함이다.
#jenkins 폴더 만들기
mkdir jenkins
#해당 폴더에 대해 권한 부여하기
sudo chown -R 1000 ./jenkins
여기까지 끝났으면 젠킨스 컨테이너를 띄우면 된다.
sudo docker run -d --name jenkins \
-v /home/ec2-user/jenkins:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 8080:8080 \
-e TZ=Asia/Seoul \
jenkins
- -d: 백그라운드 실행
- -v: 볼륨 마운트
- -p: 포트 설정
- -e: 환경변수 설정. 옵션으로 한국시간 설정
EC2 for Deployment
배포용 EC2는 도커 허브에서 받아온 이미지를 컨테이너로 띄우는 역할이기 때문에
간단하게 도커만 설치해 주면 된다.
#패키지 업데이트
sudo yum -y upgrade
#도커 설치
sudo yum -y install docker
#도커 설치 작업이 잘 되었는지 버전 확인
docker -v
#도커 시작
sudo service docker start
#도커 그룹에 사용자 추가 -> docker가 그룹명, ec2-user가 사용자명
sudo usermod -aG docker ec2-user
newgrp docker
여기까지 해서 AWS 관련 설정은 모두 마쳤다.
다음 글에서는 젠킨스와 깃허브 웹훅 설정 및 자동배포까지 구현한다.
'Development > Cloud' 카테고리의 다른 글
[Trouble Shooting]AWS 타임아웃 설정 (0) | 2023.07.11 |
---|---|
[Jenkins+Docker]두 대의 EC2로 CI/CD 구현하기(3/3) (0) | 2023.07.04 |
[Jenkins+Docker]두 대의 EC2로 CI/CD 구현하기(2/3) (0) | 2023.07.01 |
[Cloud]AWS EC2, GitHub Webhook, Jenkins, Docker를 이용한 CI/CI 파이프라인 (0) | 2023.04.26 |
[Grafana]바로 복붙해서 쓰면 되는 cAdvisor+Prometheus+Grafana (0) | 2023.04.14 |
[Cloud]CI, CD, 배포 자동화(Deployment Automation) (0) | 2022.10.06 |
- Total
- Today
- Yesterday
- 유럽
- 자바
- 야경
- Backjoon
- 세계일주
- spring
- java
- 세모
- 유럽여행
- 동적계획법
- 스프링
- 중남미
- a6000
- 기술면접
- 리스트
- 백준
- 면접 준비
- 알고리즘
- 스트림
- RX100M5
- Python
- 남미
- 세계여행
- Algorithm
- 칼이사
- 맛집
- 지지
- 여행
- 파이썬
- BOJ
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |