docker-学习-5

docker-学习第五天

1. 昨天的练习回顾

1.1. 练习1

1、以nginx为基础镜像编写dockerfile。并构建为一个名为nginxtest的镜像,要求镜像内安装一个tcpdump工具,下载或从本地拉取一个tar包并解压。构建镜像后运行容器,并暴露端口访问。(要求熟悉dockerfile常用指令,容器运行常见参数,以及如何进入容器内部)

[root@docker-1 Dockerfile]# mkdir yuan
[root@docker-1 Dockerfile]# cd yuan/
[root@docker-1 yuan]# vim Dockerfile
[root@docker-1 yuan]# cat Dockerfile 
FROM nginx:latest
WORKDIR /
RUN apt-get update && apt-get install tcpdump -y
RUN curl -O https://nginx.org/download/nginx-1.25.1.tar.gz && tar xf nginx-1.25.1.tar.gz
ENTRYPOINT ["/docker-entrypoint.sh"]
EXPOSE 80
STOPSIGNAL SIGQUIT
CMD ["nginx", "-g", "daemon off;"]
[root@docker-1 yuan]# 

[root@docker-1 yuan]# docker build -t scnginx:1.0 .
[+] Building 187.4s (7/7) FINISHED                                                                             
 => [internal] load build definition from Dockerfile                                                           
 => => transferring dockerfile: 308B                                                                           
 => [internal] load metadata for docker.io/library/nginx:latest                                                
 => [internal] load .dockerignore                                                                              
 => => transferring context: 2B                                                                                
 => CACHED [1/4] FROM docker.io/library/nginx:latest                                                           
 => [2/4] RUN apt-get update && apt-get install tcpdump -y                                                     
 => [3/4] RUN curl -O https://nginx.org/download/nginx-1.25.1.tar.gz && tar xf nginx-1.25.1.tar.gz             
 => exporting to image                                                                                         
 => => exporting layers                                                                                        
 => => writing image sha256:c2f927b6b99793f3012e5065e75ddd83c663cf0923c33d6f0a4f713fb760da60                   
 => => naming to docker.io/library/scnginx:1.0                                                                 
[root@docker-1 yuan]# docker images|grep scnginx
scnginx      1.0       c2f927b6b997   5 minutes ago   172MB
[root@docker-1 yuan]# 

[root@docker-1 yuan]# docker run -d -p 4433:80 --name li-5 scnginx:1.0
9669cf417c8e3cf30bb641b3592924def5c64b15904324e203d467e53c6c29af
[root@docker-1 yuan]# docker ps
CONTAINER ID   IMAGE         COMMAND                   CREATED         STATUS         PORTS                                   NAMES
9669cf417c8e   scnginx:1.0   "/docker-entrypoint.…"   2 seconds ago   Up 2 seconds   0.0.0.0:4433->80/tcp, :::4433->80/tcp   li-5
[root@docker-1 yuan]# 

image-20240205154936840

1.2. 练习2

1.以centos7作为基础镜像
2.在里面安装好ip,vim,ping命令
3.安装好nginx
4.启动容器的时候,就启动nginx

[root@docker-1 Dockerfile]# mkdir renlei/
cd /renlei
[root@docker-1 renlei]# vim onekey_install-nginx.sh
[root@docker-1 renlei]# cat onekey_install-nginx.sh 
#!/bin/bash

#解决软件的依赖关系,需要安装的软件包
yum install epel-release -y
yum -y install zlib zlib-devel pcre pcre-devel gcc gcc-c++ autoconf automake make psmisc lsof vim wget -y

#新建luogan用户和组
id  lilin || useradd lilin -s /sbin/nologin

#下载nginx软件
mkdir  /lilin99 -p
cd /lilin99
wget  https://nginx.org/download/nginx-1.21.4.tar.gz

#解压软件
tar xf nginx-1.21.4.tar.gz 
#进入解压后的文件夹
cd nginx-1.21.4

#编译前的配置
./configure --prefix=/usr/local/sclilin99  --user=lilin --group=lilin   

#如果上面的编译前的配置失败,直接退出脚本
if (( $? != 0));then
    exit
fi
#编译,启动2个进程去编译,这样速度快
make -j 2
#编译安装
make  install

#修改PATH变量
echo  "PATH=$PATH:/usr/local/sclilin99/sbin" >>/root/.bashrc

[root@docker-1 renlei]# 

[root@docker-1 renlei]# vim Dockerfile 
FROM centos:7
RUN yum install iproute vim net-tools -y
WORKDIR /sc
COPY onekey_install-nginx.sh /sc
RUN bash onekey_install-nginx.sh
EXPOSE 80
CMD ["/usr/local/sclilin99/sbin/nginx", "-g", "daemon off;"]
[root@docker-1 renlei]# 

