使用Distillery项目构建Docker容器化Elixir应用指南
前言
在现代应用部署中,容器化技术已成为主流选择。本文将详细介绍如何利用Distillery项目为Elixir应用构建高效的Docker镜像,实现生产环境的容器化部署。
准备工作
在开始之前,请确保:
- 已熟悉Elixir应用的基本开发流程
- 了解如何使用Distillery构建发布包
- 系统已安装Docker环境
构建策略
我们采用多阶段构建策略,具有以下优势:
- 构建阶段:包含完整的编译环境
- 运行阶段:仅包含运行时必要组件
- 显著减小镜像体积
- 降低安全风险
Dockerfile详解
基础镜像选择
ARG ALPINE_VERSION=3.8
FROM elixir:1.7.2-alpine AS builder
我们选择Alpine Linux作为基础,因其轻量级特性。注意构建镜像和运行镜像的Alpine版本必须一致,确保运行时兼容性。
构建参数
ARG APP_NAME
ARG APP_VSN
ARG MIX_ENV=prod
ARG SKIP_PHOENIX=false
ARG PHOENIX_SUBDIR=.
这些参数允许灵活配置构建过程,特别是对于Phoenix应用和非Phoenix应用的处理。
构建阶段
-
安装依赖:
RUN apk update && \ apk add --no-cache \ nodejs \ yarn \ git \ build-base
-
获取项目依赖:
RUN mix do deps.get, deps.compile, compile
-
处理前端资源(Phoenix应用):
RUN if [ ! "$SKIP_PHOENIX" = "true" ]; then \ cd ${PHOENIX_SUBDIR}/assets && \ yarn install && \ yarn deploy && \ cd - && \ mix phx.digest; \ fi
-
构建发布包:
RUN \ mkdir -p /opt/built && \ mix distillery.release --verbose && \ cp _build/${MIX_ENV}/rel/${APP_NAME}/releases/${APP_VSN}/${APP_NAME}.tar.gz /opt/built
运行阶段
FROM alpine:${ALPINE_VERSION}
运行阶段仅包含必要组件:
- bash
- openssl-dev
关键配置:
ENV REPLACE_OS_VARS=true \
APP_NAME=${APP_NAME}
优化构建
.dockerignore文件
创建.dockerignore
文件排除不必要的文件:
_build/
deps/
.git/
.gitignore
Dockerfile
Makefile
README*
test/
priv/static/
Makefile自动化
推荐使用Makefile简化构建流程:
.PHONY: help
APP_NAME ?= `grep 'app:' mix.exs | sed -e 's/\[//g' -e 's/ //g' -e 's/app://' -e 's/[:,]//g'`
APP_VSN ?= `grep 'version:' mix.exs | cut -d '"' -f2`
BUILD ?= `git rev-parse --short HEAD`
help:
@echo "$(APP_NAME):$(APP_VSN)-$(BUILD)"
@perl -nle'print $& if m{^[a-zA-Z_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
build: ## 构建Docker镜像
docker build --build-arg APP_NAME=$(APP_NAME) \
--build-arg APP_VSN=$(APP_VSN) \
-t $(APP_NAME):$(APP_VSN)-$(BUILD) \
-t $(APP_NAME):latest .
run: ## 在Docker中运行应用
docker run --env-file config/docker.env \
--expose 4000 -p 4000:4000 \
--rm -it $(APP_NAME):latest
配置管理
推荐使用Distillery的配置提供器:
release :myapp do
set config_providers: [
{Distillery.Releases.Config.Providers.Elixir, ["${RELEASE_ROOT_DIR}/etc/config.exs"]}
]
set overlays: [
{:copy, "rel/config/config.exs", "etc/config.exs"}
]
end
配置文件示例:
use Mix.Config
config :myapp, MyApp.Repo,
username: System.get_env("DATABASE_USER"),
password: System.get_env("DATABASE_PASS"),
database: System.get_env("DATABASE_NAME"),
hostname: System.get_env("DATABASE_HOST")
config :myapp, MyApp.Endpoint,
http: [port: String.to_integer(System.get_env("PORT") || "8080")]
本地测试
环境变量配置
创建config/docker.env
文件:
HOSTNAME=localhost
SECRET_KEY_BASE="your_secret_key"
DATABASE_HOST=db
DATABASE_USER=postgres
DATABASE_PASS=postgres
DATABASE_NAME=myapp_db
PORT=4000
Docker Compose配置
创建docker-compose.yml
文件:
version: '3.5'
services:
web:
image: "myapp:latest"
ports:
- "80:4000"
env_file:
- config/docker.env
depends_on:
- db
db:
image: postgres:10-alpine
volumes:
- "./volumes/postgres:/var/lib/postgresql/data"
ports:
- "5432:5432"
env_file:
- config/docker.env
启动服务:
docker-compose up
生产部署建议
-
安全考虑:
- 避免在镜像中存储敏感信息
- 使用Docker secrets管理凭证
- 定期更新基础镜像
-
性能优化:
- 调整Erlang VM参数
- 合理配置连接池大小
- 监控系统资源使用情况
-
扩展性:
- 考虑使用Docker Swarm或Kubernetes编排
- 实现健康检查机制
- 配置日志聚合
常见问题解决
-
Makefile格式错误:
- 确保使用制表符而非空格
- 错误示例:
multiple target patterns
-
运行时依赖缺失:
- 确认构建和运行阶段使用相同的基础镜像版本
- 检查所有必要的系统库是否包含
-
配置不生效:
- 验证
REPLACE_OS_VARS
设置 - 检查配置文件路径是否正确
- 验证
通过本文的指导,您应该能够成功构建并部署容器化的Elixir应用。Distillery与Docker的结合为Elixir应用提供了高效、可靠的部署方案。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考