Dockerfile 实战指南:解锁高效容器化开发

news2024/12/27 16:10:55

一、Dockerfile 简介

Dockerfile 是构建镜像的文本文件,通过一系列指令描述镜像构建过程,构建操作由 Docker daemon 进行,它会先验证语法,然后逐一运行指令,每次生成一个新的镜像层,直到构建出最终的镜像。
Dockerfile 集成了构建镜像所需的全部步骤,从选择基础镜像到运行容器,极大地简化了应用程序的部署和环境配置流程。通过 Dockerfile,开发者可以实现自动化、可重复、一致的构建过程,这对于团队协作和持续集成 / 持续部署流程至关重要。
Docker 镜像是一个特殊的分层文件系统,包含应用程序和必要的依赖环境,但并不包含任何的动态信息。构建一个镜像,实际上就是为镜像中的每一层创建相应的配置。因此,可以把构建的命令语句、参数配置等信息都写入一个脚本中,这样,“docker commit” 命令的无法重复的问题、镜像臃肿的问题就都被解决了。这个脚本就是 Dockerfile。

(一)什么是 Dockerfile?

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。构建一个镜像,就是为镜像中的每一层创建相应的配置,而 Dockerfile 则是将这些配置信息以指令的形式记录下来。Dockerfile 可以使用 “docker build” 命令进行编译。在编译过程中,每一条指令的内容就是描述该层应如何进行构建。当我们需要定制自己额外的需求时,只需要在 Dockerfile 文件的基础上添加或者修改指令,重新生成新的镜像即可。

(二)Dockerfile 示例

下面通过一个简单的示例来演示如何使用 Dockerfile。在这个示例中,将基于 Nginx 的镜像来构建一个新的镜像,并在该镜像中部署一个简单的 Web 网页。

  1. 创建一个文件 “Dockerfile”。在该文件中输入以下命令。
FROM nginx
RUN echo '<h1>This is a Demo HTML</h1>' >/usr/share/nginx/html/index.html
  1. 在 Dockerfile 所在的目录下执行 “docker build” 命令构建镜像。构建的过程如下图所示。提示:“docker build” 命令会在当前目录下寻找名为 “Dockerfile” 的文件,然后对该文件进行编译生成镜像。如果文件名不是 Dockerfile,则可以在使用 “docker build” 命令加上 “-f” 参数指定文件名称。

  2. 查看新生成的镜像,如下图所示。

  3. 使用新生成的镜像创建容器。
    docker run -d -p 7788:80 mynginx

  4. 使用浏览器访问宿主机的 7788 端口,可以看到如下图所示界面。

(三)Docker File 文件详解

下图展示了 Docker 镜像、容器和 Dockerfile 三者的关系。可以看出使用 Dockerfile 文件定义镜像,然后运行镜像启动容器。下表列出了一个完整的 Dockerfile 文件的组成部分。当完成了 Dockerfile 的编写后,使用 “docker build” 命令将会根据 Dockerfile 中上下文的内容构建新 Docker 镜像。整个构建的过程会被递归处理。因此,如果在 Dockerfile 中含有子路径或 URL 等信息,则它们都将被递归进行构建。
提示:在使用 “docker build” 进程镜像构建时,还可以通过 “-t” 参数指定生成镜像的仓库地址和标签等信息。Dockerfile 构建镜像的过程请参考下图。“docker build” 命令在使用 Dockerfile 生成镜像时,会通过 Docker 的守护进程执行 Dockerfile 中的每一条指令,并在每一步执行完成后生成一个新镜像。当所有的指令执行完成后,会输出最终镜像的 ID。当镜像最终生成后,Docker 的守护进程会自动清理 Docker 的上下文环境,并自动重用已生成的中间镜像,以加速构建的速度。图中方框的部分表明,在构建过程中使用到了 Dockerfile 的缓存机制。

二、Dockerfile 关键字详解

1. FROM 关键字

指定基础镜像,新镜像是基于哪个镜像构建的,建议使用官方镜像作为基础镜像,如 Alpine,体积小且严格控制。在 Dockerfile 中,FROM指令必须作为第一个指令出现,它为后续的构建步骤提供了基础环境。例如:FROM ubuntu:20.04,这里指定了以 Ubuntu 20.04 版本的镜像作为基础镜像。

2. MAINTAINER/LABEL 关键字

MAINTAINER指定维护者信息,例如:MAINTAINER John Doe <john.doe@example.com>。但按照官方文档描述,MAINTAINER已逐渐过时,目前更推荐使用LABEL来设置元数据。
LABEL用于给镜像打标签,相对MAINTAINER更灵活。可以设置多个元数据,一个LABEL是键值对,多个键值对之间使用空格分开,命令换行时使用反斜杠\。例如:LABEL version="1.0" description="This is a demo image" by="Developer Name"

3. RUN 关键字

构建过程中运行的命令,有 shell 格式和 exec 格式两种。
shell 格式:RUN <command>,命令在 shell 中运行,默认情况下在 Linux 上是/bin/sh -c,在 Windows 上是cmd /S /C。例如:RUN apt-get update
exec 格式:RUN ["executable", "param1", "param2"]。例如:RUN ["npm", "install"]

4. WORKDIR 关键字

