【Docker】Dockerfile使用技巧

在这里插入图片描述

开启Buildkit

BuildKit是Docker官方社区推出的下一代镜像构建神器,可以更加快速,有效,安全地构建docker镜像。

尽管目前BuildKit不是Docker的默认构建工具,但是完全可以考虑将其作为Docker(v18.09+)的首选构建工具。

官方文档:https://docs.docker.com/build/buildkit/

下面介绍一下怎么开启BuildKit。

/etc/docker/daemon.json里添加(如果没有这个文件,则新建), 然后重启docker

{ "features": { "buildkit": true } }

或者在执行docker build命令时设置

$ DOCKER_BUILDKIT=1 docker build .

镜像的选择

可以前往官网学习官方的镜像怎么制作的:https://github.com/docker-library/official-images

基础镜像的选择原则:

  • 官方镜像优于非官方的镜像,如果没有官方镜像,则尽量选择Dockerfile开源的。
  • 固定版本tag而不是每次都使用latest
  • 尽量选择体积小的镜像

下面的镜像列表中,都是jre8的镜像,但是由于基础的镜像不同导致最终镜像大小不同。

$ docker image ls
REPOSITORY        TAG             IMAGE ID       CREATED         SIZE
eclipse-temurin   8-jre-jammy     ec4a8981544b   6 days ago      223MB
eclipse-temurin   8-jre-focal     e588bf105eb7   3 weeks ago     227MB
eclipse-temurin   8-jre-alpine    f7a454a165ae   3 weeks ago     135MB
eclipse-temurin   8-jre-centos7   e5b6f35176e9   23 months ago   350MB
openjdk           8-jre-alpine    f7a292bbb70c   4 years ago     84.9MB

Jammy和Focal:这两个都是Ubuntu的版本代号。"Focal"对应的是Ubuntu 20.04 LTS(长期支持版),"Jammy"对应的则是更加新的Ubuntu版本。Ubuntu是一个非常受欢迎的Linux发行版,因为它既有强大的功能,又有着广大的用户和开发者社区。

Alpine:Alpine Linux是一个面向安全、简单和轻量级的Linux发行版,它的镜像大小通常远小于基于 Ubuntu或其他发行版的镜像。这使得它非常适合于Docker镜像,因为小的镜像可以更快地被拉取和部署。

AdoptOpenJDK停止发布OpenJDK二进制,而Eclipse Temurin是它的延伸,提供更好的稳定性。

减少镜像的分层

例如下面的镜像:

from centos:7label author=morirsenv WORK_DIR /usr/localarg version=6.2.5workdir $WORK_DIRADD redis-${version}.tar.gz .run yum -y update
run yum install -y wget gcc gcc-c++ automake autoconf libtool make
run make -C redis-${version}expose 6379env REDIS_HOME $WORK_DIR/redis-6.2.5env PATH $PATH:$REDIS_HOME/srcentrypoint ["redis-server"]

查询镜像的分层:

$ docker image history redis:6.2.5.1
IMAGE          CREATED             CREATED BY                                      SIZE      COMMENT
444f31557106   57 seconds ago      ENTRYPOINT ["redis-server"]                     0B        buildkit.dockerfile.v0
<missing>      57 seconds ago      ENV PATH=/usr/local/sbin:/usr/local/bin:/usr…   0B        buildkit.dockerfile.v0
<missing>      57 seconds ago      ENV REDIS_HOME=/usr/local/redis-6.2.5           0B        buildkit.dockerfile.v0
<missing>      57 seconds ago      EXPOSE map[6379/tcp:{}]                         0B        buildkit.dockerfile.v0
<missing>      57 seconds ago      RUN |1 version=6.2.5 /bin/sh -c make -C redi…   122MB     buildkit.dockerfile.v0
<missing>      About an hour ago   RUN |1 version=6.2.5 /bin/sh -c yum install …   302MB     buildkit.dockerfile.v0
<missing>      About an hour ago   RUN |1 version=6.2.5 /bin/sh -c yum -y updat…   358MB     buildkit.dockerfile.v0
<missing>      About an hour ago   ADD redis-6.2.5.tar.gz . # buildkit             10.4MB    buildkit.dockerfile.v0
<missing>      2 hours ago         WORKDIR /usr/local                              0B        buildkit.dockerfile.v0
<missing>      2 hours ago         ARG version=6.2.5                               0B        buildkit.dockerfile.v0
<missing>      2 hours ago         ENV WORK_DIR=/usr/local                         0B        buildkit.dockerfile.v0
<missing>      2 hours ago         LABEL author=morirs                             0B        buildkit.dockerfile.v0
<missing>      2 years ago         /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>      2 years ago         /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B
<missing>      2 years ago         /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4…   204MB

