티스토리 뷰

728x90
반응형

목차

     

     

     

    시작하기 전에, 이 글은 

     

    https://backtony.github.io/spring/aws/2021-08-08-spring-cicd-1/#%EB%8F%84%EC%BB%A4-%EC%84%B8%ED%8C%85

     

    Spring & Jenkins & Docker & DockerHub & GitHub 활용한 CI/CD

    Java, JPA, Spring을 주로 다루고 공유합니다.

    backtony.github.io

    위 글을 사실상 그대로 베낀 것이다.

     

    몇 번이고 젠킨스+도커로 배포를 하면서 수없이 많이 읽었고 도움을 많이 받았으나,

     

    이러다 해당 글이 삭제라도 되는 날엔 내가 길을 잃을 것 같아 아카이빙 + 최신버전 반영 차원에서 작성한다.

     

    Stacks

     

    이번 구현에서 내가 사용하고 있는 기술 스택이다.

     

    • M1 MacBook Air
    • Spring WebFlux
    • Gradle 8.1.1
    • EC2 두 대(젠킨스 용, 배포 용)
    • Java 17
    • Jenkins
    • Docker
    • IntelliJ
    • DockerHub private Repository
    • Github private Repository

     

    Flow

     

    워크플로우를 간략하게 정리하면 아래와 같다.

     

    1. GitHub 레포지토리로 코드를 푸시한다.
    2. Webhooks를 이용해 Jenkins에서 코드를 가져온다.
    3. 이어서 젠킨스 내부에서 다음과 같은 과정을 거친다.

      1. 가져온 코드를 빌드(및 테스트)한다.
      2. 미리 작성한 Dockerfile을 이용해 이미지를 빌드하고 준비된 Docker Hub에 푸시한다.
      3. 역시 미리 작성한 deploy.sh 파일을 배포용 EC2로 전송한 뒤 실행한다.
      4. deploy.sh 내부에는 기존 Docker 이미지 삭제 및 새로운 이미지 풀 및 실행 코드가 담겨있다.
    4. 운영용 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 관련 설정은 모두 마쳤다.

     

    다음 글에서는 젠킨스와 깃허브 웹훅 설정 및 자동배포까지 구현한다.

    반응형
    댓글
    공지사항
    최근에 올라온 글
    최근에 달린 댓글
    Total
    Today
    Yesterday
    링크
    «   2024/05   »
    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
    글 보관함