[root@docker-1 renlei]# docker build -t renweb:1.0 .
[+] Building 342.1s (10/10) FINISHED                                                           docker:default
 => [internal] load build definition from Dockerfile                                                     0.0s
 => => transferring dockerfile: 243B                                                                     0.0s
 => [internal] load metadata for docker.io/library/centos:7                                              0.0s
 => [internal] load .dockerignore                                                                        0.0s
 => => transferring context: 2B                                                                          0.0s
 => CACHED [1/5] FROM docker.io/library/centos:7                                                         0.0s
 => [internal] load build context                                                                        0.0s
 => => transferring context: 881B                                                                        0.0s
 => [2/5] RUN yum install iproute vim net-tools -y                                                     127.7s
 => [3/5] WORKDIR /sc                                                                                    0.0s 
 => [4/5] COPY onekey_install-nginx.sh /sc                                                               0.0s 
 => [5/5] RUN bash onekey_install-nginx.sh                                                             213.7s 
 => exporting to image                                                                                   0.6s 
 => => exporting layers                                                                                  0.6s 
 => => writing image sha256:77d49c8ba1e0f0514fac7833e031ef4fd3b85048e3c546d24659fb88a693937c             0.0s 
 => => naming to docker.io/library/renweb:1.0                                                            0.0s 
[root@docker-1 renlei]#                               

[root@docker-1 renlei]# docker run -d -p 4422:80  --name renweb-1  renweb:1.0                                 
730b13da5358627bb843d82f73d840305ba274ca8efbccb44a54b740b1ecf073                                              
[root@docker-1 renlei]# docker ps|grep renweb-1
730b13da5358   renweb:1.0    "/usr/local/sclilin9…"   14 seconds ago   Up 13 seconds   0.0.0.0:4422->80/tcp, :::4422->80/tcp   renweb-1
[root@docker-1 renlei]# 

image-20240205160101670

2. 命令

2.1. 看镜像的详细信息

[root@docker-1 ~] docker inspect hnweb:1.0

要加名字和版本号

3. Dockerfile指令

3.1. 常见的指令

