2万字长文:Docker必知必会系列

安装docker

安装:

Docker 分为 CE 和 EE 两大版本。CE 即社区版(免费,支持周期 7 个月),EE 即企业版,强调安全,付费使用,支持周期 24 个月。

**Docker CE 分为 **stable``testnightly 三个更新频道。

**官方网站上有各种环境下的 **安装指南,这里主要介绍 Docker CE 在 CentOS上的安装。

安装前卸载

如果之前安装过旧版本的Docker,可以使用下面命令卸载:

yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-selinux \
                  docker-engine-selinux \
                  docker-engine \
                  docker-ce

首先需要大家虚拟机联网,安装yum工具

yum install -y yum-utils \
           device-mapper-persistent-data \
           lvm2 --skip-broken

然后更新本地镜像源:

# 设置docker镜像源
yum-config-manager \
    --add-repo \
    https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
​
yum makecache fast

然后输入命令:

yum install -y docker-ce

docker-ce为社区免费版本。稍等片刻,docker即可安装成功。

演示demo

按照官网https://docs.docker.com/engine/install/centos/的文档地址,完成docker的启动、运行hello-worlddemo的示例。

卸载docker

按照下面的步骤卸载docker

# 1.
yum remove docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 2.
rm -rf /var/lib/docker
# 3.
rm -rf /var/lib/containerd

卸载执行之前建议先停止docker
systemctl stop docker.

配置镜像加速

首先去官网获取自己的加速地址。

按照官方提供的步骤进行镜像地址的修改:

请在此添加图片描述

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://zjv4zmyk.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

上面执行之后运行下面的命令,执行hello-world程序。

docker run hello-world

请在此添加图片描述

如上表示成功运行!

run的工作流程

请在此添加图片描述

Docker常用命令

帮助启动类命令

顾名思义,这类命令一般用来帮助启动和管理docker容器的。

# 启动docker
systemctl start docker
# 停止docker
systemctl stop docker
# 重启dcoker
systemctl restart docker
# 查看docker状态
systemctl status docker
# 开机启动
systemctl enable docker
# 查看docker概要信息
docker info
# 查看docker帮助命令
docker --help
# 具体的命令帮助
docker 具体的命令 --help

镜像命令

顾名思义,就是用来操作和管理docker镜像的命令。

# 显示本机上的镜像
docker images [options]
# options:
- a 列出所有本地镜像(含历史镜像层)
- q 只显示镜像ID 
# ————————————————————————————————————————————————
# 搜索镜像
docker search 镜像名称
# options
--limit number 镜像名称 默认显示点赞数高的前number个搜索结果
# 远程拉取镜像,如果镜像名称后面不指定版本号TAG,就会默认拉取最新版
docker pull 镜像名称
# 查看镜像/容器/数据卷所占的空间
docker system df
# 删除某个镜像
# 强制删除加上-f参数
docker rmi 镜像名称或者ID
# 全部删除的命令
docker rmi -f $(docker images -qa)

面试题

  • 谈谈什么是docker虚悬镜像?

仓库名、标签都是的镜像,俗称虚悬镜像dangling images


容器命令

顾名思义,就是用来操作和管理docker每一个具体容器的命令。
这里以操作ubuntu容器作为演示实例。

参数说明

—name=“容器的新名字” 为容器指定一个名称,不指定会随机分配一个
-d: 后台运行容器并返回容器的ID,也就是启动守护式容器(守护进程、后台运行)
-i:以交互模式运行容器,通常与-t参数一起使用
-t: 为容器创新分配一个伪输入终端,通常与-i一起使用
-P :随机端口映射,
-p:指定端口映射(如:-p 8080:8080)

# 运行容器
docker run [参数options]

需要注意的是,由于Ubuntu本身也是一个操作系统,如果需要,我们可以使用-it参数进入交互运行模式,容器启动后,会弹出一个属于ubuntu的操作终端。

请在此添加图片描述

注意后面的/bin/bash用来指定交互使用的shell类型。
如果需要退出容器交互,使用exit命令。

# 查看docker容器运行情况
docker ps [options]
  • options

-a 列出当前所有正在运行的容器和历史运行过的容器
-l 显示最近创建的容器
-n 显示最近n个创建的容器
-q 静默模式,只显示容器的编号
更多命令请参考help

# 重启容器
docker restart 容器ID或名称
# 停止容器
docker stop 容器ID或名称
#强制停止容器
docker kill 容器ID或名称
# 删除容器
docker rm 容器ID或名称
# 一次性删除多个容器
docker rm -f$(docker ps -a -q)
docker ps -a -q | xargs docker rm
# 查看运行容器的日志
docker logs 容器ID或名称
# 查看容器内部运行细节
docker inspect 容器ID
# 后台运行模式进入容器内部
1.docker exec -it 容器ID 操作的shell
2.docker attach 容器ID