每一行的RUN命令都会产生一层image layer, 导致镜像的臃肿。

修改为如下:

from centos:7label author=morirsenv WORK_DIR /usr/localarg version=6.2.5workdir $WORK_DIRADD redis-${version}.tar.gz .run yum -y update \&& yum install -y wget gcc gcc-c++ automake autoconf libtool make \&& run make -C redis-${version}expose 6379env REDIS_HOME $WORK_DIR/redis-6.2.5env PATH $PATH:$REDIS_HOME/srcentrypoint ["redis-server"]

新的镜像分层如下:

$ docker history redis:6.2.5.2
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
fa6f23e424bc   30 seconds ago   ENTRYPOINT ["redis-server"]                     0B        buildkit.dockerfile.v0
<missing>      30 seconds ago   ENV PATH=/usr/local/sbin:/usr/local/bin:/usr…   0B        buildkit.dockerfile.v0
<missing>      30 seconds ago   ENV REDIS_HOME=/usr/local/redis-6.2.5           0B        buildkit.dockerfile.v0
<missing>      30 seconds ago   EXPOSE map[6379/tcp:{}]                         0B        buildkit.dockerfile.v0
<missing>      30 seconds ago   RUN |1 version=6.2.5 /bin/sh -c yum -y updat…   593MB     buildkit.dockerfile.v0
<missing>      2 hours ago      ADD redis-6.2.5.tar.gz . # buildkit             10.4MB    buildkit.dockerfile.v0
<missing>      2 hours ago      WORKDIR /usr/local                              0B        buildkit.dockerfile.v0
<missing>      2 hours ago      ARG version=6.2.5                               0B        buildkit.dockerfile.v0
<missing>      2 hours ago      ENV WORK_DIR=/usr/local                         0B        buildkit.dockerfile.v0
<missing>      2 hours ago      LABEL author=morirs                             0B        buildkit.dockerfile.v0
<missing>      2 years ago      /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
<missing>      2 years ago      /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B
<missing>      2 years ago      /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4…   204MB

镜像的大小变化如下:

$ docker image ls
REPOSITORY        TAG             IMAGE ID       CREATED              SIZE
redis             6.2.5.2         fa6f23e424bc   About a minute ago   807MB
redis             6.2.5.1         444f31557106   15 minutes ago       996MB

合理使用缓存

在构建的时候尽量将不变的结构放在Dockerfile的前面,经常变化的结构放在Dockerfile的后面,这样构建的时候不变的部分层构建过了就无需再次构建,节约时间,可以在构建的日志中看到CACHED

s$ docker image build -f redis.dockerfile2 -t redis:6.2.5.2 .
[+] Building 268.3s (9/9) FINISHED=> [internal] load build definition from redis.dockerfile2                                                                                0.0s=> => transferring dockerfile: 412B                                                                                                       0.0s=> [internal] load .dockerignore                                                                                                          0.0s=> => transferring context: 2B                                                                                                            0.0s=> [internal] load metadata for docker.io/library/centos:7                                                                                0.0s=> [1/4] FROM docker.io/library/centos:7                                                                                                  0.0s=> [internal] load build context                                                                                                          0.0s=> => transferring context: 42B                                                                                                           0.0s=> CACHED [2/4] WORKDIR /usr/local                                                                                                        0.0s=> CACHED [3/4] ADD redis-6.2.5.tar.gz .                                                                                                  0.0s=> [4/4] RUN yum -y update  && yum install -y wget gcc gcc-c++ automake autoconf libtool make  && make -C redis-6.2.5                   265.0s=> exporting to image                                                                                                                     3.2s=> => exporting layers                                                                                                                    3.2s=> => writing image sha256:fa6f23e424bc6088f6cc84d5ff67ae1376f18fbc906e14b670bc3e4c316046e6                                               0.0s=> => naming to docker.io/library/redis:6.2.5.2                                                                                           0.0s

合理使用.dockerignore

Docker是client-server架构,理论上Client和Server可以不在一台机器上。

在构建docker镜像的时候,需要把所需要的文件由CLI(client)发给Server,这些文件实际上就是build context。

举例:

$ cat redis6.2.6.dockerfile
from centos:7label author=morirsenv WORK_DIR /usr/localarg version=6.2.6workdir $WORK_DIRCOPY . .run tar -zxvf redis-${version}.tar.gz
run yum -y update
run yum install -y wget gcc gcc-c++ automake autoconf libtool make
run make -C redis-${version}expose 6379env REDIS_HOME $WORK_DIR/redis-6.2.5env PATH $PATH:$REDIS_HOME/srcentrypoint ["redis-server"]

