Docker容器:数据管理与镜像的创建(主要基于Dockerfile)

目录

一、Docker 数据管理

1、数据卷(Data Volumes)

2、数据卷容器(DataVolumes Containers)

二、容器互联(使用centos镜像)

三、Docker 镜像的创建

1、基于现有镜像创建

2、基于本地模板创建

3、基于Dockerfile 创建

3.1 联合文件系统(UnionFS)

3.2 docker镜像的分层(基于AUFS构建)

3.2.1 镜像的分层

3.2.2 涉及技术

3.3 镜像加载原理

3.3 为什么 Docker 里的centos的大小才200M

3.4 认识 Dockerfile

3.5 Dockerfile 结构

3.6 Docker 镜像结构的分层

3.7 Dockerfile 操作常用的指令

四、Dockerfile 镜像实战

1、构建 SSH 镜像

1.1 建立工作目录

1.2 创建 sshd Dockerfile 文件

1.3 生成镜像

1.4 启动容器并修改root密码

2、构建 systemctl 镜像

2.1 建立工作目录

2.2 创建 systemctl Dockerfile 文件

2.3 生成镜像

2.4 启动容器,并挂载宿主机目录挂载到容器中,和进行初始化

2.5 进入容器,使用 systemcd 管理服务

3、构建 apache 镜像

3.1 建立工作目录

3.2 创建 nginx Dockerfile 文件

3.3 创建启动容器时执行的脚本

3.4 准备网站页面

3.5 生成镜像

3.6 新镜像运行容器

3.7 浏览器测试页面

4、构建 nginx 镜像

4.1 建立工作目录并上传nginx安装包

4.2 创建 nginx Dockerfile 文件

4.3 创建启动容器时执行的脚本

4.4 生成镜像

4.5 启动容器并开启宿主机端口映射

4.6 浏览器测试页面

5、构建 tomcat 镜像

5.1 建立工作目录并上传所需安装包

5.2 创建 tomcat Dockerfile 文件

5.3 生成镜像

5.4 启动容器并指定宿主机端口映射 tomcat 8080 端口

5.5 浏览器测试访问页面

6、构建 mysql 镜像

6.1 建立工作目录并上传mysql安装包

6.2 创建 mysql Dockerfile 文件

6.3 可选创建启动容器时执行的脚本

6.4 编辑mysql主配置文件

6.5 生成镜像

6.6 启动容器,并进行初始化

6.7 进入容器,授权远程连接 mysql

五、总结

1、数据管理

2、创建镜像

2.1 基于现有镜像创建

2.2 基于本地模版创建

2.3 基于 Dockerfile 创建镜像


一、Docker 数据管理

管理 Docker 容器中数据主要有两种方式:数据卷(Data Volumes)数据卷容器(DataVolumes Containers)

1、数据卷(Data Volumes)

  • 数据卷是一个供容器使用的特殊目录,位于容器中
  • 可将宿主机的目录挂载到数据卷上,对数据卷的修改操作立刻可见,并且更新数据不会影响镜像,从而实现数据在宿主机与容器之间的迁移
  • 数据卷的使用类似于 Linux 下对目录进行的 mount 操作
  • 数据卷通常适用于挂载服务器的配置文件目录、网页站点目录、日志目录

案例一:创建数据卷

(1)创建新容器并设置数据卷,然后在容器的数据卷目录写入新文件

#宿主机目录/var/www 挂载到容器中的/data1
注意:宿主机本地目录的路径必须是使用绝对路径。如果路径不存在,Docker会自动创建相应的路径
docker run -it -v /mnt:/data1 --name web1 centos:7 /bin/bash            
#-v 选项可以在容器内创建数据卷

#在容器的数据卷目录里写入新文件,并退出
ls 
echo "welcome to my world" > /data1/test
cat /data1/test
exit

(2)查看宿主机的挂载点目录是否有刚创建的新文件

ls /mnt
cat /mnt/test

(3)创建一个新容器并使用web1容器的数据卷挂载点目录,则新容器就有相应的挂载点目录和目录中的所有文件

docker run -it -v /mnt:/data1 --name example centos:7 /bin/bash

ls
cat /data1/test

(4)在本地宿主机上的挂载点目录/mnt下写入新文件 

echo "hello world" > /mnt/bak
cat /mnt/bak

 (5)开启web1和example容器,并分别进入这两个容器,能查看到在挂载点目录有bak文件(这是在宿主机上写入的新数据文件)

#开启web1容器,能查看到在挂载点目录有bak文件(这是在宿主机上写入的新数据文件)
docker start web1
docker exec -it web1 /bin/bash
cat /data1/bak 
exit

#开启example容器,能查看到在挂载点目录有bak文件(这是在宿主机上写入的新数据文件)
docker start example 
docker exec -it example /bin/bash
ls /data1/
cat /data1/bak 
exit

案例二: 将外部的nginx配置文件迁移到nginx的容器中,并且能访问到nginx容器提供的页面

(1) 上传nginx.conf配置文件并创建nginx01容器,然后将本地的nginx配置文件挂载到容器的nginx配置文件  

cd /opt   #上传nginx.conf配置文件到宿主机目录
docker run -itd --name nginx01 -p 80:80 -v /opt/nginx.conf:/etc/nginx/nginx.conf nginx /bin/bash
#创建nginx01容器,并将本地的nginx配置文件挂载到容器的nginx配置文件    