推荐使用docker exec而不是attach,因为退出终端不会退出容器.
attach不会启动新进程,exit退出会导致容器停止,而exec则没有这种问题。

问题

有时候使用-d后台运行一个容器之后,在使用docker ps查看发现并没有运行记录,也就是已经退出,这是什么情况?

docker 容器后台运行,必须有一个前台进程,容器运行的命令如果不是哪些一直挂起的命令(top,tail等),就会自动退出的。
所以可以通过交互模式运行。

从容器拷贝文件到主机

docker cp 容器ID:容器内路径 目的主机路径

注意改操作是在主机上进行。

导入/导出容器

  • export

导出容器的内容流作为一个tar归档文件

  • import

从tar包中的内容创建一个新的文件系统,再导入为镜像

  • 命令操作
# 导出
docker export 容器ID > 文件名.tar
# 导入
cat 文件名.tar | docker import -镜像用户/名:版本号

请在此添加图片描述


Docker镜像(基础理论)

镜像的概念

镜像是一种轻量级、可执行的独立软件包,它包含了某个软件所需要的所有内容,我们把应用程序和配置依赖打包好形成以一个可交付的运行环境,这个打包好的环境就是image镜像,其中包含了代码、运行时所需的库、环境变量和配置文件等内容。****只有通过这个镜像文件才能生成Docker容器实例。

文件联合系统(UnionFS)

UnionFS是一种分层、轻量级并且高性能的文件系统,支持****对文件系统的修改作为一次提交来一层层的叠加。同时可以将不同目录挂载到同一个虚拟文件系统下。

UnionFS文件系统也是docker镜像的基础。镜像可以通过分层来进行继承,如此就可以基于基础镜像来制作各种具体的应用镜像。

一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

Docker镜像加载原理

Docker的镜像实际上是由一层层的文件系统组成,即前面提到的UnionFS。

几个术语的概念

  • bootfs(boot file system)

主要包含bootloaderkernel,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在**Docker镜像的最底层是引导文件系统****bootfs****。**这一层与经典的Linux/Unix系统是一样的,包含了boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs

  • rootfs(root file system)

bootfs之上,包含的就是典型Linux系统中的/dev,/proc,/bin,/etc等标准目录文件。rootfs就是各种不同的操作系统发行版,比如UnuntuCentOS等。

请在此添加图片描述

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

Docker采用这种分层结构的优势

镜像分层最大的一个好处就是资源共享,方便复制迁移和复用。

比如说有多个镜像都从系统的base镜像构建而来,那么Docker Host只需要在磁盘保存一份base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。

重点,圈起来,要考

docker镜像都是只读的,容器层是可写的。当容器启动时,一个新的可写层被加载到镜像的顶部,这一层通常被称为容器层,容器层之下的都叫镜像层。

所有对容器层的改动(CRUD之类)都只会发生在容器层中,只有容器层是可写的,其下的所有镜像层都只是只读。

请在此添加图片描述


Docker的Commit命令

实操案例

我们将在已有的ubunutu镜像的基础上,运行改镜像容器并在内部安装vim命令(原来的没有的)。安装之后通过commit命令将该镜像重新提交为副本镜像,此时该镜像就是一个已经包含有vim支持的Ubuntu镜像,同时也包含了所有之前宿主机上Ubuntu镜像的所有内容和功能。

查看原始的Ubuntu镜像和容器情况。

请在此添加图片描述

可以看到,ID尾号29的是我们原始的镜像,而正在运行的ID尾号的0a则是通过运行29镜像创建出来的新的镜像,我们在0a中安装vim命令支持后,通过commit重新构建。

请在此添加图片描述

构建过程如下:

docker commit -m='update vim cmd' -a='八尺妖剑' 3cb0176c220a ubuntu/myubuntu:1.2

解释一下命令:
开局一个docker commit 准备全靠参数。
-m参数用来指定提交的内容,类似于git中commit的提交信息
-a 参数用来指定本此版本的提交作者。
之后跟需要提交的镜像ID 再是本次提交的镜像版本情况。

请在此添加图片描述

如上,构建提交之后,我们再次查看images的情况。

请在此添加图片描述

是不是发现新的镜像已经成功构建,由于我们新增了vim概功能的支持,再大小上,新版本的ubuntu:1.0也比原来的版本大了不少。如此,如果今后我们再使用自己commit的新版本的ubuntu镜像时,就会发现它自带了vim功能,且保留了原来一切的内容。

当然,你也可以再在base镜像的基础上构建含有更多功能的其他版本镜像,也可以在新构建的镜像的基础上再次构建新的镜像,支持套娃操作,不过,在功能强大的同时,体积也不会拉跨!


本地镜像上传

首先开通自己的镜像仓库之后,创建命名空间。

