Dockerfile
📃Dockerfile
dockerfile
(不区分大小写)是镜像配置的入口,相当于每次我们使用构件镜像时(docker build
)都需要准备一份dockerfile
,docker
根据文件内的指令一条一条的执行,最终生成镜像
- 多阶段构建:创建镜像的过程中,每执行一行关键字都相当于新建一个数据镜像层。最终输出中,我们可以将一些做准备的层,安装软件的层都抛弃,只保留最终软件安装成后的层,确保最终镜像的最小化。
必要流程
- 指定环境的时区,在dockerfile中定义,可以确保所有平台兼容
ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
基础流程
# 使用当前目录下的 dockerfile 生成容器
# 一般吗建议添加 -t 参数指定 tagName,否则创建的对象会是一个None对象
docker build . -t name
docker build -t adobe-test .
# 运行容器,同时赋予一个tag 前台
docer run -it --name adobe-test-api -d
# 运行容器,同时赋予一个tag 后台
docer run -it --name adobe-test-api -d
# 默认采用的是bridge模块,可能会无法访问
docker run -it --name adobe-test-api -p 4040:4040 -d adobe-test
# 使用host模块
docker run -it --net host --name adobe-test-api -d adobe-test
# 返回一个容器的id
9d8d4e0774396ed7cf7043378adxxxxxx
# 通过id进入容器
docker exec -it {容器di} /bin/bash
常用关键字
关键字 | 说明 | 特性 |
---|---|---|
FROM | 引用镜像 | 多阶段构建 |
WORKDIR | 工作目录(镜像内) | |
COPY | 从外部复制文件到镜像 | |
RUN | 镜像内执行命令 | |
CMD | 每次执行镜像时运行的命令 | |
MAINTAINER | ||
EXPOSE | 指定端口和协议 ,一般使用更灵活的docker -p 代替 | |
ENV | 给镜像设置环境变量 | |
ADD | ||
ENTRYPOINT | ||
VOLUME | ||
USER | 指定镜像内使用什么用户运行指令 | |
ONBUILD | ||
ARG | 添加build时可以外部提供的动态参数 |
加粗的指令是最常用的,加星牢记
From
- 必须是
dockerfile
的首个命令 - 基于哪个镜像文件
- 配合
as
关键字多阶段构建,(或者默认第一个FROM为索引0)
VOLUME
Volume指令的主要作用是指定一个映射卷,既直接将宿主系统下的目录映射到镜像内,保证了数据不需要存储到镜像,且多个镜像能访问同一个卷,保证了数据的唯一性。
# 声明了镜像内的两个目录是挂载目录
# docker会自动在宿主系统创建挂载点
# 需要自由指定挂载点的话,需要使用Docker-Cpompose或者docker run命令
VOLUME ["/xxxx", "/ddddd"]
通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的
- 镜像间共享挂载点
# 镜像共享卷
docker run --name xxx -it --volumes-from {关联镜像} image:tag command
通过 run 指定映射
通过
run
指定的挂载设置会覆盖镜像原本的设置,所以建议所有卷挂载都使用run
命令来指定
# 通过 run 命令设置
docker run --name xxx -it -v {宿主路径}:{镜像路径} image:tag command
- 查看挂载点信息
docker inspect {imageName}
"Mounts": [
{
"Name": "0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01",
"Source": "/var/lib/docker/volumes/0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true
}
// Destination
// 镜像挂载的目录
// Source
// 绑定在宿主机的目录
制作专门共享卷的镜像作为中转
多个容器要共享数据的时候,可以先制作出一个专门保存挂载信息的数据容器,其他容器使用
--volumes-from {}
来共享关联这个数据容器,只需要维护一份dockerfile
因为容器的卷本质上对应主机上的目录,所以这个数据容器也不需要启动。
尽量使用 docker-compose 来应付这种需要共享数据的场合
WORKDIR
- 切换镜像内的工作目录,如果目录不存在会自动创建
WORKDIR {镜像路径}
WORKDIR /src/app # 等价于 RUN mkdir -p /src/app && cd /src/app
COPY
- 从外部复制文件到镜像内
COPY {本地路径} {镜像路径}
COPY . . # 复制当前文件夹下的所有内容到 workdir
ADD
详细规则:https://www.cnblogs.com/zdz8207/p/linux-docker-add-copy.html
- 可以外部复制文件到镜像内
- 可直接从网络路径下载文件到镜像内,但会新建多层,需配合多阶段构建使用
- 通过复制的文件,会被自动加压
- 任何URL形式下载的压缩包都不会自动解压
- 目标目录使用 "/" 结尾,ADD会将目标识别为目录,如果不存在, 则自动创建
RUN
- 在镜像内执行
shell
命令 - 每执行一次
RUN
指令都会新建一个数据层,可以将多个指令合并在同一个RUN
# shell格式
RUN <command>
#或者
# exec格式
# exce默认不调用shell,所以需要指定shell,否则对应用户的环境变量不会生效
RUN ["/bin/bash", "-c", "echo", "$HOME"]
- 多条命令执行写法
# 保证同一层使用同一个缓存文件
RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
注意:
apt-get update 等更新语句不应在单行RUN指令内执行,应使用
&&
添加后续操作,这样可以更好的使用缓存
注意:
避免单单使用全局的包更新指令,建议指定安装最新版的包来实现更新
不建议:
apt-get update
建议:
apt-get install -y xxx包名
CMD
- 外部通过
docker run
启动镜像的时候运行的命令 - 多条CMD指令时,只有最后一条会被执行
# shell格式
CMD node app.js -p
# exec执行
CMD ["node", "app.js", '-p']
# 配合ENTRYPOIN指令使用
CMD ["param1", "param2"]
ENTRYPOINT
USER
- 指定一个或多个用户来运行指令,用户存在与镜像内
FROM python:3.7.5-slim
# 镜像内新建用户
RUN net user /add python375
# 镜像内使用该用户
USER python375
ENV
- 添加环境变量到镜像
# 声明
ENV PYTHON_PATH="github.com/lattecake/hello"
# 使用
RUN mkdir -p /go/src/${GITPATH}
ARG
ARG TEST
docker build -t yibu-mongo -f ./dockerfile-mongodb . --build-arg TEST=123
ARG指令需要再FROM指令后面才能正常使用,
🌟参考文献
🌰 常用方案
python + fastapi 环境
FROM python:3.10.2-slim as base
WORKDIR /temp
COPY requirements.txt .
RUN pip install --upgrade pip && \
pip install -r requirements.txt
FROM python:3.10.2-slim
WORKDIR /app
COPY --from=base /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
COPY . .
RUN python -V
WORKDIR /app/src
CMD ["python", "main.py"]
echo "\
FROM python:3.10.2-slim as base
WORKDIR /temp
COPY requirements.txt .
RUN pip install --upgrade pip -i https://mirrors.aliyun.com/pypi/simple/ && \
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
FROM python:3.10.2-slim
WORKDIR /app
COPY --from=base /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
RUN python -V
WORKDIR /app/src
CMD [\"python\", \"-V\"]
" > Dockerfile
- build
docker build -f dockerfile-server -t fastapi-image:base .
- run
docker run -d -p 0.0.0.0:4040:4040 --net=psd-tools --name psd-tools-test psd-tools-image:v1 python main.py
- create
docker run -d -p 0.0.0.0:4040:4040 --net=psd-tools --name psd-tools-v1 psd-tools-image:v1 /bin/bash
- 优化版(国内)
# 先构建fastapi的环境
echo "\
FROM python:3.10.2-slim
WORKDIR /temp
COPY requirements.txt .
RUN pip install --upgrade pip -i https://mirrors.aliyun.com/pypi/simple/ && \
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
RUN python -V
CMD [\"python\", \"-v\"]
" > Dockerfile_base
docker build -t fastapi-image:base -f ./Dockerfile_base .
# 基于环境构建项目
echo "\
FROM fastapi-image:base as base
COPY --from=base /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
WORKDIR /app
COPY . .
CMD [\"python\", \"-v\"]
" > Dockerfile_project
docker build -t fastapi-psd-tools:v1 -f ./Dockerfile_project .
echo "\
FROM python:3.10.2-slim as base
WORKDIR /temp
COPY requirements.txt .
RUN pip install --upgrade pip && \
pip install -r requirements.txt
FROM python:3.10.2-slim
WORKDIR /app
COPY --from=base /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages
COPY . .
RUN python -V
WORKDIR /app/src
CMD [\"python\", \"test.py\"]
" > Dockerfile
docker build -t fastapi-image:base .
docker run -it --name fastapi-test fastapi-image:base python
python3.7.5 + nodejs12.4.0
参考资料:https://juejin.cn/post/6844903870439620622
docker build -f <dockerfile名称> -t <新镜像名称>
docker build --no-cache -t yibuwx-app-test .
docker build -t yibuwx-egg .
docker run -it --network wxyibu --ip 172.25.0.100 -p 7001:7001 yibuwx-egg:latest /bin/bash
docker cp /home/test/Project/app/docker/app-admin/code_test/config/config.default.js 9d3af7b442d9:/app/server-eggjs/config/config.default.js
- 传统构建
FROM python:3.7.5-slim AS base
LABEL maintainer="capsion@qq373704015"
WORKDIR /temp
ADD ./pngquant-linux.tar.bz2 /temp
################################# 部署python3.7.5 #####################################
# 复制python依赖列表
COPY ./requirements.txt .
# 安装python要用到的包
RUN pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/
################################# 部署nodejs #####################################
# 在线下载
# ADD http://nodejs.org/dist/v12.4.0/node-v12.4.0-linux-x64.tar.gz .
# 离线安装
ENV NODE_TAR=node-v12.4.0-linux-x64
COPY ./${NODE_TAR}.tar.gz .
# 使用ADD指令下载远程压缩文件,不会触发自动解压功能
ADD ./$NODE_TAR.tar.gz /temp
ENV PATH=$PATH:/temp/${NODE_TAR}/bin
COPY ./package.json .
RUN npm config set registry https://registry.npmmirror.com
RUN npm i --unsafe-perm=true
FROM python:3.7.5-slim
ENV NODE_TAR=node-v12.4.0-linux-x64
WORKDIR /app
# 复制解压好的node
COPY --from=base /temp/${NODE_TAR} /app/${NODE_TAR}
COPY --from=base /temp/node_modules /app/server-eggjs/node_modules
# 复制安装好的py包
COPY --from=base /usr/local/lib/python3.7/site-packages /usr/local/lib/python3.7/site-packages
# 复制pngquant
COPY --from=base /temp/pngquant /app/bin/pngquant
# 添加node环境变量
ENV PATH=$PATH:/app/${NODE_TAR}/bin:/app/bin
RUN python -V
RUN node -v
CMD ["/bin/bash"]
- 多阶段构建
FROM python:3.7.5-slim AS base
MAINTAINER capsion@qq373704015
WORKDIR /temp
# 复制python依赖列表
COPY ./requirements.txt .
# 下载nodejs
ADD http://nodejs.org/dist/v12.4.0/node-v12.4.0-linux-x64.tar.gz .
# 使用ADD指令下载远程压缩文件,不会触发自动解压功能
RUN tar -zxvf node-v12.4.0-linux-x64.tar.gz -C /opt && \
ENV PATH=$PATH:/opt/node-v12.4.0-linux-x64/bin
RUN npm install
# 安装python要用到的包
RUN pip install -r requirements.txt -i https://pypi.douban.com/simple/
FROM python:3.7.5-slim
WORKDIR /app
# 复制解压好的node
COPY --from=base /opt/node-v12.4.0-linux-x64 /app/node-v12.4.0-linux-x64
COPY --from=base /temp/node_modules /app/core/node_modules
# 复制安装好的py包
COPY --from=base /usr/local/lib/python3.7/site-packages /usr/local/lib/python3.7/site-packages
# 添加node环境变量
ENV PATH=$PATH:/opt/node-v12.4.0-linux-x64/bin
RUN python --version && node -v && npm -v
CMD ["/bin/bash"]
# 使用apt安装nodejs
# 修改apt源 => 安装wget => 下载node压缩包
# 使用gz而不使用xz因为xz需要另外安装xz解压依赖,apt安装并不容易,所以改用gz
# RUN echo "" > /etc/apt/sources.list && \
# echo "deb http://mirrors.ustc.edu.cn/debian stable main contrib non-free" >> /etc/apt/sources.list && \
# echo "deb http://mirrors.ustc.edu.cn/debian stable-updates main contrib non-free" >> /etc/apt/sources.list && \
# apt-get update && \
# apt-get install wget -y && \
# wget http://nodejs.org/dist/v12.4.0/node-v12.4.0-linux-x64.tar.gz && \
# tar -zxvf node-v12.4.0-linux-x64.tar.gz -C /opt/ && \
调试
pngquant 环境搭建
echo "\
# syntax=docker/dockerfile:1
FROM alpine:latest
# 作者信息
MAINTAINER capsion@qq373704015
ENV username=\"pngquant\"
RUN set -eux && \
sed -i s/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g /etc/apk/repositories && \
apk add --no-cache pngquant
COPY entrypoint.sh /
RUN chmod +x /entrypoint.sh
ENTRYPOINT [\"/entrypoint.sh\"]
CMD [\"--help\"]
" > dockerfile
nginx
参考文献:官方文档
在docker部署nginx采用官方基础镜像+自定义配置文件,基本可以满足大部分中小项目场景需求,所以了解和学习官方镜像使用也非常重要
# 使用alpine版本
FROM nginx:1.21.4-alpine
MAINTAINER capsion@qq373704015
# 复制 ssl文件和配置文件到镜像内
# 外部指定配置文件比较灵活
# COPY . .
# 添加 daemon off 关闭后台启动,docker需要一个前台程序
CMD ["nginx" "-c" "/etc/nginx/nginx.conf" "-g" "daemon" "off"]
# 运行
docker run --name xxxx-nginx-container -d nginx
docker run --name xxxx-nginx-container -d nginx -v xxxx:/etc/nginx/nginx.conf -p 80:80
如果使用自定义的.conf配置文件,需要把后台运行关闭,使用前台模式运行
-g daemon off
,不然的容器无法启动。
动态环境变量 (> =1.19 的官方镜像)
- 🐙 docker-compose.yml 映射 .templates 文件夹
web:
image: nginx:1.21.4-alpine
# 添加templates文件夹的映射,可以在这个文件夹存放我们的变量文件
# templates 目录下存在 *.template
volumes:
- ./templates:/etc/nginx/templates
ports:
- "8080:80"
environment:
- NGINX_HOST=foobar.com
- NGINX_PORT=80
准备 *.template
准备模板文件,且内容是对应需要替换的变量
listen ${NGINX_PORT};
输出
最终输出在镜像内的配置文件会:
listen 80;
- 还可以通过修改变量改变镜像内 templates 文件夹
只读模式
使用 --read-only
模式运行,需要确保nginx
映射以下目录:
# 这两个目录是ngxin基础要求的写目录
-v $(pwd)/nginx-cache:/var/cache/nginx
-v $(pwd)/nginx-pid:/var/run nginx
redis
FROM redis:6.0.9-alpine
COPY redis.conf /redis/redis.conf
COPY dump.rdb /redis/data
CMD [ "redis-server", "/redis/redis.conf" ]
docker
run
--name myredis
redis:6.0.9
redis-server /usr/local/etc/redis/redis.conf
docker pull redis:6.0.9-alpine
mongodb
事前准备
# 创建目录
使用镜像:docker.io/mongo4.4
docker pull
# 使用 MongoDB 4.4 镜像作为基础镜像
FROM mongo:4.4
# 使用变量来定义 MongoDB 配置参数
ARG MONGO_INITDB_ROOT_USERNAME=hongqi
ARG MONGO_INITDB_ROOT_PASSWORD=HI.123
ARG MONGO_PORT=27017
ARG MONGO_LOG_DIR=/var/log/mongodb
ARG MONGO_DATA_DIR=/data/db
# 创建 MongoDB 数据目录和日志目录
RUN mkdir -p ${MONGO_DATA_DIR} ${MONGO_LOG_DIR} \
&& chown -R mongodb:mongodb ${MONGO_DATA_DIR} ${MONGO_LOG_DIR}
# 创建一个初始化脚本,该脚本会在 MongoDB 首次启动时运行
COPY init-mongo.js /docker-entrypoint-initdb.d/
# 设置容器启动时执行的命令
CMD ["mongod"]
# 初始化脚本内容
RUN echo "Waiting for MongoDB to start..."
RUN echo "db.createUser({user: '${MONGO_INITDB_ROOT_USERNAME}', pwd: '${MONGO_INITDB_ROOT_PASSWORD}', roles: [{role: 'root', db: 'admin'}]});" > /docker-entrypoint-initdb.d/init-mongo.js \
&& chmod +x /docker-entrypoint-initdb.d/init-mongo.js
# 确保 MongoDB 容器在启动时执行初始化脚本
RUN chmod 0755 /docker-entrypoint-initdb.d/init-mongo.js
# 暴露 MongoDB 端口
EXPOSE ${MONGO_PORT}
# 构建镜像
docker build -t my-mongo:4.4 .
docker build -t yibu-mongo -f ./dockerfile-mongodb
# 运行容器
docker run -d --name my-mongo -p ${MONGO_PORT}:${MONGO_PORT} my-mongo:4.4