指定进入容器时的目录。使用WORKDIR可以设置容器内的工作目录,后续的指令将在这个目录下执行。例如:WORKDIR /app,如果目录不存在,会自动创建。

5. ENV 关键字

设置容器内环境变量,方便访问程序。通过ENV可以设置环境变量,这些变量在构建过程和容器运行时都有效。例如:ENV NODE_ENV production,在后续的指令中可以使用这个环境变量,如RUN echo $NODE_ENV

6. ADD 关键字

将宿主机资源拷贝进镜像中,会自动解压缩,还能从远程读取资源。ADD指令可以将宿主机上的文件或目录复制到镜像中。如果源是一个压缩文件,它会自动解压缩。例如:ADD myfile.tar.gz /app,会将myfile.tar.gz解压缩到容器的/app目录下。同时,ADD还支持从远程 URL 获取资源,例如:ADD http://example.com/file.txt /app,会从指定 URL 下载文件并复制到容器的/app目录。

7. COPY 关键字

将宿主机资源拷贝到镜像中,只支持读取构建所在宿主机资源,更透明。COPYADD功能类似,但不会自动解压缩文件,也不能从远程读取资源。例如:COPY myfile.txt /app,只会将宿主机上的myfile.txt复制到容器的/app目录。Docker 开发者推荐在满足同等功能的情况下,尽量使用COPY指令,以避免ADD指令可能带来的意外情况。

8. VOLUME 关键字

挂载数据卷,根据构建出来的镜像运行容器时,默认有构建时挂载信息。VOLUME指令用于在容器中创建一个数据卷,这个数据卷可以被多个容器共享,并且数据写入不会影响镜像层。例如:VOLUME /data,在容器运行时,可以将宿主机上的目录挂载到这个数据卷上,实现数据的持久化存储。

9. EXPOSE 关键字

指定运行容器时对外暴露的端口。EXPOSE指令用于指定容器在运行时要对外暴露的端口。例如:EXPOSE 8080,这只是声明了容器要暴露的端口,但要让外部能够访问这些端口,还需要在运行容器时使用-p参数进行端口映射。

10. CMD 关键字

指定启动容器时要执行的命令,只有最后一个会生效,创建容器时指定命令会覆盖 CMD 命令。CMD指令用于指定容器启动时默认执行的命令和参数。如果 Dockerfile 中有多个CMD指令,只有最后一个会生效。并且,在创建容器时,可以通过命令行参数覆盖CMD指定的命令。例如:CMD ["node", "app.js"],如果在运行容器时使用docker run <image> bash,则会覆盖CMD指定的命令,执行bash命令。

11. ENTRYPOINT 关键字

指定启动容器时要执行的命令,可以追加命令,执行时机同 CMD。ENTRYPOINT指令用于指定容器启动时要执行的命令,与CMD不同的是,ENTRYPOINT指定的命令不会被docker run命令行参数覆盖,而是会将这些参数作为附加参数传递给ENTRYPOINT指定的命令。例如:ENTRYPOINT ["node"],如果运行容器时使用docker run <image> app.js,则容器会执行node app.js

12. ARG 关键字

定义变量,和写代码时定义变量一样。ARG用于在构建镜像时定义变量,这些变量可以在后续的指令中使用。例如:ARG BUILD_ENV=production,在RUN指令中可以使用这个变量,如RUN if [ "$BUILD_ENV" = "production" ]; then npm install --production; else npm install; fi

13. ONBUILD 关键字

基于父镜像构建新镜像时,父镜像的 ONBUILD 会被触发。ONBUILD指令用于在构建新镜像时,当新镜像基于包含ONBUILD指令的父镜像构建时,父镜像的ONBUILD指令会被触发执行。例如:ONBUILD RUN echo "This is triggered when building a child image",当一个新镜像基于这个镜像构建时,这个命令会被执行。

三、Dockerfile 实战案例

1. 构建 Flask 镜像

使用 Python 和 Flask 构建一个简单的 Web 应用,通过 Dockerfile 构建镜像并启动容器,在网页输入服务器 IP 和端口即可看到输出。
首先创建一个 Flask 应用,以下是一个简单的示例:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello from Flask!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

然后编写 Dockerfile:

FROM python:3.10
WORKDIR /app
COPY..
RUN pip install flask
EXPOSE 5000
CMD ["python", "your_flask_app.py"]

在项目目录下执行以下命令构建镜像:

docker build -t flask-app.

启动容器:

docker run -d -p 5000:5000 flask-app

现在可以在网页中输入服务器 IP 和 5000 端口,就能看到 “Hello from Flask!” 的输出。

2. 配置 stress 容器

使用 Ubuntu 镜像构建一个 stress 容器,通过不同的启动参数来观察容器的行为。
1、构建镜像模拟测试编写 Dockerfile

FROM ubuntu:latest
RUN apt-get update && apt-get install stress

构建镜像:

docker build -t stress:latest.

启动容器:

docker run -it --rm --cpus=2 stress:latest /bin/bash

执行 stress 命令使用 stress 命令创建 4 个繁忙的进程消耗 cpu 资源:

stress -c 4

或者已存在的容器安装 stress:
安装前准备

yum install wget gcc gcc-c++ make -y

下载 stress

https://src.fedoraproject.org/repo/pkgs/stress/stress-1.0.4.tar.gz/a607afa695a511765b40993a64c6e2f4/

