16.2.다중 아키텍처 이미지를 만들기 위한 Dockerfile 스크립트

다중 아키텍처 이미지 빌드 * 다중 아키텍처 이미지를 만들 수 있는 방법은 크게 두 가지다. * 먼저 멀티 스테이지 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
  1. 022~026: Dockerfile마다 다른 값이 하드 코딩된 문자열이 출력된다. 그다음에는 현재 CPU 아키텍처와 운영체제 종류를 출력하는 명령을 실행한다.
  2. 033~036: platform 플래그를 사용하지 않아도 도커 엔진이 에뮬레이션 기능을 사용하므로 인텔 컴퓨터에서도 ARM 이미지를 실행할 수 있다.

  3. 리눅스 대상 이미지의 Dockerfile 스크립트는 대상 아키텍처를 나타내는 하드 코딩된 문자열을 제외하면 거의 비슷한 내용이다.

  4. 윈도 대상 이미지의 Dockerfile 스크립트도 동작은 같지만 명령어가 다르다.
  5. Dockerfile 스크립트를 여러 개 만드는 방식의 장점이 여기에 있다.
  6. 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
  1. 002, 013: 이미지 각 버전마다 기반 이미지가 다른데, 이 기반 이미지는 다중 아키텍처 이미지가 아니라 특정 아키텍처 대상 이미지를 사용한다.
  2. 012: 줄 바꿈 이스케이프 문자를 백슬래시(\)에서 백틱(`)으로 변경해 백슬래시를 경로 구분자로 사용할 수 있게 했다.
  3. 019: 리눅스의 uname에 해당하는 윈도 명령이 없기 때문에 윈도에서는 CPU 아키텍처 이름이 정의된 환경 변수 값을 출력하게 했다.

  4. 서드파티 애플리케이션의 다중 아키텍처 버전 이미지를 만들고 싶다면 대개는 이렇게 Dockerfile 스크립트를 여러 개 만드는 방법을 사용해야 한다.

  5. 직접 개발한 애플리케이션이라면 어렵지 않게 단일 Dockerfile 스크립트를 만들어 관리 부담을 줄일 수 있을 것이다.
  6. 하지만 이런 경우 모든 대상 운영체제에서 공통적으로 사용할 수 있는 명령어만 사용해야 한다.

실습 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
  1. 008: 리눅스용 이미지로 실행한 컨테이너가 정상적으로 실행되지 않는다. 리눅스 명령어가 아닌 dir 명령어가 사용됐기 때문이다.

  2. 이미지는 정상적으로 빌드되지만, 컨테이너를 실행해 보면 제대로 실행되지 않는다.

  3. 다중 아키텍처 이미지를 만들 때는 이 점을 항상 염두에 두어야 한다.
  4. 특히 시작 스크립트가 복잡하다면 더욱 주의가 필요하다.
  5. 운영체제에 없는 명령어가 RUN 인스트럭션에서 사용됐다면 이미지를 빌드하는 시점에 알 수 있지만, CMD 인스트럭션에 사용됐다면 컨테이너를 실제로 실행해 보기 전에는 그 사실을 알 수 없다.
  6. 다중 아키텍처 이미지를 레지스트리에 푸시해 보기 전에 마지막으로 도커가 지원하는 아키텍처를 알아보자.
  7. 다중 아키텍처 이미지를 다루다 보면 낯선 아키텍처 코드명을 보게 될 것이다.

도커에서 지원하는 아키텍처와 코드명 | 운영체제 | 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 컴퓨터를 운영 중이라면 메인프레임 애플리케이션도 컨테이너로 이전할 수 있다

links

social