Dockerfile详解:构建简单高效的容器镜像

科技   2024-10-21 07:31   广东  

    码字不易,戳下方名片,关注+星标

本文主要讲解内容:

    Dockerfile简介
    Dockerfile常见指令详解
    构建镜像实例(重点)
    Dockerfile优化技巧



1 Dockerfile简介

Dockerfile是一个包含了一系列命令的文本文件,这些命令可以用于自动化地创建一个Docker镜像。通过编写Dockerfile,可以将环境配置、应用程序代码、依赖关系等打包成一个镜像,便于快速创建容器。

用户可以将自己的应用打包成镜像,从而让应用在容器中运行。还可以对官方镜像进行扩展,打包成适合生产环境的应用镜像。

2 Dockerfile常用指令

2.1 FROM:指定基础镜像

指定构建新镜像时使用的基础镜像,通常必须是Dockerfile的第一个有效指令

# 格式
FROM <image:[版本标签]>

# 指定基础镜像
FROM centos
FROM ubuntu:20.04


# 说明:如果不指定版本标签,默认使用latest

2.2 LABEl:添加镜像的元数据

LABEL一般使用键值对方式。

# 格式
LABEL <key>=<value> <key>=<value>....

# 为镜像添加元数据
LABEL version="2.0" description="业务系统第二个版本"

# 说明:一条LABEL可以指定多条元数据,尽量不要写多个LABEL

2.3 RUN:构建镜像时执行的命令

有两种执行方式

方式一:shell执行

# 格式
RUN <command>

# 示例
RUN yum update -y

# 说明:RUN 指令创建的中间镜像会被缓存,并在下次构建中使用。可以在构建时使用--no-cache取消缓存:
docker build --no-cache

方式二:exec执行

# 格式:
RUN ["executable", "参数1", "参数2"]

# 示例
RUN ["/bin/bash", "-c", "echo hello"]

2.4 ENV:在容器内部设置环境变量

# 格式
ENV <key> <value>

# 示例
ENV MYPATH /usr/local

2.5 ADD:将本地文件添加到镜像中

相当于scp。只是scp 需要将用户名和密码的权限验证,而ADD 不用。

tar 类型文件会自动解压,可以访问网络资源,类似 wget

# 语法
ADD <src> <dest>
ADD ["src", "dest"]

# 示例
COPY nginx.tar /opt

# 说明:路径可以是相对路径或绝对路径,建议使用绝对路径。
# 尽量不要把<src> 写成一个文件夹,如果<src> 是一个文件夹,复制整个目录的内容

2.6 COPY:将文件或目录复制到镜像中。

功能类似 ADD,但不会自动解压文件,也不能访问网络资源

# 语法
COPY <src> <dest>
COPY ["<src>", "<dest>"]

与 ADD 区别,COPY 的只能是本地文件,其他用法一致

2.7 VOLUME:指定持久化目录

# 格式
VOLUME ["/path/to/dir"]

# 示例
VOLUME ["/data"]
VOLUME ["/data/log", "/data/config"]
# 一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统

容器使用的是AUFS(联合文件系统),这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。所以如果想要数据持久化,就得使用VOLUME

功能说明:卷可以在容器间共享和重用;修改卷后会立即生效;对卷的修改不会对镜像产生影响

2.8 CMD:容器启动时运行的命令(不常用)

# 语法
CMD ["executable","param1","param2"]
CMD command param1 param2
  
# 示例
CMD echo $LANG

2.9 ENTRYPOINT:容器启动时运行的命令(常用)

# 语法
ENTRYPOINT ["executable", "param1", "param2"] 
ENTRYPOINT command param1 param2

  
# 示例
ENTRYPOINT java -jar /data/config.jar

ENTRYPOINT和CMD的异同点:

相同点:

(1)只能写一条,如果写了多条,那么只有最后一条生效

(2)容器启动时才运行,运行时机相同

不同点:

(1)ENTRYPOINT不会被运行的command覆盖,而CMD则会被覆盖

(2)如果我们在Dockerfile种同时写了ENTRYPOINT和CMD,并且CMD指令不是一个完整的可执行命令,那么CMD指定的内容将会作为ENTRYPOINT的参数

2.10 EXPOSE:暴露容器运行时的监听端口给外部

# 格式:
EXPOSE <port> [<port>...]

# 示例:
EXPOSE 8080
EXPOSE 443/tcp 80/tcp

注意:

EXPOSE 并不会让容器的端口访问到主机。在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口

如果没有暴露端口,后期也可以通过docker run -p 8080:8080 方式映射端口,但不能通过 -P 形式映射

2.11 WORKDIR:工作目录