安装

tar zxf stress-1.0.4.tar.gz
cd stress-1.0.4
./configure
make
make install

3. 构建 SSH、Systemctl、nginx、tomcat、mysql 镜像

介绍了多种常见服务的镜像构建方法。
构建 SSH 镜像:

mkdir /opt/sshd
cd /opt/sshd
vim Dockerfile
#第一行必须指明基于的基础镜像
FROM centos:7
#作者信息
MAINTAINER this is ssh image <wl>
#镜像的操作指令
RUN yum -y update
RUN yum -y install openssh* net-tools lsof telnet passwd
RUN echo'abc1234'|passwd --stdin root
RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config\t\t\t\t\t\t#不使用 PAM 认证
RUN sed -ri '/^session\\s+required\\s+pam_loginuid.so/s/^/#/' /etc/pam.d/sshd\t\t#取消 pam 限制
RUN ssh-keygen -t rsa -A\t\t\t\t\t\t\t\t\t\t\t\t\t\t#生成密钥认证文件
RUN mkdir -p /root/.ssh &&chown root.root /root &&chmod 700 /root/.ssh
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
#/usr/sbin/sshd -D 用于前台启动 sshd 服务
//生成镜像
docker build -t sshd:centos.
//启动容器并修改 root 密码
docker run -d -P sshd:centos
docker ps -a
ssh localhost -p 49155

构建 Systemctl 镜像:

mkdir /opt/systemctl
cd /opt/systemctl
vim Dockerfile
FROM sshd:centos
MAINTAINER this is systemctl image <wl>
ENV container docker
#除了 systemd-tmpfiles-setup.service,删除其它所有文件
RUN (cd /lib/systemd/system/sysinit.target.wants/;for i in *;do[$i== systemd-tmpfiles-setup.service ]||rm -f $i;done);\\rm -f /l

构建 nginx 镜像:

mkdir /opt/nginx
cd /opt/nginx
cp /opt/nginx-1.12.0.tar.gz /opt/nginx
vim Dockerfile
#基于基础镜像
FROM centos:7
#用户信息
MAINTAINER this is nginx image <zhuo>
#添加环境包
RUN yum -y update
RUN yum -y install pcre-devel zlib-devel gcc gcc-c++ make
RUN useradd -M -s /sbin/nologin nginx
#上传 nginx 软件压缩包,并解压
ADD nginx-1.12.0.tar.gz /usr/local/src/
#指定工作目录
WORKDIR /usr/local/src/nginx-1.12.0
RUN./configure \\
--prefix=/usr/local/nginx \\
--user=nginx \\
--group=nginx \\
--with-http_stub_status_module && make && make install
ENV PATH /usr/local/nginx/sbin:$PATH
#指定 http 和 https 端口
EXPOSE 80
EXPOSE 443
RUN echo "daemon off;">> /usr/local/nginx/conf/nginx.conf\t\t\t#关闭 nginx 在后台运行
#添加宿主机中 run.sh 到容器中
ADD run.sh /run.sh
RUN chmod 755 /run.sh
CMD ["/run.sh"]

编写脚本:

vim run.sh
#!/bin/bash
/usr/local/nginx/sbin/nginx

生成镜像:

docker build -t nginx:centos.
docker run -d -P nginx:centos

构建 tomcat 镜像:

mkdir /opt/tomcat
cd /opt/tomcat
cp /opt/jdk-8u91-linux-x64.tar.gz /opt/tomcat
cp /opt/apache-tomcat-8.5.16.tar.gz /opt/tomcat
vim Dockerfile
FROM centos:7
MAINTAINER this is tomcat image <zhuo>
ADD jdk-8u91-linux-x64.tar.gz /usr/local/
WORKDIR /usr/local/
RUN mv jdk1.8.0_91 /usr/local/java
ENV JAVA_HOME /usr/local/java
ENV JRE_HOME ${JAVA_HOME}/jre
ENV CLASSPATH.:${JAVA_HOME}/lib:${JRE_HOME}/lib
ENV PATH $JAVA_HOME/bin:$PATH
ADD apache-tomcat-8.5.16.tar.gz /usr/local/
WORKDIR /usr/local/
RUN mv apache-tomcat-8.5.16 /usr/local/tomcat
EXPOSE 8080
#CMD ["/usr/local/tomcat/bin/catalina.sh","run"]
ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]

生成镜像:

docker build -t tomcat:centos.
docker run -d --name tomcat01 -p 1216:8080 tomcat:centos

构建 MySQL 镜像:

mkdir /opt/mysqld
cd /opt/mysqld
vim Dockerfile
FROM centos:7
MAINTAINER this is mysql image <zhuo>
RUN yum -y install gcc gcc-c++ ncurses ncurses-devel bison cmake make
RUN useradd -M -s /sbin/nologin mysql
ADD mysql-boost-5.7.20.tar.gz /usr/local/src/
WORKDIR /usr/local/src/mysql-5.7.20/
RUN cmake \\
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \\
-DMYSQL_UNIX_ADDR=/usr/local/mysql/mysql.sock \\
-DSYSCONFDIR=/etc \\
-DSYSTEMD_PID_DIR=/usr/local/mysql \\
-DDEFAULT_CHARSET=utf8 \\
-DDEFAULT_COLLATION=utf8_general_ci \\
-DWITH_INNOBASE_STORAGE_ENGINE=1 \\
-DWITH_ARCHIVE_STORAGE_ENGINE=1 \\
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \\
-DWITH_PERFSCHEMA_STORAGE_ENGINE=1 \\
-DMYSQL_DATADIR=/usr/local/mysql/data \\
-DWITH_BOOST=boost \\
-DWITH_SYSTEMD=1&& make && make install
RUN chown -R mysql:mysql /usr/local/mysql/
RUN rm -rf /etc/my.cnf
ADD my.cnf /etc/
RUN chown mysql:mysql /etc/my.cnf
ENV PATH=/usr/local/mysql/bin:/usr/local/mysql/lib:$PATH
WORKDIR /usr/local/mysql/
RUN bin/mysqld \\
--initialize-insecure \\
--user=mysql \\
--basedir=/usr/local/mysql \\
--datadir=/usr/local/mysql/data
RUN cp /usr/local/mysql/usr/lib/systemd/system/mysqld.service /usr/lib/systemd/system/
EXPOSE 3306
ADD run.sh /usr/local/src
RUN chmod 755 /usr/local/src/run.sh
RUN sh /usr/local/src/run.sh
vim my.cnf

4. 构建自己的应用镜像

以 Tomcat 中运行程序为例,展示了如何编写 Dockerfile、构建镜像、运行镜像并部署项目。
首先准备好要部署的项目文件,假设是一个简单的 Web 应用。然后编写 Dockerfile:

FROM tomcat:latest
COPY your_project_directory /usr/local/tomcat/webapps/

在项目目录下执行以下命令构建镜像:

docker build -t your_app_image.

启动容器:

docker run -d -p 8080:8080 your_app_image

四、Dockerfile 注意事项

1. FROM 语法的选择

在选择镜像时,应遵循三个基本原则:
官方镜像优于非官方镜像,选择官方认证的镜像可以保证安全性,避免木马和侵入程序。
固定版本的 Tag,而非每次都使用latest。进入镜像详细页面,选择Tags选项卡,会看到很多版本的镜像。需根据项目需求选择固定版本,避免因前后版本不兼容带来的维护性和稳定性问题。
功能满足且体积小。选择基础镜像时要考虑到后续会在基础上添加很多内容和应用,镜像是分层的,体积越大复杂度越高,所以应选择体积小的镜像以保持简洁。

2. RUN 语法的优化

将多个命令放在一起执行,减少镜像层数和大小。例如,避免以下错误示范:

RUN apt-get update
RUN apt-get install wget
RUN wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linux_amd64.tar.gz
RUN tar zxf ipinfo_2.0.1_linux_amd64.tar.gz
RUN mv ipinfo_2.0.1_linux_amd64 /usr/bin/ipinfo
RUN rm -rf ipinfo_2.0.1_linux_amd64.tar.gz

正确的做法是:

RUN apt-get update && apt-get install wget && wget https://github.com/ipinfo/cli/releases/download/ipinfo-2.0.1/ipinfo_2.0.1_linux_amd64.tar.gz && tar zxf ipinfo_2.0.1_linux_amd64.tar.gz && mv ipinfo_2.0.1_linux_amd64 /usr/bin/ipinfo && rm -rf ipinfo_2.0.1_linux_amd64.tar.gz

这样用&&将多个命令放在一起只RUN一次,可控制最终得到的镜像大小。

3. COPY 与 ADD 的区别

在复制普通文件时,COPYADD相似,但ADD在添加 gzip 文件时可自动解压。同时,COPY不支持从远程读取资源,而ADD可以从远程 URL 获取资源,例如:ADD http://example.com/file.txt /app,会从指定 URL 下载文件并复制到容器的/app目录。然而,Docker 开发者推荐在满足同等功能的情况下,尽量使用COPY指令,以避免ADD指令可能带来的意外情况。

4. WORKDIR 切换工作目录

WORKDIR命令类似于 Linux 的cd命令,为后续指令配置工作目录。例如:WORKDIR /app,如果目录不存在,会自动创建。

5. ARG 与 ENV 命令的不同

ARGENV都可以用来设置变量,但有以下不同:
作用域不同,ARG声明后可在构建时修改变量,而ENV在构建过程和容器运行时都有效。
ARG在构建阶段之外不能在后续指令中使用,如果想在构建阶段使用ARG声明的带有默认值的变量,需要在构建阶段通过ARG声明没有值的同名参数。

6. CMD 容器启动命令

CMD设置容器启动时默认执行的命令,可被docker run提供的参数覆盖,多个CMD时只有最后一个执行。例如:CMD ["node", "app.js"],如果在运行容器时使用docker run <image> bash,则会覆盖CMD指定的命令,执行bash命令。

五、在项目中运用 Dockerfile

1. Docker 和 Dockerfile 的重要性