请在此添加图片描述

命名空间创建之后,我们在命名空间下创建一个新的镜像仓库,用来存储我们自己构建的镜像数据。

请在此添加图片描述

在镜像仓库创建结束之后,会自动跳转到官方提供的操作指南页,安装提示一步一步将我们的镜像上传到仓库中。

请在此添加图片描述

比如我将前面创建的ubuntu:1.2上传到自己的镜像仓库,操作如下:

请在此添加图片描述

如此等待pushing完成即可在远程仓库中看到自己上传的镜像了,同时也可以自由拉取仓库中的镜像文件来使用,如果是公开的仓库,还可以给其他人进行使用,拉取的命令官方页提供了:

docker pull registry.cn-hangzhou.aliyuncs.com/xu-docker/myubuntu:[镜像版本号]

本地镜像推送到私有库

Docker Registry

Dockerhub这样的公共镜像仓库可能不太方便,涉及机密的公司不可能提供镜像给公网,所以需要创建一个本地私人仓库供给团队使用,基于公司内部项目构建镜像。Docker Registry是官方提供的工具,可以用于构建私有镜像仓库。

私有库搭建流程

拉取registry

docker pull registry

运行私有库

默认情况,仓库被创建在容器的/var/lib/registry目录下,建议自行用容器卷映射,方便于宿主机联调。

docker run -d -p 5000:5000  -v /ilikexff/myregistry/:/tmp/registry --privileged=true registry

请在此添加图片描述

参数说明:

-d 表示设为后台运行
-p 指定运行使用的端口号(宿主机端口号:容器内端口号)
-v 指定数据卷映射

在启动私有仓库之后,为了能更好的理解整个push流程,下面我在源ubuntu镜像的基础上新commit一个镜像,该镜像新增一个net-tools工具,通过ifconfig命令可以查看当前容器的IP地址。

请在此添加图片描述

能看到,ID为346的就是新创建的容器。

请在此添加图片描述

接下来我们将通过commit构建完成这个新的镜像,我给他命名为myubuntu:1.2,通过下面的命令提交构建。

docker commit -m='update ifconfig cmd' -a='八尺妖剑' 3f16668ea346 ubuntu/myubuntu:1.2

请在此添加图片描述

下面就将该镜像作为新的镜像推送到私服仓库。

在执行推送之前,我们最好查看一下远程私服仓库的镜像情况。

curl -XGET http://101.37.150.110:5000/v2/_catalog

注意命令是在宿主机执行,记得IP改一下自己的。执行命令这个命令之后出现下面的情况表示该私服仓库还没有任何镜像。

请在此添加图片描述

血的教训:请关闭防火墙,放行5000端口!!!!

血的教训:请关闭防火墙,放行5000端口!!!!

血的教训:请关闭防火墙,放行5000端口!!!!

不然怕你命令执行几百次都没有响应,会激怒心中那头暴躁的小野兽!!嗷嗷~~

按照下面的格式准备好新的镜像,

docker tag 镜像:Tag Host:Port/Repository:Tag

所以有

docker tag ubuntu/myubuntu:1.2  101.37.150.110:5000/ubuntu/myubuntu:1.2

请在此添加图片描述

先别急着push,处于安全考虑,docker是禁止使用http协议推送镜像的,所以这里需要先修改配置文件,暂时取消禁制。

# 打开该文件
vim /etc/docker/daemon.json

请在此添加图片描述

如上,新增部分的内容我已经用蓝色框出来了,注意右边的逗号,需要符合JSON格式哈。还有IP改为自己的IP,别做无脑CV工程师。

开始推送镜像到私服仓库。

docker push 101.37.150.110:5000/ubuntu/myubuntu:1.2

如果推送的时候遇到这种情况,原因是前面修改的文件可能没有生效,解决办法就是重启docker,然后运行docker registry私服,再次推送就成功了:

https://images.waer.ltd/img/image-20220813222450784.png

推送之后,可以再次查看私服中有哪些镜像。

curl -XGET http://101.37.150.110:5000/v2/_catalog

请在此添加图片描述

至此向私服推送镜像就完成了,可以通过下面的方式从私服拉取刚刚push的镜像下来玩玩看看正不正常,这不是必须的步骤,主要是感受一下这个commit、push、pull的过程。

docker pull 101.37.150.110:5000/ubuntu/myubuntu:1.2

数据卷

概念

卷就是目录或者文件,存在于一个或者多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过UnionFS,提供的一些用于持续存储或共享数据的特性。

前面的内容可还有印象,归因于容器数据的备份,手动cp。
关于容器的导入导出,impot、export命令。

上面的内容本质上都是为了对容器镜像数据进行备份而来的,但实际操作起来=比较麻烦。所以卷设计的目的就是****数据的持久化,完全独立于容器的生存周期,因此Docker不会再容器删除时把挂载的数据卷也顺走了。

