Programming-[Infra]/Docker

도커 교과서(엘튼 스톤맨, 심효섭) - 15. 다중 아키텍처 빌드

컴퓨터 탐험가 찰리 2023. 5. 7. 15:01
728x90
반응형

 

1. 다중 아키텍처 지원이 필요한 이유

 
이 교재의 맨 처음 글에서 도커는 가상 머신과 다르게, 실행하고 있는 컴퓨터와 운영체제는 공유하면서 IP, host, 드라이브를 개별적으로 갖는다고 했었다(architecture-specific). 따라서 도커의 이미지 빌드 및 실행은 대상 컴퓨터의 운영 체제로 어떤 아키텍처를 갖느냐에 영향을 받게 된다. arm64, amd64 등 여러 아키텍처에 따라 개별적인 관리가 필요하다.
 
클라우드에서만 하더라도 AWS에서 ARM 아키텍처를 사용하여 가상 머신을 열고 노드로 컨테이너를 구동하면 AMD 프로세서를 사용하는 경우에 비해서 단가가 절반 정도로 저렴하다고 한다. 그리고 IoT 기반의 프로세서에서 동작하게 할려는 경우 라즈베리파이처럼 ARM 프로세서를 사용하는 아키텍처에서 프로젝트의 이미지를 구동해야할 수 있다.
 

다중 아키텍처 지원 이미지를 특정 아키텍처용으로 빌드해보기

 

cd ch16/exercises
docker build -t diamol/ch16-whoami:linux-arm64 --platform linux/arm64 ./whoami # 이미지 빌드
docker image inspect diamol/ch16-whoami:linux-arm64 -f '{{.Os}}/{{.Architecture}}' # 이미지의 아키텍처 확인
docker info -f '{{.OSType}}/{{.Architecture}}' # 내 컴퓨터의 도커 엔진의 아키텍처 확인

 
내 컴퓨터는 linux/aarch64라는 코드명을 갖는 아키텍처인 반면, 이미지는 linx-arm64용으로 태그를 달아서 빌드했기 때문에 linux/arm64 코드명의 아키텍처로 빌드되었음을 확인할 수 있다. (물론 둘다 ARM 계열이다.)
 
이렇게 특정 아키텍처로 이미지를 빌드할 수 있었던 이유는 해당 diamol/ch16-whoami 이미지가 도커 허브 레지스트리에 다중 아키텍처를 지원할 수 있도록 여러 종류의 아키텍처 버전별로 등록되어있기 때문이다.
 
도커는 이미지를 내려받는 컴퓨터의 아키텍처와 일치하는 이미지만을 내려받는다.
만약 다중 아키텍처를 지원하지 않고 내 컴퓨터와 다른 아키텍처로 구성된 이미지를 다운받으려고 하면 다운로드조차 되지 않는다. 
 

docker image pull mcr.microsoft.com/windows/nanoserver:1809

 
linux/arm64 아키텍처를 사용하고 있기 때문에 윈도우용으로만 제공되는 이미지는 다운로드 받을 수 없다고 나온다. 에러 메시지에 manifest list라는 이름이 나오는데, 이미지가 지원하는 아키텍처 이름 리스트 정도라고 보면된다. 뒤에서 다시 다룰 것이다.
 
윈도우 nanoserver
참고로 윈도우의 nanoserver는 윈도우 서버를 최소한의 기능으로 구현하기 위한 이미지로, 윈도서버 2012의 경우 11GB 수준인데 비해 윈도 나노서버 2016을 나노서버로 설치하는 경우 160MB만 요구한다.
 
 

2. 다중 아키텍처 이미지 빌드해보기

 
좀 더 정확한 이해를 위해서 교재에서 제공하는 이미지를 다중 아키텍처용으로 빌드해본다.
 
다중 아키텍처 빌드를 위해서는 아키텍처별로 상응하는 Dockerfile을 따로 작성해야한다.
아키텍처마다 지원되는 베이스 이미지도 다르고, 프로세서에 직접 명령을 내릴 수 있는 명령어도 다르기 때문이다.
 
실습해보는 애플리케이션 이미지는 인텔 ADM(리눅스, 윈도우), 32bit ARM(리눅스), 64bit ARM(리눅스) 총 4가지로 빌드해본다.

cd ./folder_list
docker image build -t diamol/ch16-folder-list:linux-amd64 -f ./Dockerfile.linux-amd64 --platform linux/arm64 .
docker image build -t diamol/ch16-folder-list:linux-arm64 -f ./Dockerfile.linux-arm64 .
docker image build -t diamol/ch16-folder-list:linux-arm -f ./Dockerfile.linux-arm --platform linux/arm .

# 확인
docker container run diamol/ch16-folder-list:linux-amd64
docker container run diamol/ch16-folder-list:linux-arm64
docker container run diamol/ch16-folder-list:linux-arm

 
명령어를 살펴보면 -t를 통해 각 아키텍처마다 태그명을 달리했다. 그리고 Dockerfile을 개별적으로 정의하였다. 
--platform은 내 컴퓨터의 아키텍처와 다른 경우 이미지를 빌드할 아키텍처를 직접 정의해주는 명령어이다. 내 경우는 arm64 아키텍처라서 amd64, arm 아키텍처를 빌드하는 명령어에는 --platform 명령어를 추가해주었다.

 
아키텍처별로 기반이미지, 사용할 수 있는 명령어가 다르다.
 