(2)查看 nginx.conf配置文件指定的网页站点根目录

(3)进入到nginx01容器中,然后创建站点目录和网页文件,最后启动nginx服务

#进入到nginx01容器中
docker exec -it nginx01 /bin/bash

#创建站点目录和网页文件
mkdir /mnt/html
echo " hello world" > /mnt/html/index.html

#启动nginx服务
/usr/sbin/nginx

(4)浏览器访问宿主机IP地址,测试能否查看到网页资源

2、数据卷容器(DataVolumes Containers)

如果需要在容器之间共享一些数据,最简单的方法就是使用数据卷容器

数据卷容器是一个独立的容器,专门用来提供数据卷供其他容器挂载。当你创建一个数据卷容器时,它会在容器的指定目录中创建一个数据卷,其他容器可以通过挂载这个数据卷来访问其中的数据

(1)创建一个容器web2作为数据卷容器

#创建一个容器作为数据卷容器
docker run -it --name web2 -v /mnt -v /opt centos:7 /bin/bash

#在数据卷容器中的数据卷目录中写入新文件
echo "this is hello" > /mnt/abc.txt
echo "this is world" > /opt/ABC.txt

(2) 使用 --volumes-from 来挂载 web2 容器中的数据卷到新的容器

#使用 --volumes-from 来挂载 web2 容器中的数据卷到新的容器
docker run -it --volumes-from web2 --name web3 centos:7 /bin/bash

cat /mnt/abc.txt
cat /opt/ABC.txt

二、容器互联(使用centos镜像)

容器互联是通过容器的名称在容器间建立一条专门的网络通信隧道。简单点说,就是会在源容器和接收容器之间建立一条隧道,接收容器可以看到源容器指定的信息

(1)创建并运行源容器

#创建并运行源容器取名web4
docker run -itd -P --name web4 centos:7 /bin/bash 

(2)创建并运行接收容器取名web5,使用--link选项指定连接容器以实现容器互联

#创建并运行接收容器取名web5,使用--link选项指定连接容器以实现容器互联
docker run -itd -P --name web5 --link web4:web4 centos:7 /bin/bash            
#--link 容器名:连接的别名
#web4:web4:第一个web4指容器名称为web4,第二个web4是别名,可自定义

(3)进入接收容器web5,使用ping命令来测试能否联通web4 

#进web5容器
docker exec -it web5 bash
#使用ping命令来测试能否联通web4 
ping web4

三、Docker 镜像的创建

创建镜像有三种方法,分别为基于已有镜像创建、基于本地模板创建以及基于Dockerfile创建

1、基于现有镜像创建

(1)首先创建并启动一个容器,在容器里新增数据

docker run -it --name test centos:7 /bin/bash
echo "hello world" > 1.txt
exit
docker ps -a

(2)然后将新增数据后的容器提交为新的镜像,需要使用该容器的 ID 号创建新镜像

docker ps -a | grep test   #查看test容器的ID
docker commit -m "new" -a "centos" 6e642a617401 centos:news  #创建新镜像
#常用选项:
-m:说明信息
-a:作者信息
-p:生成过程中停止容器的运行

docker images

(3)创建新容器并使用该镜像 

docker run -it --name ke centos:news /bin/bash
ls
cat 1.txt

2、基于本地模板创建

通过导入操作系统模板文件可以生成镜像,模板可以从 OPENVZ 开源项目下载

下载地址为:http://openvz.org/Download/template/precreated

方法一:浏览器下载包并上传至Linux机器
cd /opt      #上传debian-7.0-x86-minimal.tar.gz

方法二:直接在Linux机器下载包
wget http://download.openvz.org/template/precreated/debian-7.0-x86-minimal.tar.gz

#导入为镜像
cat debian-7.0-x86-minimal.tar.gz | docker import - debian:test
#查看当前所有镜像
docker images

#创建新容器并运行,可使用刚导入的debian镜像
docker run -itd --name deb debian:test /bin/bash
#也可进入并使用该容器
docker exec -it deb /bin/bash

3、基于Dockerfile 创建

3.1 联合文件系统(UnionFS)

  • UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下
  • Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像
  • 特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
  • 我们下载的时候看到的一层层的就是联合文件系统

联合文件系统的主要优点包括:

① 节省空间:由于联合文件系统的特性,相同的文件只需在底层文件系统存储一次,因此可以节省存储空间

② 快速构建和部署:通过将不同层的文件系统组合在一起,可以快速构建和部署容器镜像

③ 轻量级:联合文件系统允许容器共享相同的基础镜像层,从而减少了资源消耗

常见的联合文件系统实现包括 OverlayFS、AUFS、btrfs、Devicemapper等。这些技术在不同的操作系统和容器平台中有不同的支持程度,但它们都提供了类似的功能,使得容器技术能够更高效地利用文件系统资源

3.2 docker镜像的分层(基于AUFS构建)

3.2.1 镜像的分层

镜像不是一个单一的文件,而是有多层构成。容器其实是在镜像的最上面加了一层读写层,在运行容器里做的任何文件改动,都会写到这个读写层。如果删除了容器,也就删除了其最上面的读写层,文件改动也就丢失了。Docker 使用存储驱动管理镜像每层内容及可读写层的容器层

  • Dockerfile 中的每个指令都会创建一个新的镜像层
  • 镜像层将被缓存和复用
  • 当Dockerfile 的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应镜像层缓存就会失效
  • 某一层的镜像缓存失效,它之后的镜像层缓存都会失效
  • 镜像层是不可变的,如果在某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件,只是这个文件在 Docker 容器中不可见了

