[Docker] Docker Compose랑 M1이 싸우면 누가 이겨?

내가 이겨

Somewhere between M1 and Docker Compose

이 글을 쓰는 시점이 에러가 발생했던 시점과 약간의 차이가 있어서

몇몇 부분 기억에 의존해서 쓴 부분이 있는데 양해 바랍니다.

TL;DR

이슈 1

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

해결 방법

Docker Desktop (혹은 docker daemon 을 실행시킬 수 있는 다른 수단) 을 설치해 준다.

이슈 2

M1에서만 발생

failed to solve: shivjm/node-chromium:node16-chromium119-alpine: failed to resolve source metadata for docker.io/shivjm/node-chromium:node16-chromium119-alpine: no match for platform in manifest: not found

해결 방법

.yml 에 한 줄을 추가해 보자.

...
services:
  프로젝트 명:
  ...
  # platform 명시 필요
  platform: linux/amd64
...

친절한 번외

docker 명령어를 사용하는 경우에는 뒤에 --platform 옵션을 넣어주도록 하자.

$ docker build ~ --platform=linux/amd64

근토 (근황 Talk 라는 뜻)

사내에서 대부분의 프론트 배포는 데봅스 팀에서 진행했기 때문에 CI (빌드 및 배포) 관련 내용을 거의 모르던 인피덕

기존에는 Github Actions 를 사용하여 바로 서버에 배포하는 식으로 자동화한 상태였다.

그러나 요 며칠간 코드를 Github 에서 Bitbucket 으로 이관하자는 이야기가 오가던 때,

배포 관련 내용도 Bitbucket Pipeline + Docker 로 진행하자고 결론이 나왔다.

ㅎㅎ 배포 안 하실 거예요?

인피덕: ㅋㅋㅋ

Docker: 왜 웃어요? ㅋㅋ

Docker: 진짜 궁금한 건데

인피덕: 네?

Docker: 아 배포 안 하시냐고요 ㅎ

---

+ 팀장님: 도커 ㄱㄱ? 도커 찍먹이나 해 봐라

살려줭

레츠고 도커

.Dockerfile.yml 파일을 생성한다. 블로그 포스팅을 위해 약간의 후처리를 진행했다.

# .Dockerfile

# 프로젝트의 node 버전: 16
FROM node:16-alpine as build

WORKDIR /infiduk

COPY package.json yarn.lock /infiduk/
RUN yarn
ADD . /infiduk/

ARG server
RUN yarn build:${server}
# docker-compose.yml

version: "3.5"

services:
  프로젝트명:
    image: 프로젝트명:네트워크_구분_값
    build:
      context: ./
      dockerfile: .Dockerfile
      args:
        - server=네트워크_구분_값
    ports:
      - "외부_포트_번호:내부_포트_번호"

그리고 빌드 고고

웬만하면 바로 Docker Desktop을 설치할 것을 강력 권장

Docker Desktop 을 사용하지 않고 예전에 잠시 Docker를 배웠던 기억을 되살려

Terminal 환경에서 띄워보려고 homebrewDocker 를 설치

$ brew install docker docker-compose

해당 명령어로 설치한 후 docker-compose 로 실행을 하면?

$ docker-compose -f docker-compose.yml build

wow

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

바로 에러 뿜뿜

이렇게 실행하려면 Docker Desktop 을 대체할 만한 친구 (colima) 와 추가 설정이 필요하다.

(추가 설정을 진행하지 않으면 빌드 시 프로세스 중간에 에러를 내뿜는다.)

그리고 어차피 Docker Desktop 를 설치하면 GUI 뿐만 아니라 커맨드 라인에서도 사용할 수 있도록 지원하기 때문에

맥에서 Docker 를 사용하려고 한다면 Docker Desktop 을 설치하도록 하자.

스냅과의 사투

Docker Desktop 으로 1차 위기를 극복한 인피덕

이번엔 react-snap 라이브러리가 발목을 잡고 말았다.

이 프로젝트는 React 를 사용해서 만든 프로젝트로, 스냅을 사용해서 SEO 를 지원하고 있었는데… 제발요

$ react-snap
Error: Failed to launch chrome!
rosetta error: failed to open elf at /lib64/ld-linux-x86-64.so.2

이건 무슨 에러일까

Docker Desktop 설정?

이리저리 질문 폭탄을 던져본 인피덕

