현재 Ubuntu 빌드 서버가 있고, CI-CD를 구축한 상태이다. 그런데 로컬 빌드 서버가 왜 필요할까? 빌드 서버가 aws ec2 freetier이기 때문에 CPU는 1코어, 스왑 메모리를 제외한 기본 메모리 1기가이다. 자동적으로 실행되는 건 좋지만, 버그가 생기거나 특정 시간에 빌드가 몰리면 굉장히 답답하다. 현재 Compile → Test → Build → Deploy 파이프라인이 있고, 완료되는 데 대략 5분~8분정도 걸린다.
M1에서 로컬로 빌드하면 1분이 채 안 걸린다! 하지만, 이 과정이 정말 순조롭지 않았다. 이제는 뚝딱하겠지만, 한 번 되기까지 삽질한 과정을 공유한다.
삽질한 시간까지 생각하면, 로컬로 빌드를 백 번 이상 해야 본전이다ㅎ_ㅎ..
sudo gitlab-runner run
gitlab-runner run // 변경
sudo gitlab-runner run
명령어를 통해 root 권한으로 gitlab-runner가 실행되었고, 따라서 docker 또한 root 권한으로 실행되었다.gitlab-runner run
명령어를 사용했는데, 올바르게 서버가 설정되어 있음에도 반응이 없었다.https://stackoverflow.com/questions/56153664/gitlab-runner-listen-address-not-defined-error
sudo chmod 755 /etc/gitlab-runner/config.toml
sudo chown ${USER} /etc/gitlab-runner/config.toml
sudo chmod -R 755 builds/
sudo chown -R ${USER} builds/
gitlab-runner run -c ~/config.toml
실행할 때 지정할 수도 있다./Library/LaunchAgents/gitlab-runner.plist
에서 설정을 아래와 같이 추가하면, gitlab-runner가 실행될 때 사용하는 계정을 지정할 수 있다. 해당 계정으로 파일이 새로 만들어진다.<key>UserName</key>
<string>$USER</string>
이미지를 빌드하고 서버에서 해당 이미지를 실행할 때 아래와 같은 에러가 뜬다. 즉, 빌드할 때는 ARM64 아키텍처로 이미지가 빌드되었지만, 실행하는 서버는 Ubuntu Amd64라 발생하는 문제이다.
WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64/v3) and no specific platform was requested
docker run --privileged --rm tonistiigi/binfmt --install all
docker buildx build --platform linux/amd64 -t $IMAGE_NAME:$IMAGE_TAG .
위 명령어를 통해 멀티 플랫폼 이미지를 만들 수 있다. https://docs.docker.com/build/building/multi-platform/#qemu
로컬 gradle로 빌드한 후 openjdk:17 이미지로 빌드한다.
처음엔 tags를 환경 변수로 설정하고 싶었는데, tags에 $BUILD_MACHINE 처럼 환경 변수로 지정하면 아래처럼 트리거 되지 않는다.
그러면 어떻게 특정 러너를 실행할 수 있을까? rules if
를 사용하여 트리거할 로컬 머신을 설정할 수 있다. YAML 앵커 문법을 사용하면 <<: * 상속받을 부모를 정할 수 있어서 재사용성이 좋아진다.
아래는 YAML 앵커 문법으로 기존 빌드 스크립트에 Mac os x 빌드 머신을 추가한 것이다.
variables:
IMAGE_NAME: jinyhehe/spacestory
IMAGE_TAG: $CI_COMMIT_SHA
stages:
- compile
- test
- build
- deploy
.compile_template: &compile_template
stage: compile
script:
- gradle build --exclude-task test
compile_juny:
<<: *compile_template
before_script:
- export PATH="/home/ubuntu/.sdkman/candidates/gradle/current/bin:$PATH"
tags:
- juny
rules:
- if: '$BUILD_MACHINE == "juny"'
compile_junylocal:
<<: *compile_template
tags:
- juny-local
rules:
- if: '$BUILD_MACHINE == "juny-local"'
.test_template: &test_template
stage: test
script:
- gradle build --exclude-task test
test_juny:
<<: *test_template
before_script:
- export PATH="/home/ubuntu/.sdkman/candidates/gradle/current/bin:$PATH"
tags:
- juny
rules:
- if: '$BUILD_MACHINE == "juny"'
test_junylocal:
<<: *test_template
tags:
- juny-local
rules:
- if: '$BUILD_MACHINE == "juny-local"'
.build_template: &build_template
stage: build
before_script:
- cat $SPRING_ENV > src/main/resources/env.yml
build_juny:
<<: *build_template
image: docker:26.1.3
services:
- docker:26.1.3-dind
variables:
DOCKER_TLS_CERTDIR: "/certs"
script:
- echo $DOCKER_REGISTRY_PASS | docker login --username $DOCKER_REGISTRY_USER --password-stdin
- docker build -t $IMAGE_NAME:$IMAGE_TAG .
- docker tag $IMAGE_NAME:$IMAGE_TAG $IMAGE_NAME:latest
- docker push $IMAGE_NAME:$IMAGE_TAG
- docker push $IMAGE_NAME:latest
tags:
- juny
rules:
- if: '$BUILD_MACHINE == "juny"'
build_junylocal:
<<: *build_template
script:
- cat $DOCKER_FILE > Dockerfile
- gradle build --exclude-task test
- docker login
- docker run --privileged --rm tonistiigi/binfmt --install all
- docker buildx build --platform linux/amd64 -t $IMAGE_NAME:$IMAGE_TAG -t $IMAGE_NAME:latest --push .
tags:
- juny-local
rules:
- if: '$BUILD_MACHINE == "juny-local"'
.deploy_template: &deploy_template
stage: deploy
before_script:
- chmod 400 $SSH_KEY
- mkdir -p ~/.ssh
- ssh-keyscan -H 13.125.206.46 >> ~/.ssh/known_hosts
script:
- ssh -i $SSH_KEY ubuntu@13.125.206.46 "echo $DOCKER_REGISTRY_PASS | docker login --username $DOCKER_REGISTRY_USER --password-stdin && docker rm spring-app -f || true && docker pull $IMAGE_NAME:latest && docker run -d -p 8080:8080 --name spring-app --network juny $IMAGE_NAME:latest"
deploy_juny:
<<: *deploy_template
tags:
- juny
rules:
- if: '$BUILD_MACHINE == "juny"'
deploy_junylocal:
<<: *deploy_template
tags:
- juny-local
rules:
- if: '$BUILD_MACHINE == "juny-local"'
// gradle.properties
org.gradle.daemon=false
org.gradle.jvmargs=-Xmx4096m
docker run --privileged --rm tonistiigi/binfmt --install all
qemu provider와 gradle 호환성 문제가 발생한 거라고 생각한다. 많은 시간 들였는데 해결하지 못해서 아쉬운 부분이다.