교재에서 예시로 든 Dockerfile을 비교한 부분을 살펴보자.

# 리눅스용
FROM diamol/base:linux-arm64

WORKDIR /app
COPY file.txt .
CMD echo "Built as: linux/arm64" && \
    uname -a && \
    ls /app

# 윈도우용
# escape=`
FROM diamol/base:windows-amd64

WORKDIR /app
COPY file.txt .

CMD echo Built as: windows/amd64 && `
    echo %PROCESOR_ARCHITECTURE% %PROCESSOR_IDENTIFIER% && `
    dir /B C:\app

 
우선 베이스 이미지가 다르다. FROM절의 linux-arm64, windows-amd64 이미지는 각 아키텍처용으로만 제공되는 이미지를 기반으로한다. 다시말해 diamol/base:linux-arm64는 linux-arm64만 제공하는 이미지를 기반으로 저자가 새롭게 구축한 이미지이다. 해당 folder-list 애플리케이션은 이 이미지를 기반으로해서 arm64용 folder-list 애플리케이션을 만든다.
 
그리고 CMD에서 사용하는 명령어가 다르다. 윈도우용에서는 백틱 기호를 이스케이프용 문자로 지정하여 리눅스에서 사용하는 경로 표시용 슬래시(/)를 CMD에서 사용했다. 이외에도 아키텍처별로 CMD 속에서 각 운영체제(커널) 쪽으로 전달할 수 있는 명령어에 차이가 있기 때문에 개별적으로 Dockerfile을 작성해줘야한다.
 
 
 

3. 다중 아키텍처 이미지를 레지스트리에 푸시

 
위에서 생성한 다중 아키텍처 이미지들을 레지스트리에 푸시할 것이다. 아래 명령어에서 나의 도커 허브 계정은 이메일 @ 뒷 부분은 빼고 입력해야 정상적으로 태그를 달 수 있다.
 

# 나의 도커 계정 이름을 환경 변수로 정의
$dockerId='{나의 도커 허브 계정}' # 윈도우
dockerId='{나의 도커 허브 계정}' # 리눅스 계열

# 나의 계정의 레포지터리에 푸시하기 위해서 각 이미지에 계정 이름을 포함하여 태그로 등록
docker image tag diamol/ch16-folder-list:linux-amd64 $dockerId/ch16-folder-list:linux-amd64
docker image tag diamol/ch16-folder-list:linux-arm64 $dockerId/ch16-folder-list:linux-arm64
docker image tag diamol/ch16-folder-list:linux-arm $dockerId/ch16-folder-list:linux-arm

# 이미지 푸시
docker image push $dockerId/ch16-folder-list:linux-arm64
docker image push $dockerId/ch16-folder-list:linux-amd64
docker image push $dockerId/ch16-folder-list:linux-arm

 
교재 내용과 안맞는 부분이 있어서 약간 헤맸다.

docker image tag <source 이미지 이름>:<source 이미지 태그> <등록할 레포지토리 이름>:<등록할 태그 이름>

위 형식으로 작성해야한다.
 
 
그리고 

docker image push <푸시할 레포지토리 이름>

위 형식으로 작성해야한다. 다만 이렇게 레포지토리 이름만 넣어주면 :latest 태그인 이미지만 푸시된다. 각 태그의 이미지를 푸시하고 싶다면 태그명을 직접 명명해줘야한다.
 
예를 들어 아래 그림에선 계정 이름/ch16-folder-list 라는 레포지토리 이름으로 작성된 이미지들이 docker image push 계정이름/ch16-folder-list 로 명령 시 푸시될 것이다.

 
각 푸시 명령어 입력 시 이미지별로 존재하는 이미지 레이어에 대한 검사가 들어간다. 도커 허브상의 다른 레포지토리에 등록된 이미지 레이어라면 굳이 업로드를 하지않고 해당 레이어를 참조하는 것을 확인할 수 있다(Mounted from ... 부분들).

 
 
그리고 도커 허브의 내 계정에서 태그별로 달리 등록된 이미지 목록을 확인할 수 있다.

 
 
 

매니페스트 정보 등록

 
이미지에서 어떤 아키텍처들을 지원하는지 등의 구성 정보를 표시하는 것을 매니페스트(manifest) 리스트라고 한다. 도커 레지스트리에는 위에서 진행한 것처럼 아키텍처별로 이미지를 푸시한 뒤에 이 정보들을 표시하는 매니페스트 정보를 만들어서 따로 푸시해주어야 한다. 우선 교재에서는 설정 파일상 실험적 기능(experimental)을 사용하는 부분을 enabled로 바꿔주어야 매니페스트 기능을 사용할 수 있다고 되어있으나, 시간이 많이 흘러서인지 매니페스트 기능을 그냥 사용할 수 있었다.
 

