目录
一、Docker镜像的创建
情况说明:创建镜像有三种方法,分别为基于已有的容器创建、基于本地模板创建以及基于Dockerfile创建
1、基于现有容器创建
1.1 启动新的容器
命令示例:首先创建并启动一个容器,在容器里新增数据
docker run -it --name test centos:7 /bin/bash
echo "hello world" |tee 1.txt
exit
docker ps -a
输出结果:
[root@MineGi ~]# docker run -it --name test centos:7 /bin/bash
[root@372617ed7dd0 /]# echo "hello world" |tee 1.txt
hello world
[root@372617ed7dd0 /]# exit
exit
[root@MineGi ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
372617ed7dd0 centos:7 "/bin/bash" 30 seconds ago Exited (0) 6 seconds ago test
[root@MineGi ~]#
1.2 提交为新镜像
docker commit -m "new-1.txt" -a "centos" test centos:new-1.txt #创建新镜像
#常用选项:
-m:说明信息
-a:作者信息
-p:生成过程中停止容器的运行
docker images |grep new-1.txt
命令示例:然后将新增数据后的容器提交为新的镜像,需要使用该容器的 ID 号创建新镜像
docker ps -a
docker images |grep new-1.txt
docker commit -m "new-1.txt" -a "centos" test centos:new-1.txt
docker images |grep new-1.txt
输出结果:
[root@MineGi ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
372617ed7dd0 centos:7 "/bin/bash" About a minute ago Exited (0) 51 seconds ago test
[root@MineGi ~]# docker images |grep new-1.txt
[root@MineGi ~]# docker commit -m "new-1.txt" -a "centos" test centos:new-1.txt
sha256:7e23e7ad18dd92566340c51588d58bab2a681f466a07b7b4eafdc6c98931aba7
[root@MineGi ~]# docker images |grep new-1.txt
centos new-1.txt 7e23e7ad18dd 3 seconds ago 204MB
[root@MineGi ~]#
1.3 启动新的容器
命令示例:创建新容器并使用该镜像
docker run -it centos:new-1.txt /bin/bash
ls
cat 1.txt
exit
docker rm -f $(docker ps -aq)
docker ps -a
输出结果:
[root@MineGi ~]# docker run -it centos:new-1.txt /bin/bash
[root@5993132ccb28 /]# ls
1.txt bin etc lib media opt root sbin sys usr
anaconda-post.log dev home lib64 mnt proc run srv tmp var
[root@5993132ccb28 /]# cat 1.txt
hello world
[root@5993132ccb28 /]# exit
exit
[root@MineGi ~]# docker rm -f $(docker ps -aq)
5993132ccb28
372617ed7dd0
[root@MineGi ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@MineGi ~]#
2、基于本地模板创建
情况说明:通过导入操作系统模板文件可以生成镜像,模板可以从 OPENVZ 开源项目下载
2.1 下载地址
下载地址为:http://openvz.org/Download/template/precreated
2.2 下载文件
【docker-images:百度网盘】
方法一:浏览器下载包并上传至Linux机器
cd /opt #上传centos-7-x86_64-minimal.tar.gz
方法二:直接在Linux机器下载包
wget http://download.openvz.org/template/precreated/centos-7-x86_64-minimal.tar.gz
命令示例:
wget http://download.openvz.org/template/precreated/centos-7-x86_64-minimal.tar.gz
ll centos-7-x86_64-minimal.tar.gz
ls -lh centos-7-x86_64-minimal.tar.gz
输出结果:
[root@MineGi ~]# wget http://download.openvz.org/template/precreated/centos-7-x86_64-minimal.tar.gz
--2024-12-18 10:43:30-- http://download.openvz.org/template/precreated/centos-7-x86_64-minimal.tar.gz
正在解析主机 download.openvz.org (download.openvz.org)... 130.117.225.97
正在连接 download.openvz.org (download.openvz.org)|130.117.225.97|:80... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:145639219 (139M) [application/x-gzip]
正在保存至: “centos-7-x86_64-minimal.tar.gz”
100%[================================================================>] 145,639,219 1.49MB/s 用时 2m 4s
2024-12-18 10:45:35 (1.12 MB/s) - 已保存 “centos-7-x86_64-minimal.tar.gz” [145639219/145639219])
[root@MineGi ~]# ll centos-7-x86_64-minimal.tar.gz
-rw-r--r-- 1 root root 145639219 11月 27 2016 centos-7-x86_64-minimal.tar.gz
[root@MineGi ~]# ls -lh centos-7-x86_64-minimal.tar.gz
-rw-r--r-- 1 root root 139M 11月 27 2016 centos-7-x86_64-minimal.tar.gz
[root@MineGi ~]#
2.3 导入镜像
#导入为镜像
cat centos-7-x86_64-minimal.tar.gz | docker import - centos:minimal
#查看当前所有镜像
docker images
命令示例:
docker images |grep minimal
cat centos-7-x86_64-minimal.tar.gz | docker import - centos:minimal
docker images |grep minimal
输出结果:
[root@MineGi ~]# docker images |grep minimal
[root@MineGi ~]# cat centos-7-x86_64-minimal.tar.gz | docker import - centos:minimal
sha256:58b814914e6ead5f301d0347105ed0653106a28e6b046578e82100d8e3442ed3
[root@MineGi ~]# docker images |grep minimal
centos minimal 58b814914e6e 5 seconds ago 435MB
[root@MineGi ~]#
2.4 运行容器
#创建新容器并运行,可使用刚导入的centos镜像
docker run -itd --name centos centos:minimal /bin/bash
#也可进入并使用该容器
docker exec -it centos1 /bin/bash
命令示例:
docker run -it centos:minimal /bin/bash
ls
cat /etc/redhat-release
uname -r
exit
docker rm -f $(docker ps -aq) &>/dev/null
docker ps -a
输出结果:
[root@MineGi ~]# docker run -it centos:minimal /bin/bash
[root@e145e427967a /]# ls
bin dev fastboot lib lost+found mnt proc run srv tmp var
boot etc home lib64 media opt root sbin sys usr
[root@e145e427967a /]# cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
[root@e145e427967a /]# uname -r
3.10.0-1127.el7.x86_64
[root@e145e427967a /]# exit
[root@MineGi ~]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@MineGi ~]#
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.4 为什么Docker里的centos的大小才200M
- 因为对于精简的OS,rootfs可以很小,只需要包含最基本的命令、工具和程序库就可以了,因为底层直接用宿主机的kernel,自己只需要提供rootfs就可以了
- 由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs
3.5 认识Dockerfile
- Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)
- 镜像不包含任何动态数据,其内容在构建之后也不会被改变
- 镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile
- Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了Dockerfile,当我们需要定制自己额外的需求时,只需在Dockerfile上添加或者修改指令,重新生成 image 即可, 省去了敲命令的麻烦
- 除了手动生成Docker镜像之外,可以使用Dockerfile自动生成镜像。Dockerfile是由多条的指令组成的文件,其中每条指令对应 Linux 中的一条命令,Docker 程序将读取Dockerfile 中的指令生成指定镜像。
3.6 Dockerfile结构
- Dockerfile结构大致分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令
- Dockerfile每行支持一条指令,每条指令可携带多个参数,支持使用以“#“号开头的注释
3.7 Docker镜像结构的分层
镜像不是一个单一的文件,而是有多层构成。容器其实是在镜像的最上面加了一层读写层,在运行容器里做的任何文件改动,都会写到这个读写层。如果删除了容器,也就删除了其最上面的读写层,文件改动也就丢失了。Docker使用存储驱动管理镜像每层内容及可读写层的容器层
- Dockerfile 中的每个指令都会创建一个新的镜像层;
- 镜像层将被缓存和复用;
- 当Dockerfile 的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效;
- 某一层的镜像缓存失效,它之后的镜像层缓存都会失效;
- 镜像层是不可变的,如果在某一层中添加一个文件,然后在下一层中删除它,则镜像中依然会包含该文件,只是这个文件在 Docker 容器中不可见了
3.8 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是一种加密的网络协议,常用于安全地远程登录到计算机系统,并在远程系统上执行命令
# 以CentOS 7为基础镜像(你也可以根据需求选择其他CentOS版本,比如CentOS 8等)
FROM centos:7
#维护镜像的用户信息
MAINTAINER sshd image <mg>
#安装OpenSSH服务器和客户端工具、net-tools(用于网络配置和诊断)lsof(用于列出打开文件的工具)、telnet(用于远程登录测试)
RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
yum install -y openssh* net-tools lsof telnet && \
sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config && \
ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key && \
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
#复制本地当前目录的公钥到容器中
ADD id_rsa.pub /root/.ssh/authorized_keys
#Docker容器监听SSH服务的22端口
EXPOSE 22
#对于OpenSSH服务器,由于其默认行为已经是前台模式,因此不需要额外指定参数FOREGROUND
#为了确保将输出发送到控制台并以调试模式持续运行,仍需要在启动命令中添加-D参数
CMD ["/usr/sbin/sshd" , "-D"]
#生成镜像名称为sshd-centos,标签为v1
docker build -t sshd-centos:v1 .
# -t 参数用于指定构建镜像的名称及标签
# . 就是指示Docker在当前目录中查找名为Dockerfile的文件,并以此文件作为构建镜像的基础
命令示例:
mkdir -p /data/dockerfiles/ssh-centos
cd !$
ssh-keygen -t rsa -f /root/.ssh/id_rsa -P "" -q
cp /root/.ssh/id_rsa.pub ./
cat >Dockerfile <<'eof'
FROM centos:7
MAINTAINER sshd image <mg>
RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
yum install -y openssh* net-tools lsof telnet && \
sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config && \
ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key && \
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key && \
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
ADD id_rsa.pub /root/.ssh/authorized_keys
EXPOSE 22
CMD ["/usr/sbin/sshd" , "-D"]
eof
ls
docker build -t sshd-centos:v1 .
docker images |grep sshd
docker run -d -p 33:22 sshd-centos:v1
docker ps -a
ssh localhost -p 33
hostname -i
logout
docker rm -f $(docker ps -aq) &>/dev/null
输出结果:
[root@MineGi ~]# mkdir -p /data/dockerfiles/ssh-centos
[root@MineGi ~]# cd !$
cd /data/dockerfiles/ssh-centos
[root@MineGi ssh-centos]# ssh-keygen -t rsa -f /root/.ssh/id_rsa -P "" -q
[root@MineGi ssh-centos]# cp /root/.ssh/id_rsa.pub ./
[root@MineGi ssh-centos]# cat >Dockerfile <<'eof'
> FROM centos:7
> MAINTAINER sshd image <mg>
> RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
> yum install -y openssh* net-tools lsof telnet && \
> sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config && \
> ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key && \
> ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key && \
> ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
> ADD id_rsa.pub /root/.ssh/authorized_keys
> EXPOSE 22
> CMD ["/usr/sbin/sshd" , "-D"]
> eof
[root@MineGi ssh-centos]# ls
Dockerfile id_rsa.pub
[root@MineGi ssh-centos]# docker build -t sshd-centos:v1 .
[+] Building 0.1s (8/8) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 557B 0.0s
=> [internal] load metadata for docker.io/library/centos:7 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/3] FROM docker.io/library/centos:7 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 432B 0.0s
=> CACHED [2/3] RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Ce 0.0s
=> [3/3] ADD id_rsa.pub /root/.ssh/authorized_keys 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:ec605109a541802171d6b4949ac7134f5aa9ce3e1aba1bf542364c6b1fc2e220 0.0s
=> => naming to docker.io/library/sshd-centos:v1 0.0s
[root@MineGi ssh-centos]# docker images |grep sshd
sshd-centos v1 ec605109a541 11 seconds ago 556MB
[root@MineGi ssh-centos]# docker run -d -p 33:22 sshd-centos:v1
c03843b2b94133e247b2b90af3af7c544220569b460b780bdc70d1fea41b2bd6
[root@MineGi ssh-centos]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c03843b2b941 sshd-centos:v1 "/usr/sbin/sshd -D" 5 seconds ago Up 4 seconds 0.0.0.0:33->22/tcp, :::33->22/tcp goofy_chatelet
[root@MineGi ssh-centos]# ssh localhost -p 33
The authenticity of host '[localhost]:33 ([::1]:33)' can't be established.
RSA key fingerprint is SHA256:+L5+An3amtj2fysb3gtdVxIFzXVbmbHY8jI9vhJrv7w.
RSA key fingerprint is MD5:bc:50:74:62:14:bf:f5:17:02:0b:87:d6:40:90:9d:b3.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:33' (RSA) to the list of known hosts.
[root@c03843b2b941 ~]# hostname -i
172.17.0.2
[root@c03843b2b941 ~]# logout
Connection to localhost closed.
[root@MineGi ssh-centos]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi ssh-centos]#
2、构建 systemctl 镜像
FROM sshd-centos:v1
MAINTAINER systemctl image <mg>
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"])
命令示例:
mkdir -p /data/dockerfiles/systemctl
cd !$
cat >Dockerfile <<'eof'
FROM sshd-centos:v1
MAINTAINER systemctl image <mg>
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /etc/systemd/system/*.wants/*; \
rm -f /lib/systemd/system/multi-user.target.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" ]
eof
docker build -t systemd:v1 .
docker images |grep systemd
输出结果:
[root@MineGi ssh-centos]# mkdir -p /data/dockerfiles/systemctl
[root@MineGi ssh-centos]# cd !$
cd /data/dockerfiles/systemctl
[root@MineGi systemctl]# cat >Dockerfile <<'eof'
> FROM sshd-centos:v1
> MAINTAINER systemctl image <mg>
> ENV container docker
> RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
> rm -f /etc/systemd/system/*.wants/*; \
> rm -f /lib/systemd/system/multi-user.target.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" ]
> eof
[root@MineGi systemctl]# docker build -t systemd:v1 .
[+] Building 0.6s (6/6) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 644B 0.0s
=> [internal] load metadata for docker.io/library/sshd-centos:v1 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/2] FROM docker.io/library/sshd-centos:v1 0.0s
=> [2/2] RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; 0.4s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:4bd6499116312c00676050f80092f856e4bfd11afe0955b9fd20a8b96310ec56 0.0s
=> => naming to docker.io/library/systemd:v1 0.0s
[root@MineGi systemctl]# docker images |grep systemd
systemd v1 4bd649911631 19 seconds ago 556MB
[root@MineGi systemctl]#
#启动容器,并挂载宿主机目录挂载到容器中,和进行初始化
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 &
命令示例:
docker run --name test --privileged -d -P -v /sys/fs/cgroup:/sys/fs/cgroup:ro systemd:v1 /sbin/init
docker ps -a
docker exec -it test bash
systemctl status sshd
systemctl start sshd
systemctl is-active sshd
exit
docker rm -f $(docker ps -aq) &>/dev/null
docker ps -a
输出结果:
[root@MineGi systemctl]# docker run --name test --privileged -d -P -v /sys/fs/cgroup:/sys/fs/cgroup:ro systemd:v1 /sbin/init
055f672dc41d3fe1c2f709c040cce0b105fb2fadbb952d0c417ec382317e1979
[root@MineGi systemctl]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
055f672dc41d systemd:v1 "/sbin/init" 5 seconds ago Up 4 seconds 0.0.0.0:1024->22/tcp, :::1024->22/tcp test
[root@MineGi systemctl]# docker exec -it test bash
[root@055f672dc41d /]# systemctl status sshd
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; disabled; vendor preset: enabled)
Active: inactive (dead)
Docs: man:sshd(8)
man:sshd_config(5)
[root@055f672dc41d /]# systemctl start sshd
[root@055f672dc41d /]# systemctl is-active sshd
active
[root@055f672dc41d /]# exit
exit
[root@MineGi systemctl]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi systemctl]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@MineGi systemctl]#
3、构建 apache 镜像
vim Dockerfile
FROM centos:7 # 基于的基础镜像centos:7
MAINTAINER apache image <mg> # 维护镜像的用户信息
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
#使用方法一时必须得创建,使用其他方法可不创建
vim run.sh
#!/bin/bash
rm -rf /run/httpd/* # 清理httpd的缓存
/usr/sbin/apachectl -D FOREGROUND # 指定为前台运行
命令示例:
mkdir -p /data/dockerfiles/apache-centos
cd !$
cat >Dockerfile <<'eof'
FROM centos:7
MAINTAINER apache image <mg>
RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
yum install -y httpd &&\
yum clean all
EXPOSE 80
ADD index.html /var/www/html
ADD run.sh /run.sh
RUN chmod 755 /run.sh
CMD ["/run.sh"]
eof
cat >run.sh <<'eof'
#!/bin/bash
rm -rf /run/httpd/*
/usr/sbin/apachectl -D FOREGROUND
eof
echo "this is apache web" >index.html
docker build -t httpd-centos:v1 .
docker images |grep httpd-centos
docker run -d -p 999:80 httpd-centos:v1
docker ps -a
hostname -I
curl 10.4.7.11:999
docker rm -f $(docker ps -aq) &>/dev/null
docker ps -a
输出结果:
[root@MineGi systemctl]# mkdir -p /data/dockerfiles/apache-centos
[root@MineGi systemctl]# cd !$
cd /data/dockerfiles/apache-centos
[root@MineGi apache-centos]# cat >Dockerfile <<'eof'
> FROM centos:7
> MAINTAINER apache image <mg>
> RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
> yum install -y httpd &&\
> yum clean all
> EXPOSE 80
> ADD index.html /var/www/html
> ADD run.sh /run.sh
> RUN chmod 755 /run.sh
> CMD ["/run.sh"]
> eof
[root@MineGi apache-centos]# cat >run.sh <<'eof'
> #!/bin/bash
> rm -rf /run/httpd/*
> /usr/sbin/apachectl -D FOREGROUND
> eof
[root@MineGi apache-centos]# echo "this is apache web" >index.html
[root@MineGi apache-centos]# docker build -t httpd-centos:v1 .
[+] Building 0.9s (10/10) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 354B 0.0s
=> [internal] load metadata for docker.io/library/centos:7 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/5] FROM docker.io/library/centos:7 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 159B 0.0s
=> CACHED [2/5] RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && yum install 0.0s
=> [3/5] ADD index.html /var/www/html 0.0s
=> [4/5] ADD run.sh /run.sh 0.0s
=> [5/5] RUN chmod 755 /run.sh 0.3s
=> exporting to image 0.4s
=> => exporting layers 0.4s
=> => writing image sha256:66dce47c4bebffa62fc7e1f991a6d6a231059686a6fa4ba3f5b900807a6b9c64 0.0s
=> => naming to docker.io/library/httpd-centos:v1 0.0s
[root@MineGi apache-centos]# docker images |grep httpd-centos
httpd-centos v1 66dce47c4beb 13 seconds ago 261MB
[root@MineGi apache-centos]# docker run -d -p 999:80 httpd-centos:v1
3b1721f89c4d70d16d86fbdadd035527a657f8453ea5aa5b7153af1c8f1e7246
[root@MineGi apache-centos]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3b1721f89c4d httpd-centos:v1 "/run.sh" 5 seconds ago Up 4 seconds 0.0.0.0:999->80/tcp, :::999->80/tcp optimistic_nobel
[root@MineGi apache-centos]# hostname -I
10.4.7.11 172.17.0.1
[root@MineGi apache-centos]# curl 10.4.7.11:999
this is apache web
[root@MineGi apache-centos]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi apache-centos]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@MineGi apache-centos]#
4、构建 nginx 镜像
下载地址:Index of /download/
【Nginx:百度网盘】
vim Dockerfile
FROM centos:7
MAINTAINER nginx image <mg>
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的全局配置项的
命令示例:
mkdir -p /data/dockerfiles/nginx-centos
cd !$
wget https://nginx.org/download/nginx-1.22.0.tar.gz
cat >Dockerfile <<'eof'
FROM centos:7
MAINTAINER nginx image <mg>
ADD nginx-1.22.0.tar.gz /opt/
ADD run.sh /run.sh
RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
yum -y install pcre-devel zlib-devel gcc gcc-c++ make && \
useradd -M -s /sbin/nologin nginx && \
yum clean all && \
chmod 755 /run.sh
WORKDIR /opt/nginx-1.22.0
RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx \
--with-http_stub_status_module && make -j 2 && make install
ENV PATH /usr/local/nginx/sbin:$PATH
EXPOSE 80
EXPOSE 443
RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf
CMD ["/run.sh"]
eof
cat >run.sh <<'eof'
#!/bin/bash
/usr/local/nginx/sbin/nginx
eof#!/bin/bash
ll
docker build -t nginx-centos:v1 .
docker images |grep nginx-centos
docker run -d -p 80:80 nginx-centos:v1
docker ps -a
curl -I 10.4.7.11
docker rm -f $(docker ps -aq) &>/dev/null
docker ps -a
输出结果:
[root@MineGi apache-centos]# mkdir -p /data/dockerfiles/nginx-centos
[root@MineGi apache-centos]# cd !$
cd /data/dockerfiles/nginx-centos
[root@MineGi nginx-centos]# wget -q https://nginx.org/download/nginx-1.22.0.tar.gz
[root@MineGi nginx-centos]# cat >Dockerfile <<'eof'
> FROM centos:7
> MAINTAINER nginx image <mg>
> ADD nginx-1.22.0.tar.gz /opt/
> ADD run.sh /run.sh
> RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
> yum -y install pcre-devel zlib-devel gcc gcc-c++ make && \
> useradd -M -s /sbin/nologin nginx && \
> yum clean all && \
> chmod 755 /run.sh
> WORKDIR /opt/nginx-1.22.0
> RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx \
> --with-http_stub_status_module && make -j 2 && make install
> ENV PATH /usr/local/nginx/sbin:$PATH
> EXPOSE 80
> EXPOSE 443
> RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf
> CMD ["/run.sh"]
> eof
[root@MineGi nginx-centos]# cat >run.sh <<'eof'
> #!/bin/bash
> /usr/local/nginx/sbin/nginx
> eof
[root@MineGi nginx-centos]# ll
总用量 1060
-rw-r--r-- 1 root root 639 12月 19 13:53 Dockerfile
-rw-r--r-- 1 root root 1073322 5月 24 2022 nginx-1.22.0.tar.gz
-rw-r--r-- 1 root root 40 12月 19 13:53 run.sh
[root@MineGi nginx-centos]# docker build -t nginx-centos:v1 .
[+] Building 90.6s (12/12) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 678B 0.0s
=> [internal] load metadata for docker.io/library/centos:7 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/7] FROM docker.io/library/centos:7 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 117B 0.0s
=> CACHED [2/7] ADD nginx-1.22.0.tar.gz /opt/ 0.0s
=> [3/7] ADD run.sh /run.sh 0.0s
=> [4/7] RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && yum -y install pc 60.7s
=> [5/7] WORKDIR /opt/nginx-1.22.0 0.0s
=> [6/7] RUN ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_stub_status_module && make -j 2 & 28.5s
=> [7/7] RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf 0.3s
=> exporting to image 0.9s
=> => exporting layers 0.9s
=> => writing image sha256:e568fd65475f9354be78bf8b27a5c24c5f8d830475bf9957f6c8b6efad019cc5 0.0s
=> => naming to docker.io/library/nginx-centos:v1 0.0s
[root@MineGi nginx-centos]# docker images |grep nginx-centos
nginx-centos v1 e568fd65475f 3 minutes ago 349MB
[root@MineGi nginx-centos]# docker run -d -p 80:80 nginx-centos:v1
5e0d65d6f4ef0036ff39ee4eaccd6126606879595ba9a2da3834ef181746b385
[root@MineGi nginx-centos]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5e0d65d6f4ef nginx-centos:v1 "/run.sh" 6 seconds ago Up 5 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp, 443/tcp optimistic_herschel
[root@MineGi nginx-centos]# curl -I 10.4.7.11
HTTP/1.1 200 OK
Server: nginx/1.22.0
Date: Thu, 19 Dec 2024 06:00:36 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Thu, 19 Dec 2024 05:55:34 GMT
Connection: keep-alive
ETag: "6763b556-267"
Accept-Ranges: bytes
[root@MineGi nginx-centos]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi nginx-centos]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@MineGi nginx-centos]#
5、构建 tomcat 镜像
【JDK:百度网盘】
【Tomcat:百度网盘】
jdk6:https://www.oracle.com/cn/java/technologies/javase-java-archive-javase6-downloads.html
jdk8:https://www.oracle.com/cn/java/technologies/javase/javase8u211-later-archive-downloads.html
Tomcat:https://archive.apache.org/dist/tomcat/
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服务
# 使用更推荐的 LABEL 指令设置维护者信息
LABEL maintainer="tomcat image <mg>"
# 先设置工作目录为 /usr/local,后续操作都在此目录下进行相关解压和移动操作,减少 WORKDIR 指令切换次数
WORKDIR /usr/local
# 考虑先将 JDK 压缩包下载到宿主机,再使用 COPY 指令复制进容器,提高稳定性和可控性
# 这里假设宿主机当前目录下有 jdk-8u291-linux-x64.tar.gz 文件
COPY jdk-8u291-linux-x64.tar.gz.
RUN tar -zxvf jdk-8u291-linux-x64.tar.gz && \
mv jdk1.8.0_291 java && \
# 设置 Java 环境变量
export JAVA_HOME=/usr/local/java && \
export JRE_HOME=${JAVA_HOME}/jre && \
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib && \
export PATH=$JAVA_HOME/bin:$PATH
# 同样先将 Tomcat 压缩包复制进容器,再解压和移动
COPY apache-tomcat-8.5.16.tar.gz.
RUN tar -zxvf apache-tomcat-8.5.16.tar.gz && \
mv apache-tomcat-8.5.16 tomcat
# 暴露 8080 端口
EXPOSE 8080
# 只保留 ENTRYPOINT,因为它定义了容器启动时执行的命令,CMD 在此处冗余且可能导致一些启动行为的混淆
ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh", "run"]
命令示例:
mkdir -p /data/dockerfiles/tomcat-centos
cd !$
#wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.16/bin/apache-tomcat-8.5.16.tar.gz
cat >Dockerfile <<'eof'
FROM centos:7
LABEL maintainer="tomcat image <mg>"
WORKDIR /usr/local
ADD jdk-8u291-linux-x64.tar.gz ./
ADD apache-tomcat-8.5.16.tar.gz ./
RUN mv jdk1.8.0_291 java && \
mv apache-tomcat-8.5.16 tomcat
ENV JAVA_HOME=/usr/local/java
ENV JRE_HOME=${JAVA_HOME}/jre
ENV CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
ENV PATH=$JAVA_HOME/bin:$PATH
EXPOSE 8080
ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]
eof
ll
docker build -t tomcat-centos:v1 .
docker images |grep tomcat-centos
docker run -d --name tomcat1 -p 888:8080 tomcat-centos:v1
docker ps -a
curl -I 10.4.7.11:888
docker rm -f $(docker ps -aq) &>/dev/null
docker ps -a
输出结果:
[root@MineGi nginx-centos]# mkdir -p /data/dockerfiles/tomcat-centos
[root@MineGi nginx-centos]# cd !$
cd /data/dockerfiles/tomcat-centos
[root@MineGi tomcat-centos]# rz -E
rz waiting to receive.
[root@MineGi tomcat-centos]# rz -E
rz waiting to receive.
[root@MineGi tomcat-centos]# cat >Dockerfile <<'eof'
> FROM centos:7
> LABEL maintainer="tomcat image <mg>"
> WORKDIR /usr/local
> ADD jdk-8u291-linux-x64.tar.gz ./
> ADD apache-tomcat-8.5.16.tar.gz ./
> RUN mv jdk1.8.0_291 java && \
> mv apache-tomcat-8.5.16 tomcat
> ENV JAVA_HOME=/usr/local/java
> ENV JRE_HOME=${JAVA_HOME}/jre
> ENV CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
> ENV PATH=$JAVA_HOME/bin:$PATH
> EXPOSE 8080
> ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh","run"]
> eof
[root@MineGi tomcat-centos]# ll
总用量 150744
-rw-r--r-- 1 root root 9417469 10月 14 18:45 apache-tomcat-8.5.16.tar.gz
-rw-r--r-- 1 root root 411 12月 19 14:36 Dockerfile
-rw-r--r-- 1 root root 144935989 10月 30 11:01 jdk-8u291-linux-x64.tar.gz
[root@MineGi tomcat-centos]# docker build -t tomcat-centos:v1 .
[+] Building 0.1s (10/10) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 450B 0.0s
=> [internal] load metadata for docker.io/library/centos:7 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/5] FROM docker.io/library/centos:7 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 99B 0.0s
=> CACHED [2/5] WORKDIR /usr/local 0.0s
=> CACHED [3/5] ADD jdk-8u291-linux-x64.tar.gz ./ 0.0s
=> CACHED [4/5] ADD apache-tomcat-8.5.16.tar.gz ./ 0.0s
=> CACHED [5/5] RUN mv jdk1.8.0_291 java && mv apache-tomcat-8.5.16 tomcat 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:dba02f27d5cf29eda07cff8e1257117f94c927103e9f7f0a84ca8b991c04f8ff 0.0s
=> => naming to docker.io/library/tomcat-centos:v1 0.0s
[root@MineGi tomcat-centos]# docker images |grep tomcat-centos
tomcat-centos v1 dba02f27d5cf 10 minutes ago 950MB
[root@MineGi tomcat-centos]# docker run -d --name tomcat1 -p 888:8080 tomcat-centos:v1
b7a5543ca1b9e42b5cc41d576623e738a5cf83e6b2658babcfe19c9a9254c8ad
[root@MineGi tomcat-centos]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b7a5543ca1b9 tomcat-centos:v1 "/usr/local/tomcat/b…" 6 seconds ago Up 4 seconds 0.0.0.0:888->8080/tcp, :::888->8080/tcp tomcat1
[root@MineGi tomcat-centos]# curl -I 10.4.7.11:888
HTTP/1.1 200
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 19 Dec 2024 06:37:32 GMT
[root@MineGi tomcat-centos]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi tomcat-centos]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@MineGi tomcat-centos]#
6、构建 mysql 镜像
注意事项:构建MySQL镜像,将虚拟机的内存临时调到大些,防止报错或卡顿
https://mirrors.aliyun.com/mysql/
【MySQL:百度网盘】
命令示例:
mkdir -p /data/dockerfiles/mysql-centos
cd !$
wget /data/tpges https://mirrors.aliyun.com/mysql/MySQL-5.7/mysql-boost-5.7.36.tar.gz
ll
输出结果:
[root@MineGi tomcat-centos]# mkdir -p /data/dockerfiles/mysql-centos
[root@MineGi tomcat-centos]# cd !$
cd /data/dockerfiles/mysql-centos
[root@MineGi mysql-centos]# wget -q /data/tpges https://mirrors.aliyun.com/mysql/MySQL-5.7/mysql-boost-5.7.36.tar.gz
[root@MineGi mysql-centos]# ll
总用量 51728
-rw-r--r-- 1 root root 52968383 9月 7 2021 mysql-boost-5.7.36.tar.gz
[root@MineGi mysql-centos]#
命令示例:
cat >Dockerfile <<'eof'
FROM centos:7
MAINTAINER mysql image <mg>
RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
yum -y install gcc gcc-c++ cmake make bison bison-devel ncurses ncurses-devel libtirpc \
libtirpc-devel libxml2-devel openssl-devel libevent-devel libaio-devel libcurl-devel libarchive-devel \
boost-devel zlib-devel gnutls-develncurses && useradd -M -s /sbin/nologin mysql && yum clean all
ADD mysql-boost-5.7.36.tar.gz /usr/local/src/
ADD my.cnf /etc/my.cnf
WORKDIR /usr/local/src/mysql-5.7.36/
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 && \
chown -R mysql:mysql /usr/local/mysql/ && \
chown mysql:mysql /etc/my.cnf
EXPOSE 3306
WORKDIR /usr/local/mysql/bin/
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
VOLUME [ "/usr/local/mysql" ]
CMD ["/usr/sbin/init"]
eof
输出结果:
[root@MineGi mysql-centos]# cat >Dockerfile <<'eof'
> FROM centos:7
> MAINTAINER mysql image <mg>
> RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
> yum -y install gcc gcc-c++ cmake make bison bison-devel ncurses ncurses-devel libtirpc \
> libtirpc-devel libxml2-devel openssl-devel libevent-devel libaio-devel libcurl-devel libarchive-devel \
> boost-devel zlib-devel gnutls-develncurses && useradd -M -s /sbin/nologin mysql && yum clean all
> ADD mysql-boost-5.7.36.tar.gz /usr/local/src/
> ADD my.cnf /etc/my.cnf
> WORKDIR /usr/local/src/mysql-5.7.36/
> 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 && \
> chown -R mysql:mysql /usr/local/mysql/ && \
> chown mysql:mysql /etc/my.cnf
> EXPOSE 3306
> WORKDIR /usr/local/mysql/bin/
> 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
> VOLUME [ "/usr/local/mysql" ]
> CMD ["/usr/sbin/init"]
> eof
[root@MineGi mysql-centos]#
如果使用脚本来设置启动容器时运行mysqld服务,就需要创建run.sh脚本
vim run.sh
#!/bin/bash
/usr/local/mysql/bin/mysqld
systemctl enable mysqld
命令示例:
cat >my.cnf <<'eof'
[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
eof
输出结果:
[root@MineGi mysql-centos]# cat >my.cnf <<'eof'
> [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
> eof
[root@MineGi mysql-centos]#
命令示例:
docker build -t mysql-centos:v1 .
docker images |grep mysql-centos
docker run --name mysql_server -d -P --privileged mysql-centos:v1 /usr/sbin/init
docker ps -a
输出结果:
[root@MineGi mysql-centos]# docker build -t mysql-centos:v1 .
[+] Building 2470.2s (13/13) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 1.60kB 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/8] FROM docker.io/library/centos:7 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 75B 0.0s
=> [2/8] RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && yum -y install g 131.0s
=> [3/8] ADD mysql-boost-5.7.36.tar.gz /usr/local/src/ 8.9s
=> [4/8] ADD my.cnf /etc/my.cnf 0.0s
=> [5/8] WORKDIR /usr/local/src/mysql-5.7.36/ 0.0s
=> [6/8] RUN cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DMYSQL_UNIX_ADDR=/usr/local/mysql/mysql.sock -DSYSCONFDIR=/et 2277.4s
=> [7/8] WORKDIR /usr/local/mysql/bin/ 0.3s
=> [8/8] RUN ./mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data && cp /u 7.3s
=> exporting to image 45.1s
=> => exporting layers 45.1s
=> => writing image sha256:1f91ce33f68eaade1f2a7283420f189838e69bd8233ce23e617e425935fa131a 0.0s
=> => naming to docker.io/library/mysql-centos:v1 0.0s
[root@MineGi mysql-centos]# docker images |grep mysql-centos
mysql-centos v1 1f91ce33f68e 11 minutes ago 8.07GB
[root@MineGi mysql-centos]# docker run --name mysql_server -d -P --privileged mysql-centos:v1 /usr/sbin/init
700dad29b95d803e5ccf0836b5a996306605094dd2481d7121f28acb9331d049
[root@MineGi mysql-centos]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
700dad29b95d mysql-centos:v1 "/usr/sbin/init" 24 seconds ago Up 8 seconds 0.0.0.0:1024->3306/tcp, :::1024->3306/tcp mysql_server
[root@MineGi mysql-centos]#
docker exec -it mysql_server /bin/bash
# 可以选择修改密码:
# 给root账号设置密码
# mysqladmin -u root -p password "123456" 直接回车
# 登录 mysql -u root -p123456
mysql> 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的权限,使新授权的权限立即生效
命令示例:
docker exec -it mysql_server /bin/bash
mysql -u root -p
grant all privileges on *.* to 'root'@'%' identified by 'abc123';
grant all privileges on *.* to 'root'@'localhost' identified by 'abc123';
flush privileges;
exit
exit
docker rm -f $(docker ps -aq) &>/dev/null
docker ps -a
输出结果:
[root@MineGi mysql-centos]# docker exec -it mysql_server /bin/bash
[root@700dad29b95d bin]# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.36 Source distribution
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> grant all privileges on *.* to 'root'@'%' identified by 'abc123';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> grant all privileges on *.* to 'root'@'localhost' identified by 'abc123';
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
mysql> exit
Bye
[root@700dad29b95d bin]# exit
exit
[root@MineGi mysql-centos]# docker rm -f $(docker ps -aq) &>/dev/null
[root@MineGi mysql-centos]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@MineGi mysql-centos]#
三、总结
1、创建镜像
1.1 基于现有镜像创建
docker run 创建并启动容器;再通过 docker exec/cp 等容器操作指令修改容器内容;然后 docker commit 提交成新的镜像
1.2 基于本地模版创建
从网上下载现有的镜像模版 ,或使用 docker export 导出本地容器的快照模版,然后 docker import - 将快照模版导入本地镜像。
1.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命令进行合并
- 尽可能得使用最简洁的基础镜像
- 使用多阶段(多级)构建