프로젝트는 국비 교육 기관 저장소(Gitlab)에서 진행되었고, 프로젝트가 끝나도 외부에서 접근할 수 없었다. 결국 깃랩 공개 저장소나 깃허브 공개 저장소로 옮겨야 했는데 투표에 따라 깃허브로 옮기게 되었다.
curl --header "PRIVATE-TOKEN: {privateToken}" "{domain}/api/v4/projects/{projectId}/pipelines"
curl --header "PRIVATE-TOKEN: {privateToken}" "{domain}/api/v4/projects/{projectId}/pipelines/{id}"
import os
import requests
GITLAB_TOKEN = os.getenv('GITLAB_TOKEN')
GITLAB_PROJECT_ID = os.getenv('GITLAB_PROJECT_ID')
GITLAB_URL = f'https://kdt-gitlab.elice.io/api/v4/projects/{GITLAB_PROJECT_ID}/pipelines'
headers = {
'PRIVATE-TOKEN': GITLAB_TOKEN
}
# 모든 파이프라인을 가져옴
def get_pipelines():
pipelines = []
page = 1
while True:
response = requests.get(GITLAB_URL, headers=headers, params={'page': page, 'per_page': 100})
response.raise_for_status()
pipeline_response = response.json()
if not pipeline_response:
break
pipelines.extend(pipeline_response)
page += 1
return pipelines
# 특정 파이프라인 세부 정보를 가져옴
def get_pipeline_details(pipeline_id):
pipeline_url = f'https://kdt-gitlab.elice.io/api/v4/projects/{GITLAB_PROJECT_ID}/pipelines/{pipeline_id}'
response = requests.get(pipeline_url, headers=headers)
response.raise_for_status()
return response.json()
pipelines = get_pipelines()
total_pipelines = len(pipelines)
# 모든 파이프라인 Duration 시간을 더함
total_duration = 0
for pipeline in pipelines:
pipeline_id = pipeline['id']
pipeline_details = get_pipeline_details(pipeline_id)
duration = pipeline_details.get('duration')
if duration is not None:
total_duration += duration
total_duration_minutes = total_duration / 60
print(f'총 파이프라인 갯수: {total_pipelines}')
print(f'총 파이프라인 사용시간: {total_duration_minutes}')
대략 3주간 367개의 파이프라인이 실행되었고, 977시간이 소요되었다. 생각보다 많은 시간을 사용했다는 것에 놀랐고, 개별 파이프라인 실행속도는 사소할지 몰라도 반복적으로 실행하여 누적되면 그 차이는 사소하지 않다. 파이프라인은 중복이 없어야 하고, 빠르게 실행되어야 한다.
굳이 로컬 빌드 서버를 사용할 이유는 없었고, github hosted runner를 사용하기로 했다. 테스트해 본 결과 로컬 빌드 서버에서는 매번 의존성을 설치할 필요는 없었으나 빌드하는 데 시간이 오래 걸렸고, github hosted runner는 매번 필요한 의존성을 설치해도 이전보다 더 빠르게 동작하였다.
기존에는 Compile이라는 단계가 존재했다. gradle로 빌드하고 실패하면 다음 단계로 진행하지 않는 것인데, 이 부분은 Build 스테이지에서 또 한 번 빌드하므로 중복된다. 또한 Test 단계에서도 중복된다. Test 단계에서는 ./gradlew build test
로 테스트만 진행되는데 해당 단계에서 이미 Compile 에러는 잡아준다. 따라서 불필요하게 시간을 잡아먹던 Compile 스테이지를 제거했다. 빌드 속도가 대략 20~30초 더 빨라졌다.
기존에는 docker-in-docker(dind)를 이용해 빌드 환경을 구축하고 배포했는데, 토이 프로젝트에서는 dind까지 쓸 필요가 없다. 빌드할 때마다 환경에 따라 설정이 꼬일 염려가 없고, 동시에 여러 파이프를 실행시킬 상황이 없기 때문이다. dind를 내려받는 시간과 제한된 도커 리소스로 인해 속도가 조금 더 느렸지만, 이를 제거하여 빌드 속도가 대략 20~30초 더 빨라졌다.
jobs:
Deploy:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: echo ${{ secrets.ENV_LOCAL }} > .env.local
- run: npm ci
- run: npm run build
- name: Next cache build
id: next-build-cache
uses: actions/cache@v4
with:
path: |
.next/cache
key: ${{ runner.os }}-next-build-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-next-build-
- run: npm run build
- name: Set up jdk17
uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '17'
cache: 'gradle'
# Run actions/setup-java@v4
# Installed distributions
# Creating settings.xml with server-id: github
# Writing to /home/runner/.m2/settings.xml
# Received 233806950 of 242195558 (96.5%), 222.8 MBs/sec
# Cache Size: ~231 MB (242195558 B)
# /usr/bin/tar -xf /home/runner/work/_temp/5bff7d4d-4d54-41b8-acfc-9b4ac9464ca3/cache.tzst -P -C /home/runner/work/backend/backend --use-compress-program unzstd
# Cache restored successfully
# Cache restored from key: setup-java-Linux-gradle-b5f8b219da233fd5274dc83c92b7496fae144a8b62e0031545559fdfb82e6b42
# Received 242195558 of 242195558 (100.0%), 115.4 MBs/sec
rules if
로 트리거 조건을 설정할 수 있었지만, github에서는 Settings-branches
에서 해당 조건을 추가할 수 있었다.name: CI Pipeline
run-name: ${{ github.actor }} is currently working on continuous integration 🚀
on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev
workflow_dispatch:
jobs:
Test:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- run: echo "${{ secrets.ENV_YML }}" > ./src/main/resources/env.yml
- name: Set up jdk17
uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '17'
cache: 'gradle'
- run: ./gradlew build test --no-daemon
name: CD Pipeline
run-name: ${{ github.actor }} is currently deploying 🚀
on:
workflow_run:
workflows: ["CI Pipeline"]
types:
- completed
env:
IMAGE_NAME: jinyhehe/spacestory
IMAGE_TAG: "1.0"
DOCKER_REGISTRY_USER: ${{ secrets.DOCKER_REGISTRY_USER }}
DOCKER_REGISTRY_PASS: ${{ secrets.DOCKER_REGISTRY_PASS }}
jobs:
build:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Build image
run: |
echo "${{ secrets.ENV_YML }}" > ./src/main/resources/env.yml
echo $DOCKER_REGISTRY_PASS | docker login --username $DOCKER_REGISTRY_USER --password-stdin
docker build -t $IMAGE_NAME:$IMAGE_TAG .
docker push $IMAGE_NAME:$IMAGE_TAG
deploy:
needs: build
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Setup ssh
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H 13.125.206.46 >> ~/.ssh/known_hosts
- name: Deploy image
run: ssh -i ~/.ssh/id_rsa ubuntu@13.125.206.46 "echo $DOCKER_REGISTRY_PASS | docker login --username $DOCKER_REGISTRY_USER --password-stdin && docker rm app -f || true && docker pull $IMAGE_NAME:$IMAGE_TAG && docker run -d -p 8080:8080 --name app --network juny $IMAGE_NAME:$IMAGE_TAG"
name: CD Pipeline
run-name: ${{ github.actor }} is currently deploying 🚀
on:
push:
branches:
- main
- dev
pull_request:
branches:
- main
- dev
workflow_dispatch:
jobs:
Deploy:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: echo ${{ secrets.ENV_LOCAL }} > .env.local
- run: npm ci
- name: Next cache build
id: next-build-cache
uses: actions/cache@v4
with:
path: |
.next/cache
key: ${{ runner.os }}-next-build-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-next-build-
- run: npm run build
- name: Sending out/
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H 34.64.229.17 >> ~/.ssh/known_hosts
cat ~/.ssh/id_rsa
rsync -avz --delete -e "ssh -i ~/.ssh/id_rsa" out/ elice@34.64.229.17://home/elice/nginx/html/