Docker로 Elixir Phoenix 앱 배포

· by 박승재

엘릭서(Elixir)는 얼랭(Erlang)VM에서 동작하는 함수형/동시성 프로그래밍 언어입니다.

피닉스(Phoenix)는 엘릭서(Elixir)로 작성된 MVC 웹 프레임워크로, Ruby on Rails와 Django를 사용했다면 구조가 비슷해 쉽게 입문할 수 있습니다.

엘릭서에서는 mix release를 이용해 독립적인(self-contained) 앱으로 컴파일할 수 있습니다.

도커(Docker)는 컨테이너라는 가상 실행 환경 위에서 사용자의 코드를 실행할 수 있는 가상화 기술로, 도커를 이용해 엘릭서 앱을 배포해보겠습니다.

Dockerfile

도커에서는 이미 공식적으로 엘릭서 이미지를 제공하기 때문에 이것을 가져다 사용하면 됩니다.

# syntax=docker/dockerfile:1
FROM elixir:alpine AS build

저장 공간을 줄이기 위해 alpine 이미지를 이용했습니다.

참고: 효율적인 도커 이미지 만들기

WORKDIR /usr/src/app_name

ENV MIX_ENV prod

빌드 환경의 기초가 되는 WORKDIR과 환경변수(MIX_ENV=prod)를 정의합니다.

RUN mix do local.hex --force, local.rebar --force

그리고 Hexrebar을 설치합니다.

도커의 레이어 캐시를 활용하기 위해, mix do로 하나의 RUN 안에 넣어줍니다.

COPY mix.exs mix.lock ./

RUN mix do deps.get, deps.compile

의존성 파일을 복사하고, 의존성을 가져와 컴파일합니다.

만약 애셋(assets) 파일이 존재한다면 의존성을 가져온 이후에, 애셋 파일을 빌드합니다. (레이어 캐시를 활용하기 위해)

COPY assets assets

RUN npm ... && \
    mix phx.digest

mix phx.digest정적 파일을 압축하는 명령입니다.

참고: Phoenix - mix phx.digest

COPY . .

RUN mix do compile, release

나머지 파일을 복사하고 컴파일 후 릴리즈를 생성합니다.

여기서 바로 bin/app start를 해도 되지만, 도커의 Mutli-stage 빌드를 이용하면 더 작은 용량으로 Dockerfile을 최적화할 수 있습니다.

참고: Docker Multi-stage build

FROM alpine:3.14

WORKDIR /usr/local

이후, 필요한 라이브러리를 설치하고 서울 시간대로 설정합니다.

참고: Debian과 Ubuntu에서 Locale과 Timezone 설정하기

RUN apk add --no-cache ncurses-libs tzdata
ENV TZ Asia/Seoul

ncurses-libs는 릴리즈 앱 실행에 필요한 libncursesw.so를 사용하기 위해 설치합니다.

COPY --from=build /usr/src/app_name/_build/prod/rel/app_name .

EXPOSE 3000
CMD ["bin/app_name", "start"]

COPY로 빌드 이미지에서 빌드한 릴리즈 앱을 가져옵니다.

EXPOSE에는 피닉스 앱에서 사용하는 포트를 작성합니다.

마지막으로 CMD를 이용해 엘릭서 앱을 실행합니다.

지금까지의 코드를 정리하면 아래와 같습니다.

Dockerfile:

# syntax=docker/dockerfile:1
FROM elixir:alpine AS build

WORKDIR /usr/src/app_name

ENV MIX_ENV prod

RUN mix do local.hex --force, local.rebar --force

COPY mix.exs mix.lock ./

RUN mix do deps.get, deps.compile

COPY . .

RUN mix do compile, release

FROM alpine:3.14

WORKDIR /usr/local

RUN apk add --no-cache ncurses-libs tzdata
ENV TZ Asia/Seoul

COPY --from=build /usr/src/app_name/_build/prod/rel/app_name .

EXPOSE 3000
CMD ["bin/app_name", "start"]

참고: Phoenix - Deploying with Releases