构建目录下的文件:

total 4848
drwxrwxr-x 2 morris morris    4096 Sep 19 19:30 ./
drwxrwxr-x 4 morris morris    4096 Sep 18 10:00 ../
-rw-rw-r-- 1 morris morris 2465302 Jul 22  2021 redis-6.2.5.tar.gz
-rw-rw-r-- 1 morris morris 2476542 Oct  4  2021 redis-6.2.6.tar.gz
-rw-rw-r-- 1 morris morris     356 Sep 18 11:28 redis.dockerfile
-rw-rw-r-- 1 morris morris     360 Sep 18 11:39 redis.dockerfile2
-rw-rw-r-- 1 morris morris     373 Sep 19 19:30 redis6.2.6.dockerfile

构建的时候,第一行输出就是发送build context大小为4.947MB,这里包含了不需要的文件redis-6.2.5.tar.gz

$ docker image build -f redis6.2.6.dockerfile -t redis:6.2.6.1 .
Sending build context to Docker daemon  4.947MB
Step 1/14 : from centos:7---> eeb6ee3f44bd

编写.dockerignore文件,忽略掉不需要的文件,然后放到docker构建上下文的根路径下。

$ docker image build -f redis6.2.6.dockerfile -t redis:6.2.6.1 .
Sending build context to Docker daemon  2.482MB
Step 1/14 : from centos:7---> eeb6ee3f44bd

再次构建build context大小变为2.482MB

镜像的多阶段构建

假如有一个C的程序,我们想用Docker去做编译,然后执行可执行文件。

#include <stdio.h>void main(int argc, char *argv[])
{printf("hello %s\n", argv[argc - 1]);
}

构建一个Docker镜像,因为要有C的环境,所以我们选择gcc这个image

FROM gcc:9.4COPY hello.c /src/hello.cWORKDIR /srcRUN gcc --static -o hello hello.cENTRYPOINT [ "/src/hello" ]CMD []

build和测试:

$ docker image build -f c.dockerfile -t hello:1.0 .
... ...$ docker container run --rm -it hello:1.0 hello
hello hello$ docker image ls
REPOSITORY        TAG             IMAGE ID       CREATED          SIZE
hello             1.0             93b8a1824b80   45 seconds ago   1.14GB

可以看到镜像非常的大,1.14GB

实际上当我们把hello.c编译完以后,并不需要这样一个大的GCC环境,一个小的alpine镜像就可以了。

这时候我们就可以使用多阶段构建了。

FROM gcc:9.4 AS builderCOPY hello.c /src/hello.cWORKDIR /srcRUN gcc --static -o hello hello.cFROM alpine:3.13.5COPY --from=builder /src/hello /src/helloENTRYPOINT [ "/src/hello" ]CMD []

构建和测试:

$ docker image build -f c2.dockerfile -t hello:2.0 .
... ...$ docker container run --rm -it hello:2.0 hi
hello hi$ docker image ls
REPOSITORY        TAG             IMAGE ID       CREATED          SIZE
hello             2.0             8127f3ac5ea6   4 seconds ago    6.55MB
hello             1.0             93b8a1824b80   45 seconds ago   1.14GB

可以看到这个镜像非常小,只有6.55MB。

尽量使用非root用户

Root的危险性

docker的root权限一直是其遭受诟病的地方,docker的root权限有那么危险么?我们举个例子。

假如我们有一个用户,叫morris,它本身不具有sudo的权限,所以就有很多文件无法进行读写操作,比如/root目录它是无法查看的。

$ ls /root
ls: cannot open directory '/root': Permission denied

但是这个用户有执行docker的权限,也就是它在docker这个group里。

$ groups
morris docker

这时,我们就可以通过Docker做很多越权的事情了,比如,我们可以把这个无法查看的/root目录映射到docker container里,你就可以自由进行查看了。

$ docker container run -it --rm -v /root:/root/tmp centos:7 bash
[root@9cc0d1275a15 /]# ls /root/tmp
snap

更甚至我们可以给我们自己加sudo权限:

$ docker container run -it --rm -v /etc/sudoers:/root/sudoers centos:7 bash
[root@744b21d23ba9 /]# echo "demo    ALL=(ALL)       ALL" >> /root/sudoers
[root@744b21d23ba9 /]# more /root/sudoers | grep demo
demo    ALL=(ALL)       ALL

然后退出container,morris用户已经有sudo权限了。