Docker Desktoprosetta 관련 설정이 있다고 해서 찾아봤는데

Docker_Desktop_Rosetta

이미 체크가 된 상태라서 PASS

스냅 설정? pupppeter?

react-snap 라이브러리의 Github 을 참고해 봤을 때, puppeteer 관련 설정하는 부분이 있어 확인해 봤다.

하지만.. 해당 글에 있는 대로 .Dockerfile 을 변경해 봐도 소용이 없었다.

아래 코드는 해당 글에 있던 .Dockerfile 의 예시이다.

# .Dockerfile

FROM node:14-slim

# Install latest chrome dev package and fonts to support major charsets (Chinese, Japanese, Arabic, Hebrew, Thai and a few others)
# Note: this installs the necessary libs to make the bundled version of Chromium that Puppeteer
# installs, work.
RUN apt-get update \
    && apt-get install -y wget gnupg \
    && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
    && sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
    && apt-get update \
    && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
      --no-install-recommends \
    && rm -rf /var/lib/apt/lists/*

# If running Docker >= 1.13.0 use docker run's --init arg to reap zombie processes, otherwise
# uncomment the following lines to have `dumb-init` as PID 1
# ADD https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_x86_64 /usr/local/bin/dumb-init
# RUN chmod +x /usr/local/bin/dumb-init
# ENTRYPOINT ["dumb-init", "--"]

# Uncomment to skip the chromium download when installing puppeteer. If you do,
# you'll need to launch puppeteer with:
#     browser.launch({executablePath: 'google-chrome-stable'})
# ENV PUPPETEER_SKIP_DOWNLOAD true

# Install puppeteer so it's available in the container.
RUN npm init -y &&  \
    npm i puppeteer \
    # Add user so we don't need --no-sandbox.
    # same layer as npm install to keep re-chowned files from using up several hundred MBs more space
    && groupadd -r pptruser && useradd -r -g pptruser -G audio,video pptruser \
    && mkdir -p /home/pptruser/Downloads \
    && chown -R pptruser:pptruser /home/pptruser \
    && chown -R pptruser:pptruser /node_modules \
    && chown -R pptruser:pptruser /package.json \
    && chown -R pptruser:pptruser /package-lock.json

# Run everything after as non-privileged user.
USER pptruser

CMD ["google-chrome-stable"]

올라와 있는 도커 이미지를 사용하자!

팀장님께서 이슈를 확인하시다가 그냥 있는 거 쓰자! 하고 알려주신 방법

DockerChromium, Node 등등이 설치된 이미지를 받아서 빌드

# .Dockerfile_최종_진짜_최종

FROM shivjm/node-chromium:node16-chromium119-alpine as build

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1\ # Chromium 설치 건너뛰기
    PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser # path 설정

WORKDIR /infiduk

COPY package.json yarn.lock /infiduk/
RUN yarn
ADD . /infiduk/

ARG server
RUN yarn build:${server}

아직 끝나지 않은 에러

팀장님께서는 위의 방법으로 성공했다고 하셨는데 내 맥에서는 계속 rosetta 에러가 발생했다.

에러의 /lib64/ld-linux-x86-64.so.2 이 부분을 봤을 때

뭔가 환경이 안 맞을 거 같다는 생각이 든 인피덕

구글링 결과 M1 을 사용하는 경우 .yml 파일에 platform 부분을 추가해 주라는 글을 발견

# docker-compose_최종_이것도_진짜_최종.yml

services:
  프로젝트명:
    image: 프로젝트명:네트워크_구분_값
    platform: linux/amd64 # 이 부분 추가
    build:
      context: ./
      dockerfile: .Dockerfile
      args:
        - server=네트워크_구분_값
    ports:
      - "외부_포트_번호:내부_포트_번호"

그리고 다시 docker-compose 명령어로 빌드하면?

대 성 공

결론

같은 코드라도 안 된다면 분명 어딘가에 이유는 있다.

M1과 Docker Compose가 싸우면 누가 이겨? 결국 내가 이겨

추가 정보

.yml 파일에 명시한 versiondocker-compose v2.25.0 이상부터 필수 값이 아니기 때문에 삭제해 주는 게 좋다.

참고

이 글의 저작권은 Attribution-NonCommercial 4.0 International 라이센스를 따릅니다. Attribution-NonCommercial 4.0 International