第2节 docker实用操作


❤️💕💕新时代拥抱云原生,云原生具有环境统一、按需付费、即开即用、稳定性强特点。Myblog:http://nsddd.topopen in new window


[TOC]

前言

由docker引入k8s

docker容器化技术

  1. 基础镜像MB级别
  2. 创建简单
  3. 隔离性强
  4. 启动速度秒级
  5. 移植和分享方便

dockerfile

💡前面我们都知道了用commit提交镜像,用tag打包镜像,但是其实commit命令是在镜像的每一层每一层上面进行添加。所以此时就有了dockerfiledockerfile就是一条条的指令,每一条指令代表的一层。

可以想象c语言的makefile、Linux的bash脚本

目录选择:

其实对于我个人喜欢在Linux的根目录下创建专门存放docker的镜像,喜欢在win的D盘根目录下创建docker镜像

mkdir -p /docker/nginx && mkdir -p /docker/tomcat

FROM指定镜像:

FROM就是指定基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。

FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

Docker Storeopen in new window上有非常多的高质量的官方镜像,有可以直接拿来使用的服务类的镜像,如 nginx、redis、mongo、mysql、httpd、php、tomcat 等;也有一些方便开发、构建、运行各种语言应用的镜像,如 node、openjdk、python、ruby、golang 等。可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。

除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。

⚠️其实这一点我很疑惑的,就是创建一个空白的镜像后面该怎么样运行呢

scratch空白镜像

如果你以scratch为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。没有任何基础镜像,我怎么去执行我的程序呢,其实对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接FROM scratch会让镜像体积更加小巧。使用 Go 语言 开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。

run命令

RUN指令是用来执行命令行命令的。由于命令行的强大能力,RUN指令在定制镜像时是最常用的指令之一。其格式有两种:

  • shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式。

    RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
    
  • exec 格式:RUN ["可执行文件", "参数1", "参数2"],这更像是函数调用中的格式。 既然 RUN 就像 Shell 脚本一样可以执行命令,那么我们是否就可以像 Shell 脚本一样把每个命令对应一个 RUN 呢?比如这样:

    FROM debian:jessie
    RUN apt-get update
    RUN apt-get install -y gcc libc6-dev make
    RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"
    RUN mkdir -p /usr/src/redis
    RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
    RUN make -C /usr/src/redis
    RUN make -C /usr/src/redis install
    

之前说过,Dockerfile 中每一个指令都会建立一层,RUN 也不例外。每一个 RUN 的行为,就和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像。

Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。

镜像压缩和发送

这个我认为是一个比较有用的技巧,就是把镜像整一个压缩包,然后发送出去

[root@VM-4-6-centos ~]# docker save -o my_cloudreve.tar docker.io/3293172751/my_cloudreve:1.0
[root@VM-4-6-centos ~]# ls |grep my_cloudreve.tar 
my_cloudreve.tar

远程传输scp

[root@VM-4-6-centos ~]# scp my_cloudreve.tar root@110.42.175.115:/scp/

image-20221018100209153

新的机器启用镜像

docker load -i 压缩包名称.tar

推送到远程仓库

将应用打包为镜像

以前的土方法

Java为例:

  1. springboot打包jar
  2. 把jar上传服务
  3. 服务器运行jar

docker解决方案

使用dockerfile指定应用如何打包

创建Java项目

打包dockerfile

FROM openjdk:8-jdk-slim
LABEL maintainer=leifengyang

