Skip to main content

5.Dockerfile

Dockerfile简介

Dockerfile 是一个文本文件,包含一系列用于自动化构建 Docker 镜像的指令和参数。通过编写 Dockerfile,你可以定义容器的环境、设置基础镜像、运行命令、复制文件等,从而创建一个自定义的 Docker 镜像。

常用命令

  • FROM: 指定基础镜像,构建的新镜像将基于该镜像。

    FROM ubuntu:20.04
  • MAINTAINER: 设置镜像的作者信息(已经不推荐使用,而是使用 LABEL 指令)。

    MAINTAINER Your Name <[email protected]>
  • LABEL: 设置镜像的元数据信息,比如维护者、版本等。

    LABEL maintainer="Your Name <[email protected]>"
  • RUN: 在镜像中运行命令,用于安装软件包、配置环境等。

    RUN apt-get update && apt-get install -y \
    package1 \
    package2
  • COPY: 将文件从主机复制到镜像中。

    COPY ./source /destination
  • ADD: 类似于 COPY,但还支持 URL 和解压缩功能。

    ADD ./source /destination
  • WORKDIR: 设置工作目录,后续命令将在这个目录下执行。

    WORKDIR /app
  • EXPOSE: 暴露容器运行时的端口。

    EXPOSE 80
  • CMD: 设置容器启动时执行的默认命令。

    CMD ["executable","param1","param2"]
  • ENTRYPOINT: 设置容器启动时执行的默认命令,并允许在运行容器时提供参数。

    ENTRYPOINT ["executable", "param1", "param2"]

示例文件:

# 使用 Node.js 14 作为基础镜像
FROM node:14

# 设置工作目录
WORKDIR /app

# 复制 package.json 和 package-lock.json 到工作目录
COPY package*.json ./

# 安装应用程序的依赖
RUN npm install

# 将当前目录下的所有文件复制到工作目录
COPY . .

# 暴露应用程序运行的端口
EXPOSE 3000

# 设置容器启动时执行的默认命令
CMD ["node", "app.js"]

最佳实践:

  1. 使用官方基础镜像: 尽量使用官方仓库提供的基础镜像,如 ubuntu, alpine, node, python 等。
  2. 合并 RUN 命令: 将多个 RUN 命令合并为一个,减少镜像层的数量,节省空间。
  3. 清理缓存: 在安装软件包后,使用 apt-get cleanyum clean all 来清理缓存,减小镜像大小。
  4. 指定标签版本:FROM 指令中指定版本,避免使用 latest,确保镜像的可重现性。
  5. 最小化层数: 尽量减少镜像的层数,以提高构建速度和减小镜像大小。
  6. 使用 .dockerignore: 在构建上下文目录中添加 .dockerignore 文件,避免不必要的文件被复制到镜像中。

Dockerfile打包过程

Docker 镜像的打包过程通常包括编写 Dockerfile、构建镜像、推送镜像到镜像仓库等步骤。

一般步骤

  • 编写 Dockerfile
  • 构建镜像
  • 查看构建的镜像
  • 推送到镜像仓库(可选)
  • 拉去镜像运行

以下创建一个 Node.js 应用演示

编写 Dockerfile

创建一个 Node.js 应用

在一个空白目录下创建一个简单的 Node.js 应用。我们假设有一个 app.js 文件,内容如下:

const http = require('http');

const server = http.createServer((req, res) => {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello, Docker!\n');
});

const PORT = 3000;
server.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});

创建 Dockerfile

在同一目录下创建一个名为 Dockerfile 的文件,内容如下:

# 使用 Node.js 14 作为基础镜像
FROM node:14

# 设置工作目录
WORKDIR /app

# 复制 package.json 和 package-lock.json 到工作目录
COPY package*.json ./

# 安装应用程序的依赖
RUN npm install

# 将当前目录下的所有文件复制到工作目录
COPY . .

# 暴露应用程序运行的端口
EXPOSE 3000

# 设置容器启动时执行的默认命令
CMD ["node", "app.js"]

构建 Docker 镜像

打开终端,进入到包含 app.jsDockerfile 的目录,执行以下命令:

docker build -t my-node-app:1.0 .

这将根据 Dockerfile 中的指令构建一个名为 my-node-app,标签为 1.0 的 Docker 镜像。

查看构建的镜像

执行以下命令查看构建的镜像:

docker images

找到你刚刚构建的 my-node-app 镜像,并记下其镜像 ID 或名称。

推送容器

一般都是同送到本地镜像,需要自己搭建本地仓库,搭建仓库操作此处略过。

docker push my-node-app:1.0

运行容器

使用以下命令在容器中运行应用程序:

docker run -p 3000:3000 my-node-app:1.0

这将启动一个容器,将容器的 3000 端口映射到主机的 3000 端口,并在容器中运行你的 Node.js 应用。

验证访问

打开浏览器,访问 http://localhost:3000,你应该能够看到应用程序返回的 "Hello, Docker!" 消息。

日志输出

当在生产环境中使用 Dockerfile 时,需要确保容器内的应用程序可以将日志输出到标准输出(stdout)或标准错误(stderr),以便 Docker 日志驱动程序能够捕获这些日志。

其效果是输入docker log命令可以查看到程序输出的日志,

如果程序无法直接输出到 stdout 或 stderr,可以考虑使用适当的工具来重定向程序的日志输出。例如,使用 docker run 命令的 -a stdout-a stderr 选项来将容器的 stdout 或 stderr 重定向到宿主机上的文件,然后使用其他工具来监视这些文件并将日志转发到 Docker 日志系统。

示例

Node.js示例

Node.js项目结构:

project/

├── Dockerfile
├── package.json # Node.js 应用程序的依赖和启动脚本
└── index.js # 应用程序的入口文件

dockerfile示例:

# 使用 Node.js 官方提供的 LTS 镜像作为基础镜像
FROM node:14-alpine

# 设置工作目录
WORKDIR /app

# 复制 package.json 和 package-lock.json(如果存在)到容器中
COPY package*.json ./

# 安装应用程序依赖
RUN npm install --production # 安装生产环境下的依赖

# 复制应用程序代码到容器中
COPY . .

# 最重要的部分:设置容器的启动命令
CMD ["node", "index.js"]
  • CMD 指令中,设置了容器的启动命令为 node index.js,这里假设 index.js 是应用程序的入口文件。关键在于,Node.js 应用程序通常会将日志输出到控制台,因此这样设置可以确保日志被输出到容器的 stdout,从而能够被 Docker 日志系统捕获。

Java示例

Java 程序中,可以使用标准的日志框架,如 Java Util Logging、Log4j、Logback 等,来将日志输出到控制台。

Java项目结构:

project/

├── Dockerfile
└── src/
└── Main.java # 主程序文件

Main.java 代码示例:

import java.util.logging.Logger;

public class Main {
// 获取 logger 实例
private static final Logger logger = Logger.getLogger(Main.class.getName());

public static void main(String[] args) {
logger.info("This is an info message");
logger.warning("This is a warning message");
logger.severe("This is a severe message");
}
}

Dockerfile示例:

# 使用 OpenJDK 官方提供的镜像作为基础镜像
FROM openjdk:14-alpine

# 设置工作目录
WORKDIR /app

# 复制编译后的 Java 类文件到容器中
COPY src/Main.class .

# 最重要的部分:设置容器的启动命令
CMD ["java", "Main"]

构建 Docker 镜像并运行容器:

docker build -t my-java-app .
docker run my-java-app

测试是否输出log:

docker logs xxxx

查看上面命令是否有日志输出。