본문 바로가기
Dev Tools/Docker

[Docker] GitHub Actions - Docker Image 자동 배포, run(CD) (2)

by lucas_owner 2023. 2. 19.

GitHub Actions - Docker Image 자동 배포 (CD)

- info

이전 포스팅에서 GitHub Actions 를 사용하여 CI 파이프라인을 구축했었다.

GitHub master 브랜치에 push 되었을 경우, jar빌드, docker image빌드, docker hub 푸시(퍼블리시)

 

CI를 구축해놓았으니 CD를 구축해야한다.

한마디로 docker hub에 푸시된 image를 EC2에서 새롭게 pull 받아 실행하는것이다.

github master 브랜치에 push하는 순간 test 부터, EC2에 배포 및 실행까지 자동으로 이루어지는것이다.

또한 이전에 포스팅 되었던 글에서 추가 된 내용이 많다. (제대로 공부하지 못하고 적용하려니, 엄청난 삽질의 연속..)

 

* 주의할점 및 유의사항 (필독!)

이 방법은 결국 EC2에 수동 배포하는 방식을 자동화 한것이기 때문에, 효율적으로 좋지 않습니다. 
서비스를 더욱 효율적이고 안정적이게 사용 하고 싶으면, AWS CodeDeploy 와 Jenkins, Travis CI 와 연동해서 사용하는것이 더욱 좋은 방법입니다. 

필자는 CodeDeploy를 사용하지 않고, CI/CD 파이프라인 구축을 위해 해당 방법을 사용했습니다. 
(개인 프로젝트 진행과 함께, CI/CD 파이프라인 구축 공부 목적 이었다. 또한 공식문서 및 구글자료들을 찾아봤음에도 명쾌한 내용이 없었다.)

 

** 이전 포스팅을 보고 진행하는것을 추천합니다. (내용이 어느정도 이어지는 부분이 존재합니다.)

https://lucas-owner.tistory.com/49

 

[Docker] GitHub Actions - Docker Image 자동 빌드, push(CI)

GitHub Actions 를 사용한 Docker Image 자동 빌드, push - Info Docker를 사용하여 EC2에 배포하는 방법들을 포스팅해왔다, 실제로 해봤다면 알겠지만 해당 작업은 상당히 복잡한 프로세스를 갖고있고, 자동

lucas-owner.tistory.com

 

  • 순서
    • AWS IAM 설정
    • EC2 인스턴스 패스워드 접근 설정
    • GitHub Actions Secret Key 추가 
    • gradle.yml 파일 수정

- 이번 부분은 설정할 부분과, 설명이 상당히 방대하다. 필요에따라 필요한 부분만 확인하는것도 좋을것 같다. 

 

 

1.  AWS IAM 설정

- AWS IAM 이란? AWS의 특정 기능들을 사용할 수 있는 권한을 가진 사용자를 생성 할 수 있는 기능이다. 

 

- Access Key, Secret Key를 발급받을 수 있으며, 해당 Key 들로 AWS 서비스에 접근, 사용할 수 있습니다.

(추후 깃허브에서 EC2에 대한 접근권한을 받아야 하기때문에 설정해주어야 한다)

*** 해당 Key들은 절때!! 외부에 유출되어서는 안된다. (안전한 장소 보관 필수)

 

1-1. 사용자 생성

 

- AWS IAM - 대쉬보드 엑세스관리 - 사용자 - 사용자 추가

 

- 사용자 이름을 설정(나중에 알아볼수 있는 이름을 권장한다.)

 

- 검색: EC2FullAccess -> 선택 후 추가 -> 다음 -> 이어서 사용자 생성(뒷부분은 설정할것이 없음)

- 사용자가 생성이 되었다면, detail 화면으로 진입 후 이어서 설정을 추가한다. 

 

1-2. 엑세스 키 발급 

- 엑세스 키 만들기를 통하여 진행. 

 

- 이후 발급된 엑세스키, 시크릿키 모두 안전한곳에 저장을 필수로 해야합니다!! (추후 사용해야함.)

 

 

2. EC2 설정 - 패스워드로 인스턴스 접근

- EC2 인스턴스의 경우 .pem 키를 통해 ssh 연결하는 방식을 써왔습니다만,