特点:

1:数据卷可在容器之间共享或重用数据 2:卷中的更改可以直接实时生效 3:数据卷中的更改不会包含在镜像的更新中 4:数据卷的生命周期一直持续到没有容器使用它为止

运行一个带有容器卷存储功能的容器实例

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录      镜像名

这里特别注意一下--privileged=true参数,它的作用就是开启数据卷的目录权限,否则数据卷在挂载使用的过程中可能会遇到一些权限不足等等乱七八糟的问题,所以保险起见,建议都带上它,无害!

使用示例

演示数据卷的大致使用过程以及一些需要注意的地方。

作这样一个约定:

我们在宿主机(centos)上运行一个ubuntu镜像,并通过数据卷挂载的方式将镜像的数据文件目录挂载到宿主机的/tmp/dokcer_backup目录下,对应于ubuntu镜像中的/tmp/docker_data目录。

上面的约定可以简单的使用映射的方式表示:

/tmp/docker_backup:/tmp/docker_data 冒号左边的部分表示宿主机的目录,右边部分表示映射的镜像内部的目录。

完成上述的映射设置之后,理论上我们在docker容器内部/tmp/docker_data/目录下产生的所有文件都会实时的更新到宿主机的/docker_backup/目录下。

具体的操作

  • 挂载运行ubuntu镜像容器。
docker run -it --privileged=true -v /tmp/docker_backup:/tmp/docker_data --name=myub1 ubuntu

请在此添加图片描述

容器已经运行,我们在容器内进入指定的映射目录,看看是否真的存在,

请在此添加图片描述

确实能找到这个路径,事实上,我们挂载的数据卷的目录,如果提前没有创建,那么系统会自动检测,不存在就会帮你自动创建,所以不用担心路径目录不存在的情况。

同理,在宿主机中也是可以找到/tmp/docker_backup/目录的。

  • 创建数据文件

在容器内的指定目录下随意创建一个文件,回到宿主机的目录下看看是否真的能够同步过去。

在容器内目录创建一个dockers.txt文件。

cd /tmp/docker_data/
touch dockers.txt

请在此添加图片描述

回到宿主机看看情况。

请在此添加图片描述

中国人不骗中国人,这个文件确实被同步到宿主机了。

那么,既然在容器内的文件数据能够同步到宿主机,宿主机上产生的数据会不会一样也能够被同步到容器内呢??

答案是肯定的,这里就不作演示了,自己试试就知道了。

  • 查看挂载信息

挂载是挂载了,映射也没啥问题。但如果时间够长,操作够复杂,也难免会出现遗忘的情况,就是我可能不记得自己的宿主机挂载到容器哪个位置了,这时候就要用到之前的一个命令:inspect

docker inspect 容器ID

请在此添加图片描述

命令执行的结果返回的是一个很长的JSON数据,但就本处的内容而言,只需要了解其中一小部分即可,如上图,JSON串中有一块名为Mounts的数据,这就是挂载的情况。
Source:宿主机对应的目录
Destination:容器内映射的目录
其他信息…

如果此时容器停止,宿主机文件有变动,再次重启容器,那么宿主机的变更也还会同步到容器内的哈

同时,-v参数可以有多个,也就是数据卷支持同时挂载多个

权限调整

上面执行的挂载使用的默认规则,也就是挂载用的容器内部目录拥有rw读写权限。

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw      镜像名

如果说实际需要,我们还可以自己调整容器内目录的权限为ro即只读权限(read only)。

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro     镜像名
卷的继承&共享

假设我们对Ubuntu1和宿主机作了映射之后,再需要另外一个镜像来复用Ubuntu1的数据卷挂载信息,可以通过继承Ubtuntu1的方式实现。

docker run -it  --privileged=true --volumes-from 父类  --name u2 ubuntu

特点:

Ubuntu1(简称u1)作为被u2继承的父镜像,他们和宿主机之间是可以信息互通的。
尽管u2继承自u1,如果u1挂掉了,此时并不会影响u2和宿主机之间的互通
若重启挂掉的u2之后,之前u1和宿主机之间的数据也会同步到u2

Docker踢馆记

话说有一天,作为后起之秀的docker,觉得自己备受爱戴,牛逼坏了的它准备背起行囊,周游业内各国名将,所到之处,那是腥风血雨,寸草不生…….

安装Tomcat

镜像拉取

镜像可以在官方的dockerhub搜索,然后按照上面的拉取命令拉取。官方镜像地址:https://hub.docker.com/_/tomcat

请在此添加图片描述

记住,如果在拉取时不指定版本号,那默认会拉取最新版本,但就tomcat最新的docker版来说,其实是有一些坑的,为了节约时间和篇幅(主要是我七牛云OSS空间东西太多,不想贴图了哈哈哈)我简单的说一下这个坑就好了。

