ZIGUQUIZ 배포 및 CI/CD 과정 정리

규바·2024년 3월 21일
0
post-thumbnail

인스턴스 생성 & 도메인 연결

  1. 무료 요금제 gcp 생성 (아무 글 보고 따라했음, 쉬움)
  2. 외부 IP 주소(=탄력적 IP) 할당 출처
    • VPC 네트워크 -> IP 주소 -> 외부 고정 주소 예약
      (표준, IPv4, 리전, VM에 연결(중요)) 연결 안하면 요금 부과
  3. 방화벽 설정
    • VPC 네트워크 -> 방화벽 -> 방화벽 규칙 만들기
      (로그 사용안함, 수신, 허용, IPv4범위 0.0.0.0/0, TCP 포트에 허용할 포트)

      바보같이 8080 안열고 끙끙대던 과거를 기억하길 ...

HTTPS 적용하려면
도메인 제공 업체에서 DNS A 레코드를 수정해줍니다.

A 레코드의 ip 값들이 전부 가비아로 잡혀있는데, 이것들을 모두 자신의 서버 ip로 변경합니다. 출처

Docker

vm의 ssh에서 docker 설치

$ sudo apt-get update
$ sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

$ sudo mkdir -m 0755 -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

$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
$ sudo docker --version

docker-compose 설치

$ sudo curl -L "https://github.com/docker/compose/releases/download/1.27.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
$ docker-compose -v

docker-compose.yml

version: "3"

services:
        application:
                image: ziguquiz_spring
                environment:
                        SPRING_DATASOURCE_URL: jdbc:mysql://내 클라우드 mysql
                        SPRING_DATASOURCE_USERNAME: root
                        SPRING_DATASOURCE_PASSWORD: 비밀번호
                restart: always
                container_name: ziguquiz_spring
                ports:
                        - "8080:8080"
        frontend:
                image: ziguquiz_react
                restart: always
                container_name: ziguquiz_react
                ports:
                        - "3000:3000"

아쉬운 점 참고!!
docker-composed에 이미 있는 컨테이너를 올려 실행하는 건 안되는 듯! 이미 수동으로 올려 이것저것 다한 proxy-server를 docker-compose에 올리는게 안됐음

이미 스프링부트에 연결해놨는데 여기에도 db연결 해야하는지는 잘 모르겠음 일단 했음

React DockerFile

FROM node:18
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install 
COPY . ./
EXPOSE 3000

CMD ["npm", "start"]

SpringBoot DockerFile

FROM openjdk:17
COPY build/libs/solution-challenge-team3-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]

수동으로 올리기

로컬에서
bootJar로 jar 빌드하기
docker login
docker build -t 계정명/리포지토리명 ./ :이미지 빌드
docker push 계정명/리포지토리명 :도커허브로 push
서버에서
sudo docker login
sudo docker pull 계정명/리포지토리명
sudo docker images :pull 제대로 됐는지 확인
sudo docker tag pull한이미지이름 만들이미지이름
ex) sudo docker tag skb0606/ziguquiz ziguquiz_spring
ziguquiz_spring을 컨테이너에 올려 배포할 것이고 변경사항이 반영된 이미지를 ziguquiz_spring에 덮어씌워서 지속 배포
sudo docker-compose up

배포 url : http://VM인스턴스외부IP:포트/

Github Actions (CI/CD)

테스트는 없음

환경변수 설정

Settings -> Security -> Sercrets and variables -> Actions

application.yml 등등 넣기. 수정 불가 !

IP주소도 환경변수에 넣었어야 했을 듯

SSH 키 생성

  1. puttygen 사용해서 키 생성
    - Generate 를 클릭한 후 마우스를 마구 흔들어 위 화면처럼 키를 생성합니다.

    • Key comment에 root 등과 같은 적당한 이름 적어주시고,
    • Key passphrase는 선택사항이긴 하지만 보안을 위해 원하시는 비밀번호로 적어줍니다.
    • Save private key를 눌러 로컬의 원하는 폴더에 저장합니다. (추후에 써야하니 해당 폴더 위치는 기억합니다.)
    • Conversions 탭을 눌러 Export OpenSSH key를 눌러 로컬의 원하는 폴더에 저장합니다. 저는 private key와 같은 폴더에 저장해줬습니다.

    위에 두개 구분하자