① Kernel(内核层)

是操作系统的核心组件,负责管理硬件资源、提供系统服务,并为应用程序提供运行环境。在Docker场景下,提及 Kernel 通常是指 Docker 宿主机的 Kernel,而不是镜像内部的 Kernel

② Base Image(基础镜像层)

是构建其他 Docker 镜像的基础。它通常是最底层的镜像,包含一个精简的操作系统环境(如Alpine Linux、Ubuntu、CentOS等)以及必要的系统工具

③ Image(只读镜像层)

是 Docker 中用于创建容器的模板,它是由一系列分层组成的。每个镜像层代表了对前一层的增量更改,如安装一个软件包、添加文件或修改配置。镜像层是只读的,且每一层都有一个唯一的标识符

④ Container(容器层)

是基于镜像实例化的、轻量级的、可执行的软件单元。容器包含了运行特定应用所需的所有依赖(代码、运行时、库、环境变量等),并利用Linux内核的隔离机制与其他容器及宿主机隔离。每个容器都从其对应的镜像顶部的读写层(也称为“容器层”或“Overlay层”)开始,在此之上进行运行时的写入操作

⑤ Worke(工作节点)

在需要修改文件时创建文件的副本,而不是直接修改原始文件。在容器中,这意味着当容器试图修改镜像中的文件时,文件系统并不直接修改原始文件,而是在需要时将原始文件复制到新的位置,然后对副本进行修改。确保原始镜像层的完整性,同时允许容器在自己的文件系统视图中进行修改,而不会影响其他容器或原始镜像

⑥ Merge(合并视图层)

对 Docker 镜像信息进行抽象、组织并展示给用户的逻辑层面;实际上是软件为用户提供的一种逻辑抽象和交互界面,用于展示和操作 Docker 镜像的相关信息。由于它是一个逻辑概念,且通过用户接口隐藏了底层细节,所以被称为“看不见的”

3.2.2 涉及技术

(1)bootfs (boot file system) 内核空间

  • 主要包含bootloader和kernel,bootloader主要是引导加载kernel, Linux刚启 动时会加载bootfs文件系统
  • 在Docker 镜像的最底层是bootfs,这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会把临时创建的bootfs这个文件系统删掉
  • 在linux操作系统中(不同版本的linux发行版本),linux加载bootfs时会将rootfs设置为read-only,系统自检后会将只读改为读写,让我们可以在操作系统中进行操作

(2)rootfs (root file system) 内核空间

  • 在bootfs之上(base images, 例如centos、ubuntu)
  • 包含的就是典型Linux 系统中的/dev, /proc, /bin, /etc 等标准目录和文件
  • rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等

3.3 镜像加载原理

其实就是当容器启动时,镜像的各个层通过联合文件系统技术被叠加到一起,形成一个单独的文件系统视图

① 分层结构:Docker镜像采用分层结构,每一层包含了文件系统的一部分和相关设置。这些层相互叠加,形成完整的镜像

② 联合文件系统:Docker使用联合文件系统(UnionFS)技术将这些分层的只读文件系统叠加在一起,形成一个虚拟的文件系统视图

③ 镜像加载:当容器被创建时,Docker会根据镜像的定义,将这些层加载到内存中,并创建一个可写的容器层,以便容器内的应用程序可以对其进行修改而不影响原始镜像

④ 写时复制:对于容器内的文件修改,Docker使用写时复制(Copy-on-Write)技术,即只有在需要修改文件时才会复制底层数据,确保原始镜像层的完整性

⑤ 一旦镜像的各个层被加载并合并到一起,容器运行时负责启动容器进程,并提供隔离的运行环境,使得应用程序能够在其中独立运行

① 我们可以理解成一开始内核里什么都没有,操作一个命令下载debian,这时就会在内核上面加了一层基础镜像;再安装一个emacs,会在基础镜像上叠加一层image

② 接着再安装一个apache,又会在images上面再叠加一层image。最后它们看起来就像一个文件系统即容器的rootfs

③ 在Docker的体系里把这些rootfs叫做Docker的镜像

④ 但是,此时的每一层rootfs都是read-only的,我们此时还不能对其进行操作

⑤ 当我们创建一个容器,也就是将Docker镜像进行实例化,系统会在一层或是多层read-only的rootfs之上分配一层空的read-write的rootfs

3.3 为什么 Docker 里的centos的大小才200M

  • 因为对于精简的OS,rootfs可以很小,只需要包含最基本的命令、工具和程序库就可以了,因为底层直接用宿主机的kernel,自己只需要提供rootfs就可以了
  • 由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs

3.4 认识 Dockerfile

  • Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)
  • 镜像不包含任何动态数据,其内容在构建之后也不会被改变
  • 镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile
  • Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了Dockerfile,当我们需要定制自己额外的需求时,只需在Dockerfile上添加或者修改指令,重新生成 image 即可, 省去了敲命令的麻烦
  • 除了手动生成Docker镜像之外,可以使用Dockerfile自动生成镜像。Dockerfile是由多条的指令组成的文件,其中每条指令对应 Linux 中的一条命令,Docker 程序将读取Dockerfile 中的指令生成指定镜像。