Dockerfile 是一个用来构建 Docker 镜像的文本文件,它包含了一系列的指令,每一条指令都会创建一个新的镜像层。Dockerfile 的指令有以下几种:

  • FROM:这是 Dockerfile 的第一条指令,它指定了镜像的基础层,也就是从哪个镜像开始构建。例如,FROM ubuntu:18.04 表示从 Ubuntu 18.04 的镜像开始构建。

  • RUN:这是 Dockerfile 的最常用的指令,它用来在镜像中执行一些命令,通常是安装一些软件包或库。例如,RUN apt-get update && apt-get install -y python3 表示在镜像中更新软件源并安装 Python 3。

  • COPY:这是 Dockerfile 的另一个常用的指令,它用来将本地文件或目录复制到镜像中的指定位置。例如,COPY app.py /app/ 表示将本地的 app.py 文件复制到镜像中的 /app/ 目录下。

  • ADD:这是 Dockerfile 的一个类似于 COPY 的指令,它也用来将本地文件或目录复制到镜像中的指定位置,但是它还有一些额外的功能,如可以解压压缩文件,或者从 URL 下载文件。例如,ADD https://example.com/file.tar.gz /app/ 表示从网址下载 file.tar.gz 文件并解压到镜像中的 /app/ 目录下。

  • CMD:这是 Dockerfile 的一个用来指定容器启动时默认执行的命令的指令,它只能有一条,如果有多条,只有最后一条会生效。例如,CMD ["python3", "app.py"] 表示容器启动时默认执行 python3 app.py 命令。

  • ENTRYPOINT:这是 Dockerfile 的一个用来指定容器启动时的入口点的指令,它和 CMD 类似,但是它可以接受容器运行时传入的参数,而 CMD 不可以。例如,ENTRYPOINT ["ping"] 表示容器启动时的入口点是 ping 命令,如果运行时传入了 google.com 参数,那么容器就会执行 ping google.com 命令。

  • EXPOSE:这是 Dockerfile 的一个用来声明容器内部的端口号的指令,它不会真正地将端口暴露出来,而是只是一个文档化的作用,表示容器提供了哪些服务。例如,EXPOSE 80 表示容器提供了 80 端口的服务,如 HTTP。

  • ENV:这是 Dockerfile 的一个用来设置环境变量的指令,它可以在镜像中或者容器运行时使用。例如,ENV PORT 8080 表示设置环境变量 PORT 的值为 8080。

  • WORKDIR:这是 Dockerfile 的一个用来设置工作目录的指令,它会影响后续的 RUN,COPY,ADD,CMD,ENTRYPOINT 等指令的执行路径。例如,WORKDIR /app 表示设置工作目录为 /app,那么后续的指令都会在 /app 下执行。

  • VOLUME:这是 Dockerfile 的一个用来创建数据卷的指令,它可以将容器中的某个目录挂载到宿主机上,从而实现数据的持久化和共享。例如,VOLUME /data 表示创建一个数据卷,将容器中的 /data 目录挂载到宿主机上。

  • USER:这是 Dockerfile 的一个用来指定容器运行时的用户的指令,它可以提高容器的安全性,避免以 root 用户运行。例如,USER www-data 表示指定容器运行时的用户为 www-data。

  • LABEL:这是 Dockerfile 的一个用来添加元数据的指令,它可以给镜像添加一些标签,如作者,版本,描述等。例如,LABEL maintainer="John Doe" version="1.0" description="A simple web app" 表示给镜像添加了维护者,版本,描述等标签。

  • ARG:这是 Dockerfile 的一个用来定义构建参数的指令,它可以在构建镜像时传入一些变量,从而实现动态的配置。例如,ARG PORT=80 表示定义了一个构建参数 PORT,它的默认值为 80,但是可以在构建时修改,如 docker build --build-arg PORT=8080 .

  • ONBUILD:这是 Dockerfile 的一个用来定义触发器的指令,它可以在当前镜像被用作其他镜像的基础层时执行一些命令。例如,ONBUILD RUN pip install -r requirements.txt 表示当当前镜像被用作其他镜像的基础层时,会自动执行 pip install -r requirements.txt 命令。

  • STOPSIGNAL:这是 Dockerfile 的一个用来指定容器停止时的信号的指令,它可以覆盖默认的 SIGTERM 信号,使用其他的信号来优雅地停止容器。例如,STOPSIGNAL SIGKILL 表示指定容器停止时的信号为 SIGKILL,强制杀死容器。

  • HEALTHCHECK:这是 Dockerfile 的一个用来检查容器健康状态的指令,它可以定期执行一些命令,来判断容器是否正常运行。例如,HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/ || exit 1 表示每隔 5 分钟执行一次 curl -f http://localhost/ 命令,如果返回非 0 值,就表示容器不健康。

3.2. ENTRYPOINT和CMD的区别

ENTRYPOINT是比较新的用法,当ENTRYPOINT和CMD都存在的时候,以ENTRYPOINT为准,这个时候,cmd就成了ENTRYPOINT里的参数(参数位置):

ENTRYPOINT ["docker-entrypoint.sh"] 

EXPOSE 3306 33060 

CMD ["mysqld"]

这是 Dockerfile 的三条指令,它们的含义如下:

  • ENTRYPOINT [“docker-entrypoint.sh”]:这是用来指定容器启动时的入口点的指令,它表示容器启动时会执行 docker-entrypoint.sh 这个脚本,这个脚本通常是用来初始化一些配置或环境变量,或者执行一些前置操作,如创建数据库,设置密码等。
  • EXPOSE 3306 33060:这是用来声明容器内部的端口号的指令,它表示容器提供了 3306 和 33060 这两个端口的服务,这两个端口分别是 MySQL 的默认端口和 X Protocol 的端口,用来提供数据库的连接和访问。
  • CMD [“mysqld”]:这是用来指定容器启动时默认执行的命令的指令,它表示容器启动时默认执行 mysqld 这个命令,这个命令是用来启动 MySQL 服务器的,它会接受容器运行时传入的参数,如 --user=root--password=123456 等。

相当于docker-entrypoint.sh mysqld —》mysqld就相当于位置参数传递过去了

3.3. RUN中的set指令

set指令能设置所使用shell的执行方式,可依照不同的需求来做设置.

语法 set [±abCdefhHklmnpPtuvx]

参数说明:

-e  若指令传回值不等于0,则立即退出shell。

-u  当执行时使用到未定义过的变量,则显示错误信息。

-x  执行指令后,会先显示该指令的执行过程及所下的参数。

例子:

