GitHub Actions는 코드 저장소(repository)로 유명한 GitHub에서 제공하는 CI(Continuous Integration, 지속 통합)와 CD(Continuous Deployment, 지속 배포)를 위한 비교적 최근에 추가된 서비스입니다. 당연히 GitHub에서 코드를 관리하고 있는 소프트웨어 프로젝트에서 사용할 수 있으며 개인은 누구나 GitHub에서 코드 저장소를 무료로 만들 수 있기 때문에 다른 CI/CD 서비스 대비 진입장벽이 낮은 편입니다.
GitHub Actions를 사용하면 자동으로 코드 저장소에서 어떤 이벤트(event)가 발생했을 때 특정 작업이 일어나게 하거나 주기적으로 어떤 작업들을 반복해서 실행시킬 수도 있습니다. 예를 들어, 누군가가 코드 저장소에 Pull Request를 생성하게 되면 GitHub Actions를 통해 해당 코드 변경분에 문제가 없는지 각종 검사를 진행할 수 있고요. 어떤 새로운 코드가 메인(main) 브랜치에 유입(push)되면 GitHub Actions를 통해 소프트웨어를 빌드(build)하고 상용 서버에 배포(deploy)할 수도 있습니다. 뿐만 아니라 매일 밤 특정 시각에 그날 하루에 대한 통계 데이터를 수집시킬 수도 있습니다.
이렇게 소프트웨어 프로젝트에서 지속적으로 수행해야하는 반복 작업들을 업계에서는 소위 CI/CD라고 많이 줄여서 부르는데요. 사람이 매번 직접 하기에는 비효율적인데다가 실수할 위험도 있기 때문에 GitHub Actions와 같은 자동화시키는 것이 유리합니다.
아래는 예제에 쓰인 docker image를 push하는 yaml 파일입니다.
name: Docker Image CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-and-push-image:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: chogudwns
password: ${{ secrets.DOCKER_HUB_PW }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
push: true
tags: chogudwns/saramin
가장 처음의 name은 workflow의 이름입니다.
그 다음의 on 은 해당 workflow가 수행될 trigger인 Event를 의미합니다. push - branches - main 은 main branch 에 push 가 일어나면 수행된다는 의미입니다. 그렇기 때문에 요청된 PR 을 merge 하거나 main branch 에 직접 push 하면 해당 workflow가 trigger 됩니다.
jobs 는 pipeline을 구성하는 부분입니다. steps 처음을 보면 "name: Checkout" 부분에 uses: actions/checkout@v3 로 되어 있는데 미리 정의된 action입니다. 실체 소스는 https://github.com/actions/checkout 으로 접속하면 볼 수 있으며 해당 기능은 디폴트로 workflow가 수행되는 github repository 의 소스 (현재 project 의 소스)를 내려받는 기능입니다. 내려 받을 repository 를 바꿀려면 변경 가능합니다.
stebs는 여러개로 이루어져 job을 구성합니다. "name: Set up Docker Buildx" 의 steb은 builder driver 나 platform 등을 세팅하는 부분입니다. 역시 자세한 부분은 https://github.com/docker/setup-buildx-action 에서 확인 가능합니다.
"name: Login to DockerHub" 는 docker hub 에 접근하기 위해서 id 와 password 를 지정하고 docker hub에 로그인하는 부분입니다. 이를 위해서는 github repository 의 settings 로 들어가서 좌측 하단의 secrets >> Actions 에서 Action 용 secret 을 만들어줘야 합니다.
실습에 사용한 github repository는 제가 이전에 생성했던 검색어를 입력하면 사람인 채용공고 사이트에서 채용공고를 크롤링하는 코드가 있는 repository를 사용했습니다.
스크린샷
csv 파일 예시
name: Docker Image CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build-and-push-image:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
with:
username: chogudwns
password: ${{ secrets.DOCKER_HUB_PW }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
push: true
tags: chogudwns/saramin
자동 image push 성공
aws의 EC2 인스턴스를 server instance로 이용했습니다.
인스턴스가 docker hub에 접근해 이미지를 pull 하고 해당 이미지를 run 할 수 있게 하였습니다.
docker를 다운받습니다.
$ sudo su
$ yum install -y docker
$ systemctl start docker
$ systemctl enable docker
외부에서도 docker를 접근 가능하게 권한을 변경합니다.
chmod 666 /var/run/docker.sock
이제 파이프라인에 방금 만든 인스턴스에 접근하여 image를 pull하고 실행하는 코드를 작성해야 합니다.
먼저 github에 secret으로 EC2의 호스트명과 EC2 key를 저장합니다.
yaml 파일에 코드를 추가합니다.
- name: EC2 Docker Run
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ubuntu
key: ${{ secrets.EC2_KEY }}
script: |
sudo su
docker rm -f $(docker ps -qa)
docker rmi chogudwns/saramin
docker pull chogudwns/saramin
docker run -p -d 80:1323 -t saramin chogudwns/saramin
container stop 과 remove를 한번에 하기 위해 -f 옵션을 줬습니다.
workflow가 docker run에서 멈추지 않기 위해 -d 옵션으로 백단에서 실행했습니다.
workflow가 성공했음을 확인했습니다.
이제는 소스코드를 변경하고 push를 해보겠습니다.
전체적인 흐름은
1. source code 변경
2. github action workflow 실행
3. docker image 생성
4. docker image push
5. ec2 instance에서 docker image pull
6. ec2 instance에서 docker container 실행
순서 입니다.
페이지의 header를 변경해보겠습니다.
성공적으로 변경된 것을 확인가능합니다.
저는 Jenkins와 Travis CI, 그리고 이번에 github actions를 사용해 보았는데 github actions의 장점은 public repository에 대해 2,000분까지 무료이고 github 레포지토리와의 연동이 매우 쉽다는 것입니다.
또한 github actions는 안전합니다. GitHub Actions는 GitHub의 보안 인프라를 기반으로 구축되므로 코드와 리소스가 안전하게 유지됩니다.
뿐만 아니라 따로 설치할 종속성이 없다는 것이 장점입니다. Jenkins는 Java로 만들어졌기 때문에 JDK가 필요하고 만약 Container로 실행하면 노드에 Docker도 포함되어야 합니다.