ssh-rsa로 시작해서 root(key comment인듯)로 끝나는 ssh public 키를 메타데이터에 등록함

  1. ssh 접속 테스트

    • putty에서 keycomment@외부ip를 host name에 적음 (root@외부ip)
    • connection - SSH - Auth에서 Browse에서 로컬에 저장해둔 private Key 선택
    • passphrrase를 입력하란 문구가 나오면, 아까 puttyGen에서 입력했던 passphrase를 입력
  2. github에 ssh keys 등록

    • GitHub 계정 설정(리포지토리말고 계정) 에서 "SSH and GPG keys" 탭으로 이동하여, "New SSH key" 버튼을 클릭
    • title은 원하는 이름으로 넣어주세요. 저는 프로젝트 이름으로 넣어줬습니다.
    • Key 부분에 PuttyGen에서 복사한 public key 내용을 그대로 붙여넣기 (public key는 위에 puttygen 사진에서 제가 가려놓은 부분입니다.)

이 부분 한 것 같지 않은데 잘 돌아감...했나..? 아닌 것 같은데

  1. 환경변수로 private key 등록

    • SSH_PRIVATE_KEY라는 이름으로 아까 로컬에 저장해둔 openSSHkey 파일의 내용을 그대로 복사해와 붙여 넣어줍니다. (중요,,,, ---begin--- 포함해서 ---end--- 전부 끝까지 )
    • SSH_USERNAME라는 이름으로 아까 Key comment 내용을 넣어줍니다. ex) root
    • SSH_PASSPHRASE라는 이름으로 Key passphrase 내용을 넣어줍니다.

yml 파일 전문

./github/workflows/gradle.yml

name: Java CI with Gradle

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:

    runs-on: ubuntu-latest
    #permissions:
      #contents: read

    steps:
    - uses: actions/checkout@v4
    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'
    # Gradlew 실행 허용
    - name: Run chmod to make gradlew executable
      run: chmod +x ./gradlew
    # Configure Gradle for optimal use in GiHub Actions, including caching of downloaded dependencies.
    # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
    - name: Setup Gradle
      uses: gradle/actions/setup-gradle@ec92e829475ac0c2315ea8f9eced72db85bb337a # v3.0.0
    # 환경 변수 설정
    - name: Set environment values
      run: |
        cd ./src/main/resources
        touch ./application.yml
        echo "${{ secrets.APPYML }}" > ./application.yml
      shell: bash      
    # Gradle build (Test 제외)
    - name: Build with Gradle
      uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
      with:
        arguments: clean build -x test
    # Docker build
    - name: Docker build
      run: |
        docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_PASSWORD }}
        docker build -t ziguquiz .
        docker tag ziguquiz skb0606/ziguquiz:${GITHUB_SHA::7}
        docker push skb0606/ziguquiz:${GITHUB_SHA::7}
    - name: Deploy
      uses: appleboy/ssh-action@master
      with:
        host: !!! 외부 IP주소 !!!!!!
        username: ${{ secrets.SSH_USERNAME }}
        key: ${{ secrets.SSH_PRIVATE_KEY }}
        passphrase: ${{ secrets.SSH_PASSPHRASE }}
        envs: GITHUB_SHA
        script: |
          sudo docker login -u ${{ secrets.DOCKERHUB_USERNAME }} -p ${{ secrets.DOCKERHUB_PASSWORD }}
          sudo docker pull skb0606/ziguquiz:${GITHUB_SHA::7}
          sudo docker tag skb0606/ziguquiz:${GITHUB_SHA::7} ziguquiz_spring
          sudo docker-compose up -d