功能类似cd命令。后续指令将在该目录中执行。

2.12 其他指令

MAINTAINER:指定作者

USER:设置启动容器的用户

ONBUILD:用于设置镜像触发器

HEALTHCHECK:用于检查容器健康状况

3 制作镜像实例(重点)

3.1 制作镜像语法

docker build -t 镜像名:标签名 Dockerfile路径(可以是绝对路径,也可以是相对路径)

3.2 实例1:构建nginx镜像

(1)编写Dockerfile

[root@harbor ~]# cd /data/dockerfile/nginx/ 
[root@harbor nginx]# cat Dockerfile 
# 使用官方Nginx镜像
FROM nginx:1.25

# 复制自定义配置文件
COPY nginx.conf /etc/nginx/nginx.conf

# 复制网站文件
COPY html /usr/share/nginx/html

# 暴露Nginx端口
EXPOSE 80

(2)编写自动配置文件和网站文件

这里根据你自己情况来编写,放在dockerfile同级目录下

(3)构建镜像

如果是使用官方镜像的话,会出现以下错误,拉不到镜像

最近dockerhub不稳定,比较麻烦

解决镜像问题

使用公开的镜像加速服务:docker.m.daocloud.io/

第一步:拉取nginx镜像

需要跟dockerfile中同版本

docker pull docker.m.daocloud.io/nginx:1.25 

第二步:修改标签

docker tag docker.m.daocloud.io/nginx:1.25  nginx:1.25 

完成以上两步就可以再次执行build过程了

如上图,已成功构建mynginx镜像。

(4)运行容器

docker run -d -p 80:80 --name mynginx mynginx

3.3 实例2:构建 Java 应用镜像

(1)准备工作

确保你的Java应用已经打包成JAR文件,并放在Dockerfile同级目录下

(2)编写Dockerfile

FROM openjdk:8
MAINTAINER liyb <liyb@gdhmail.com>
RUN cp -a-f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \ 
mkdir /work
copy *.jar /work/app.jar
EXPOSE 9999 
ENTRYPOINT java -jar /work/app.jar

(3)构建镜像

如遇无法下载基础镜像的问题,跟上面实例做法一样。

docker bulid -t myapp .

(4)运行容器

docker run -d -p 8080:8080 myapp

4 Dockerfile优化技巧

在编写高效的Dockerfile时,可以遵循以下最佳实践,以便优化镜像的构建和运行性能:

4.1 使用轻量基础镜像

选择小巧的基础镜像,如alpine,以减少最终镜像的体积。

4.2 合并命令

每个指令(如 RUN、COPY 等)都会生成一个新的镜像层。使用&&将多个RUN命令合并,减少镜像层数,从而提高构建速度和效率。

如下面例子

RUN wget http://nginx.org/download/nginx-$NGINX_VERSION.tar.gz \
    && tar -zxvf nginx-$NGINX_VERSION.tar.gz \
    && cd nginx-$NGINX_VERSION \
    && ./configure --prefix=/usr/local/nginx --with-http_ssl_module \
    && make \
    && make install \

4.3 缓存优化:

合理地安排指令顺序。将不常变化的指令放在Dockerfile前面,常变化的放在后面,以利用缓存,加快构建速度。

4.4 使用.dockerignore:

排除不必要的文件,减小上下文大小,提升构建速度。

4.5 多阶段构建

利用多阶段构建,仅将最终运行所需的文件复制到最终镜像,降低镜像大小。

4.6 优化入口点和命令

使用ENTRYPOINT和CMD正确配置容器启动方式,确保灵活性和一致性。

4.7 按需复制文件

只复制构建所需的文件,而不是整个项目


以上是我对dockerfile的一些知识的总结和理解,如有错漏,敬请指出!


欢迎转发点亮下方“在看”图标让更多的人看到


如果不想错过精彩内容,记得在公众号页面右上角设为星标,这样每次新文章推送才会第一时间出现在你的订阅列表中。感谢支持!!



往期精彩文章


手把手教你搭建企业级Harbor镜像仓库


【Docker系列知识】常用命令大全汇总


部署Docker的三种常用方法【值得收藏】


局域网内构建统一可访问的YUM源(基础运维必备技能)


Linux文件处理三剑客详解(运维高手必备)


Tomcat常用配置和调优(生产环境必备技巧)


Nginx配置文件详解及常用功能配置(实用率90%)

firewalld防火墙的详细讲解(实用率99%)



运维李哥不背锅
专注于各种运维技术、,分享Linux基础知识,服务器,数据库,云原生和网络安全等相关技术,各种进阶知识等着你,助你成为技术达人!
 最新文章