COPY target/*.jar /app.jar

ENTRYPOINT ["java","-jar","/app.jar"]

构建:

docker build -t java-demo:v1.0 .

重新启动:

docker run -d -p 8080:8080 --name myjava java-demo:v1.0

docker 清理使用的空间

清理 Docker 使用的空间:

建议使用 Docker 命令来清理不再使用的容器。可以使用以下命令清理容器、网络文件、镜像和构建缓存:

docker system prune -a

此外,也可以清除不再使用的卷:

docker volumes prune

有时候,它可能很快就把磁盘占满了,所以要经常检查它的根目录(的磁盘占用情况),但是不建议手动删除或编辑 Docker 文件,最好使用 prune 命令来释放磁盘空间。

Dockerinit

Dockerinit是Docker容器启动时运行的初始化进程。它负责设置容器的环境,包括设置网络、挂载已指定的任何卷,以及执行Dockerfile的ENTRYPOINT或CMD指令中指定的命令。Dockerinit通常由Docker守护进程启动,并在容器中作为PID 1运行。

容器进程和应用进程

在 Docker 容器中,容器进程是运行容器的进程,应用程序进程是在容器内运行应用程序的进程。容器进程负责管理容器的资源和网络,而应用进程负责运行应用。

容器进程和应用程序进程之间的一个关键区别是:

  • 容器进程以特殊权限运行,而应用程序进程没有。
  • 容器进程可以访问主机系统的资源,并且可以控制在容器内运行的其他进程。
  • 另一方面,应用进程受限于分配给容器的资源,并且不能访问主机系统的资源或控制在容器中运行的其它进程。
  • 另一个区别是容器进程通常由 Docker 守护进程启动,而应用程序进程由容器进程启动。
  • 容器进程通常是创建容器时启动的第一个进程,它负责启动应用程序进程和可能需要的任何其他进程。

Linux 绑定挂载机制

Docker 使用的是 Linux 的绑定挂载 (bind mount) 技术,这种挂载方式会把宿主机的文件或目录挂载到容器中。

当你使用 docker run 命令挂载一个目录时,Docker 会把宿主机目录挂载到容器中,并且在容器中对该目录的任何修改会同步到宿主机。这对于在容器中运行应用程序并将其输出保存到宿主机目录中非常有用。

例如,假设你有一个应用程序在容器中运行,并生成一些输出文件。你可以使用下面的命令将宿主机的目录挂载到容器中,以便将应用程序的输出保存到宿主机目录中:

$ docker run -v /host/dir:/container/dir <image>

这将把宿主机的 /host/dir 目录挂载到容器的 /container/dir 目录。你也可以使用绝对路径或相对路径来指定源目录和目标目录。

绑定机制中修改文件会发生什么?

在使用绑定挂载时,对容器中的文件进行修改会同步到宿主机目录中。

例如,假设你使用下面的命令将宿主机的 /host/dir 目录挂载到容器的 /container/dir 目录:

$ docker run -v /host/dir:/container/dir <image>

然后,你在容器中使用以下命令修改 /container/dir 目录中的文件:

$ echo "new content" > /container/dir/file.txt

这将在容器中创建或覆盖文件 /container/dir/file.txt ,并且对文件的修改会同步到宿主机的 /host/dir/file.txt 文件中。

同样的,如果你在宿主机上修改 /host/dir/file.txt 文件,那么这些修改也会反映到容器的 /container/dir/file.txt 文件中。

绑定挂载是一种很有用的功能,可以让你在容器中轻松访问和修改宿主机目录中的文件。

内核角度分析:

在 Linux 内核的角度来看,绑定挂载是一种特殊的文件系统挂载方式。

当你执行 "mount" 命令时,你可以指定一个源路径和一个目标路径。源路径是要挂载的文件系统,目标路径是挂载点,即挂载后文件系统在文件系统树中的位置。

在绑定挂载的情况下,源路径和目标路径都是在同一个文件系统中的路径。因此,在绑定挂载的情况下,你可以将一个目录挂载到另一个目录上,而不是将一个文件系统挂载到另一个文件系统上。

绑定挂载可以通过 "mount" 命令的 "--bind" 选项来实现。例如,你可以使用下面的命令将目录 /host/dir 绑定挂载到目录 /container/dir 上:

$ mount --bind /host/dir /container/dir

在这种情况下,对 /container/dir 目录的任何修改都会同步到 /host/dir 目录中。

END 链接

参考

https://www.qikqiak.com/k8s-book/