다중 아키텍처 이미지 빌드 * 다중 아키텍처 이미지를 만들 수 있는 방법은 크게 두 가지다. * 먼저 멀티 스테이지 Dockerfile 스크립트를 이용해 컨테이너에서 소스 코드를 빌드하고 패키징하는 방법이다. * 단, 이 방법을 사용하려면 애플리케이션에 사용된 SDK나 런타임에 원하는 아키텍처를 지원해야 한다. * 첫 번째 방법의 가장 큰 장점은 Dockfile 스크립트 하나로 다른 아키텍처의 컴퓨터에서 이미지를 빌드하면 해당 아키텍처의 이미지를 만들 수 있다는 점이다. * 다만 빌드에 사용된 이미지가 다중 아키텍처 이미지가 아니거나 원하는 아키텍처를 모두 지원하지 않는다면 이 방법은 사용할 수 없다. * 이럴 때는 Dockerfile 스크립트를 아키텍처나 운영체제별로 따로 작성해야 한다. * 이 방법은 Dockerfile 가짓수가 늘어나는 만큼 관리 업무가 늘어나지만 대상 아키텍처마다 이미지에 원하는 대로 변화를 줄 수 있다.
실습에 앞서 * 이번 장의 실습은 런타임에 대한 정보와 디렉터리의 파일 목룩을 출력하는 아주 간단한 애플리케이션인 folder-list를 소재로 한다. * 이 애플리케이션은 네 개의 Dockerfile 스크립트가 있는데, 각각 인텔(원도), 인텔(리눅스), 32비트 ARM(리눅스), 64비트 ARM(리눅스) 아키텍처에 해당한다. * 도커 데스크톱의 에뮬레이션 기능을 사용하면 이들 중 세 가지 아키텍처를 빌드할 수 있다.
실습 플랫폼별 Dockerfile 스크립트를 사용해 각 플랫폼용 이미지를 빌드해 보자. 각 Dockerfile 스크립트는 내용이 조금씩 다르며 컨테이너를 실행하면 그 차이를 알 수 있다.
- 컨테이너를 실행하면 하드 코딩된 해당 이미지의 대상 운영체제와 아키텍처 정보가 나오고, 그 뒤로는 도커 엔진의 실제 운영체제와 아키텍처 정보가 출력된다.
- 도커 엔진에서 필요한 경우 에뮬레이션 기능을 사용하므로, 여기서는 32비트 ARM과 64비트 ARM 이미지의 컨테이너를 실행하며 이 에뮬레이션 기능이 사용됐다.
001) ➜ cd ./folder-list
002)
003) # 네이티브 아키텍처(인텔/AMD)로 이미지를 빌드한다
004) ➜ folder-list git:(main) ✗ docker image build -t diamol/ch16-folder-list:linux-amd64 -f ./Dockerfile.linux-amd64 .
005) [+] Building 1.7s (9/9) FINISHED
006) => exporting to image 0.0s
007) => => naming to docker.io/diamol/ch16-folder-list:linux-amd64 0.0s
008)
009) # 64비트 ARM 아키텍처로 이미지를 빌드한다
010) ➜ folder-list git:(main) ✗ docker image build -t diamol/ch16-folder-list:linux-arm64 -f ./Dockerfile.linux-arm64 --platform linux/arm64 .
011) [+] Building 0.5s (8/8) FINISHED
012) => exporting to image 0.0s
013) => => naming to docker.io/diamol/ch16-folder-list:linux-arm64 0.0s
014)
015) # 32비트 ARM 아키텍처로 이미지를 빌드한다
016) ➜ folder-list git:(main) ✗ docker image build -t diamol/ch16-folder-list:linux-arm -f ./Dockerfile.linux-arm --platform linux/arm .
017) [+] Building 0.9s (8/8) FINISHED
018) => exporting to image 0.0s
019) => => naming to docker.io/diamol/ch16-folder-list:linux-arm 0.0s
020)
021) # 빌드한 각 이미지로 컨테이너를 실행해 출력 내용을 확인한다
022) ➜ folder-list git:(main) ✗ docker container run diamol/ch16-folder-list:linux-amd64
023) WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
024) Built as: linux/amd64
025) Linux 514ab660b320 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 x86_64 Linux
026) file.txt
027)
028) ➜ folder-list git:(main) ✗ docker container run diamol/ch16-folder-list:linux-arm64
029) Built as: linux/arm64
030) Linux 408177fcf28f 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 aarch64 Linux
031) file.txt
032)
033) ➜ folder-list git:(main) ✗ docker container run diamol/ch16-folder-list:linux-arm
034) Built as: linux/arm32
035) Linux cbdb2370e789 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 armv7l Linux
036) file.txt
- 022~026: Dockerfile마다 다른 값이 하드 코딩된 문자열이 출력된다. 그다음에는 현재 CPU 아키텍처와 운영체제 종류를 출력하는 명령을 실행한다.
-
033~036: platform 플래그를 사용하지 않아도 도커 엔진이 에뮬레이션 기능을 사용하므로 인텔 컴퓨터에서도 ARM 이미지를 실행할 수 있다.
-
리눅스 대상 이미지의 Dockerfile 스크립트는 대상 아키텍처를 나타내는 하드 코딩된 문자열을 제외하면 거의 비슷한 내용이다.
- 윈도 대상 이미지의 Dockerfile 스크립트도 동작은 같지만 명령어가 다르다.
- Dockerfile 스크립트를 여러 개 만드는 방식의 장점이 여기에 있다.
- Dockerfile 스크립트의 인스트럭션이 전혀 달라도 동작은 같도록 할 수있기 때문이다.
예제 16-1 리눅스용 이미지와 윈도용 이미지의 Dockfile 스크립트 비교
001) # 리눅스용 이미지
002) FROM diamol/base:linux-arm64
003)
004) WORKDIR /app
005) COPY file.txt .
006)
007) CMD echo "Built as: linux/arm64" && \
008) uname -a && \
009) ls /app
010)
011) # 윈도용 이미지
012) # escape=`
013) FROM diamol/base:windows-amd64
014)
015) WORKDIR /app
016) COPY file.txt .
017)
018) CMD echo Built as: windows/amd64 && `
019) echo %PROCESSOR_ARCHITECTURE% %PROCESSOR_IDENTIFIER% && `
020) dir /B C:\app
- 002, 013: 이미지 각 버전마다 기반 이미지가 다른데, 이 기반 이미지는 다중 아키텍처 이미지가 아니라 특정 아키텍처 대상 이미지를 사용한다.
- 012: 줄 바꿈 이스케이프 문자를 백슬래시(\)에서 백틱(`)으로 변경해 백슬래시를 경로 구분자로 사용할 수 있게 했다.
-
019: 리눅스의 uname에 해당하는 윈도 명령이 없기 때문에 윈도에서는 CPU 아키텍처 이름이 정의된 환경 변수 값을 출력하게 했다.
-
서드파티 애플리케이션의 다중 아키텍처 버전 이미지를 만들고 싶다면 대개는 이렇게 Dockerfile 스크립트를 여러 개 만드는 방법을 사용해야 한다.
- 직접 개발한 애플리케이션이라면 어렵지 않게 단일 Dockerfile 스크립트를 만들어 관리 부담을 줄일 수 있을 것이다.
- 하지만 이런 경우 모든 대상 운영체제에서 공통적으로 사용할 수 있는 명령어만 사용해야 한다.
실습 folder-list 애플리케이션 디렉터리에는 다중 아키텍처 이미지를 빌드하기 위한 Dockerfile 스크립트 파일이 하나 더 있다. 이 스크립트는 다중 아키텍처 이미지를 기반 이미지로 삼았지만, 리눅스 명령어와 윈도 명령어를 섞어 사용했기 때문에 모든 아키텍처에서 컨테이너가 정상적으로 실행되지 않는다.
001) # 다중 아키텍처 이미지 빌드하기
002) ➜ folder-list git:(main) ✗ docker image build -t diamol/ch16-folder-list .
003) [+] Building 3.2s (9/9) FINISHED
004) => exporting to image 0.0s
005) => => naming to docker.io/diamol/ch16-folder-list 0.0s
006)
007) # 빌드한 이미지로 컨테이너 실행하기
008) ➜ folder-list git:(main) ✗ docker container run diamol/ch16-folder-list
009) Built as multi-arch
010) Linux 76b458ad80d6 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 aarch64 Linux
011) /bin/sh: dir: not found
-
008: 리눅스용 이미지로 실행한 컨테이너가 정상적으로 실행되지 않는다. 리눅스 명령어가 아닌 dir 명령어가 사용됐기 때문이다.
-
이미지는 정상적으로 빌드되지만, 컨테이너를 실행해 보면 제대로 실행되지 않는다.
- 다중 아키텍처 이미지를 만들 때는 이 점을 항상 염두에 두어야 한다.
- 특히 시작 스크립트가 복잡하다면 더욱 주의가 필요하다.
- 운영체제에 없는 명령어가 RUN 인스트럭션에서 사용됐다면 이미지를 빌드하는 시점에 알 수 있지만, CMD 인스트럭션에 사용됐다면 컨테이너를 실제로 실행해 보기 전에는 그 사실을 알 수 없다.
- 다중 아키텍처 이미지를 레지스트리에 푸시해 보기 전에 마지막으로 도커가 지원하는 아키텍처를 알아보자.
- 다중 아키텍처 이미지를 다루다 보면 낯선 아키텍처 코드명을 보게 될 것이다.
도커에서 지원하는 아키텍처와 코드명 | 운영체제 | CPU 아키텍처 | 워드 길이 | CPU 종류 | 아키텍처 코드명 | | -- | -- | -- | -- | -- | | 윈도 | 인텔/AMD | 64비트 | amd64 | x86_64 | | 리눅스 | 인텔/AMD | 64비트 | amd64 | x86_64 | | 리눅스 | ARM | 64비트 | arm64 | aarch64, armv8 | | 리눅스 | ARM | 32비트 | amd | arm32v7, armv7, armhf |
- 여기 언급된 플랫폼 외에도 지원 플랫폼이 더 있지만 주요 플랫폼은 표에 언급된 대로다.
- amd64 CPU는 인텔과 AMD CPU에서 함께 사용되는 인스트럭션셋으로, 실질적으로 거의 모든 데스크톱, 서버, 랩톱 컴퓨터의 CPU가 이 아키텍처를 채택했다(도커는 이 외에도 32비트 인텔 x86 아키텍처를 추가로 지원한다).
- 32비트 및 64비트 ARM 프로 세서는 휴대폰, IoT 장치, (라즈베리 파이로 유명한) 단일 보드 컴퓨터 등에 주로 쓰인다.
- 라즈베리 파이 3까지는 32비트였으나 4부터는 64비트 프로세서가 장착됐다.
- 메인프 레임 환경인 IBM CPU 아키텍처와 리눅스도 충실히 지원하므로 IBM 2, POWER, PoWerPC 컴퓨터를 운영 중이라면 메인프레임 애플리케이션도 컨테이너로 이전할 수 있다