$ ls /etc/sudoers
/etc/sudoers

如何使用非root用户

通过groupadd和useradd创建一个nonroot的组和用户,通过USER指定后面的命令要以nonroot这个用户的身份运行

from centos:7label author=morirsenv WORK_DIR /usr/localarg version=6.2.5workdir $WORK_DIRADD redis-${version}.tar.gz .run yum -y update \&& yum install -y wget gcc gcc-c++ automake autoconf libtool make \&& make -C redis-${version} \&& groupadd -r nonroot \&& useradd -r -g nonroot nonroot \&& chown -R nonroot:nonroot $WORK_DIRUSER nonrootexpose 6379env REDIS_HOME $WORK_DIR/redis-6.2.5env PATH $PATH:$REDIS_HOME/srcentrypoint ["redis-server"]

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

黔院长 | 邀您一同共筑养生健康项目!

黔院长&#xff0c;作为一家有百年技术传承并致力于打造大健康产业的企业&#xff0c;为更好的践行“为健康而生&#xff0c;助天下无疾”的初心和使命&#xff0c;更好的让健康事业造福百姓&#xff0c;让更多的人能够从这份事业当中获益&#xff0c;现面向全国火热招商&#…

【Chrome】使用k8s、docker部署无头浏览器Headless,Java调用示例

什么是无头浏览器&#xff1f; 无头浏览器是一种没有图形用户界面的浏览器。无头浏览器不通过其图形用户界面(GUI)控制浏览器的操作&#xff0c;而是使用命令行。 为什么要用Chrome无头&#xff1f; Chrome Headless用于抓取(谷歌)、测试(开发者)和黑客(黑客)。搜索引擎&…

短视频矩阵系统源码/技术应用搭建

短视频矩阵系统开发围绕的开发核心维度&#xff1a; 1. 多账号原理开发维度 适用于多平台多账号管理&#xff0c;支持不同类型账号矩阵通过工具实现统一便捷式管理。&#xff08;企业号&#xff0c;员工号&#xff0c;个人号&#xff09; 2. 账号矩阵内容开发维护 利用账号矩…

香港科技大学广州|可持续能源与环境学域博士招生宣讲会—广州大学城专场!!!(暨全额奖学金政策)

香港科技大学广州&#xff5c;可持续能源与环境学域博士招生宣讲会—广州大学城专场&#xff01;&#xff01;&#xff01;&#xff08;暨全额奖学金政策&#xff09; “面向未来改变游戏规则的——可持续能源与环境学域” &#xfffd;&#xfffd;&#xfffd;专注于能源环…

代码随想录算法训练营第三十一天丨 贪心算法part02

122.买卖股票的最佳时机 II 思路 本题首先要理清楚两点&#xff1a; 只有一只股票&#xff01;当前只有买股票或者卖股票的操作 想获得利润至少要两天为一个交易单元。 #贪心算法 这道题目可能我们只会想&#xff0c;选一个低的买入&#xff0c;再选个高的卖&#xff0c;…

如何把Elasticsearch中的数据导出为CSV格式的文件

前言| 本文结合用户实际需求用按照数据量从小到大的提供三种方式从ES中将数据导出成CSV形式。本文将重点介Kibana/Elasticsearch高效导出的插件、工具集&#xff0c;通过本文你可以了解如下信息&#xff1a; 1&#xff0c;从kibana导出数据到csv文件 2&#xff0c;logstash导…

rockchip 3588 HDMI avmute

概述 HDMI (High-Definition Multimedia Interface) 是一种数字接口标准&#xff0c;用于传输高清视频和多通道音频信号。AVMUTE 是 HDMI 规范中的一个术语&#xff0c;表示"Audio-Video Mute"&#xff08;音视频静音&#xff09;。AVMUTE 通常与 HDMI 设备的音频和…

HDMI线EMI超标整改方案

HDMI端口辐射&#xff08;EMI&#xff09;超标解决方案_hdmi esd器件对 emi的影响-CSDN博客HDMI端口辐射&#xff08;EMI&#xff09;超标解决方案一、HDMI EMC设计要求&#xff1a;1、HDMI EMC设计原理图( 图 一 )2、HDMI元件选型及参数说明&#xff1a;&#xff08;图一所示&…

分发糖果[困难]

优质博文&#xff1a;IT-BLOG-CN 一、题目 n个孩子站成一排。给你一个整数数组ratings表示每个孩子的评分。你需要按照以下要求&#xff0c;给这些孩子分发糖果&#xff1a; 【1】每个孩子至少分配到1个糖果。 【2】相邻两个孩子评分更高的孩子会获得更多的糖果。 请你给每个孩…