我们在拉取最新版的tomcat之后,一般情况下,只需要按照官方提供的运行命令直接启动tomcat,然后访问映射的端口号即可成功访问到它经典的猫页,可新版的tomcat,在这些步骤完成之后访问发现出现了404。原因是在tomcat的配置文件webapps中的内容是空的,新的东西应该是webapps.dist,所以解决办法:把webapps.dist目录换成webapps

  • 将原来的webapps目录删除

rm rf webapps

  • webapps.dist替换为webapps

mv webapps.dist webapps

  • 打完收工!!这次就能看在浏览器看到猫叔了。
免修改版本演示

所以鉴于上,我直接演示其他版本的tomcat的整个安装流程。

# 拉取免修改的tomcat版本,虽然我执行的是运行命令,但由于我本来就没有这个镜像,所以它会自动拉取
docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8

查看启动成功之后,我们在浏览器访问ip:8080端口,看看能不能顺利的去到猫叔家。

请在此添加图片描述

好,成功了,so easy to happy !!

下面请跟着我打一套组合拳,一口气灭它9族,毕竟我是个莫得感情的机器人,你于我无用了,我就会无情的抛弃你。

docker stop 容器ID
docker rm -f 容器ID
docker rmi 镜像ID

打完收工,进发下一家!!!

此时轻松拿下猫叔的docker嘴角上扬,心想,猫叔都都不堪一击,接下来的MySql也不会棘手!!!

安装MySql

为了证明自己的实力,docker并不打算挑战最新版的mysql(毕竟新人经验不足),而是直接对线常胜将军mysql:5.7,它的资历虽比猫叔略逊那么一点点,但自己经验那叫一个老道,稳如老狗!于是乎,mysql:5.7欣然接受了docker的挑战:

# 拉取mysql:5.7
docker pull mysql:5.7
# 运行容器实例(数据卷挂载的方式)
docker run -d -p 3306:3306 --privileged=true -v /tools/mysql/log:/var/log/mysql -v /tools/mysql/data:/var/lib/mysql -v /tools/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456  --name mysql mysql:5.7

请在此添加图片描述

第一回合下来,docker感觉没有任何压力,轻松拿捏就是了!!!

基本配置
# 在宿主机上切到/conf目录
cd /tools/mysql.conf
# 新建my.cnf,通过挂载卷在宿主机操作容器
vim.cnf
# 添加文件内容
[client]
default_character_set=utf8 
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
# 重启实例,加载配置
docker restart mysql

第二回合就这样结束了。尽管mysql此时已伤痕累累,但docker额头也是渗出了豆大的汗珠,它暗自嘀咕:想不到这家伙确有两把刷子…

使用测试
# 进入容器内部
docker exec -it mysql bash
# 登录mysql
mysql -uroot -p
# 键入密码....
# 成功登录

请在此添加图片描述

# 查看字符集是否设置生效
# docker安装完MySQL并run出容器后,建议请先修改完字符集编码后再新建mysql库--插数据
SHOW VARIABLES LIKE 'character%';

请在此添加图片描述

# 建库建表
CREATE DATABASE t1
USE t1
CREATE TABLE user(id int,name varchar(20));

请在此添加图片描述

使用navcat客户端连接该数据库进行基本测试

请在此添加图片描述

# 新增和查询
INSERT user
VALUES(1,'ilikexff')INSERT user
VALUES(2,'八尺妖剑')SELECT id,name 
FROM user

请在此添加图片描述

第三回合到此下来,此时的docker可谓是伤敌一千,自损八百。它不曾想过,眼前这个5.7别看长的不怎么样,打起架来可是又狠又稳,一点也不含糊,甚至还请来了猫叔的远房亲戚navcat大表哥助阵。可为了面子,docker还得装作啥事没有的表情,迎接5.7的最后一击……

数据持久化测试

可以看到,在宿主机中已经有了数据库的数据文件。

请在此添加图片描述

# 对mysql进行删库跑路,再重启,以测试之前的数据卷映射是否起到了数据持久化备份的功能
docker rm -f mysql
# 重新运行mysql
docker run -d -p 3306:3306 --privileged=true -v /tools/mysql/log:/var/log/mysql -v /tools/mysql/data:/var/lib/mysql -v /tools/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456  --name mysql mysql:5.7

请在此添加图片描述

哇哦,数据果然都在,真不错!有的东西啊。

这是最后一个回合了,一架下来,mysql:5.7的伤势严重,五脏六腑都被docker摸了个遍,它捂着胸口喘息:
docker兄不愧为开发界的后起之秀,在下佩服!话毕,它又一口老血喷出,把扶着它的远方大表哥喷了一脸都是。
固为亲戚,大表哥嘴上不说,心里一阵嘀咕:
淦!!你再喷一个试试,信不信劳资反手一个大嘴巴子直接把你送走。