Docker 起源于 dotCloud 公司创始人 Solomon Hykes 在法国发起的一个公司内部项目,它是基于该公司多年云服务技术的一次革新,并于 2013 年 3 月以 Apache 2.0 授权协议开源。Docker 使用 Google 公司推出的 Go 语言进行开发实现,基于 Linux 内核的 cgroup,namespace,以及 OverlayFS 类的 Union FS 等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术。
Docker 有着诸多优势。其一,能提供一致的运行环境,便于迁移服务器,例如开发阶段的程序可以和其依赖的软件环境(如 jdk、tomcat、mysql 等)一起打包,无论在哪个机器上都能保证环境一致,避免因环境差异导致应用程序无法运行的问题;其二,它对进程进行封装隔离,容器与容器之间互不影响,可更高效地利用系统资源,比如公司举办活动面临大量流量时,运维人员只需将程序打包成镜像,然后按需运行多个容器即可,无需像以往那样耗时费力地去部署多台环境可能不一致的服务器;其三,通过镜像能够轻松复制出多个环境一致的容器。
而 Dockerfile 在自动化构建和团队协作方面发挥着关键作用。它是创建 Docker 镜像的文本文件,包含了构建镜像所需的全部指令,像选择基础镜像、安装软件包、添加文件、设置环境变量等步骤都能通过它来定义。借助 Dockerfile,开发人员无需手动一步步安装和配置环境,只要定义好容器的基础镜像、软件依赖以及启动命令等信息,就能快速自动化构建出完整的容器镜像。并且,将 Dockerfile 纳入版本控制系统(如 Git)后,团队中的每个成员都能使用相同的容器环境配置,可避免因开发环境不一致引发的各类问题,确保构建过程的可重复性和可追溯性,极大提高了团队协作效率以及应用的可靠性。

2. Docker 基础

(1)架构简介

Docker 使用客户端 - 服务器 (C/S) 架构模式,运用远程 API 来管理和创建 Docker 容器。其主要组件包括:

  • Docker 客户端:是用户与 Docker 守护进程交互的命令行界面(CLI),用户通过它发出命令,这些命令会被发送到 Docker 守护进程,由守护进程执行相应操作,像创建容器、构建镜像、查看容器状态等常用操作都可通过 docker 这个常用命令行工具来实现。
  • Docker 守护进程(通常是 dockerd):它是 Docker 架构的核心,负责管理容器生命周期、构建镜像、分发镜像等任务,一般以后台进程的方式运行,等待来自 Docker 客户端的 API 请求,像启动和停止容器、构建拉取推送镜像、管理容器网络和存储、查看容器日志等都由它来处理。
  • Docker 镜像:可以看作是容器的只读模板,每个镜像包含了应用程序运行所需的操作系统、运行时、库、环境变量以及应用代码等内容,镜像是构建容器的基础,用户可从 Docker Hub 或私有仓库获取,也能通过 Dockerfile 自行构建,并且不同容器使用同一个镜像时,容器中的文件系统层是相互独立的。
  • Docker 容器:是 Docker 镜像的运行实例,能在其中运行应用程序,提供独立的运行环境,确保应用程序在不同环境中有一致行为,容器在运行时与其他容器和宿主机共享操作系统内核,但彼此的文件系统和进程是隔离的,其生命周期由 Docker 守护进程管理,容器通常在任务完成后被销毁,不过可以在任何地方运行,因为其运行时依赖都已封装在镜像中。
  • Docker 仓库:用来存储和管理 Docker 镜像,常见的有公共仓库 Docker Hub,用户能从中下载各种官方和社区维护的镜像(如 Ubuntu、Nginx、MySQL 等),也可以上传自己的镜像分享给其他人,此外,企业内部还可部署私有 Docker 仓库来管理镜像。
  • Docker 网络:用于连接容器的虚拟网络,使得容器之间可以相互通信,Docker 支持多种网络类型,如 bridge、overlay、macvlan 等。
  • Docker 存储驱动:用于管理 Docker 容器文件系统的组件,像 overlay2、aufs、btrfs 等都是 Docker 支持的存储驱动类型。
(2)安装设置环境

以 CentOS 7.x 系统为例,安装 Docker 的步骤如下:
卸载原始 docker(如果之前安装过):

sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

安装 docker 依赖:

sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2

设置 docker 的 yum 源:

sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

安装最新版的 docker:

sudo yum install docker-ce docker-ce-cli containerd.io

启动 docker:

sudo systemctl enable docker
sudo systemctl start docker

安装完成后,可通过 docker info 命令查看 docker 信息,或使用 docker version 命令查看 docker 引擎版本来验证安装是否成功,还可以运行 sudo docker run hello-world 进行简单测试。
在其他系统(如通用所有平台的 bash 安装方式)中,Docker 官方为简化测试或开发环境下的安装流程,提供了一套便捷的安装脚本,CentOS 系统(所有 Linux 发行版本都可以使用)上可使用这套脚本安装,并且能通过 --mirror 选项使用国内源进行安装,命令如下(必须联网,sudo 表示以管理员身份运行,如果登录的就是管理员,sudo 可以省略):

curl -fsSL get.docker.com -o get-docker.sh
sudo sh get-docker.sh --mirror Aliyun
(3)常用命令基础