docker manifest inspect diamol/base

 
diamol/base 라는 이미지가 어떤 아키텍처를 지원하고 각 이미지의 타입이나 크기는 어떤지에 대한 정보를 추출할 수 있었다.

 
 
이제 앞서 생성한 이미지들을 위한 매니페스트 파일을 생성하고 푸시해본다.

docker manifest create "$dockerId/ch16-folder-list" "$dockerId/ch16-folder-list:linux-amd64" "$dockerId/ch16-folder-list:linux-arm64" "$dockerId/ch16-folder-list:linux-arm"

docker manifest push "$dockerId/ch16-folder-list"

 
성공적으로 매니페스트를 푸시하고나면 :latest 이미지가 생성되고 상세 페이지에서 OS/arch 드롭다운 메뉴를 볼 수 있다. 교재와 약간 다른 부분에서 OS/ARCH 부분을 확인할 수 있었다. 아마 도커 허브 웹페이지가 업데이트되면 이런 위치는 또 달라질 수 있을 것이다. 어쨌든 latest 부분에서 여러 아키텍처들을 선택할 수 있을 것이고, 위에서 실습한 manifest inspect 명령어로 매니페스트 정보들을 확인할 수 있을 것이다.

 
 
 
 

4. buildx

 
buildx는 build의 확장 명령어로 크로스 플랫폼 빌드를 지원한다. 즉 여러 아키텍처를 위한 병렬적 빌드가 가능하다. 교재에서는 앞선 글에서 배웠던 Play with Docker 사이트에서 노드를 2개 열고 각 노드에서 아키텍처별로 동시에 빌드를 할 수 있도록 실습해본다.
 
playwithdocker 사이트에서 node2개 생성 후 node1에서만 아래 명령어들을 입력한다.
 

node2ip=<노드2의 ip>
ssh $node2ip # ssh 접속 가능 여부 확인
exit # node1 복귀

# 로컬 소켓을 통해서 node1을 가리키는 컨텍스트를 생성
docker context create node1 --docker "host=unix:///var/run/docker.sock"
# ssh를 통해서 node2를 가리키는 컨텍스트 생성
docker context create node2 --docker "host=ssh://root@node2ip"

# 컨텍스트 확인
docker context ls

 
Buildx는 도커 CLI의 플러그인이며 보통 도커 데스크탑을 설치하면 기본적으로 추가된다. 그러나 play with docker의 노드상에는 설치되어있지 않으므로 직접 설치해줘야한다. 아래 명령어들도 node1에서 입력한다.
 

#플로그인 다운로드
wget -O /etc/docker-buildx https://github.com/docker/buildx/releases/download/v0.3.1/buildx-v0.3.1.linux-amd64

chmod a+x /etc/docker-buildx # 플로그인을 실행가능으로 설정
docker buildx create --use --name ch16 --platform linux/amd64 node1 # node1로 빌더 생성
docker buildx create --append --name ch16 --platform linux/386 node2 # node2로 빌더 생성

# 빌더 목록 확인
docker buildx ls

 
책의 명령어를 또 수정했다. 아마 play with docker 노드의 파일 path가 조금 변경된 것 같다.
wget 뒤 옵션은 -O로 대문자 O이다. file을 내려받는다는 의미를 옵션으로 주는 것 같다.
 
그리고 node상 교재에 표시된 ~/.docker/... (~는 사용자 루트 path, 이후 .docker라는 디렉토리) 가 없어서 그냥 /etc 부분에 /docker-buildx 디렉토리를 추가해서 거기에 buildx 플러그인이 다운로드 되도록 경로를 바꿨다.
 

 
docker buildx ls 명령어로 확인해보니 node2에 ssh로 접근이 안되서 문제가 생겼다. 일단 개념만 알기 위해서 아래 내용들을 진행한다.

 
이렇게 node1, node2를 이용해서 빌드팜 을 구성하고 여러 이미지를 한번에 푸시한다. 푸시하는 코드를 아래에 기입했다.
 

git clone https://github.com/sixeyed/diamol.git
cd diamol/ch16/exercises/folder-list-2/

# 도커 허브 로그인
dockerId=<도커 허브 아이디>
docker login -u $dockerId

#node1, node2 모두 사용하여 여러 태그 이미지 동시 푸시
docker buildx build -t $dockerId/ch16-folder-list-2 --platform linux/amd64, linux/386 --push .

 
명령어상 여러 태그를 콤마(,)로 구분하여 참조했는데, --platform 명령어가 1개의 argument만 받는다고한다. 뭔가 명령어가 업데이트된 것 같은데, 그냥 이렇게 buildx를 이용해서 빌드팜을 구성하고 여러 아키텍처의 이미지를 병렬적으로 푸시할 수 있다는 것만 알면 될 것 같다. 나중에 또 명령어나 인터페이스가 어떻게 바뀔지 모르니, 개념만 알고 실제 필요한 명령어나 구체적 정보는 그때가서 알아봐야겠다.

728x90
반응형