docker实在是伤的不轻,它也顾不得面子,赶紧掏出不时之需的金疮药往肚皮上就是顿贴,毕竟自己太傲娇,常年没有健身的它早就大腹便便,这次倒好,被mysql这家伙捅了几个洞,海水直流:
mysql,你江湖人称稳如老狗的名号果然不是盖的,你是个值得尊重的对手,这次就不杀你了,我得保留体力,后面还要挑战redis和nginx,他们也非等闲之辈!!说完就走了……

安装Redis

尽管和mysql那一战自己受了重伤,但好在docker有祖传的秘书,一重启又是一个全新的docker之身。它长途跋涉,来到redis家门口,悄悄门,此时一个年轻的小伙子打开了门:
你就是Redis?docker道。

小伙子摇摇头,我是jedis,我师傅在健身房等候你多时了,这边请….

在jedis的带领下,二人来到了一处宽敞的屋子,里面摆着各式各样的健身器材。场地中央,只见一人正在举着什么东西,细看去,原来是一对哑铃,分别标着****RDBAOF字样,一看就知道有些分量。
docker二话不说,身上的包袱一甩,奔着redis后脑勺就是一沙包大的拳头抡过去,两个年轻人的战斗就此拉开……

安装Nginx

待更新…

Dockerfile

概述

Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。

请在此添加图片描述

官网:https://docs.docker.com/engine/reference/builder/

构建步骤:

  • 编写Dockerfile文件
  • docker build命令构建镜像
  • docker run 依镜像运行容器实例

Dockerfile构建过程

Docklerfile基础知识
  • 每条保留字指令都必须是大写字母且后面要跟随至少一个参数。
  • 指令从上到小顺序执行
  • 表示注释内容

  • 每条指令都会创建一个新的镜像层并对镜像进行提交
执行Dockerfile的大致流程
  • docker从基础镜像运行一个容器
  • 执行一条指令并对容器作出修改
  • 执行类似docker commit的操作提交一个新的镜像层
  • docker在基于刚提交的镜像运行一个新的容器
  • 执行dockerfile中的下一条指令直到所有指令都执行完成。

所有指令执行完成。

扩展

从应用软件的角度来看,DockerfileDocker镜像与Docker容器分别代表软件的三个不同阶段,

  • Dockerfile是软件的原材料
  • Docker镜像是软件的交付品
  • Docker容器则可以认为是软件镜像的运行态,也即依照镜像运行的容器实例 Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

请在此添加图片描述

  1. Dockerfile,需要定义一个DockerfileDockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
  2. Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;
  3. Docker容器,容器是直接提供服务的。

Dockerfile常用保留字

下面列出的保留字都可以在官网查看。

FROM

基础镜像,当前镜像是基于哪个镜像的,指定一个已经存在的镜像最为模板,第一条必须是FROM。

MAINTAINER

镜像维护者的姓名和邮箱地址。

RUN

  • 容器构建时需要运行的命令。

  • 格式

    • shell

请在此添加图片描述

- exec

请在此添加图片描述

  • RUN是在docker build时运行。

EXPOSE

当前容器对外暴露的端口号。

WORKDIR

指定在创建容器之后,终端默认登录进来的工作目录,作为一个起始落脚点。

USER

指定该镜像以什么样的用户去执行,如果都不指定,默认是root。

ENV

  • 用来在构建镜像过程中设置环境变量。

  • ENV MY_PATH /usr/mytest
    这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样; 也可以在其它指令中直接使用这些环境变量,
    比如:WORKDIR $MY_PATH

ADD

将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包。

COPY

类似ADD,拷贝文件和目录到镜像中。 将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。
COPY src dest
COPY ["src", "dest"]
<src源路径>:源文件或者源目录 <dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

VOLUME

容器数据卷,用于数据保存和持久化工作。

CMD

  • 指定容器启动后的要做的事情。
  • 注意
    • Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
  • 它和前面RUN命令的区别
    • CMD是在docker run 时运行。
    • RUN是在 docker build时运行。

ENTRYPOINT

也是用来指定一个容器启动时要运行的命令
类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖, 而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
命令格式/案例
命令格式: ENTRYPOINT可以和CMD一起用,一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参。 当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令,他两个组合会变成
案例如下:假设已通过 Dockerfile 构建了 nginx:test 镜像:

请在此添加图片描述

是否传参 按照`dockerfile`编写执行 传参运行    Docker命令 `docker run  nginx:test` `docker run  nginx:test -c /etc/nginx/new.conf`   衍生出的实际命令 `nginx -c /etc/nginx/nginx.conf` `nginx -c /etc/nginx/new.conf`   

优点
在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数。

注意
Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

案例演示

构建需求

