Dockerfile
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明,支持以#注释。Dockerfile由一行行命令语句组成。docker是按顺序执行dockerfile里的指令,每一个dockerfile的第一个非注释行的指令,必须是FROM指令,用于为文件构建过程中指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境中。实践中,基准镜像可以是任何课用的镜像文件,默认情况下,docker不存在时,则会从docker registry(远端)上拉去镜像文件
指令
| 指令 | 说明 | 示例 |
|---|---|---|
| FROM | 指定基础镜像 | FROM ubuntu:20.04 |
| RUN | 执行命令(构建时) | RUN apt-get update && apt-get install -y python3 |
| COPY | 复制本地文件到镜像 | COPY ./app /app |
| ADD | 类似 COPY,支持 URL 和解压 | ADD https://example.com/file.tar.gz /tmp/ |
| WORKDIR | 设置工作目录 | WORKDIR /app |
| ENV | 设置环境变量 | ENV PYTHON_VERSION=3.8 |
| ARG | 定义构建时变量(构建后可被覆盖) | ARG VERSION=latest |
| EXPOSE | 声明容器运行时监听的端口(不实际发布) | EXPOSE 8080 |
| CMD | 容器启动时的默认命令(可被覆盖) | CMD ["python3", "app.py"] |
| ENTRYPOINT | 容器启动时的主要命令(不易被覆盖) | ENTRYPOINT ["python3"] |
| VOLUME | 创建挂载点 | VOLUME /data |
| USER | 指定运行命令的用户 | USER appuser |
| LABEL | 添加元数据 | LABEL maintainer="dev@example.com" |
| HEALTHCHECK | 定义容器健康检查 | `HEALTHCHECK --interval=30s CMD curl -f http://localhost/ |
| ONBUILD | 设置当本镜像被用作基础镜像时执行的指令 | ONBUILD COPY . /app |
| STOPSIGNAL | 设置停止容器时发送的系统信号 | STOPSIGNAL SIGTERM |
| SHELL | 覆盖默认的 shell | SHELL ["/bin/bash", "-c"] |
Dockerfile基本用法
dockerfile
FROM alpine
WORKDIR /
LABEL kevinchen
RUN apk add httpd
EXPOSE 80
ENTRYPOINT ["nginx"]
#FROM:定制的镜像都是基于FROM 的镜像,这里的 ngi需要的基础镜像。后续的操作都是基于 nginx。
#RUN:用于执行后面跟着的命令行命令。
#COPY 复制指令,从上下文目录中复制文件或者目录到容器里指定路径
#ADD 指令和 COPY 的使用格式一致.不同之处如下:
#ADD 的优点:在执行 <源文件> 为tar压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
#ADD 的缺点:在不解压的前提下,无法复制 tar 压令镜像构建缓存失效,从而可能会令镜像构建变得构建
bash
# 基本构建
docker build -t myapp:latest .
# 指定Dockerfile
docker build -t myapp -f dockerfiles/Dockerfile.prod .镜像优化
基础镜像优化
dockerfile
# 不推荐 - 过大
FROM ubuntu:latest
# 推荐 - 轻量级
FROM alpine:3.14
# 或
FROM debian:buster-slim
# 或
FROM gcr.io/distroless/static多阶段构建
dockerfile
# 第一阶段:构建环境。可以是基础运行环境如编译安装Nginx等。
FROM golang:1.16 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# 第二阶段:运行环境
FROM alpine:3.14
WORKDIR /app
# 引入第一阶段基础环境
COPY --from=builder /app/myapp .
CMD ["./myapp"]构建过程优化
dockerfile
# 合并 RUN 指令
RUN apt-get update && \
apt-get install -y package1 package2 && \
rm -rf /var/lib/apt/lists/*
# 不常变化的放前面
COPY package.json .
RUN npm install
# 常变化的放后面
COPY . .
# 清理不必要的文件
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
&& \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# 删除缓存和临时文件
RUN npm install && \
npm cache clean --force安全优化
dockerfile
# 使用非 root 用户
RUN addgroup -S appgroup && \
adduser -S appuser -G appgroup
USER appuser扫描镜像漏洞
bash
docker scan <image-name>排除不需要的文件
.dockerignore 文件用于在构建 Docker 镜像时,指定哪些文件和目录应当被排除在镜像之外。它类似于 .gitignore 文件的作用,用来控制哪些文件不应被包含在 Docker 镜像中,从而减少镜像的大小,提高构建效率,并避免不必要的文件暴露。
tex
node_modules
.git
*.log
Dockerfile
.dockerignore经典案例
构建Nginx镜像
配置文件
nginx.conf
ini
worker_processes auto;
worker_rlimit_nofile 65535;
worker_cpu_affinity auto;
events {
worker_connections 1024;
use epoll;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_iso8601] '
'"$request_method $request_uri $server_protocol" '
'$status $body_bytes_sent $request_length '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct=$upstream_connect_time '
'uht=$upstream_header_time urt=$upstream_response_time '
'upstream=$upstream_addr upstream_status=$upstream_status '
'host=$host conn=$connection req=$connection_requests';
sendfile on;
keepalive_timeout 65;
client_header_timeout 20;
client_body_timeout 20;
server_tokens off;
gzip on;
gzip_types text/plain text/javascript application/x-javascrip t text/css text/xml application/xml application/xml+rss;
include conf.d/*.conf;
}conf.d/www.conf
ini
server {
listen 80;
server_name example.com www.example.com;
root /data/wwwroot/www;
index index.html;
location / {
try_files $uri $uri/ /index.html;
error_page 404 /404.html;
error_page 403 /404.html;
}
location ~ \.(css|js|gif|jpg|jpeg|png|bmp|ico)$ {
proxy_cache_valid 200 304 1h;
proxy_cache_valid 404 1m;
expires 3h;
}
}多阶段构建
dockerfile
FROM alpine:3.22.0 AS nginx-base
LABEL AUTHER="kevinchen"
# 设置变量
ENV NGINX_VERSION=1.26.3
ARG CONFIG="\
--prefix=/usr/local/nginx \
--conf-path=/usr/local/nginx/conf/nginx.conf \
--sbin-path=/usr/local/nginx/sbin/nginx \
--error-log-path=/usr/local/nginx/logs/error.log \
--http-log-path=/usr/local/nginx/logs/access.log \
--user=www \
--group=www \
--with-http_ssl_module \
--with-http_realip_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_mp4_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_random_index_module \
--with-http_secure_link_module \
--with-http_stub_status_module \
--with-http_auth_request_module \
--with-http_xslt_module=dynamic \
--with-http_image_filter_module=dynamic \
--with-http_geoip_module=dynamic \
--with-threads \
--with-stream \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-stream_realip_module \
--with-stream_geoip_module=dynamic \
--with-http_slice_module \
--with-mail \
--with-mail_ssl_module \
--with-compat \
--with-file-aio \
--with-http_v2_module \
"
# 编译安装
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
apk update && apk upgrade && apk add --no-cache \
build-base \
linux-headers \
pcre-dev \
zlib-dev \
openssl-dev \
libxml2-dev \
libxslt-dev \
gd-dev \
geoip-dev \
wget \
tar && \
wget https://nginx.org/download/nginx-$NGINX_VERSION.tar.gz -O nginx.tar.gz && \
tar -zxf nginx.tar.gz && \
rm -f nginx.tar.gz && \
cd nginx-$NGINX_VERSION && \
./configure $CONFIG --with-debug && \
make -j$(getconf _NPROCESSORS_ONLN) && \
make install && \
rm -rf /nginx-$NGINX_VERSION && \
rm -rf /var/cache/apk/*
COPY conf /usr/local/nginx/conf
# 第二阶段
FROM alpine:3.22.0
COPY --from=nginx-base /usr/local/nginx /usr/local/nginx
# COPY nginx.conf /usr/local/nginx/conf/nginx.conf
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && \
apk add --no-cache \
openssl-dev \
pcre-dev \
# libxml2-dev \
# libxslt-dev \
# gd-dev \
# geoip-dev \
zlib-dev && \
ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx && \
addgroup -S www && \
adduser -s /sbin/nologin -H -D -G www www && \
chown -R www:www /usr/local/nginx && \
rm -rf /var/cache/apk/* && \
mkdir -p /data/wwwroot/www && \
chown www:www /data/wwwroot/www
# 注意系统端口范围限制(1-999)
# USER www
WORKDIR /data/wwwroot/www
EXPOSE 80
CMD ["nginx","-g","daemon off;"]构建和运行命令
bash
# 构建镜像
docker build -t nginx-web:alpine-1.0.0 .
# 运行容器
docker run -d \
-p 8080:80 \
-v /path/to/your/html:/data/wwwroot/www \
--name my-nginx \
nginx-web:v1.0.1构建JDK镜像
Dockerfile
bash
cat > jdk-dockerfile << 'EOF'
FROM alpine:3.10
ARG JDK_VERSION=22.0.1
ADD https://download.java.net/java/GA/jdk${JDK_VERSION}/c7ec1332f7bb44aeba2eb341ae18aca4/8/GPL/openjdk-${JDK_VERSION}_linux-x64_bin.tar.gz /tmp/
RUN cd /tmp && \
tar xf openjdk-${JDK_VERSION}_linux-x64_bin.tar.gz -C /usr/local/ && \
ln -s /usr/local/jdk-${JDK_VERSION}/bin/* /usr/local/bin/ && \
rm -rf openjdk-${JDK_VERSION}_linux-x64_bin.tar.gz
ENV JAVA_HOME=/usr/local/jdk-${JDK_VERSION}
ENV JRE_HOME=${JAVA_HOME}/jre
ENV CLASSPATH=.:${JAVA_HOME}/lib
ENV JAVA_PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin
ENV PATH=$PATH:${JAVA_PATH}
ENV TZ=Asia/Shanghai
WORKDIR /app
EXPOSE 8080
EOF
docker build -t openjdk:alpine-1.0 -f jdk-dockerfile .多阶段构建
bash
# 构建阶段
FROM maven:3.6-openjdk-8 AS builder
WORKDIR /build
COPY . .
RUN mvn clean package -DskipTests
# 运行阶段
FROM openjdk:8-jdk-alpine
ENV TZ=Asia/Shanghai
RUN ln -sf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /app
COPY --from=builder /build/target/admin.jar app.jar
ENV JAVA_OPTS="-Xms512m -Xmx1024m -Djava.security.egd=file:/dev/./urandom"
EXPOSE 8001
CMD ["sh", "-c", "java $JAVA_OPTS -jar yshop-admin-3.3.jar --spring.profiles.active=docker"]