일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- varchar
- 이메일 비동기
- AWS Lambda
- 성능개선
- 레디스
- url 단축기
- SMTP
- 비동기
- Spring
- mysql
- M오더
- spring actuator
- explain
- 페이징
- 결제누락
- 빅맥
- health check
- ALB
- Docker
- 포트원
- 선착순
- scheduling
- ECR
- JMeter
- redis
- 동시성 문제
- Lock
- cache miss
- buildx
- 실행계획
- Today
- Total
jjunhub
docker buildx 빌드 시간 단축하기 본문
부제 : 조건에 맞을 땐, buildx 대신 build --platform 쓰자
상황
AWS ECR에 ARM64, AMD64 두 플랫폼에서 각각 사용할 수 있는 이미지를 올리고자 하였다.
dev용 ec2는 t2.micro ← x86 = AMD64
prod용 pod는 t4 이상 ← ARM64
문제 코드
name: Deploy dev server
on:
push:
branches:
- "develop"
pull_request:
branches:
- "develop"
workflow_dispatch:
jobs:
build:
name: Build Java Project With Dockerfile
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout the repo
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
- name: Login to Amazon ECR
run: |
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com
- name: Build and push Docker image to Amazon ECR with Tag
run: |
COMMIT_SHA=$(git rev-parse --short HEAD)
docker buildx build \\
--platform linux/amd64,linux/arm64 \\
-t ${{ secrets.AWS_ACCOUNT_ID }}/${{ secrets.ECR_REPOSITORY }}:$COMMIT_SHA \\
-t ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ secrets.ECR_REPOSITORY }}:$COMMIT_SHA \\
--push .
해당 코드는 buildx 도구를 불러와서 2가지 OS에 대한 이미지를 만드는 코드이다.
문제점
buildx 도구는 진~짜 많은 플랫폼에 대해서 빌드할 수 있게 설정하여 가져온다.
따라서 이 docker buildx 명령어를 사용하는 순간 엄청나게 오래 걸릴 수 밖에 없는 구조이다.
문제 해결
문제가 되는 buildx를 쓰지말자!가 목표였다. 이를 위해서 docker build를 직접 2차례 진행하였다. arm64용으로 한 번( for MAC OS ), amd64용으로 한 번(for Ubuntu) 그리고 나서 이 두 개의 이미지를 한 개의 manifest로 묶어서 Index 처리를 해주었다.
아래 코드를 통해서 문제 해결을 시도했다.
name: Deploy dev server
on:
push:
branches:
- "develop"
pull_request:
branches:
- "develop"
workflow_dispatch:
jobs:
build:
name: Build Java Project With Dockerfile
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout the repo
uses: actions/checkout@v4
- name: Set commit SHA
run: echo "COMMIT_SHA=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
- name: Login to Amazon ECR
run: |
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com
- name: Build and push Docker image for amd64
run: |
docker build --platform linux/amd64 \\
-t ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ secrets.ECR_REPOSITORY }}:${{ env.COMMIT_SHA }}-amd64 .
docker push ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ secrets.ECR_REPOSITORY }}:${{ env.COMMIT_SHA }}-amd64
- name: Build and push Docker image for arm64
run: |
docker build --platform linux/arm64 \\
-t ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ secrets.ECR_REPOSITORY }}:${{ env.COMMIT_SHA }}-arm64 .
docker push ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ secrets.ECR_REPOSITORY }}:${{ env.COMMIT_SHA }}-arm64
- name: Create and push Docker manifest
run: |
docker manifest create ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ secrets.ECR_REPOSITORY }}:dev-${{ env.COMMIT_SHA }} \\
--amend ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ secrets.ECR_REPOSITORY }}:${{ env.COMMIT_SHA }}-amd64 \\
--amend ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ secrets.ECR_REPOSITORY }}:${{ env.COMMIT_SHA }}-arm64
docker manifest push ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ secrets.ECR_REPOSITORY }}:dev-${{ env.COMMIT_SHA }}
결과
6분 54초에서 1분 48초로 약 70프로 시간이 단축되었다.
개선 방식의 문제점 & 해결책
이렇게 여러 번 테스트 하면서 느낀 점은.. ECR 용량이 금방 터지겠구나였다. 하나의 이미지가 여러 플랫폼을 지원할 수 있도록 제공하는 것이 아니기 때문에 반드시 2배 이상이 소요되기 때문이다.
따라서 이를 위해서 ECR LifeCycle 설정까지 수행하였다.
이는 ECR 이미지 개수들을 내가 작성한 정책(조건)에 맞춰서 관리해주는 설정이다.
위처럼 설정하여 dev- 접두사가 붙은 이미지 세트들에 대해서 2개씩만 존재하도록 설정하였다. dev- 접두사를 붙인 이유는 prod- 접두사를 따로 붙여서, dev 이미지를 여러 번 배포하더라도 이와 별개로 prod- 이미지를 유지하기 위해서이다.
느낀점
의외로 무식한 방법이 제일 빠르다!
추가로..
Q : 왜 도커에서 buildx가 주로 사용되는가? 그리고 왜 여기선 사용하지 않았는가?
A : buildx를 사용하면 거의 대부분의 크로스 플랫폼 빌드, 병렬 빌드, 캐시 개선 등의 기능을 제공받을 수 있다. 하지만 buildx 도구를 위해 불러오는 것만으로도 overhead가 엄청나게 큰 편이다. 이번 프로젝트의 경우에는 AMD64, ARM64 딱 2가지의 OS만 처리하면 돼서 이를 기본으로 제공하는 docker —platform 옵션으로 해결하는 것이 최적의 상황으로 느껴진다.