基于最新版的centos镜像构建,使具备vim+ifconfig+jdk11支持。
具体版本:jdk-11.0.16_linux-x64_bin.tar.gz
我将上面下载的JDK放到了/root目录下。

文件编写

编写内容之前先pull一下centos镜像。
docker pull centos

FROM centos:7
MAINTAINER 八尺妖剑<ilikexff@163.com>
 
ENV MYPATH /usr/local
WORKDIR $MYPATH

#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk-11.0.16_linux-x64_bin.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-11.0.16_linux-x64_bin.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk-11.0.16
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH

EXPOSE 80

CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash

同样的,Dockerfile文件也放在和JDK相同的/root目录下。

构建Dockerfile
docker build -t centosjava11:1.5 .

格式:docker build -t 新镜像名字:TAG .
注意TAG后面有一个空格再加上.(半角)

构建过程

请在此添加图片描述

能看到确实已经执行到了文件脚本的最后一行并打印了成功的输出。查看镜像发现,确实已经成功构建

请在此添加图片描述

那么是不是真的具有了前面需求中的功能,我们验验货。

docker run -it 容器ID /bin/bash

请在此添加图片描述

验证通过,需求提到的所有功能已经全部支持。

虚悬镜像体验

概念

仓库名、标签都是的镜像,俗称dangling

来自己创建一个虚悬镜像体验一下。下面的Dockerfile的内容:

from ubuntu
CMD echo 'action is success'

运行:

docker build .

查看镜像

# 专门查看虚悬镜像的命令
docker image ls -f dangling=true

请在此添加图片描述

一般情况下,虚悬镜像可能由于我们再创建和输删除镜像的过程中出现异常产生的,本身并没有实用价值,所以如果出现虚悬镜像,建议直接删除,不要留恋!!添dog???没有好下场。

删除虚悬镜像

docker image prune

Docker微服务实战

通过IDEA新建一个普通微服务模块

maven配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.docker</groupId>
    <artifactId>docker-boot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>docker-boot</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.properties

server.port=8081
blog.addr=https://www.waer.ltd

helloController.java

package com.waer.docker.dockerboot.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SuppressWarnings("all")
/**
 * @author: 八尺妖剑
 * @date: 2022/8/29 18:09
 * @email: ilikexff@gmail.com
 * @blog: https://www.waer.ltd
 */
@RestController
public class helloController {
    @Value("${server.port}")
    private String port;
    @Value("${blog.addr}")
    private String addr;

    @GetMapping("/hello/docker")
    public String helloDocker () {
        return "服务端口号:" + port + "博客地址:" + addr;
    }
}

将项目打成jar包

请在此添加图片描述


编写Dockerfile文件并上传

# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER 八尺妖剑
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为hello_docker.jar
ADD docker-boot-0.0.1-SNAPSHOT.jar hello_docker.jar
# 运行jar包
RUN bash -c 'touch /hello_docker.jar'
ENTRYPOINT ["java","-jar","/hello_docker.jar"]
#暴露8081端口作为微服务
EXPOSE 8081
CMD echo '构建完成.....build success!'

之后将写好得文件上传到/root/docker目录下,当然这个目录你可以自定义,但是建议把jar包和dockerfile放到相同目录下。

请在此添加图片描述


构建镜像

命令

docker build -t hello_docker:1.5 .

请在此添加图片描述

docker images

请在此添加图片描述


运行容器

运行命令之前请确保8081端口已经打开。

docker run -d -p 8081:8081 hello_docker:1.5

请在此添加图片描述

如果在运行是遇到下面得问题

请在此添加图片描述

这是由于打包得本地Java版本和FROM 得Java版本不一致导致得,严格地说就是使用高版本打包得jar运行在低版本得java环境得不到支持。解决方法是修改本地pom.xml:

<properties>
    <java.version>1.8</java.version>
</properties>

修改为1.8再刷新maven之后重新打包上传即可解决。

Docker网络

开局一条命(令)

在宿主机上启动docker之后,我们通过ifconfig命令查看主机的网络情况:

请在此添加图片描述

你会发现这里多了一个名为docker0的网络模块。不严格的说,这个就是docker的网络。

查看网络模式

docker默认有三大网络模式,通过下面的命令可以查看。

docker network ls

请在此添加图片描述

分别是桥接、主机、空模式。

装备全靠help

了解关于doker网络的基本命令的使用,最快的方式就是官方的help命令。

docker network COMMAND --help

请在此添加图片描述

通过一个小案例实际操作一遍上面的大部分命令。我们自己创建一个docker网络。

docker network create mynet

查看网络

docker network ls

查看网络数据源

docker network inspect mynet

删除网络

docker network rm mynet

docker网络可以作容器的互联和通信、端口映射。容器IP变动时可以通过服务名称直接进行网络通信,而不受到影响。

网络模式