以下是一些 Docker 的常用命令:

  • docker build:用于构建 Docker 镜像,例如 docker build -t my-image. 命令会在当前目录下寻找名为 Dockerfile 的文件(如果文件名不是 Dockerfile,则可以加上 -f 参数指定文件名称),然后按照其中的指令构建出名为 my-image 的镜像,最后的 . 表示使用当前目录作为构建的上下文环境。
  • docker run:用来运行容器,像 docker run -d -p 8080:8080 my-image 命令,其中 -d 表示让容器在后台运行,-p 参数用于进行端口映射(将宿主机的 8080 端口映射到容器内的 8080 端口),my-image 则是指定要运行的镜像名称。
  • docker ps:列出正在运行的容器,若加上 -a 参数(即 docker ps -a),则会列出所有的容器(包括已停止的),会展示容器的相关信息,如容器 ID、镜像名称、创建时间、状态等。
  • docker exec:可在运行的容器中执行命令,例如 docker exec -it my_container bash 命令能进入名为 my_container 的容器内部,并开启一个交互式的 bash 终端,方便在容器内进行操作。
  • docker pull:从 Docker Hub 或其他指定的注册表中拉取镜像,比如 docker pull ubuntu 就是拉取官方的 Ubuntu 镜像到本地。
  • docker push:将本地构建好的镜像上传到 Docker Hub 或指定的私有仓库中,格式为 docker push <username>/<image_name>,需要先登录相应仓库账号才行。

3. 编写第一个 Dockerfile

(1)选择基础镜像

选择基础镜像时通常要遵循以下原则:
首先,官方镜像优于非官方镜像,官方认证的镜像安全性更高,能避免木马和侵入程序等隐患。比如常用的 Ubuntu、Nginx、MySQL 等官方镜像,都是经过严格审核和维护的,可以放心使用。
其次,尽量选择固定版本的 Tag,而非每次都使用 latest。进入镜像详细页面,选择 Tags 选项卡,会看到很多版本的镜像,应根据项目需求挑选固定版本,否则可能因前后版本不兼容带来维护性和稳定性方面的问题,例如应用程序在开发环境使用某个依赖的最新版本正常运行,但到了生产环境由于 latest 版本更新导致出现兼容性故障。
最后,要考虑功能满足且体积小的镜像。因为镜像是分层的,基础镜像体积越大,后续添加内容和应用后复杂度越高,所以选择体积小的镜像有助于保持整个镜像简洁,像 Alpine 镜像就是以体积小且严格控制著称,常被作为基础镜像使用,例如 FROM alpine:latest 就是选择了最新版本的 Alpine 镜像作为基础来构建后续的镜像内容。

(2)编写步骤和最佳实践

下面以构建一个简单的 Python Flask 应用镜像为例,展示 Dockerfile 的编写步骤:

# 选择 Python 3.10 版本的官方镜像作为基础镜像
FROM python:3.10
# 设置容器内的工作目录为 /app,如果目录不存在会自动创建
WORKDIR /app
# 将当前目录(宿主机上 Dockerfile 所在目录)下的所有文件复制到容器内的 /app 目录下
COPY..
# 运行命令安装 Flask 依赖包
RUN pip install flask
# 声明容器运行时要对外暴露的端口为 5000
EXPOSE 5000
# 指定容器启动时要执行的命令,这里是运行名为 your_flask_app.py 的 Python 文件
CMD ["python", "your_flask_app.py"]

编写 Dockerfile 的最佳实践包括:
保持简洁易读和易于维护:尽量使用单行指令,避免过多的多行复杂指令,让 Dockerfile 的结构清晰明了,方便后续查看和修改,例如将多个相关的安装命令用 && 连接起来放在一个 RUN 指令中,像 RUN apt-get update && apt-get install -y wget && wget https://example.com/file.tar.gz && tar zxf file.tar.gz 这样的形式,而不是分成多个 RUN 指令分别执行,有助于减少镜像层数,进而控制镜像大小。
合理利用版本控制系统:使用如 Git 这样的版本控制系统管理 Dockerfile 和相关文件,确保构建过程可重复、可追溯,团队成员可以方便地查看历史变更记录以及回滚到之前的稳定版本,便于协作开发和运维。

(3)构建过程详解

以上述 Flask 应用的 Dockerfile 为例,在项目目录下执行以下命令来构建镜像:

docker build -t flask-app.

执行该命令后,Docker 守护进程会读取 Dockerfile 中的指令,按顺序执行每一条指令。首先从指定的基础镜像(python:3.10)启动一个临时容器,接着在这个容器内依次执行后续指令,比如执行 COPY 指令复制文件、RUN 指令安装依赖等,每执行完一条指令就会提交一个新的镜像层,最终当所有指令执行完成后,输出最终镜像的 ID,并根据 -t 参数(-t flask-app)给镜像打上指定的标签(flask-app),方便后续识别和使用该镜像。
构建好镜像后,使用以下命令启动容器:

docker run -d -p 5000:5000 flask-app

-d 参数让容器在后台运行,-p 5000:5000 则将宿主机的 5000 端口和容器内的 5000 端口进行映射,这样就能通过访问宿主机的 5000 端口来访问容器内运行的 Flask 应用了。

4. 高级 Dockerfile 技巧

(1)多阶段构建优化镜像大小和构建时间

在应用容器技术的软件开发中,控制容器镜像大小很重要。如果构建的镜像既是编译软件的环境,又是软件最终运行环境,往往很难控制镜像大小。多阶段构建就能很好地解决这个问题,它允许在不同的构建阶段使用不同的基础镜像和构建策略,优化构建过程并减少最终镜像的大小。
例如,构建一个 Go 语言应用的镜像,在编译阶段需要 Go 语言的编译环境,而运行阶段只需要一个小巧的运行环境(如 Alpine 镜像)即可。使用多阶段构建的 Dockerfile 示例如下:

# 第一阶段:构建阶段,选择 Go 语言特定版本的镜像作为基础镜像,并命名该阶段为 builder
FROM golang:1.7.3 AS builder
WORKDIR /go/src/github.com/alexellis/href-counter/
COPY app.go.
RUN go get -d -v golang.org/x/net/html \
    && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app.

# 第二阶段:生成阶段,选择 Alpine 镜像作为基础镜像,用于最终的运行环境
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
# 从第一阶段(builder 阶段)构建好的镜像中复制编译生成的二进制文件到当前阶段的镜像中
COPY --from=builder /go/src/github.com/alexellis/href-counter/app.
CMD ["./app"]

通过这种方式,Go 语言的编译环境相关的大量依赖等内容只会存在于第一阶段的临时镜像中,最终生成的运行镜像只包含了应用运行必需的内容,大大减小了镜像体积,同时也保持了 Dockerfile 的可读性和可维护性,而且只需要一个 Dockerfile 文件就能完成整个复杂的构建过程,无需像以往那样编写多个 Dockerfile 和复杂的构建脚本。

(2)使用 ARG 和 ENV 管理变量
  • ARG(构建时变量):用于在构建镜像时定义变量,这些变量可以在后续的构建指令中使用,作用域主要在构建阶段,在构建阶段之外不能在后续指令中使用。例如:ARG BUILD_ENV=production,可以在 RUN 指令中根据这个变量来执行不同的操作,像 RUN if [ "$BUILD_ENV" = "production" ]; then npm install --production; else npm install; fi,根据构建环境变量的值决定是安装生产环境依赖还是开发环境依赖。并且如果想在构建阶段使用 ARG 声明的带有默认值的变量,需要在构建阶段通过 ARG 声明没有值的同名参数来使用。
  • ENV(环境变量):设置的变量在构建过程和容器运行时都有效,方便在容器内访问程序以及配置一些运行时需要的参数等。比如 ENV NODE_ENV production,后续指令中就能通过 $NODE_ENV 来引用这个变量,像 RUN echo $NODE_ENV 这样进行操作,也可以在容器启动后运行的应用程序中使用这些环境变量进行相应的配置和逻辑处理。

合理运用 ARGENV 变量,可以让 Dockerfile 更灵活地适应不同的构建需求以及容器运行时的配置要求,提高镜像构建和应用部署的通用性和可配置性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2266494.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows nmake 安装openssl

windows nmake 编译和安装 openssl 本文提供了在Windows环境下安装OpenSSL的详细步骤&#xff0c;包括下载Perl、NASM和VisualStudio&#xff0c;配置环境变量&#xff0c;使用PerlConfigure设置平台&#xff0c;通过nmake进行编译、测试和安装。整个过程涉及32位和64位版本的选…

智能家居实训室中,STC单片机驱动的“互联网+”智能家居系统设计

一、引言 随着经济的快速发展&#xff0c;人们对家居环境的智能化、网络化需求日益增强&#xff0c;智能家居的研究也因此受到了国内外相关机构的广泛关注。STC单片机凭借其卓越的性能和广泛的应用领域&#xff0c;成为了智能家居系统设计的优选方案。作为一种先进的微控制器&…

分析排名靠前的一些自媒体平台,如何运用这些平台?

众所周知&#xff0c;现在做网站越来越难了&#xff0c;主要的原因还是因为流量红利时代过去了。并且搜索引擎都在给自己的平台做闭环改造。搜索引擎的流量扶持太低了。如百度投资知乎&#xff0c;给知乎带来很多流量扶持&#xff0c;也为自身内容不足做一个填补。 而我们站长…

[计算机网络]OSPF协议

开放最短路径优先OSPF 1&#xff09;OSPF的工作方式 1>和谁交换消息 使用洪泛法&#xff0c;向本自治系统的所有路由器发送消息。 2>交换什么消息 发送的消息就是与本路由器相邻的所有路由器的链路状态&#xff0c;但这只是路由器所知道的部分信息。 链路状态就是说…

攻防世界PWN刷题笔记(引导模式)1-3

感谢组长和其他高手让我入门学pwn&#xff0c;个人感觉做题和看课程应该一块推进&#xff0c;光看课程&#xff0c;容易疲乏&#xff0c;而且缺乏经验。只做题&#xff0c;学的知识缺乏体系&#xff0c;因此决定立志每天看课&#xff0b;做题&#xff08;先保证不挂科的前提下&…

【机器学习案列】车牌自动识别系统:基于YOLO11的高效实现

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

upload-labs关卡记录12

直接上传一句话木马&#xff0c;发现提示&#xff1a; 很明显这是一个白名单&#xff0c;而且不是前端的js检查&#xff0c;而是服务端的检查&#xff0c;因此我们使用bp抓包&#xff0c;改一下文件类型试试&#xff1a; 找到包之后&#xff0c;我们对content-type进行一个更改…

3、计算机中数制与码制

计算机中的数据是以二进制存储&#xff0c;但是日常使用的数据为十进制&#xff0c;除了十进制还有八进制和十六进制。它们之间存在一定的转化关系。 1、数制间转换 一个数据可以有不同的表现形式&#xff0c;比如&#xff1a; 1.1、十进制转二进制 十进制转其他进制可以使用短…