아이디, 비밀번호를 통해 연결하는 방법이 존재합니다. 

추후 깃허브에서 AWS에 접근하려면 해당 방법으로 접근해야 하기때문에 설정을 해주도록 하겠습니다.

 

2-1. 아이디, 비밀번호 설정 

 

2-1-1. 아이디 

- 아이디의 경우 EC2의 username 이다. 모른다면 아래 명령어를 사용하여 확인하면 됩니다.

- 커맨드를 사용하면 출력되는 내용이 username(아이디) 이다.

$whoami

 

2-1-2. 패스워드 설정

- 아래의 커맨드를 이어서 하게 된다면, password 입력창이 나온다. 입력 후 복사해둡니다.(추후 사용) 

$sudo passwd [username]

# 예시 - sudo passwd ubuntu

 

2-2. 패스워드 연결 방식 사용 설정 

- 단순히 패스워드를 설정 해서 EC2에서 패스워드로 접근할 수 있는것은 아닙니다. 

- 아래의 방식을 사용하여 패스워드로 연결을 허용하는 설정을 해줍니다.

 

2-2-1. sshd_config 수정 

$sudo vi /etc/ssh/sshd_config

 

  1. vi 진입이후 /Password 입력 -> 검색
  2. no -> yes 로 수정.

 

2-2-2. sshd service 재시작

- 설정이후 sshd를 적용하기 위해 restart - 1초미만

$sudo systemctl restart sshd 

# 혹은 
#sudo service sshd restart

 

2-3. 아이디/패스워드 접속 테스트 진행

- 아이디(username), 설정한 패스워드를 통해 ssh 접속을 테스트 해보자.

# local 진행
# sudo ssh [username]@[ec2 인스턴스 ip (퍼블릭 IPv4 DNS)]

$sudo ssh ubuntu@ec2.~

- 이후 패스워드 입력 후 접속이 되는지 확인 하면됩니다.

 

 

3. Github Actions Secret Key 등록(추가)

- 이전 글을 보고 그대로 했다면 등록되어있는 항목들이 있을것입니다. 하지만 추가해줘야 하는 키들이 많이 생겼습니다. 

 

- 이번에는 AWS 접속을 위한 key, AWS에 접근할 수 있는 권한을 얻기위한 key를 세팅해줘야 합니다 (필수). 

- 리스트는 위와 같다. 추가된 부분만 아래에 하나씩 설명 하도록 하겠습니다. (만약 기존의 시크릿키에 대해 알고싶다면 이전 포스팅을 보고오는것을 추천합니다.)

 

  • AWS_ACCESS_KEY_ID : IAM에서 발급받았던 Access Key. 
  • AWS_SECRET_ACCESS_KEY : IAM 에서 발급 받았던 Secret Key
  • AWS_SG_ID : EC2 보안그룹으로 지정되어있는 '보안그룹의 ID' 이다. (보안그룹에서 확인 후 설정)
  • EC2_HOST : EC2의 퍼블릭 IPv4 주소. 
  • EC2_PASSWORD : EC2에 접근/연결 설정해두었던 패스워드.
  • EC2_SSH_PORT : SSH로 접근할 port.
  • EC2_USERNAME : EC2의 계정명. 

- 해당 항목들을 모두 등록 해주도록 하자!! (외부에 유출되면 안되는 것들입니다!!!!)

 

 

4. grdle.yml 수정

- 가장 삽질을 많이 했던 부분입니다... 

잠시 이유를 설명하고 넘어가도록 하겠습니다. 

- GitHub Actions를 사용하여 AWS 접근할 경우 상당히 많은 프로세스들을 거쳐야만 한다.

- GitHub Actions 에서 정한 '메뉴얼' 을 정확하게 지켜줘야한다.

- 띄어쓰기, 들여쓰기, 연결정보 및 연결방법 등등....

- 수많은 error 를 보며 문제점을 계속해서 찾아내고, 수정한 최적의 방법을 찾아야 했다... 
(구글문서, 공식문서 어디에도 정보들이 없어서, error 로그만 보고 수정을 진행했다,,,)

- GitHub Actions To AWS Connection 에 대한 정보는 아래 공식문서를 통해 정보를 얻었다.
https://github.com/appleboy/ssh-action