请在此添加图片描述

上面列出的四种模式分别使用下面的方式进行指定:

--network bridge 指定,默认使用docker0
--network host指定
--network none指定
--network container:NAME或者容器ID指定

容器实例内默认网络IP生成规则

先启动两个容器

请在此添加图片描述

再通过docker inspect 容器名来查看容器的网络情况。

请在此添加图片描述

请在此添加图片描述

可以看到两个都是采用bridge桥接模式且公用一个网关,但各自的IP是不一样的。也就是说docker容器内部的ip是有可能会发生改变的。

bridge

Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。

查看 bridge 网络的详细信息,并通过 grep 获取名称项

docker network inspect bridge | grep name或者ifcong | grep docker

请在此添加图片描述


Docker-compose容器编排

概述

ComposeDocker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器。

docker建议我们每一个容器中只运行一个服务,因为docker容器本身占用资源极少,所以最好是将每个服务单独的分割开来但是这样我们又面临了一个问题?如果我需要同时部署好多个服务,难道要每个服务单独写Dockerfile然后在构建镜像,构建容器,这样累都累死了,所以docker官方给我们提供了docker-compose多服务部署的工具。

例如要实现一个Web微服务项目,除了Web服务容器本身,往往还需要再加上后端的数据库mysql服务容器,redis服务器,注册中心eureka,甚至还包括负载均衡容器等等。

Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。

可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。


下载安装

下载安装学习,首选官方文档。

下载地址

文档地址

注意先去官方文档看一下compose和docker版本之间的要求,别看着命令就是一顿瞎搞,结果下了个寂寞…

具体命令
# 下载compose
curl -SL https://github.com/docker/compose/releases/download/v2.7.0/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
# 提升权限
chmod +x /usr/local/bin/docker-compose
# 查看版本
docker-compose --version

核心概念

文件

docker-compose.yml

服务(service)

一个个应用容器实例,比如订单服务、库存服务、mysql容器、nginx容器或者redis容器。

工程(project)

由一组关联的应用容器组成的一个完整的业务单元,在docker-compose.yml中定义。


使用步骤

  • 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件。
  • 使用docker-compose.yml定义一个完整的业务单元,安排好整体应用中的各个容器服务。
  • 执行docker-compose up命令来启动并运行整个应用程序,完成一键部署上线。

Compose常用命令

# 帮助
docker-compose -h
# 启动所有的docker-compose服务
docker-compose up
# 启动服务并保持后台运行
docker-compose up -d
# 停止并删除容器、网络、卷、镜像
docker-compose down
# 进入容器实例内部
 docker-compose exec [docker-compose.yml文件中写的服务id] /bin/bash
# 展示当前docker-compose编排过的运行的所有容器
docker-compose ps
# 展示当前docker-compose编排过的容器进程
docker-compose top
# 检查配置
docker-compose config
# 检查配置,有问题才有输出
docker-compose config -q
# 重启服务
docker-compose restart   
# 启动服务
docker-compose start     
# 停止服务
docker-compose stop      

Portainer

概述

Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。

官方文档

下载安装

具体的安装细节可以参考官方文档,执行下面的命令可以直接安装之。

docker run -d -p 8000:8000 -p 9000:9000 --name portainer     --restart=always     -v /var/run/docker.sock:/var/run/docker.sock     -v portainer_data:/data     portainer/portainer

其实本质上就是跑了一个容器,注意需要打开9000和8000端口。容器跑起来之后,浏览器访问IP:9000即可打开管理页面。

请在此添加图片描述

设置密码注册之后可以看到主模板概览如下。

请在此添加图片描述

至此安装完毕!


使用Portainer安装Ngnix

请在此添加图片描述

基本的配置就是这样,如果对网络、数据卷挂载等复杂的操作,把页面下拉就可以看到,如果了解了命令行的使用方式以及基本原理,那么可视化就更容易理解了。


这篇博客全部内容就暂时固定了,后面有时间会补更一些实战方面的内容,毕竟纸上得来终觉浅!

相关推荐

  1. Linux中的mount命令

    2024-04-24 14:18:02       59 阅读
  2. 10个的SQL聚合函数

    2024-04-24 14:18:02       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-24 14:18:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-24 14:18:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-24 14:18:02       82 阅读
  4. Python语言-面向对象

    2024-04-24 14:18:02       91 阅读

热门阅读

  1. spring boot 基础案例【1】在页面上打印hellow world

    2024-04-24 14:18:02       36 阅读
  2. 代码随想录算法训练营day38

    2024-04-24 14:18:02       30 阅读
  3. Kylin 使用心得

    2024-04-24 14:18:02       36 阅读
  4. Kotlin语法入门-自定义注解(7)

    2024-04-24 14:18:02       32 阅读
  5. 建造者模式

    2024-04-24 14:18:02       35 阅读