【Qt】基础(命名风格、文档查看、坐标体系、控件位置设置和获取)

1.命名风格 Qt中偏好用小驼峰&#xff0c;来命名变量/函数&#xff0c;用大驼峰命名类。 2.文档使用 2.1 光标移动到类型或方法&#xff0c;按F1。自动打开对应文档。 2.2 在帮助中打开整个文档 2.3 开始查询Assistant 3.Qt窗口坐标体系 1.左手坐标系 原点为左上角&#x…

【递归,搜索与回溯算法 综合练习】深入理解暴搜决策树:递归,搜索与回溯算法综合小专题(二)

优美的排列 题目解析 算法原理 解法 &#xff1a;暴搜 决策树 红色剪枝&#xff1a;用于剪去该节点的值在对应分支中&#xff0c;已经被使用的情况&#xff0c;可以定义一个 check[ ] 紫色剪枝&#xff1a;perm[i] 不能够被 i 整除&#xff0c;i 不能够被 per…

OpenCV putText增加中文支持

OpenCV 默认并不支持中文字符显示&#xff0c;需要增加 freetype 支持&#xff0c;也需正确设置中文字体才能正常显示中文。 OpenCV 2.x 版本没有该模块&#xff0c;而 OpenCV 3.x 及以上版本才正式引入了 freetype 模块 &#xff0c;可检查并更新到较新且包含该模块的版本。 O…

光谱相机与普通相机的区别

一、成像目的 普通相机&#xff1a;主要目的是记录物体的外观形态&#xff0c;生成人眼可见的、直观的二维图像&#xff0c;重点在于还原物体的形状、颜色和纹理等视觉特征&#xff0c;以供人们进行观赏、记录场景或人物等用途。例如&#xff0c;拍摄旅游风景照片、人物肖像等…

爬虫 APP 逆向 ---> shopee(虾皮) 电商

shopee 泰国站点&#xff1a;https://shopee.co.th/ shopee 网页访问时&#xff0c;直接弹出使用 app 登录查看&#xff0c;那就登录 shopee 泰国站点 app。 手机抓包&#xff1a;分类接口 接口&#xff1a;https://mall.shopee.co.th/api/v4/pages/get_category_tree 请求参…

[实战]推流服务SRS安装

业务场景 在Web浏览器端展示摄像头的视频数据。 协议 物联代理推流协议&#xff1a;rtmp 浏览器器拉流协议&#xff1a;http-flv 推流方案 1、Nginx加nginx-http-flv-modules模块 2、采用SRS服务器 推流服务SRS网站&#xff1a;https://ossrs.io/lts/zh-cn/ 推流服务…

kafka的备份策略:从备份到恢复

文章目录 一、全量备份二、增量备份三、全量恢复四、增量恢复 前言&#xff1a;Kafka的备份的单元是partition&#xff0c;也就是每个partition都都会有leader partiton和follow partiton。其中leader partition是用来进行和producer进行写交互&#xff0c;follow从leader副本进…

Ubuntu网络配置(桥接模式, nat模式, host主机模式)

windows上安装了vmware虚拟机&#xff0c; vmware虚拟机上运行着ubuntu系统。windows与虚拟机可以通过三种方式进行通信。分别是桥接模式&#xff1b;nat模式&#xff1b;host模式 一、桥接模式 所谓桥接模式&#xff0c;也就是虚拟机与宿主机处于同一个网段&#xff0c; 宿主机…

视频会议是如何实现屏幕标注功能的?

现在主流的视频会议软件都有屏幕标注功能&#xff0c;屏幕标注功能给屏幕分享者讲解分享内容时提供了极大的方便。那我们以傲瑞视频会议&#xff08;OrayMeeting&#xff09;为例&#xff0c;来讲解屏幕标注是如何实现的。 傲瑞会议的PC端&#xff08;Windows、信创Linux、银河…

任务8 数据库服务配置与管理

数据库服务概述 数据库管理系统 用于建立、修改、访问和维护数据库。 具有多用户和多任务的特性&#xff0c;支持多个用户和应用程序同时进行操作。 数据库管理员通过DBMS对数据库进行统一的管理和控制。 维护数据的安全性和完整性。 按照数据在数据库中的存储和管理方式…

汇通达:下沉市场零售业态进入产业互联网2.0时代

纵观2024年&#xff0c;面对全球经济增长放缓、人口红利减弱的挑战&#xff0c;消费品牌“向下”拓展&#xff0c;下沉至低线级城市乃至村镇地区的趋势愈发明显。 这是因为在三四线城市以及农村市场&#xff0c;消费需求增速较快。CIC灼识咨询在《2024中国下沉市场蓝皮书》中提…

直流无刷电机驱动与控制4-stm32定时器-六步换相输出

第F4_专题07 直流无刷电机驱动与控制(第4节)_STM32定时器基础_哔哩哔哩_bilibili STM32定时器霍尔传感器模式 1、输出比较 2、左侧通入霍尔传感器信号:经过异或门,输出0 1 0 1 0 1等信号。 3、通道输入信号时,每个电平跳变,翻转,都输出一个脉冲。所以TI1F_ED输入如下所示…