Docker build : 빌드하고 push하는 과정
Deploy : ssh 접속해서 script 실행

이미지 이름을 username/repository:커밋해시 앞 7글자로 한 것을 알 수 있다

  • 빌드(CI) 잘 되는지 확인만 하기 위해서는
    Docker build와 deploy (CD)는 지우고 Gradle build만 돌려보기
  • 확인 방법: 그냥 커밋하나 슝 날리기
  • 빈칸 잘맞추자! 잘 맞췄는데도 오류나서 이래저래 헤멤(chatGPT한테 정렬 시켰었던듯 ㅋㅎ..)
  • 중간에 저거 외부 IP주소 환경변수로 안넣고 그냥 넣었다. 복붙하지 말자

HTTPS

HTTPS 적용하려면
도메인 제공 업체에서 DNS A 레코드를 수정해줍니다.

A 레코드의 ip 값들이 전부 가비아로 잡혀있는데, 이것들을 모두 자신의 서버 ip로 변경합니다. 출처

Docker로 Nginx 컨테이너 올리기

// Nginx 이미지 받기
$ docker pull nginx

// Nginx 컨테이너 올리기
$ docker run --name proxy-server -d -p 443:443 -p 80:80 nginx

// 컨테이너 접속
$ docker exec -it proxy-server bash

컨테이너에 Certbot 패키지 설치하기

$ apt-get update

// 2개 패키지 설치
$ apt-get install certbot python3-certbot-nginx

컨테이너 내부에서 패키지 매니저를 update 해주고,인증서를 발급해 줄 certbot과nginx와 연동되어 원활한 발급을 도울 python3-certbot-nginx플러그인도 설치

Nginx 설정 파일 수정하기

// vim 설치 (당연히 한 번뿐이면 된다)
apt-get install vim

// 설정파일 수정
vim /etc/nginx/conf.d/default.conf

수정하자

// default.conf

server {
    listen       80;

    # 수정
    server_name  자신의 도메인;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    # 이 부분 추가
    location /.well-known/acme-challenge/ {
        allow all;
        root /var/www/certbot;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

인증서 발급

certbot —-nginx -d 도메인
그러고 나면 자동으로 해주면서 ...

관리자 이메일 주소(필수)
이메일 서버 등록(필수, 최초 1회)
캠페인 소식 수신 여부 (Yes, No) <- 이거 안나왔던듯?

/etc/nginx/conf.d/default.conf 전문

아쉬운 점

  1. React 도커 빌드가 안됨 npm start로 하니까 너무 무거운 거 같아서 빌드해서 쓰려고 하는데 자꾸 에러 발생했음
    그리고 아마 nginx 컨테이너 따로 두지 않고 react 파일을 여기에 올려서 서빙하듯이 써야하는 듯함....

  2. nginx 프록시 컨테이너(proxy-server)는 수동으로 올려놓고 이미 certbot다 해놨기 docker-compose.yml에 그대로 올릴 수 없었음

  3. Let's Encrypt의 인증서는 90일 유효하다. 자동갱신 되도록 하는 방법이 있는데 난 설정해놓지 않았다. 크론으로 해서 간단한 것 같은데..서버 껏다켰다 자주해서 일단은 냅둠..일단 서버 재부팅해도 cron 날아가지는 않는다고 함

위에 둘 다, 심사기간 끝나고 시간 부자일 때 여유롭게 테스트 해보자 도커 신기해서 재밌으면서도 동시에 시간에 쫓겨서 스트레스 받으니까 진짜 환장했었음. 배포 안할 수 도 없었고

참고:
https://lemontia.tistory.com/1074
https://choo.oopy.io/5c999170-dde5-4418-addc-00a0d263287c
https://choo.oopy.io/79bee99c-5768-4817-b926-c23e4120bcf4#94a49f4a-1bed-41e0-8c03-b3cdaeeb4348
https://lasbe.tistory.com/176

profile
그때그때 학습하고 있는 내용을 올려요

0개의 댓글