3.5 Dockerfile 结构

  • Dockerfile结构大致分为四个部分:基础镜像信息、维护者信息、镜像操作指令容器启动时执行指令
  • Dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用以“#“号开头的注释

3.6 Docker 镜像结构的分层

镜像不是一个单一的文件,而是有多层构成。容器其实是在镜像的最上面加了一层读写层,在运行容器里做的任何文件改动,都会写到这个读写层。如果删除了容器,也就删除了其最上面的读写层,文件改动也就丢失了。Docker使用存储驱动管理镜像每层内容及可读写层的容器层

(1)Dockerfile 中的每个指令都会创建一个新的镜像层;

(2)镜像层将被缓存和复用;

(3)当Dockerfile 的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效;

(4)某一层的镜像缓存失效,它之后的镜像层缓存都会失效;

(5)镜像层是不可变的,如果在某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件,只是这个文件在 Docker 容器中不可见了

3.7 Dockerfile 操作常用的指令

(1)指定基础镜像
格式:FROM 镜像:标签
#指定新镜像所基于的基础镜像,第一条指令必须为 FROM 指令,每创建一个镜像就需要一条 FROM 指令

(2)设置镜像的作者信息
格式:MAINTAINER 名字
#说明新镜像的维护人信息

(3)运行命令,类似于在容器中执行命令
格式:RUN 命令
#在所基于的镜像上执行命令,并提交到新的镜像中

(4)定义容器启动时执行的默认命令,并且可以被覆盖
格式:ENTRYPOINT ["要运行的程序", "参数 1", "参数 2"]
#设定容器启动时第一个运行的命令及其参数,可以通过使用命令docker run --entrypoint 来覆盖镜像中的ENTRYPOINT指令的内容

(5)定义容器启动时执行的默认命令
格式:CMD ["要运行的程序", "参数1", "参数2"] 
#上面的是exec形式,shell格式:CMD  命令 参数1 参数2
#启动容器时默认执行的命令或者脚本,Dockerfile只能有一条CMD命令。如果指定多条命令,只执行最后一条命令

注:如果在docker run时指定了命令或者镜像中有ENTRYPOINT,那么CMD就会被覆盖,CMD 可以为 ENTRYPOINT 指令提供默认参数
如:先执行 ENTRYPOINT ["rm"]
    后执行 CMD ["cp" ,"-rf",“*”]
此时,CMD执行的cp命令无效,有效的是ENTRYPOINT执行的rm命令,且CMD为ENTRYPOINT命令提供参数
-rf 和 *,所有最终执行的命令是rm -rf *

java -jar xxxxxxx.jar  8090

执行命令的优先级:RUN > ENTRYPOINT > CMD,先执行run命令后执行ENTRYPOINT命令最后执行CMD命令

(6)暴露容器的端口
格式: EXPOSE 8090
#指定新镜像加载到 Docker 时要开启的端口

(7)在镜像中设置环境变量
格式:ENV 环境变量 变量值
#设置一个环境变量的值,会被后面的 RUN 使用
linxu PATH=$PATH:/opt
  ENV PATH=$PATH:/opt

(8)将源文件复制到镜像中,源文件要与 Dockerfile 位于相同目录中,或者是一个 URL  
格式:ADD 源文件/目录 目标文件/目录

有如下注意事项:
① 如果源路径是个文件,且目标路径是以 / 结尾, 则docker会把目标路径当作一个目录,会把源文件拷贝到该目录下
如果目标路径不存在,则会自动创建目标路径
/home/data/:此路径表示目录

② 如果源路径是个文件,且目标路径是不以 / 结尾,则docker会把目标路径当作一个文件
如果目标路径不存在,会以目标路径为名创建一个文件,内容同源文件;
如果目标文件是个存在的文件,会用源文件覆盖它,当然只是内容覆盖,文件名还是目标文件名。
如果目标文件实际是个存在的目录,则会源文件拷贝到该目录下。 注意,这种情况下,最好显示的以 / 结尾,以避免混淆。
/home/data/1.txt:此路径表示文件

③ 如果源路径是个目录,且目标路径不存在,则docker会自动以目标路径创建一个目录,把源路径目录下的文件拷贝进来。
如果目标路径是个已经存在的目录,则docker会把源路径目录下的文件拷贝到该目录下。

④如果源文件是个归档文件(压缩文件),则docker会自动帮解压。    
URL下载和解压特性不能一起使用。任何压缩文件通过URL拷贝,都不会自动解压。

(9)将文件从主机复制到镜像内部
格式:COPY 源文件/目录 目标文件/目录
#只复制本地主机上的文件/目录复制到目标地点,源文件/目录要与Dockerfile 在相同的目录中

(10)在容器中创建一个挂载点
格式:VOLUME [“目录”]   

(11)指定运行容器时的用户
格式:USER 用户名/UID

(12)设置工作目录,后续命令将在此目录下执行
格式:WORKDIR 路径 /home
#为后续的 RUN、CMD、ENTRYPOINT 指定工作目录

(13)指定所生成的镜像作为一个基础镜像时所要运行的命令
ONBUILD <instruction> 
#当在一个Dockerfile文件中加上ONBUILD指令,该指令对利用该Dockerfile构建镜像(比如为A镜像)不会产生实质性影响
#但是当编写一个新的Dockerfile文件来基于A镜像构建一个镜像(比如为B镜像)时,这时构造A镜像的Dockerfile文件中的ONBUILD指令就生效了,在构建B镜像的过程中,首先会执行ONBUILD指令指定的指令,然后才会执行其它指令