物联网_01_物理设备的网络接入

设备的网络接入及物理层使用到的传输协议 现在物理设备有两种接入方式,一种是直接接入另一种是网关接入 直接接入 给物理设备添加NB-IOT通信模组等设备使之具有直接接入网络的能力 网关接入 物理设备在本地组网后通过统一的网关接入到网络(ZigBee无线组网网关).网关是处在本地…

服务器数据恢复-某银行服务器硬盘数据恢复案例

服务器故障&分析&#xff1a; 某银行的某一业务模块崩溃&#xff0c;无法正常使用。排查服务器故障&#xff0c;发现运行该业务模块的服务器中多块硬盘离线&#xff0c;导致上层应用崩溃。 故障服务器内多块硬盘掉线&#xff0c;硬盘掉线数量超过服务器raid阵列冗余级别所允…

过硫酸铵溶液蚀刻回收铜上石墨烯片的合成

引言 石墨烯是一种原子级薄层2D碳纳米材料&#xff0c;具有以六方晶格结构排列的sp2键碳原子。石墨烯因其优异的物理和电子性能而受到广泛关注。自发现石墨烯以来&#xff0c;石墨烯的基础、合成方法和潜在应用的研究一直在积极进行。 化学气相沉积是大规模生产石墨烯的有前途…

【Docker】Dockerfile常用指令

参考官方文档&#xff1a;https://docs.docker.com/engine/reference/builder/ Dockerfile常用指令 指令说明from基础镜像&#xff0c;当前镜像基于&#xff08;依赖&#xff09;哪个镜像maintainer镜像的维护者和邮箱run镜像构建时需要执行的命令workdir镜像的工作目录expos…

NSS [NCTF 2018]滴!晨跑打卡

NSS [NCTF 2018]滴!晨跑打卡 很明显是sql注入 输入一个1&#xff0c;语句直接显示了&#xff0c;非常的真诚和坦率 简单尝试了一下&#xff0c;发现有waf&#xff0c;过滤了空格 拿burp跑一下fuzz&#xff0c;看看有多少过滤 过滤了# * - 空格那我们无法通过#或者–来注释掉…

CentOS 7设置固定IP地址

当我们安装了一个虚拟机或者装了一个系统的时候&#xff0c;经常会遇到需要设置固定ip的情况&#xff0c;本文就以Centos 7为例&#xff0c;讲述如何修改固定IP地址。 1、用ifconfig命令查看使用的网卡 如上图所示&#xff0c;我们就会看到我们目前使用的网卡名称 2、编辑网卡…

【机器学习】支持向量机(实战)

支持向量机&#xff08;实战&#xff09; 目录 一、准备工作&#xff08;设置 jupyter notebook 中的字体大小样式等&#xff09;二、线性支持向量机&#xff08;核函数为线性核&#xff09;三、数据标准化的影响四、软间隔五、非线性支持向量机5.1 手动升维5.2 对比试验&#…

洗车小程序源码:10个必备功能,提升洗车体验

作为洗车行业的专家&#xff0c;我们深知在如今数字化时代&#xff0c;拥有一款功能强大的洗车小程序是提升用户体验和业务发展的关键。本文将向您介绍洗车小程序源码中的10个必备功能&#xff0c;让您的洗车业务达到新的高度。 在线预约系统 通过洗车小程序源码&#xff0c;…

强化学习代码实战(1)

机器人领域&#xff1a;控制&#xff0c;规划&#xff0c;感知等都可以用&#xff0c;可以把它作为一个优化过程&#xff0c;那么任何需要优化的问题都可以用它解决。 1.应用 深度学习&#xff1a;智能感知&#xff0c;解决智能如何理解这个世界的问题。 强化学习&#xff1a…

华为云 CodeArts Snap 智能编程助手 PyCharm 插件安装与使用指南

1 插件安装下载 1.1 搜索插件 打开 PyCharm&#xff0c;选择 File&#xff0c;点击 Settings。 选择 Plugins&#xff0c;点击 Marketplace&#xff0c;并在搜索框中输入 Huawei Cloud CodeArts Snap。 1.2 安装插件 如上图所示&#xff0c;点击 Install 按钮安装 Huawei Cl…

C++IO流

文章目录 CIO流1. C语言的输入与输出2. 流是什么3. CIO流3.1 C标准IO流3.2 C文件IO流 4 stringstream的简单介绍 CIO流 1. C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf()与printf()。 scanf(): 从标准输入设备(键盘)读取数据&#xff0c;并将值存放在…