- dial tcp ***:***: i/o timeout  -> AWS IAM 정보를 취득하지 않아서 발생.
- ssh: connect to host 000.000.000.000 port 00: Operation timed out : EC2 연결정보가 잘못되어 연결불가 에러.

 

4-1. gradle.yml 수정정보

 

- 상당히 길다, 설정정보를 추가하다 보면 길어질 수 밖에 없는것 같습니다.

추가된 내용에 대한 자세한 설명은 코드블럭 아래에서 소개하겠습니다.

name: Java CI with Gradle

on:
  push:
    branches: [ "master" ]

jobs:
  deploy: 
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v3
    
    # Spring Boot 어플리케이션 Build (1)
    - name: Spring Boot Build
      run: ./gradlew clean build --exclude-task test
    
    # Docker 이미지 Build (2)
    - name: docker image build
      run: docker build -t lucaskang134/boot-prac-ci .
    
    # DockerHub Login (3)
    - name: docker login 
      uses: docker/login-action@v2
      with: 
        username: ${{ secrets.DOCKERHUB_USERNAME }}
        password: ${{ secrets.DOCKERHUB_TOKEN }}

    # Docker Hub push (4)
    - name: docker Hub push
      run: docker push lucaskang134/boot-prac-ci
      
    # GET GitHub IP (5)
    - name: get GitHub IP 
      id: ip
      uses: haythem/public-ip@v1.2
      
    # Configure AWS Credentials (6) - AWS 접근 권한 취득(IAM)
    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v1
      with: 
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: ap-northeast-2
    
    # Add github ip to AWS (7)
    - name: Add GitHub IP to AWS
      run: |
        aws ec2 authorize-security-group-ingress --group-id ${{ secrets.AWS_SG_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32
    
    # AWS EC2 Server Connect & Docker 명령어 실행 (8)
    - name: AWS EC2 Connection
      uses: appleboy/ssh-action@v0.1.6
      with:
        host: ${{ secrets.EC2_HOST }}
        username: ubuntu
        password: ${{ secrets.EC2_PASSWORD }} 
        port: ${{ secrets.EC2_SSH_PORT }}
        timeout: 60s
        script: |
          sudo docker stop boot-prac-ci
          sudo docker rm boot-prac-ci
          sudo docker run -it -d -p 8080:8080 --name boot-prac-ci lucaskang134/boot-prac-ci
    
    # REMOVE Github IP FROM security group (9)
    - name: Remove IP FROM security group
      run: |
        aws ec2 revoke-security-group-ingress --group-id ${{ secrets.AWS_SG_ID }} --protocol tcp --port 22 --cidr ${{ steps.ip.outputs.ipv4 }}/32

- flow

yml 파일 자체를 수행해야 하는 task 별로 작성해두었지만, 전체적인 설명을 하겠습니다. 

기존에 CI 에서 CD 까지 추가됨으로서, AWS 연결 및 보안그룹을 추가해줘야 하는 문제가 있습니다. 

 

보안그룹을 기존에 github의 주소를 열어두지 않았기 때문에 IAM에서 AWS에 접근할 권한을 취득 했다고 해도, 

EC2에 접근을 하지 못하는 상황이 발생합니다. (EC2 자체는 보안그룹 명시한 IP, port 만 허용) 

 

그렇기 때문에 EC2에 접근하여 docker 배포 하기전에, AWS EC2에 GitHub IP에 대해서 보안그룹을 추가해줘야 합니다. 

모든 task가 종료된 이후에는 당연히 추가한 보안그룹을 삭제해줘야합니다.(9번 task)

 

보안그룹을 추가해주고 EC2에 접근 성공 했다면, 본래의 목적인 Docker Image를 컨테이너화 시켜줘야 합니다.

이전 포스팅에서는 docker run 실행시 컨테이너 이름을 따로 지정해주지 않았기 때문에, 

기존의 컨테이너를 종료-삭제 task 가 수행되지 않았기 때문에 --name 명령어를 통해 이름을 지정해 주었습니다. 

 

Docker 명령어를 보자면, 기존의 컨테이너 종료 -> 삭제 후 docker run 을 통해 docker hub의 image 를 실행 시켜주었습니다. 

 

 

4-2.  추가된 각 step 별 설명을 하겠습니다. (주석 오른쪽 (번호) 기준) 

 

- (5) :  Get Git Hub IP

추후 보안그룹에 깃허브의 포트를 열어줘야 하기 때문에, 깃허브의 IP를 얻어오는 step.

 

- (6) : Configure AWS Credentials 

AWS 서비스에 접근하기 위해서는, 우선적으로 접근권한을 취득해야합니다. 

미리 설정해둔 IAM Key 를 통해서 접근권한을 취득하는 task 입니다. 

* uses: ~ 는 GitHub actions에서 정의한 프로토콜을 사용합니다. 

 

- (7) : Add GitHub ip to AWS 

위에서 설명 했듯, 깃허브에서 EC2에 접근하기 위해서는 보안그룹을 추가해줘야 합니다. 

깃허브의 ip를 보안그룹에 추가해주는 task 입니다. 

 

- (8) : AWS EC2 Server Connect 

EC2에 연결, 수행할 Script를 수행하는 task 이며, Docker hub에서의 image pull & run 을 수행합니다. 

추가로 현재 구동중인 컨테이너를 정지 - 삭제 후 docker run 을 수행합니다. (컨테이너가 중복되는것을 방지한다.)

 

- (9) : REMOVE GitHub ip FROM security group 

EC2에 접근하기 위해서 추가해준 보안그룹을 삭제하는 task. 

삭제하지 않으면, 해당 Actions가 수행될 때마다 보안그룹이 추가되고, 보안에 취약해진다. 

 

5. Actions 수행 확인 및 Test 

- GitHub Actions 의 work flow

 

- EC2 내부에서의 수행중인 컨테이너 리스트


정리 및 회고

 

개인 프로젝트를 완성 후 AWS EC2, RDS 생성 및 수동 배포.

Docker 를 사용한 CI/CD 파이프라인 구축까지 구축을 하고 보니, 현업에서 훨씬 복잡하게 구축되어있는 프로세스들이 새삼 중요하다고 느꼈다. 

이미 구축되어있는 Jenkins에 Code Quality 체크 까지 모두 자동 혹은 클릭 몇번으로 이루어졌기 때문이다. 

 

하지만 실제로 일련의 파이프라인을 구축을 하고나니, 개발부터 배포까지 일련의 과정들을 좀더 간편하게, 좀더 빠르게 수행할 수 있는것을 보며 더 좋은 개발자를 지향한다면 필수로 할줄알거나, 이해하는 것이 필요하다는것을 느꼇다. (DevOps 개발자가 따로 존재 하더라도 이슈 대응 및 트러블 슈팅, 모니터링, 혹은 더나은 아키텍쳐 및 파이프라인 구축을 위해서)

 

공식문서, 구글문서들이 잘되어있다고 하더라도 '해당 프로젝트'에 알맞은 세팅들을 하기위해 트러블슈팅, 설정 등에 수많은 시간을 쏟으며,

완벽한 문서란 없다는것을 느꼇고, 지금 하는 "작업들을 왜 하는가?" 에 대해 고민을 하게 되었고, 그과정에서 자연스럽게 해당 파이프라인을 구축하기 위한 공부들을 할 수있게 되었던것 같다. (AWS, Docker, CI/CD, gradle, github) 

 

또한 나와 같은 방식으로 파이프라인을 구축하고, 공부해보고 싶은 사람이 있지 않을까? 만약 있다면 (얼마나 이 시리즈를 볼지 모르겠지만)

구축하다가 마주치는 문제들에 도움이 될 수 있지 않을까 싶어서,

해당 Spring Boot - Docker - AWS 구축 및 배포 시리즈를 포스팅을 해야겠다고 마음을 먹고 작성해왔다. 

 

해당 시리즈를 얼마나 많은 사람이 읽었는지, 이글을 읽어주셨는지는 모르겠지만 조금이라도 도움이 되었다면 좋겠습니다. 

 

틀린부분 및 수정해야할 부분, 혹은 궁금한 부분이 존재한다면 언제든 자유롭게 피드백 주시면 감사하겠습니다.

 

반응형

댓글