ONBUILD rm - rf /*
注:请各位自己在生产中如果用的是别的dockerfile 请自习阅读,否则后果自付

(14)健康检查
HEALTHCHECK [options] CMD command_to_run
#使用给定的命令进行健康检查,如果返回状态码为0,则表示容器健康;否则为不健康
HEALTHCHECK none 
#禁用健康检查

HEALTHCHECK可以包含以下选项:
--interval=duration:设置间隔多久运行一次健康检查命令,默认为30秒
--timeout=duration:设置健康检查命令运行超时时间,默认为30秒
--retries=n:设置在健康检查失败后重试的次数,默认为3次

在编写 Dockerfile 时,有严格的格式需要遵循:

  • 第一行必须使用 FROM 指令指明所基于的镜像名称
  • 之后使用 MAINTAINER 指令说明维护该镜像的用户信息
  • 然后是镜像操作相关指令,如 RUN 指令。每运行一条指令,都会给基础镜像添加新的一层
  • 最后使用 CMD 指令指定启动容器时要运行的命令操作

四、Dockerfile 镜像实战

1、构建 SSH 镜像

构建SSH镜像的作用在于为用户提供一个具备SSH(Secure Shell)功能的容器环境

SSH是一种加密的网络协议,常用于安全地远程登录到计算机系统,并在远程系统上执行命令

1.1 建立工作目录

mkdir /opt/sshd     
cd /opt/sshd

1.2 创建 sshd Dockerfile 文件

vim Dockerfile

FROM centos:7                   #基于的基础镜像centos:7       
MAINTAINER sshd image <dh>     #维护镜像的用户信息
RUN yum -y update
RUN yum install -y openssh* net-tools lsof telnet passwd
#安装OpenSSH服务器和客户端工具、net-tools(用于网络配置和诊断)、lsof(用于列出打开文件的工具)、telnet(用于远程登录测试)和passwd(用于设置密码)
RUN echo '123456' | passwd --stdin root
#设置了root用户的密码为123456
RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config
#-i选项表示直接在文件中进行修改
#将其中的UsePAM yes配置改为UsePAM no。这个修改通常用于禁用PAM认证
RUN sed -ri '/^session\s+required\s+pam_loginuid.so/ s/^/#/' /etc/pam.d/sshd
#-r选项用于启用扩展正则表达式
#使用sed命令注释了/etc/pam.d/sshd文件中与pam_loginuid.so相关的配置行
#\s+: 这是一个转义序列,表示匹配一个或多个空白字符(例如空格、制表符等)
RUN ssh-keygen -t rsa -A        #生成了SSH服务器的RSA密钥对
RUN mkdir -p /root/.ssh && chown root.root /root && chmod 700 /root/.ssh
#创建了root用户的.ssh目录,并设置权限。这个目录通常用于存放SSH用户的公钥,以实现密钥认证登录
EXPOSE 22                       
#Docker容器监听SSH服务的22端口           
CMD ["/usr/sbin/sshd" , "-D"]
#对于OpenSSH服务器,由于其默认行为已经是前台模式,因此不需要额外指定参数FOREGROUND
#为了确保将输出发送到控制台并以调试模式持续运行,仍需要在启动命令中添加-D参数

1.3 生成镜像

docker build -t sshd:centos .   #生成镜像
# -t 参数用于指定构建镜像的名称及标签
# . 就是指示Docker在当前目录中查找名为Dockerfile的文件,并以此文件作为构建镜像的基础

docker images  #查看所有镜像

1.4 启动容器并修改root密码

docker run -d -P sshd:centos
docker ps -a
ssh localhost -p 32770

#其他机器也可以使用  【ssh 宿主机ip -p 容器映射的端口号】 来登录该容器
ssh 172.16.12.10 -p 32770

########如果有网络报错提示########
[Warning] IPv4 forwarding is disabled. Networking will not work.

解决方法:
vim /etc/sysctl.conf
net.ipv4.ip_forward=1

sysctl -p
systemctl restart network
systemctl restart docker

2、构建 systemctl 镜像

2.1 建立工作目录

mkdir /opt/systemctl    
cd /opt/systemctl

2.2 创建 systemctl Dockerfile 文件

vim Dockerfile

FROM sshd:centos
MAINTAINER systemctl image <dh>
ENV container docker          
#设置一个环境变量container,其值为docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \ 
#删除除了systemd-tmpfiles-setup.service的其它所有文件       
rm -f /lib/systemd/system/multi-user.target.wants/*; \
rm -f /etc/systemd/system/*.wants/*; \
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
#CMD ["/usr/sbin/init"]
#基础镜像中的CMD指令会被继承到新镜像中,除非在新的Dockerfile中显式地覆盖它
#基础镜像(sshd:centos)已经定义了CMD指令(CMD ["/usr/sbin/sshd", "-D"])

2.3 生成镜像

docker build -t systemd:centos .   #生成镜像
# -t 参数用于指定构建镜像的名称及标签
# . 就是指示Docker在当前目录中查找名为Dockerfile的文件,并以此文件作为构建镜像的基础

docker images  #查看所有镜像

2.4 启动容器,并挂载宿主机目录挂载到容器中,和进行初始化

docker run --privileged -d -P -v /sys/fs/cgroup:/sys/fs/cgroup:ro systemd:centos /sbin/init
# --privileged: 使用特权模式,这会赋予容器访问主机上所有设备的权限
# 使container内的root拥有真正的root权限。否则,container内的root只是外部的一个普通用户权限
# -P: 将容器内部使用的网络端口映射到主机上的随机端口
# -v /sys/fs/cgroup:/sys/fs/cgroup:ro: 将主机的/sys/fs/cgroup目录挂载到容器的相同路径,并设置为只读(ro表示read-only)
# 这是为了让容器能够访问主机的 cgroup 文件系统,通常用于容器内运行systemd
# /sbin/init: 指定容器启动时要运行的命令,这里是启动systemd的初始化进程
或者:
docker run --privileged -it -P -v /sys/fs/cgroup:/sys/fs/cgroup:ro systemd:centos /sbin/init &

2.5 进入容器,使用 systemcd 管理服务

docker ps -a
#进入到容器内
docker exec -it fca5d5d475a4 bash

#使用systemd 管理 sshd 服务
systemctl start sshd
systemctl start sshd

3、构建 apache 镜像

3.1 建立工作目录

mkdir /opt/apache
cd /opt/apache

3.2 创建 nginx Dockerfile 文件

vim Dockerfile

FROM centos:7                           # 基于的基础镜像centos:7
MAINTAINER apache image <dh>           # 维护镜像的用户信息
RUN yum -y update
RUN yum install -y httpd                # 基于基础镜像安装apache
EXPOSE 80                               # Docker服务器开启80端口
ADD index.html /var/www/html/index.html # 复制本地源文件至正在构建的镜像内部
#方法一:将启动容器时运行apache服务的执行脚本复制到镜像中
ADD run.sh /run.sh               
RUN chmod 755 /run.sh                # 给镜像中的apache.sh脚本添加权限
CMD ["/run.sh"]                      # 启动容器时执行脚本

#方法二:使用ENTRYPOINT和CMD命令来设置启动容器时运行apache服务
ENTRYPOINT ["/usr/sbin/apachect1"]      # 启动容器时运行apache服务
CMD ["-D","FOREGROUND"]                
# "-D" 参数用于指定一个调试标志或定义服务器的特定行为,FOREGROUND以前台模式运行,进程结束时终止
# CMD优先级低于ENTRYPOINT,为ENTRYPOINT提供命令参数,且

#方法三:使用CMD命令来设置启动容器时运行apache服务
CMD [ "/usr/sbin/apachectl","-D", "FOREGROUND"]
或者运行容器时覆盖默认参数:
docker run my_apache_container -k start

3.3 创建启动容器时执行的脚本

使用方法一时必须得创建,使用其他方法可不创建

vim run.sh

#!/bin/bash
rm -rf /run/httpd/*                # 清理httpd的缓存
/usr/sbin/apachectl -D FOREGROUND  # 指定为前台运行

3.4 准备网站页面

echo "this is apache web" > index.html
ls

3.5 生成镜像

docker build -t httpd:centos .
# -t 参数用于指定构建镜像的名称及标签
# . 就是指示Docker在当前目录中查找名为Dockerfile的文件,并以此文件作为构建镜像的基础

docker images  #查看所有镜像

3.6 新镜像运行容器

docker run -d -p 999:80 httpd:centos
# 以后台运行基于httpd:centos的docker进程,并将宿主机999端口映射到容器的80端口
docker ps -a

3.7 浏览器测试页面

4、构建 nginx 镜像

4.1 建立工作目录并上传nginx安装包

mkdir /opt/nginx
cd /opt/nginx    #需在此路径上传nginx-1.22.0.tar.gz

4.2 创建 nginx Dockerfile 文件

vim Dockerfile

FROM centos:7
MAINTAINER nginx image <dh>
RUN yum -y install pcre-devel zlib-devel gcc gcc-c++ make
RUN useradd -M -s /sbin/nologin nginx
ADD nginx-1.22.0.tar.gz /opt/
WORKDIR /opt/nginx-1.22.0
RUN ./configure \
--prefix=/usr/local/nginx \     # 指定了NGINX安装目录
--user=nginx \
--group=nginx \
--with-http_stub_status_module && make -j 2 && make install # 启用了NGINX的stub status模块
ENV PATH /usr/local/nginx/sbin:$PATH
EXPOSE 80                       # 指定了NGINX监听的HTTP和HTTPS端口
EXPOSE 443
RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf
# daemon off;指示NGINX在前台运行,而不是作为守护进程
ADD run.sh /run.sh         
RUN chmod 755 /run.sh   
CMD ["/run.sh"]               # 容器启动时要执行的脚本
#CMD ["/usr/local/sbin/nginx", "-g", "daemon off;"]
# -g 参数是用来设置NGINX的全局配置项的

4.3 创建启动容器时执行的脚本

vim run.sh

#!/bin/bash
/usr/local/nginx/sbin/nginx

4.4 生成镜像

docker build -t nginx:centos .
# -t 参数用于指定构建镜像的名称及标签
# . 就是指示Docker在当前目录中查找名为Dockerfile的文件,并以此文件作为构建镜像的基础

docker images  #查看所有镜像

4.5 启动容器并开启宿主机端口映射

docker run -d -P nginx:centos
docker ps -a

4.6 浏览器测试页面

5、构建 tomcat 镜像

5.1 建立工作目录并上传所需安装包

mkdir /opt/tomcat
cd /opt/tomcat   #需在此目录上上传jdk-8u291-linux-x64.tar.gz、apache-tomcat-8.5.16.tar.gz

5.2 创建 tomcat Dockerfile 文件

vim Dockerfile

FROM centos:7
MAINTAINER tomcat image <dh>
ADD jdk-8u291-linux-x64.tar.gz /usr/local/  
# 将jdk……tar.gz文件解压到/usr/local/目录下
WORKDIR /usr/local/                         
# 为后续命令指定工作目录/usr/local/
RUN mv jdk1.8.0_291 /usr/local/java         
# 解压后的JDK目录重命名为java并移动到/usr/local/目录下
ENV JAVA_HOME /usr/local/java               
# 设置环境变量JAVA_HOME为/usr/local/java
ENV JRE_HOME ${JAVA_HOME}/jre               
# 设置环境变量JRE_HOME为${JAVA_HOME}/jre
ENV CLASSPATH .:${JAVA_HOME}/lib:${JRE_HOME}/lib 
# 置环境变量CLASSPATH,包含当前目录、Java库和JRE库 
ENV PATH $JAVA_HOME/bin:$PATH               
# 将JAVA_HOME/bin加入到PATH环境变量中
ADD apache-tomcat-8.5.16.tar.gz /usr/local/
WORKDIR /usr/local/                         
# 设置工作目录为/usr/local/
RUN mv apache-tomcat-8.5.16 /usr/local/tomcat 
# 将解压后的Tomcat目录重命名为tomcat并移动到/usr/local/目录下
EXPOSE 8080                                 # 暴露容器的 8080 端口
#CMD ["/usr/local/tomcat/bin/catalina.sh","run"]
# 设置容器启动时执行的命令为 /usr/local/tomcat/bin/catalina.sh run,以启动 Tomcat 服务
ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]
CMD ["/usr/local/tomcat/bin/startup.sh","start"]
# 设置容器启动时默认执行的命令为 /usr/local/tomcat/bin/startup.sh start,以启动Tomcat服务

5.3 生成镜像

docker build -t tomcat:centos .
# -t 参数用于指定构建镜像的名称及标签
# . 就是指示Docker在当前目录中查找名为Dockerfile的文件,并以此文件作为构建镜像的基础

docker images  #查看所有镜像

5.4 启动容器并指定宿主机端口映射 tomcat 8080 端口

docker run -d --name tomcat1 -p 888:8080 tomcat:centos 
docker ps -a

5.5 浏览器测试访问页面

6、构建 mysql 镜像

6.1 建立工作目录并上传mysql安装包

mkdir /opt/mysql
cd /opt/mysql   #需在此路径上上传mysql-boost-5.7.20.tar.gz

6.2 创建 mysql Dockerfile 文件

vim Dockerfile

FROM centos:7
MAINTAINER mysql image <dh>
RUN yum -y install ncurses ncurses-devel bison cmake pcre-devel zlib-devel gcc gcc-c++ make;useradd -M -s /sbin/nologin mysql
ADD mysql-boost-5.7.20.tar.gz /usr/local/src/   
# 添加并解压MySQL源码文件至/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_EXTRA_CHARSETS=all \
-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 -j 2;make install
ADD my.cnf /etc/my.cnf           
# 添加MySQL的配置文件my.cnf到镜像/etc/目录
EXPOSE 3306                      
# 暴露MySQL默认端口3306
RUN chown -R mysql:mysql /usr/local/mysql/;chown mysql:mysql /etc/my.cnf
WORKDIR /usr/local/mysql/bin/    
# 进入/usr/local/mysql/bin/目录并执行MySQL初始化命令
RUN ./mysqld \
--initialize-insecure \
--user=mysql \
--basedir=/usr/local/mysql \
--datadir=/usr/local/mysql/data;cp /usr/local/mysql/usr/lib/systemd/system/mysqld.service /usr/lib/systemd/system/;systemctl enable mysqld
ENV PATH=/usr/local/mysql/bin:/usr/local/mysql/lib:$PATH 
# 设置环境变量PATH,包括MySQL的bin和lib目录
VOLUME [ "/usr/local/mysql" ]    
# 定义数据卷/usr/local/mysql用于持久化存储MySQL数据
CMD ["/usr/sbin/init"]
#ADD run.sh /run.sh
#RUN chmod 755 /run.sh
#CMD ["/run.sh"]

6.3 可选创建启动容器时执行的脚本

如果使用脚本来设置启动容器时运行mysqld服务,就需要创建run.sh脚本

vim run.sh

#!/bin/bash
/usr/local/mysql/bin/mysqld	
systemctl enable mysqld

6.4 编辑mysql主配置文件

vim my.cnf

[client]
port = 3306
default-character-set=utf8
socket = /usr/local/mysql/mysql.sock
 
[mysql]
port = 3306
default-character-set=utf8
socket = /usr/local/mysql/mysql.sock
 
[mysqld]
user = mysql
basedir = /usr/local/mysql
datadir = /usr/local/mysql/data
port = 3306
character_set_server=utf8
pid-file = /usr/local/mysql/mysqld.pid
socket = /usr/local/mysql/mysql.sock
server-id = 1
 
sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_AUTO_VALUE_ON_ZERO,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,PIPES_AS_CONCAT,ANSI_QUOTES

6.5 生成镜像

docker build -t mysql:centos .
# -t 参数用于指定构建镜像的名称及标签
# . 就是指示Docker在当前目录中查找名为Dockerfile的文件,并以此文件作为构建镜像的基础

docker images  #查看所有镜像

6.6 启动容器,并进行初始化

docker run --name mysql_server -d -P --privileged mysql:centos /usr/sbin/init
docker ps -a

6.7 进入容器,授权远程连接 mysql

[root@localhost mysqld]# docker exec -it 06a49f2753b8 /bin/bash
# 可以选择修改密码:
# 给root账号设置密码
# mysqladmin -u root -p password "123456"  直接回车
# 登录 mysql -u root -p123456
[root@06a49f2753b8 bin]# mysql -u root -p  # 无初始密码直接回车
mysql> grant all privileges on *.* to 'root'@'%' identified by 'abc123';
# 授予了一个名为'root'的用户在任何主机上('%'表示所有主机)对所有数据库的所有表拥有全部权限,并设置了密码为'abc123'
mysql> grant all privileges on *.* to 'root'@'localhost' identified by 'abc123';
# 仅授权了在本地主机(即指定为 'localhost')上的'root'用户
mysql> flush privileges;
# 刷新MySQL的权限,使新授权的权限立即生效

五、总结

1、数据管理

(1)数据卷创建

docker run -v 宿主机绝对路径目录(不存在直接创建):容器数据集目录 --name 容器名 -it 镜像:标签 /bin/bash

(2)数据卷容器创建

1.首先创建数据卷:

docker run --name 容器a -v  /容器挂载点1 -v /容器挂载点2 -it 镜像:标签 /bin/bash

2.挂载容器a中的数据卷:

docerk run -it --volume-from 容器a --name 容器b 镜像:标签 /bin/bash

(3)容器互联,文件共享,传输

容器a:

docker run -itd -P --name 容器a 镜像:标签 /bin/bash

容器b:

docker run -itd -P --name 容器b --link 容器a:容器a的别名 镜像:标签 /bin/bash

进入容器b:

docker exec -it 容器b的id/容器b(名字) /bin/bash

2、创建镜像

2.1 基于现有镜像创建

docker run 创建并启动容器;再通过 docker exec/cp 等容器操作指令修改容器内容;然后 docker commit 提交成新的镜像

2.2 基于本地模版创建

从网上下载现有的镜像模版 ,或使用 docker export 导出本地容器的快照模版,然后 docker import - 将快照模版导入本地镜像。

2.3 基于 Dockerfile 创建镜像

Dockerfile 构建镜像的步骤:

  • 先用 FROM 指令指定基础镜像
  • 再用 MAINTAINER 指定维护人信息
  • 然后再用 RUN、EXPOSE、ADD、ENV、USER、WORKDIR 等指令编写镜像的过程
  • 最后使用 CMD 或 ENTPYONT 指令指定启动容器时执行的命令

ENTPYONT与CMD 区别:

  • 容器启动时执行命令的优先级
  • docker run --entypont=命令 镜像 选项 参数 ---> ENTPYONT ["命令","选顶","参数”] ---> docker run 镜像 命令 选项 参数  --->  CMD ["命令","选项","参数"]
  • 如果在同一个 dockerfile 文件中同时存在 ENTPYONT 和 CMD 时,ENTPYONT 会覆盖 CMD 运行命令,CMD 为提供选项和参数

ADD 和 COPY 区别:

  • 都可以复制本地文件/目录到镜像中
  • ADD 可以通过 URL 路径下的文件并复制到镜像,还可以把本地的 tar 压缩包进行解压后复制到镜像
  • COPY 支持配合 --from 选项实现多个阶段构建

如何缩小 Dockerfile 构建的镜像体积大小? 

  • 尽可能减少指令的数量,比如把RUN的linux命令进行合并
  • 尽可能得使用最简洁的基础镜像
  • 使用多阶段(多级)构建

相关推荐

  1. docker镜像创建 dockerfile

    2024-05-02 14:44:02       32 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-02 14:44:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-02 14:44:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-02 14:44:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-02 14:44:02       20 阅读

热门阅读

  1. 详解podman

    2024-05-02 14:44:02       12 阅读
  2. 004 springCloudAlibaba Gateway

    2024-05-02 14:44:02       11 阅读
  3. apache DbUtils 组件核心原理与应用

    2024-05-02 14:44:02       11 阅读
  4. Qt | QLabel 类(标签)

    2024-05-02 14:44:02       10 阅读
  5. 【Qt问题】Qt Creator 如何链接第三方库

    2024-05-02 14:44:02       13 阅读
  6. 编程一定要学好汉语,英语是次要的

    2024-05-02 14:44:02       12 阅读
  7. Linux驱动开发——(八)Linux异步通知

    2024-05-02 14:44:02       14 阅读
  8. 购物网站-批发

    2024-05-02 14:44:02       9 阅读
  9. Rust入门

    2024-05-02 14:44:02       15 阅读
  10. STM32 单片机 GPIO 的八种工作模式是什么?

    2024-05-02 14:44:02       12 阅读
  11. Linux常用命令总结

    2024-05-02 14:44:02       14 阅读