저번 시간에는 도커 이미지를 만드는 작업까지 해봤습니다. 이번 시간에는 github actions를 이용해 CI/CD를 구성해서 NCP(Naver Cloud Platform)에 배포해보는 작업을 진행해보도록 하겠습니다.
💻 참고 : https://www.ncloud.com/product/containers/containerRegistry
“도커 컨테이너 이미지를 간편하게 저장, 관리, 배포할 수 있는 서비스”. NCloud에 Container Registry 라는 곳이 있는데 이미지를 관리하는 곳인거 같습니다. 아무래도 이걸 이용해야 될 거 같습니다.
💻 공식문서 : https://guide.ncloud-docs.com/docs/containerregistry-overview
"Container Registry를 이용하려면 네이버 클라우드 플랫폼의 Object Storage를 이용 신청해 주십시오. Object Storage의 버킷에 Docker 컨테이너 이미지가 저장됩니다." - Object Storage 는 AWS S3와 같은 개념인거 같고 여기에 실제 데이터가 저장되는 모양입니다.
일단, 신청하기 전에 어떤 프로세스로 진행되는지 알아야 될 거 같아보였습니다. 무작정 신청만 할 수 없잖아요? 어느 정도 그림이 잡힌다음 진행하는 것이 맞아보였습니다. 그래서 자료를 찾아봤습니다.
참고 : https://medium.com/naver-cloud-platform/이렇게-사용하세요-container-registry를-활용한-ci-구축하기-6876a1c2637e
프로세스를 확인해보니 Jenkins를 사용하고 있더군요. Jenkins가 하는 역할은 github 이벤트 발생 시 자동으로 jenkins가 알아차려서 빌드하는 역할인거 같습니다. 이런걸 web hooks 기능이라고 하는거 같습니다. 그리고 이렇게 만들어진 이미지를 container registry와 연동해서 업로드하는 것 까지가 Jenkins의 역할로 보여집니다.
근데 아쉬운 점은 저는 github actions를 사용하고 싶었습니다. Jenkins를 사용하려면 별도 서버와 세팅을 해야하며 다소 복잡해보였습니다. 그리고 두번째로는 container registry 그 이후 단계에 대한 설명이 부족했습니다. 왜 다시 로컬로 이미지를 pull 땡겨서 띄우는 것까지만 설명이 되어있는지 잘 모르겠네요..
그러다가 결국 제가 원하던 그림을 찾았습니다. 심지어 해당 블로그에 github actions 코드가 정말 깔끔하게 정리되어있더군요. 이를 베이스로 진행하면 될 거 같았습니다.
대충 그림은 나온거 같으니 Container Registry를 세팅해봅니다. 그 전에 Object Storage 이용신청을 해야 합니다.
Object Storage 메뉴에 들어가서 이용 신청을 해줍니다.
Bucket Management 메뉴에서 버킷 생성을 클릭합니다. 대충 기본 설정으로 진행하고 일단 만들어봅니다.
해당 repository에 접근하기 위해서는 로그인이 필요합니다. (퍼블릭 레지스트리가 아니기 때문). 해당 URL은 container registry 상세를 보면 나와있습니다.
docker login <CONTAINER_REGISTRY_URL>
“네이버 클라우드 플랫폼에 생성된 레지스트리에 로그인 하기 위해서는 엔드포인트를 명시해야합니다.API 인증키가 필요하며, Username에 Access Key Id를 Password에 Secret Key를 사용해주세요.”
아. 저는 그냥 ncloud 아이디, 비번을 사용하는 건 줄 알았습니다. 이용 가이드 보니 설명이 되어있었네요. 액세스 키 발급이 안되어있어서 마이페이지 계정 관리에서 인증키 관리라는 곳에서 발급 받았습니다.
로그인은 성공했고 그러면 이미지 build하고 push 한번 해볼까요? -f
옵션으로 Dockerfile 위치를 지정해준다음 build를 시켜줍니다.
docker build -t <CONTAINER_REGISTRY_URL>/<TARGET_IMAGE[:TAG]> -f ./docker/prod.Dockerfile .
그리고 나서 push 해서 Container Registry에 올려봅니다.
docker push <CONTAINER_REGISTRY_URL>/<TARGET_IMAGE[:TAG]>
생성이 완료되었습니다.
CLI에서 build 후 push 한 것처럼, 해당 작업을 GitHub Actions이 코드가 특정 브랜치에 push 될 때마다 대신 해주도록 하면 됩니다.
name: deploy next to ncloud
on:
push:
branches: ['main']
pull_request:
branches: ['main']
jobs:
push_to_registry:
name: Push to ncp container registry
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to NCP Container Registry
uses: docker/login-action@v2
with:
registry: ${{ secrets.NCP_CONTAINER_REGISTRY }}
username: ${{ secrets.NCP_ACCESS_KEY_ID }}
password: ${{ secrets.NCP_SECRET_ACCESS_KEY }}
- name: build and push
uses: docker/build-push-action@v3
with:
context: .
file: docker/prod.Dockerfile
push: true
tags: ${{ secrets.NCP_CONTAINER_REGISTRY }}/nextjs-docker:latest
secrets: |
GIT_AUTH_TOKEN=${{ secrets.GIT_TOKEN }}
“Docker image 를 build 하고 이를 docker hub 저장소에 push 할 수 있는 방법을 소개한다. 보통은 이를 CI 로 구축하는데 CI 시스템을 따로 구축하기에는 시간과 비용이 들고 이를 유지보수 하기에도 귀찮은 면이 있다. 만약 Github 을 사용하고 있다면 10분 만에 Github Action 으로 이를 쉽게 구현할 수 있다.”
중간에 에러가 몇 차례 있었지만 각설하고 이런 문제만 해결되면 아래와 같이 성공적으로 올라간 것을 볼 수 있습니다.
NCloud에서 신규 가입 후 1년간 무료로 사용할 수 있는 가장 저렴한 서버를 제공해준다고 합니다.
일단 접속을 일단 해봅니다. 그러기 위해서는 포트 포워딩 설정이 필요한듯 합니다. 외부 ip랑 포트를 내부 ip랑 포트와 매핑하는 작업이라고 보면 될 듯 합니다.
참고 : https://coinpipe.tistory.com/131
두가지 방법으로 다 해봤는데 무응답이였습니다. 에러라도 나던가. 알고보니 ACG에서 제 아이피랑 포트 지정을 해줘야 되는거였습니다. AWS로 따지자면 인바운드 규칙인가? 아웃바운드 규칙? 설정이라고 보면 될 거 같습니다.
허용하는 IP와 포트를 지정해줘야 되는 구조입니다. 그 외 나머지는 접속을 못합니다.
ssh root@(서버 접속용 공인 IP : ***.***.***.*) -p(포트)
ssh -l 계정명 -p 포트번호 공인.아이피.주소
접속이 성공했으니 이제 github actions 코드 작성를 작성해줍니다. container registry에 있는 이미지를 target server에서 다시 pull해서 띄울 수 있게 하는 코드입니다. 민감 정보는 github secret 설정해줍니다.
80 포트에서 도커 내부 3000 포트로 띄어진 next 앱에 포트포워딩 하도록 설정합니다. 그러면 http 80으로 브라우저에서 볼 수 있을 것입니다.
pull_from_registry:
name: Connect server ssh and pull from container registry
needs: push_to_registry
runs-on: ubuntu-latest
steps:
- name: connect ssh
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.NCP_SERVER_IP }}
username: ${{ secrets.NCP_SERVER_USERNAME }}
password: ${{ secrets.NCP_SERVER_PASSWORD }}
port: ${{ secrets.NCP_SERVER_PORT }}
script: |
docker pull ${{ secrets.NCP_CONTAINER_REGISTRY }}/nextjs-docker:latest
docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
docker run -d -p 80:3000 --name nextjs-docker ${{ secrets.NCP_CONTAINER_REGISTRY }}/nextjs-docker:latest
docker image prune -f
근데 생각해보니까 저만 도커 쓰는게 아닐텐데 전부 stop하고 rm 해버리면 좀 그럴거 같습니다. 따라서 nextjs-docker만 stop하고 rm 해서 다시 띄우도록 설정했습니다.
docker stop nextjs-docker
docker rm nextjs-docker
막상 github actions를 테스트하기 전에 생각해보면 타겟 서버에 미리 도커가 설치되어있어야 될 거 같습니다. 우분투에 도커 설치하는 법을 알아보도록 합니다. 찾아보면 레퍼런스가 많으므로 따로 설명하진 않겠습니다.
이렇게 설치까지 완료 되었습니다.
$ docker --version
Docker version 23.0.1, build a5ee5b1
이제 한번 해볼까요? 아하… 타겟 서버 접속 에러가 발생했습니다. 이건 근데 당연히 ACG 설정이 안되어있으니까 접속이 안되는거네요. 그렇다고 모두 접속하라고 열어버릴수도 없고… 어떻게 할까요? github runner ip는 매번 바뀔텐데 말이죠...
======END======
2023/03/12 06:42:41 dial tcp ***:***: connect: connection refused
방법은 0.0.0.0/0 에서 22 포트 접속이 가능하도록 열어버리던가. 근데 이러면 보안이 좀 많이 취약해지지 않을까요?
또한가지 방법은 아이디, 비번 방식이 아니라 key(pem) 도 있어야 접속이 가능하겠끔 바꾸는 것입니다.
참고 : https://docs.3rdeyesys.com/compute/ncloud-compute-server-change-authentication-key.html
근데 일단은 머리 아프니까... 첫번째 방법으로 진행한다음 잘 되는지 확인하고 다시 닫아버리도록 하겠습니다. 성공적으로 되네요.
아 근데 docker login 을 안해서 도커 이미지를 못찾아서 실제 띄어지진 않았습니다. 스크립트에 추가해주도록 합니다.
docker login -u ${{ secrets.NCP_ACCESS_KEY_ID }} -p ${{ secrets.NCP_SECRET_ACCESS_KEY }} ${{ secrets.NCP_CONTAINER_REGISTRY }}
그래서 최종적으로 docker ps -a를 통해 띄어진것을 확인했습니다. 근데 막상 브라우저에서 확인할 수 없었습니다...
# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
920fd2bda24b 이미지이름 "docker-entrypoint.s…" 5 minutes ago Up 5 minutes 0.0.0.0:80->3000/tcp nextjs-docker
혹시 몰라 로컬에서 똑같이 해봤는데 로컬에서는 80으로 브라우저에서 볼 수 있었습니다. ACG 설정에서도 0.0.0.0/0 에서 80 포트 접속 다 허용하도록 해놨습니다.
근데 찾아보니 아무래도 공인 IP가 있어야 되는 모양입니다. “신청된 공인 IP는 서버에 할당되지 않더라도 보유하고 있는 동안 요금이 부과됩니다. 사용하지 않을 경우 반납해 주십시오.”. 일단 생성해서 되는지 확인하기 위해 생성해보도록 합니다. 그랬더니 잘 되었습니다.
github actions를 통해 CI/CD를 구성해서 자동으로 Container Registry에 올리고, 다시 타겟 서버에서 pull 하도록 해서 띄우는 작업까지 해봤습니다. 상당히 의미있는 시간이었던거 같습니다.
앞으로는 도메인도 연결해야 되고, https 지원을 위한 작업도 진행해야겠네요... 할 게 많군요.