RUN set -eux; \
	savedAptMark="$(apt-mark showmanual)"; \
	apt-get update; \
	apt-get install -y --no-install-recommends ca-certificates wget; \
	rm -rf /var/lib/apt/lists/*; \

这是 Dockerfile 的一条 RUN 指令,它用来在镜像中执行一些命令,通常是安装一些软件包或库。这条指令的作用如下:

  • set -eux
    

    :这是一个 shell 命令,它用来设置一些选项,如:

    • -e 表示如果命令执行失败,就退出脚本,避免继续执行错误的命令。
    • -u 表示如果使用未定义的变量,就报错,避免使用错误的变量。
    • -x 表示打印出执行的命令,方便调试和查看。
  • savedAptMark="$(apt-mark showmanual)":这是一个赋值语句,它用来将 apt-mark showmanual 这个命令的输出赋值给 savedAptMark 这个变量。apt-mark showmanual 这个命令是用来显示手动安装的软件包的,这样可以在后面恢复这些软件包的状态。

  • apt-get update:这是一个更新软件源的命令,它用来获取最新的软件包信息,以便安装最新的软件包。

  • apt-get install -y --no-install-recommends ca-certificates wget
    

    :这是一个安装软件包的命令,它用来安装

    ca-certificates
    

    wget
    

    这两个软件包,以及它们的依赖。其中:

    • -y 表示自动回答 yes,不需要用户交互。
    • --no-install-recommends 表示不安装推荐的软件包,只安装必要的软件包,以减少镜像的大小。
  • rm -rf /var/lib/apt/lists/*:这是一个删除文件的命令,它用来删除 /var/lib/apt/lists/ 这个目录下的所有文件,这个目录是用来存储软件源的信息的,删除它可以减少镜像的大小,因为这些信息在构建镜像后就不需要了。

这就是这条 RUN 指令的解释,它的目的是在镜像中安装 ca-certificateswget 这两个软件包,并且尽量减少镜像的大小。

RUN set -x \
# create nginx user/group first, to be consistent throughout docker variants
    && addgroup --system --gid 101 nginx \
    && adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid 101 nginx \
    && apt-get update \

这是 Dockerfile 的一条 RUN 指令,它用来在镜像中执行一些命令,通常是安装一些软件包或库。这条指令的作用如下:

  • set -x:这是一个 shell 命令,它用来打印出执行的命令,方便调试和查看。
  • addgroup --system --gid 101 nginx:这是一个创建用户组的命令,它用来创建一个名为 nginx 的系统用户组,它的组 ID 为 101。
  • adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos "nginx user" --shell /bin/false --uid 101 nginx:这是一个创建用户的命令,它用来创建一个名为 nginx 的系统用户,它的用户 ID 为 101,它属于 nginx 用户组,它不能登录,它没有创建家目录,它的家目录为 /nonexistent,它的注释为 “nginx user”,它的 shell 为 /bin/false。
  • apt-get update:这是一个更新软件源的命令,它用来获取最新的软件包信息,以便安装最新的软件包。

这就是这条 RUN 指令的解释,它的目的是在镜像中创建一个 nginx 用户和用户组,并且更新软件源。

4. 镜像的原理

4.1. 为什么 Docker 镜像要采用这种分层结构呢?

Docker 镜像是由多个只读层组成的,每一层都是基于上一层的修改。这种分层结构有以下几个优点:

  • 节省空间:每一层都可以被多个镜像共享,只需要存储一份即可。例如,如果有多个镜像都基于同一个操作系统,那么操作系统层就只需要存储一次。
  • 提高效率:每一层都可以被缓存,从而加快镜像的构建和拉取。例如,如果一个镜像只修改了最上层的文件,那么只需要拉取最上层即可,而不需要拉取整个镜像。
  • 增加灵活性:每一层都可以被单独修改,从而实现不同的功能。例如,可以在同一个基础镜像上添加不同的应用程序,或者在同一个应用程序镜像上修改不同的配置文件。

4.2. docker镜像分层的结构

82fe7807c2fef6ca0cff4f50a23a300

bootfs –》容器启动的时候需要的内容

rootfs –》容器内部的操作系统

这张图片是一个 Docker 容器的内部结构的示意图,它展示了一个容器是如何由不同的软件和配置层叠在一起的。下面我会逐层解释一下:

  • 内核层:这是容器的最底层,它是操作系统的核心部分,负责和计算机硬件进行交互。容器共享宿主机的内核,因此不需要在容器中安装内核。
  • bootfs 层:这是容器的第二层,它是启动文件系统,负责容器的启动过程。当容器启动完成后,这一层就会被卸载,因此不会占用空间。
  • 基础层:这是容器的第三层,它是一个基础操作系统,提供了最基本的环境和工具。这个示例中使用的是 Debian,但也可以使用其他的操作系统,如 Ubuntu,Alpine 等。
  • 依赖层:这是容器的第四层,它是在基础层之上添加的一些必要的软件包或库,为应用程序提供了依赖支持。这个示例中没有显示具体的依赖层,但可以想象,如果要运行一个 Python 应用程序,可能需要安装 Python,pip,numpy 等。
  • 应用层:这是容器的第五层,它是在依赖层之上添加的一个或多个应用程序或服务,是容器的主要功能部分。这个示例中添加了 Apache 和 emacs 两个应用程序,分别是一个网页服务器和一个文本编辑器。
  • 数据层:这是容器的最上层,它是可写的,负责存储容器运行时产生的数据或配置文件。这一层是容器的临时部分,当容器停止时,这一层的修改会被丢弃,除非使用 docker commit 命令将其保存为新的镜像。

这就是 Docker 容器的分层结构,每一层都是只读的,除了最上层的数据层,它是可写的。每一层都可以被缓存,共享,复用,从而实现了容器的高效,轻量,灵活的特点。

镜像的内核使用的是宿主机的内核

所有的容器都是共享宿主机的内核kernel

4e6bb1b4586cfc7048b79b235789195

上图 Debian 和 BusyBox上层提供各自的 rootfs,底层共用 Docker Host 的 kernel。

容器只能使用 Host 的 kernel,并且不能修改。所有容器都共用 host 的 kernel,在容器中没办法对 kernel 升级。

这张图片是一个 Linux 操作系统的组件和层次的示意图,它展示了一个操作系统是如何由不同的部分组合在一起的。下面我会逐个解释一下:

  • 内核层:这是操作系统的最底层,它是一段负责管理硬件资源,提供系统服务,执行程序的代码。内核是操作系统的核心,决定了操作系统的性能和稳定性。这个示例中使用的是 Linux 内核,它是一个开源的,跨平台的,可定制的内核。
  • BusyBox 层:这是操作系统的第二层,它是一个集成了许多常用命令和工具的软件包,如 ls,cp,cat,ping 等。BusyBox 是一个轻量级的,适合嵌入式系统的软件包,它可以提供基本的系统功能,如文件操作,网络通信,进程管理等。
  • Debian 层:这是操作系统的第三层,它是一个基于 Linux 内核的发行版,提供了一个完整的,易用的,多样化的操作系统环境。Debian 是一个广泛使用的,有着严格的质量标准和社区支持的发行版,它包含了数以万计的软件包,可以满足各种用户的需求。
  • rootfs 层:这是操作系统的最上层,它是一个可写的,负责存储用户数据和配置文件的文件系统。rootfs 是操作系统的根目录,它包含了所有的文件和目录,如 /bin,/etc,/home 等。rootfs 可以使用不同的文件系统类型,如 ext4,btrfs,zfs 等。

这就是 Linux 操作系统的组件和层次,每一层都是由不同的软件或配置构成的,从而实现了操作系统的功能和特性。我希望这个回答能够帮助你理解 Linux 操作系统的原理。

每装个软件,或者说用一次RUN 镜像就会增加一层,镜像就会越大

img

4.3. base镜像

base 镜像提供的是最小安装的 Linux 发行版

FROM scratch 官方说明:该镜像是一个空的镜像,可以用于构建busybox等超小镜像,可以说是真正的从零开始构建属于自己的镜像

4.4. 容器的启动

容器启动的时候是自下而上的

3e395e0917ab9797653db4feda75dee

这个时候涉及到容器的写实拷贝

如果在第三层找到了文件1 那就不用继续往下找了

  1. 添加文件 在容器中创建文件时,新文件被添加到容器层中。

  2. 读取文件 在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,打开并读入内存。

  3. 修改文件 在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。

  4. 删除文件 在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。

4.5. 镜像分层的好处

分层的好处在于共享资源,比如说有很多的镜像,可以从base镜像构建而来,那么docker host当中只需要在硬盘上保存一份base镜像即可,同时内存当中也只需要加载一份base镜像即可,也就是说我开多少的相同的镜像,内存在上涨值并不明显,就可以给所有的使用该base镜像的容器提供服务,而且镜像的每一层可以被单独的共享,也就是这一层如果跟其他的镜像重复的话,这一层就可以单独拿出来进行共享。

5. 小知识点

5.1. 如何让你制作的镜像比较小

  • 使用基础镜像要小
  • 少使用RUN和COPY,ADD、WORKDIR
  • 使用镜像启动容器后,再在里面安装软件,使用卷挂载数据

5.2. 镜像为什么要制作的小一点

  • 下载快
  • 存贮,占用磁盘空间小
  • 运行容器的时候占用的内容小
  • 资源消耗小
  • 17
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不冤不乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值