Docker学习
Docker最近用的真多
一、Docker概述
1、docker为什么会出现
工作中,经常出现“在我的机器上可正常工作”的问题
因为环境不一致等原因导致。。。
Docker的思想就来自于集装箱!
隔离:Docker核心思想!打包装箱!每个箱子是互相隔离的。
Docker通过隔离机制,可以将服务器利用到极致!
2、Docker的历史
Docker 是基于Go 语言实现的开源容器项目,诞生于2013 年年初,最初发起者是 dotCloud 公司。Docker 自开源后受到广泛的关注和l 讨论,目前已有多个相关项目(包括 Docker 三剑客、Kubemetes 等),逐渐形成了围绕Docker 容器的生态体系。 由于Docker 在业界造成的影响力实在太大, dotCloud 公司后来也直接改名为Docker Inc ,并专注于Docker 相关技术和产品的开发。
自从dotCloud公司开源其Docker项目后,凭借其便捷的Docker镜像技术解决了当时困扰众多PaaS项目的难题:如何为应用打包,让用户将本地的应用顺利迁移到PaaS平台,而不用顾忌应用的开发语言、配置、依赖包等诸多因素,也因此开启了全新的Docker容器时代。
3、Docker能干嘛
对开发和运维( DevOps )人员来说,可能最梦寐以求的效果就是一次创建或配置, 之后可以在任意地方、任意时间让应用正常运行。
具体说来, Docker 在开发和运维过程中,具有如下几个方面的优势:
更快速的交付和部署
使用Docker ,开发人员可以使用镜像来快速构建一套标准的开发环境;开发完成之后,测试和运维人员可以直接使用完全相同环境来部署代码。只要开发测试过的代码,就可以确保在生产环境无缝运行。Docker 可以快速创建和删除容器,实现快速迭代,大量节约开发、测试、部署的时间。并且,整个过程全程可见,使团队更容易理解应用的创建和工作过程。
更高效的资源利用
Docker 容器的运行不需要额外的虚拟化管理程序(Virtual Machine Manager, VMM ,以及Hypervisor)支持,它是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。跟传统虚拟机方式相比,要提高一到两个数量级。
更轻松的迁移和扩展
Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等,同时支持主流的操作系统发行版本。这种兼容性让用户可以在不同平台之间轻松地迁移应用。
更简单的更新管理
使用Dockerfile ,只需要小小的配置修改,就可以替代以往大量的更新工作。并且所有修改都以增量的方式被分发和更新,从而实现自动化并且高效的容器管理。
Docker 和常见的虚拟化方式的不同之处
传统方式是在硬件层面实现虚拟化,需要有额外的虚拟机管理应用和虚拟机操作系统 层。Docker 容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,因此更加 轻量级。
Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。
作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多;Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
二、Docker安装
1、Docker的基本组成
镜像(Image)
什么是 Docker 镜像?简单的理解,Docker 镜像就是一个 Linux 的文件系统(Root FileSystem),这个文件系统里面包含可以运行在 Linux 内核的程序以及相应的数据。
通过镜像启动一个容器,一个镜像就是一个可执行的包,其中包括运行应用程序所需要的所有内容:包含代码,运行时间,库,环境变量和配置文件等。
Docker 把 App 文件打包成为一个镜像,并且采用类似多次快照的存储技术,可以实现:
- 多个 App 可以共用相同的底层镜像(初始的操作系统镜像)
- App 运行时的 IO 操作和镜像文件隔离
- 通过挂载包含不同配置/数据文件的目录或者卷(Volume),单个 App 镜像可以用来运行无数个不同业务的容器
容器(container)
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
通俗来讲,镜像相当于类,容器相当于对象
仓库(repository)
仓库可看成一个代码控制中心,用来保存镜像。
仓库分为公有仓库和私有仓库。(很类似git)
Docker Hub是国外的。
阿里云…都有容器服务器(配置镜像加速!)
2、安装docker
- 使用云服务器的,可以直接去对应的官网寻找对应的安装配置方案
- 比如我这里使用的就是腾讯云的Ubuntu系统
- 执行以下命令,添加 Docker 软件源。
1 | sudo apt-get update |
- 执行以下命令,安装 Docker。
1 | sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin |
- 执行以下命令,运行 Docker。
1 | systemctl start docker |
- 执行以下命令,检查安装结果。
1 | docker info |
返回如下信息,即表示安装成功。
- 配置对应的加速源
1 | vim /etc/docker/daemon.json |
- 然后添加以下内容
1 | { |
- 执行以下命令,重启 Docker 即可。
1 | sudo systemctl restart docker |
测试使用
运行hello-world
查看镜像
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker images |
查看容器
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker ps -a |
移除容器镜像
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker rmi -f d2c94e258dcb 移除镜像 |
3、回滚hello-world流程
底层原理
docker是怎么工作的
docker是一个client-server结构的系统,docker守护进程运行在主机上,然后通过socket连接从客户端访问docker守护进程。
docker守护进程从客户端接收命令,并按照命令,管理运行在主机上的容器。
一个docker容器,是一个运行时环境,可以简单理解为进程运行的集装箱。
为什么docker比vm快
- Docker有这比虚拟机更少的抽象层,由于Docker不需要Hypervisor实现硬件资源虚拟化,运行在Docker上的程序直接使用的都是实际物理机上的硬件资源,因此在CPU、内存利用率上有明显的优势。
- **Docker利用的是宿主机的内核,而不需要使用Guest OS ** ,因此当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核,而避免引寻 ,加载操作系统内核是个比较费事费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载Guest OS,返回的新建的过程是分钟级别,而docker直接使用的是宿主机上的操作系统,则省略了返回这个的过程,因此新建一个docker容器只需要几秒钟。
虚拟机与Docker架构对比图:
三、Docker常见命令
官方文档常用命令地址:https://docs.docker.com/reference/
1、帮助命令
1 | #显示docker的版本信息。 |
2、镜像命令
docker image 查看所有本地主机上的镜像
参数和选项
-a
, –all 列出所有镜像-q
, –quiet 只显示镜像id
测试
1、查看本地主机上的镜像
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker images |
解释:
- REPOSITORY 镜像的仓库源
- TAG 镜像的标签(版本) latest表示最新的版本
- IMAGE ID 镜像id
- CREATED 镜像的创建时间
- SIZE 镜像的大小
2、列出所有镜像的id
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker images -aq |
docker search 搜索镜像
镜像仓库地址:https://hub.docker.com/
参数和选项
-f
, –filter filter 基于条件过滤
测试
1、搜索mysql镜像
在docker仓库上搜 https://hub.docker.com/
也可以直接使用命令去搜
1 | docker search **** |
不过服务器要是不太行,一般会直接超时。
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker search mysql |
docker rmi删除镜像
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker rmi -f 镜像id #删除指定镜像 |
3、容器命令
我们有了镜像,才能创建容器,所以先下载一个centos镜像来学习
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker pull centos |
启动容器
docker run [可选参数] 容器名或者容器id
创建一个新的容器并运行一个命令
可选参数
- -i: 以交互模式运行容器,通常与 -t 同时使用
- -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用
- -P: 随机端口映射,容器内部端口随机映射到主机的端口
- -p: 指定端口映射,格式为:主机(宿主)端口:容器端口
- -d: 后台运行容器,并返回容器ID;
- –name=”nginx-lb”: 为容器指定一个名称
- -e username=”ritchie”: 设置环境变量
测试:
1、使用镜像centos以交互模式启动一个容器,在容器内执行/bin/bash命令
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker run -it centos /bin/bash |
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker ps |
退出容器
1 | exit #直接退出容器并关闭 |
列出所有的容器
docker ps
可选参数
- **-a :**显示所有的容器,包括未运行的。
- **-n :**列出最近创建的n个容器。
- **-q :**静默模式,只显示容器编号。
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker ps |
删除容器
1 | docker rm -f 容器id # 删除指定容器 |
启动和停止容器
1 | docker start 容器id # 启动容器 |
4、常用其他命令
后台启动命令
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker run -d centos |
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker run -d -it centos #这种启动容器后就不会关闭了 |
查看日志
docker logs [参数与参选] 容器id
参数与选项
- -f : 跟踪日志输出
- -t : 显示时间戳
- **–since :**显示某个开始时间的所有日志
- -n或者**–tail :**仅列出最新N条容器日志
1 | # docker logs -tf -n=10 容器id |
命令docker run -d -it centos /bin/bash -c "while true;do echo zyy hello;sleep 1;done"
解释:
该命令会不停地输出字符串 “zyy hello”,每隔 1 秒钟输出一次,直到容器被停止。
其中,各个参数的含义如下:
docker run
是 Docker 命令的基本语法,用于启动一个新的容器。-d
参数表示在后台运行容器。centos
参数表示使用的镜像名称,这里使用的是 CentOS 镜像。/bin/bash -c "while true;do echo zyy hello;sleep 1;done"
参数表示在容器内部执行的 shell 命令。其中/bin/bash
是 shell 的路径,-c
参数表示在 shell 中执行指定的命令。这里的命令是一个无限循环,不停地输出字符串 “zyy hello”。
查看容器中的进程信息
docker top 容器id
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker ps |
查看镜像的元数据
docker inspect 容器id
元数据 (meta data)——“data about data” 描述数据的数据,一般是结构化数据
元数据是指从信息资源中抽取出来的用于说明其特征、内容的结构化的数据(如题名,版本、出版数据、相关说明,包括检索点等),用于组织、描述、检索、保存、管理信息和知识资源
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker inspect 4ee256515d6e |
进入当前正在运行的容器
方式一:docker exec
docker exec -it 容器id /bin/bash
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker exec -it 4ee256515d6e /bin/sh |
方式二:docker attach
docker attach 容器id
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker attach 4ee256515d6e |
区别
1 | # docker exec # 进入容器后开启一个新的终端,可以在里面操作 |
从容器拷贝到主机上、从主机拷贝到容器上
docker cp 容器id:容器文件 主机路径
docker cp 主机文件 容器id:容器路径
5、命令大全
https://pythondjango.cn/python/tools/2-docker-dockerfile/
四、Docker的使用练习
1、Docker安装nginx
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker pull nginx 1、 拉取nginx |
成功搭建(注意这里需要服务器开启对应的3344端口,外界才能访问到)
docker run -it -d --name nginx02 -p 3344:80 nginx
解释
docker run
:启动一个新的容器-it
:表示启用交互式终端并分配一个伪终端,这样我们可以在容器中交互式地执行命令。-d
:表示将容器运行在后台(守护进程)。--name nginx02
:给容器起一个名字叫做nginx02
。-p 3344:80
:将主机的 3344 端口映射到容器的 80 端口,这样我们就可以通过主机的 3344 端口来访问容器内的 Nginx 服务。nginx
:表示要启动的镜像名称为nginx
。
因此,这个命令的作用是在 Docker 中启动一个名为 nginx02
的容器,运行 Nginx 服务,并将容器的 80 端口映射到主机的 3344 端口,以便我们可以通过访问主机的 3344 端口来访问 Nginx 服务。容器会在后台运行,并启用交互式终端。
2、安装一个tomcat
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker pull tomcat 拉取镜像 |
发现服务可以访问,但是没有页面
进入服务
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker exec -it c0186e2559 /bin/bash 进入容器 |
发现webapp下为空
1 | # 原因:阿里云镜像的原因,阿里云默认是最小的镜像,所以不必要的都剔除掉 |
解决方案:将webapps.dist下的文件都拷贝到webapps下即可
1 | root@c0186e2559f5:/usr/local/tomcat# cp -r webapps.dist/* webapps |
刷新一下服务,就有页面了
问题:我们以后要部署项目,如果每次都要进入容器是不是十分麻烦?要是可以在容器外部提供一个映射路径,比如webapps,我们在外部放置项目,就自动同步内部就好了!
3、Docker安装Elesticsearch
elasticsearch暴露的端口很多
十分耗内存(所以体现测试的时候可以提前把其他docker容器先停止,启动时可以限制堆内存大小)
es 的数据一般需要放置到安全目录!挂载
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2 |
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker stats #查看cpu状态 |
docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="-Xms64m -Xmx512m" elasticsearch:7.6.2
命令解释
这是一个使用 Docker 命令行工具来启动一个 Elasticsearch 版本为 7.6.2 的容器,并设置了一些选项和参数。
具体来说,这些选项和参数的含义如下:
-d
表示在后台运行容器,即以“守护进程”模式运行,不会占用当前终端的控制台;--name es
表示给容器起一个名称为 “es”;-p 9200:9200 -p 9300:9300
表示将容器内部的 9200 端口和 9300 端口映射到主机的 9200 和 9300 端口上,以便在主机上通过浏览器或客户端连接 Elasticsearch;-e "discovery.type=single-node"
表示设置 Elasticsearch 的节点类型为 “single-node”,即单节点模式,这是一个简单的运行 Elasticsearch 的方式,适用于测试或开发环境;-e ES_JAVA_OPTS="-Xms64m -Xmx512m"
表示设置 Elasticsearch 的 Java 虚拟机参数,其中 “-Xms64m” 表示设置初始堆大小为 64MB,”-Xmx512m” 表示设置最大堆大小为 512MB;elasticsearch:7.6.2
表示要运行的容器镜像名称和版本号,这里是 Elasticsearch 官方提供的 7.6.2 版本。
总体来说,这个命令的作用是在 Docker 中启动一个 Elasticsearch 7.6.2 的容器,并将容器内部的端口映射到主机上,以便在主机上访问 Elasticsearch。其中的选项和参数可以根据需要进行修改或调整。
五、portainer可视化面板安装
- portainer(先用这个)
- rancher(CI/DI再用)
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer |
docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
解释
这是一个用于运行 Docker 容器的 Docker 命令。具体来说,该命令启动了一个名为 Portainer 的 Docker 容器,并将容器的 9000 端口映射到主机的 8088 端口,以便在主机上通过浏览器访问 Portainer。
以下是各个参数的含义:
-d
:表示以后台模式运行容器。-p 8088:9000
:表示将容器的 9000 端口映射到主机的 8088 端口。--restart=always
:表示容器在停止后总是会自动重启。-v /var/run/docker.sock:/var/run/docker.sock
:表示将主机的 Docker 守护进程的 Unix 套接字文件(/var/run/docker.sock)挂载到容器的同一位置,从而让 Portainer 可以管理主机上的其他 Docker 容器。--privileged=true
:表示在容器中开启特权模式,以便 Portainer 能够访问主机上的 Docker 守护进程。
总之,这个命令的作用是在主机上启动一个 Portainer 容器,以便通过 web 界面来管理和监控其他 Docker 容器。
- 使用图形化界面对docker容器镜像进行对应的管理
六、Docker镜像
1、镜像是什么
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含
运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
2、Docker镜像加载原理
UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,
它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系
统下(unite several directories into a single virtual fifilesystem)。Union 文件系统是 Docker 镜像的基
础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件
系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot fifile system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启
动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是
一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已
由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root fifile system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标
准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么Docker这里才200M?
对于一个精简的OS,rootfs 可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直
接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版, bootfs基本是一
致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
3、分层理解
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层一层的在下载!
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker pull redis |
思考:为什么Docker镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机
只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服
务了,而且镜像的每一层都可以被共享。
查看镜像分层的方式可以通过 docker image inspect
命令!
1 | "RootFS": { |
理解:
所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之
上,创建新的镜像层。
举一个简单的例子,假如基于 Ubuntu Linux 16.04 创建一个新的镜像,这就是新镜像的第一层;如果
在该镜像中添加 Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就
会创建第三个镜像层。
该镜像当前已经包含 3 个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有 6 个文件,这是因为最上层中的文件
7 是文件 5 的一个更新版本。
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新
镜像层添加到镜像当中。
Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统
一的文件系统。
Linux 上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储
引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。
Docker 在 Windows 上仅支持 windowsfifilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分
层和 CoW。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
特点
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
4、镜像commit
docker commit 从容器创建一个新的镜像。
1 | docker commit 提交容器副本使之成为一个新的镜像! |
实际操作
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker run -it -p 3355:8080 --name tomcat01 tomcat 启动tomcat |
如果你想要保存你当前的状态,可以通过commit,来提交镜像,方便使用,类似于 VM 中的快照!
七、容器数据卷
1、什么是容器数据卷
docker的理念回顾:
将应用和运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对于数据的要求,是希望能够
持久化的!
就好比,你安装一个MySQL,结果你把容器删了,就相当于删库跑路了,这TM也太扯了吧!
所以我们希望容器之间有可能可以共享数据,Docker容器产生的数据,如果不通过docker commit 生成
新的镜像,使得数据作为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了!这样是行
不通的!
为了能保存数据在Docker中我们就可以使用卷!让数据挂载到我们本地!这样数据就不会因为容器删除
而丢失了!
作用:
卷就是目录或者文件,存在一个或者多个容器中,由docker挂载到容器,但不属于联合文件系统,因此
能够绕过 Union File System , 提供一些用于持续存储或共享数据的特性
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂
载的数据卷
特点:
- 数据卷可在容器之间共享或重用数据
- 卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
所以:总结一句话: 就是容器的持久化,以及容器间的继承和数据共享!
2、使用容器数据卷
方式一:容器中直接使用命令来添加
挂载
1 | 命令 |
查看数据卷是否挂载成功docker inspect 容器id
测试容器和宿主机之间数据共享:可以发现,在容器中,创建的会在宿主机中看到!
测试容器停止退出后,主机修改数据是否会同步!
- 停止容器
- 在宿主机上修改文件
- 启动刚才停止的容器
- 然后查看对应的文件,发现数据依旧同步
实战:使用docker安装mysql
思考:mysql 数据持久化的问题!
下载镜像
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16root@VM-16-10-ubuntu:/home/ubuntu# docker pull mysql:5.7
5.7: Pulling from library/mysql
20e4dcae4c69: Pull complete
1c56c3d4ce74: Pull complete
e9f03a1c24ce: Pull complete
68c3898c2015: Pull complete
6b95a940e7b6: Pull complete
90986bb8de6e: Pull complete
ae71319cb779: Pull complete
ffc89e9dfd88: Pull complete
43d05e938198: Pull complete
064b2d298fba: Pull complete
df9a4d85569b: Pull complete
Digest: sha256:4bc6bc963e6d8443453676cae56536f4b8156d78bae03c0145cbe47c2aad73bb
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7启动容器
1
root@VM-16-10-ubuntu:/home/ubuntu# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
可以成功同步对应的信息,使用mysql连接工具就可以变相直接控制docker内的数据库了
docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
命名解释
这个命令使用 Docker 运行 MySQL 5.7 容器,并做出以下配置:
-d
表示容器在后台运行(即“守护进程”模式)。-p 3310:3306
将容器内的 MySQL 端口 3306 映射到主机的端口 3310 上,这样你就可以通过主机上的端口 3310 访问 MySQL 服务。-v /home/mysql/conf:/etc/mysql/conf.d
将主机上的目录/home/mysql/conf
挂载到容器的/etc/mysql/conf.d
目录中,这样你可以在主机上编辑 MySQL 配置文件,并且它们会在容器内生效。-v /home/mysql/data:/var/lib/mysql
将主机上的目录/home/mysql/data
挂载到容器的/var/lib/mysql
目录中,这样你可以在主机上保存 MySQL 数据文件,并且它们会在容器内生效。-e MYSQL_ROOT_PASSWORD=123456
设置 MySQL root 用户的密码为123456
。--name mysql01
指定容器的名称为mysql01
,以便于管理和查找。mysql:5.7
指定使用官方提供的 MySQL 5.7 镜像。
这个命令的作用是在 Docker 中创建并运行一个 MySQL 容器,同时将主机上的目录挂载到容器中,以便于配置和保存数据。
3、匿名和具名挂载
- -v 容器内路径 #匿名挂载
- -v 卷名:容器内路径 #具名挂载
- -v /宿主机路径:容器内路径 #指定路径挂载
4、初识Dockerfile
DockerFile 是用来构建Docker镜像的构建文件,是由一些列命令和参数构成的脚本。
我们在这里,先体验下,后面我们会详细讲解 DockerFile !
1 | #1.进入宿主机目录,在目录下再创建一个目录docker-test-volume,在这个新建目录下新建一个文件dockerfile |
1 | #8、发现宿主机文件 |
注意:如果访问出现了 cannot open directory: Permission denied
解决办法:在挂载目录后多加一个 –privileged=true参数即可
5、数据卷容器
命名的容器挂载数据卷,其他容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为
数据卷容器。
我们使用上一步的镜像:my-centos 为模板,运行容器 docker01,docker02,docker03,他
们都会具有容器卷volume1和volume2
我们来测试下,容器间传递共享
用my-centos镜像,启动容器docker01,在volume2目录下新建一个文件from_docker01.txt
1
2
3
4
5root@VM-16-10-ubuntu:/home/ubuntu# docker run -it --name docker01 my-centos
[root@a31ad75c98e6 /]# cd volume2
[root@a31ad75c98e6 volume2]# touch from_docker01.txt
[root@a31ad75c98e6 volume2]# ls
from_docker01.txt退出不停止容器:ctrl+p+q
1
2
3# root@VM-16-10-ubuntu:/home/ubuntu# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a31ad75c98e6 my-centos "/bin/sh -c /bin/bash" About a minute ago Up About a minute docker01用my-centos镜像,启动容器docker02,让docker02继承docker01
--volumes-from
在volume2目录下新建一个文件from_docker02.txt
1
2
3
4root@VM-16-10-ubuntu:/home/ubuntu# docker run -it --name docker02 --volumes-from docker01 my-centos
[root@de7b3fc3cf53 /]# cd volume2
[root@de7b3fc3cf53 volume2]# ls
from_docker01.txt
容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止。
存储在本机的文件则会一直保留!
八、dockerfile
大家想想,Nginx,tomcat,mysql 这些镜像都是哪里来的?官方能写,我们不能写吗?
我们要研究自己如何做一个镜像,而且我们写的微服务项目以及springboot打包上云部署,Docker就是
最方便的。
微服务打包成镜像,任何装了Docker的地方,都可以下载使用,极其的方便。
流程:开发应用=>DockerFile=>打包为镜像=>上传到仓库(私有仓库,公有仓库)=> 下载镜像 => 启动
运行。
还可以方便移植!
1、什么是dockerfile
dockerfifile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。
构建步骤:
- 编写DockerFile文件
- docker build 构建镜像
- docker run
dockerfifile文件我们刚才已经编写过了一次,这里我们继续使用 centos 来看!
https://hub.docker.com/_/centos
2、dockerfile的构建过程
基础知识
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
- # 表示注释
- 每条指令都会创建一个新的镜像层,并对镜像进行提交
流程:
- docker从基础镜像运行一个容器
- 执行一条指令并对容器做出修改
- 执行类似 docker commit 的操作提交一个新的镜像层
- Docker再基于刚提交的镜像运行一个新容器
- 执行dockerfifile中的下一条指令直到所有指令都执行完成!
说明:
从应用软件的角度来看,DockerFile,docker镜像与docker容器分别代表软件的三个不同阶段。
- DockerFile 是软件的原材料 (代码)
- Docker 镜像则是软件的交付品 (.apk)
- Docker 容器则是软件的运行状态 (客户下载安装执行)
DockerFile 面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可!
DockerFile:需要定义一个DockerFile,DockerFile定义了进程需要的一切东西。DockerFile涉及的内容
包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进
程和内核进程(当引用进行需要和系统服务和内核进程打交道,这时需要考虑如何设计 namespace的权
限控制)等等。
Docker镜像:在DockerFile 定义了一个文件之后,Docker build 时会产生一个Docker镜像,当运行
Docker 镜像时,会真正开始提供服务;
Docker容器:容器是直接提供服务的。
3、Dockerfile指令
关键字:
1 | FROM # 基础镜像,当前新镜像是基于哪个镜像的 |
4、实战测试
Docker Hub 中99% 的镜像都是通过在base镜像(Scratch)中安装和配置需要的软件构建出来的
自定一个centos镜像
编写dockerfile
直接运行centos的官方镜像
1
2
3
4
5
6
7
8
9
10root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume# docker run -it centos /bin/bash
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
a1d0c7532777: Already exists
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
[root@bcf6eb6bf82f /]# vim a
bash: vim: command not found
[root@bcf6eb6bf82f /]# ifconfig
bash: ifconfig: command not found发现,不支持vim和ifconfig命令,登陆后的默认路径是/
目的:使我们自己的镜像具备如下:登陆后的默认路径、vim编辑器、查看网络配置ifconfifig支持
准备编写DockerFlie文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume# vim mydockerfile-centos
root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume# cat mydockerfile-centos
FROM centos
MAINTATINER 6pc1<pc6pc1@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN cd /etc/yum.repos.d/
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
RUN yum -y install vim
RUN yun -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "----end------"
CMD /bin/bash说明:dockerfile中直接
RUN yum -y install vim
可能会报下面错误1
#0 1.607 Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist
说明下面这些,其实就是为了让
RUN yum -y install vim
可以执行成功1
2
3
4RUN cd /etc/yum.repos.d/
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
RUN yum -y install vim构建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume# docker build -f mydockerfile-centos -t mycentos:1.0 .
[+] Building 4.3s (11/11) FINISHED docker:default
=> [internal] load build definition from mydockerfile-centos 0.0s
=> => transferring dockerfile: 452B 0.0s
=> [internal] load metadata for docker.io/library/centos:latest 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/7] FROM docker.io/library/centos:latest 0.0s
=> CACHED [2/7] WORKDIR /usr/local 0.0s
=> CACHED [3/7] RUN cd /etc/yum.repos.d/ 0.0s
=> CACHED [4/7] RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* 0.0s
=> CACHED [5/7] RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum 0.0s
=> CACHED [6/7] RUN yum -y install vim 0.0s
=> [7/7] RUN yum -y install net-tools 3.4s
=> exporting to image 0.8s
=> => exporting layers 0.8s
=> => writing image sha256:c3dec9b6a3f811c4d5e5038392822da54ab5e069560708059a1f8bc636eca32d 0.0s
=> => naming to docker.io/library/mycentos:1.0
root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 1.0 c3dec9b6a3f8 30 seconds ago 312MB
centos latest 5d0da3dc9764 3 years ago 231MB命令:
docker build -f mydockerfile-centos -t mycentos:1.0 .
解释:这是一个Docker命令,将使用指定的Dockerfile构建一个新的Docker镜像。
具体来说,该命令的各个部分的含义如下:
docker build
:使用Docker命令构建新的镜像-f mydockerfile-centos
:指定Dockerfile的名称为mydockerfile-centos
。默认情况下,Docker使用当前目录下的名为Dockerfile
的文件作为Dockerfile,但是在这里我们指定了一个不同的名称。-t mycentos:1.0
:指定构建的镜像名称为mycentos
,标签为1.0
。标签可用于标识同一镜像的不同版本或变体。.
:指定上下文路径,即构建过程中所使用的文件路径。这里的.
表示使用当前目录作为上下文路径。
因此,该命令的含义是使用
mydockerfile-centos
文件作为Dockerfile,将当前目录下的文件作为上下文构建一个名为mycentos
、标签为1.0
的新Docker镜像。运行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume# docker run -it mycentos:1.0
[root@391dcbf08c75 local]# pwd
/usr/local
[root@391dcbf08c75 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
RX packets 9 bytes 806 (806.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@391dcbf08c75 local]# vim a
[root@391dcbf08c75 local]# ls
a bin etc games include lib lib64 libexec sbin share src列出镜像的历史
docker history 镜像id
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume# docker history c3dec9b6a3f8
IMAGE CREATED CREATED BY SIZE COMMENT
c3dec9b6a3f8 5 minutes ago CMD ["/bin/sh" "-c" "/bin/bash"] 0B buildkit.dockerfile.v0
<missing> 5 minutes ago CMD ["/bin/sh" "-c" "echo \"----end------\""] 0B buildkit.dockerfile.v0
<missing> 5 minutes ago CMD ["/bin/sh" "-c" "echo $MYPATH"] 0B buildkit.dockerfile.v0
<missing> 5 minutes ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
<missing> 5 minutes ago RUN /bin/sh -c yum -y install net-tools # bu… 14.7MB buildkit.dockerfile.v0
<missing> 6 minutes ago RUN /bin/sh -c yum -y install vim # buildkit 66.3MB buildkit.dockerfile.v0
<missing> 6 minutes ago RUN /bin/sh -c sed -i 's|#baseurl=http://mir… 8.8kB buildkit.dockerfile.v0
<missing> 6 minutes ago RUN /bin/sh -c sed -i 's/mirrorlist/#mirrorl… 8.82kB buildkit.dockerfile.v0
<missing> 6 minutes ago RUN /bin/sh -c cd /etc/yum.repos.d/ # buildk… 0B buildkit.dockerfile.v0
<missing> 6 minutes ago WORKDIR /usr/local 0B buildkit.dockerfile.v0
<missing> 6 minutes ago ENV MYPATH=/usr/local 0B buildkit.dockerfile.v0
<missing> 6 minutes ago MAINTAINER 6pc1<pc6pc1@qq.com> 0B buildkit.dockerfile.v0
<missing> 3 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 3 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 3 years ago /bin/sh -c #(nop) ADD file:805cb5e15fb6e0bb0… 231MB
CMD和ENTRYPOINT的去呗
我们之前说过,两个命令都是指定一个容器启动时要运行的命令
CMD:Dockerfifile 中可以有多个CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数
替换!
ENTRYPOINT:docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合!
自定义镜像tomcat
新建一个路径,并准备好tomcat和jdk的压缩包(官网下载后本地上传到服务器),并新建一个read.txt、新建一个Dockfile文件,并编辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# cat Dockerfile
FROM centos
MAINTAINER 6pc1<pc6pc1@qq.com>
COPY 1.txt /usr/local/read.txt
ADD apache-tomcat-9.0.95.tar /usr/local/
ADD jdk-8u202-linux-x64.tar /usr/local/
RUN cd /etc/yum.repos.d/
RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
RUN yum -y install vim
ENV MYPATH /usr/local
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk_1.8.0_202
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.95
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.95
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.95/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.95/bin/logs/catalina.out构建镜像
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker build -t diytomcat .
[+] Building 146.5s (14/14) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 866B 0.0s
=> [internal] load metadata for docker.io/library/centos:latest 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> CACHED [1/9] FROM docker.io/library/centos:latest 0.0s
=> [internal] load build context 2.5s
=> => transferring context: 206.81MB 2.5s
=> [2/9] COPY 1.txt /usr/local/read.txt 0.3s
=> [3/9] ADD apache-tomcat-9.0.95.tar.gz /usr/local/ 0.4s
=> [4/9] ADD jdk-8u202-linux-x64.tar.gz /usr/local/ 4.1s
=> [5/9] RUN cd /etc/yum.repos.d/ 0.7s
=> [6/9] RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* 0.3s
=> [7/9] RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos. 0.4s
=> [8/9] RUN yum -y install vim 134.1s
=> [9/9] WORKDIR /usr/local 0.1s
=> exporting to image 3.3s
=> => exporting layers 3.2s
=> => writing image sha256:88021913b4f29d54ed2453c16e79d7259ab5414f3dc616c6d4e98ca6dad90743 0.0s
=> => naming to docker.io/library/diytomcat
root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
diytomcat latest 88021913b4f2 34 seconds ago 718MB
mycentos 1.0 c3dec9b6a3f8 59 minutes ago 312MB
centos latest 5d0da3dc9764 3 years ago 231MB启动容器
1
2root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker run -d -p 9090:8080 --name mydiytomcat -v /home/ubuntu/test/docker-test-volume/tomcat/test:/usr/local/apache-tomcat-9.0.95/webapps/test diytomcat
99f621377dba54b318e382d8f72a16ddf321888392d27b5772e1a7eeb3b1fadf结合前面学习的容器卷将测试的web服务test发布
WEB-INF下新建一个web.xml
web.xml
1
2
3
4
5
6
7
8
9
10
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>test</display-name>
</web-app>在test下新建一个a.jsp
a.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>hello,kuangshen</title>
</head>
<body>
-----------welcome------------
<%=" my docker tomcat "%>
<br>
<br>
<% System.out.println("-------my docker tomcat-------");%>
</body>
</html>
5、发布镜像
DockerHub(不建议,大概率登录超时感觉)
- 注册dockerhub https://hub.docker.com/,注册一个账号
- 登录
- docker push直接push到仓库中,记得加tag
腾讯云镜像服务
使用个人免费版仓库
这要注意,只有个别地方才能选择个人免费版仓库,这边我选择的是广州
创建命名空间和仓库
直接快捷指令就能将容器上传至仓库了
1 | root@VM-16-10-ubuntu:/home/ubuntu# docker login ccr.ccs.tencentyun.com --username=100036351621 |
6、总结
九、Docker网络
1、理解docker0
准备工作:清空所有的容器,清空所有的镜像
1 | docker rm -f $(docker ps -a -q) # 删除所有容器 |
先做个测试–现象
制作一个可以使用
ip addr
和ping
命令的镜像(已经支持的,可以忽略这个步骤)下载tomcat原生镜像并启动tomcat容器
tomcat01
1
root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker run -d -P --name tomcat01 tomcat
查看容器
tomcat01
内部的ip地址,发现报错如下:1
2
3
4
5root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker exec -it tomcat01 ip addr
OCI runtime exec failed: exec failed: unable to start container process: exec: "ip": executable file not found in $PATH: unknown
root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker exec -it tomcat01 /bin/bash
\\root@fb4000629c55:/usr/local/tomcat# ip addr
bash: ip: command not found进入容器执行命令,即可解决
1
apt update && apt install -y iproute2
在容器
tomcat01
ping一下,发现报错如下1
2root@fb4000629c55:/usr/local/tomcat# ping 172.17.0.2
bash: ping: command not found进入容器执行命令,即可解决
1
apt-get update && apt-get install -y iputils-ping
容器执行了上面两个命令后,就可以正常使用
ip addr
和ping
这两个命令了,然后我们把容器commit一下,就有个一个新的镜像了1
root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker commit fb4000629c55 my-tomcat01:1.0
查看一下主机本地的ip 地址
ip addr
lo 本机回环地址
eth0 阿里云的私有ip
docker0 docker网桥
启动容器
tomcat01
,查看一下容器的ip,然后再查一下主机本地ipdocker会给每个容器都分配一个ip
我们再起一个容器,结果能够发现两个容器之间是能够ping通的
1
2
3
4
5
6root@fb4000629c55:/usr/local/tomcat# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.099 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.067 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.064 ms
64 bytes from 172.17.0.3: icmp_seq=4 ttl=64 time=0.060 ms
原理
每一个安装了Docker的linux主机都有一个docker0的虚拟网卡。这是个桥接网卡,使用了veth-pair
技术!
每启动一个容器,linux主机就会多了一个虚拟网卡。
veth-pair 就是一对的虚拟设备接口,它都是成对出现的。一端连着协议栈,一端彼此相连着。
正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备!
结论:tomcat1和tomcat2共用一个路由器。是的,他们使用的一个,就是docker0。任何一个容器启动
默认都是docker0网络。
docker默认会给容器分配一个可用ip。
小结
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据
Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网
关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接
通信。
Docker容器网络就很好的利用了Linux虚拟网络技术,在本地主机和容器内分别创建一个虚拟接口,并
让他们彼此联通(这样一对接口叫veth pair);
Docker中的网络接口默认都是虚拟的接口。虚拟接口的优势就是转发效率极高(因为Linux是在内核中
进行数据的复制来实现虚拟接口之间的数据转发,无需通过外部的网络设备交换),对于本地系统和容
器系统来说,虚拟接口跟一个正常的以太网卡相比并没有区别,只是他的速度快很多。
2、–link
思考一个场景,我们编写一个微服务,数据库连接地址原来是使用ip的,如果ip变化就不行了,那我们
能不能使用服务名访问呢?
jdbc:mysql://mysql:3306,这样的话哪怕mysql重启,我们也不需要修改配置了!docker提供了 –link
的操作!
原理
单纯是修改了host文件使容器名指向了对应的ip地址
从而可以直接访问对应的容器名
–link早都过时了,我们不推荐使用!我们可以使用自定义网络的方式
3、自定义网络
基本命令查看
命令如下:
1 | root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker network --help |
查看所有网络
1 | root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker network ls |
所有网络模式
网络模式 | 配置 | 说明 |
---|---|---|
bridge模式 | –net=bridge | 默认值,在Docker网桥docker0上为容器创建新的网络栈 |
none模式 | –net=none | 不配置网络,用户可以稍后进入容器,自行配置 |
container模式 | –net=container:name/id | 容器和另外一个容器共享Network namespace。kubernetes中的pod就是多个容器共享一个Network namespace |
host模式 | –net=host | 容器和宿主机共享Network namespace |
用户自定义模式 | –net=自定义网络 | 用户自己使用network相关命令定义网络,创建容器的时候可以指定为自己定义的网络 |
查看一个具体的网络的详情
1 | root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker network inspect 6ebce816547d |
拓展:
- 172.17.0.0/16 是一个 CIDR 地址,其中 /16 表示子网掩码的位数,即 255.255.0.0。这个地址范围内的 IP 地址数量是 2^16 - 2 = 65534。其中,2^16 表示该地址范围内的 IP 地址总数,而减去 2 是因为该地址范围内的第一个 IP 地址是网络地址,最后一个 IP 地址是广播地址,不能使用
- 172.17.0.0/24 是一个 CIDR 地址,其中 /24 表示子网掩码的位数,即 255.255.255.0。这个地址范围内的 IP 地址数量是 2^8 - 2 = 254。其中,2^8 表示该地址范围内的 IP 地址总数,而减去 2 是因为该地址范围内的第一个 IP 地址是网络地址,最后一个 IP 地址是广播地址,不能使用。
自定义网卡
删除原来的所有的容器(这样干净一点)
这样网络就恢复最初的样子了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 52:54:00:58:5e:1a brd ff:ff:ff:ff:ff:ff
altname enp0s5
altname ens5
inet 10.0.16.10/22 metric 100 brd 10.0.19.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe58:5e1a/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:99:03:57:1b brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:99ff:fe03:571b/64 scope link
valid_lft forever preferred_lft forever自定义网络
查看命令使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40# 自定义一个网络
root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker network create --driver bridge --subnet 192.17.0.0/16 --gateway 192.17.0.1 mynet
ecef3e6ceef718e93c001b8068e0c824086046e1e5196b050fab6ef65a8903b9
root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker network ls
NETWORK ID NAME DRIVER SCOPE
6ebce816547d bridge bridge local
05ae65613256 host host local
ecef3e6ceef7 mynet bridge local
e0876b8be916 none null local
root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "ecef3e6ceef718e93c001b8068e0c824086046e1e5196b050fab6ef65a8903b9",
"Created": "2024-09-25T19:29:21.684869939+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "192.17.0.0/16",
"Gateway": "192.17.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]基于自定义网络启动容器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# 使用自定义网络
root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker run -d -P --name tomcat-net-1 --net mynet my-tomcat01:1.0
# 发现已经成功使用上
root@VM-16-10-ubuntu:/home/ubuntu/test/docker-test-volume/tomcat# docker network inspect mynet
},
"ConfigOnly": false,
"Containers": {
"6ccd4eceb20ec77000793369ee924106f698c236e48f53e082b0cbd830289b13": {
"Name": "tomcat-net-1",
"EndpointID": "cf8a18045268e43e29e3e7ae2315af57a58560860f8fe9ce64c5f015c599dc17",
"MacAddress": "02:42:c0:11:00:02",
"IPv4Address": "192.17.0.2/16",
"IPv6Address": ""
}
},发现,我们自定义的网络docker都已经帮我们维护好了对应的关系
所以我们平时都可以这样使用网络,不使用–link效果一样,所有东西实时维护好,直接域名 ping 通。
4、网络连通
启动两个容器(默认,基于docker0的网络)
启动两个容器(默认,基于docker0的网络)
使用network connect 命令连接
1
[root@iZwz9efdd2ukk4oauustczZ ~]# docker network connect mynet tomcat-1
再次验证,通了
看一下tomcat-1的网络信息(tomcat01拥有了双ip)
再看一下mynet的网络信息
结论:如果要跨网络操作别人,就需要使用 docker network connect [OPTIONS] NETWORK CONTAINER
连接
十、Docker compose
Compose 是用于定义和运行多容器 Docker 应用程序的工具。
通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
Compose 使用的三个步骤:
- 使用 Dockerfile 定义应用程序的环境
- 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行
- 最后,执行 docker-compose up 命令来启动并运行整个应用程序
中文文档:http://www.dockerinfo.net/docker-compose-%e9%a1%b9%e7%9b%ae
官方文档:https://docs.docker.com/compose/
compose安装 要注意和Docker同一个版本
这里有独立版和插件版两种,区别感觉不大,主要就是命令的使用的一点点差别,我这主要使用的是独立版
Compose 独立版
请注意,Compose standalone 使用
-compose
语法 而不是当前标准语法compose
。
例如,docker-compose up
使用 Compose standalone 时输入 ,而不是docker compose up
。
要下载并安装 Compose 独立版,请运行:
1
curl -SL https://github.com/docker/compose/releases/download/v2.29.6/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
将可执行权限应用于安装目标路径中的独立二进制文件。
使用 测试并执行撰写命令
docker-compose
。提示
如果安装后命令
docker-compose
失败,请检查您的路径。您还可以创建指向或路径中任何其他目录的符号链接/usr/bin
。例如:$ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
compose使用
1、设置
为项目创建目录:
1
2mkdir composetest
cd composetest在您的项目目录中创建一个名为的文件
app.py
并粘贴以下代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)在此示例中,是应用程序网络上的 redis 容器的主机名,并使用
redis
默认端口。6379
笔记
请注意函数的编写方式
get_hit_count
。如果 Redis 服务不可用,此基本重试循环会多次尝试请求。这在应用程序上线时启动时很有用,但如果在应用程序的生命周期内需要随时重新启动 Redis 服务,也会使应用程序更具弹性。在集群中,这也有助于处理节点之间的瞬时连接断开。在您的项目目录中创建另一个名为的文件
requirements.txt
并粘贴以下代码:1
2flask
redis创建一个
Dockerfile
并粘贴以下代码:1
2
3
4
5
6
7
8
9
10
11# syntax=docker/dockerfile:1
FROM python:3.10-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run", "--debug"]重要的
检查
Dockerfile
文件扩展名是否为.txt
。某些编辑器可能会自动附加此文件扩展名,从而导致运行应用程序时出现错误。
2、在Compose文件中定义服务
Compose 简化了整个应用程序堆栈的控制,使您可以轻松地在单个易于理解的 YAML 配置文件中管理服务、网络和卷。
在您的项目目录中创建一个名为的文件compose.yaml
并粘贴以下内容:
1 | services: |
该Compose文件定义了两个服务:web
和redis
。
该web
服务使用从当前目录中构建的镜像Dockerfile
。然后它将容器和主机绑定到公开端口。8000
此示例服务使用 Flask Web 服务器的默认端口5000
。
该redis
服务使用 从 Docker Hub 注册表中提取的公共Redis映像。
3、使用 Compose 构建并运行您的应用
使用单个命令,您可以从配置文件创建并启动所有服务。
- 从您的项目目录中,通过运行启动您的应用程序
docker compose up
。、 - 每访问一次网站,次数应该都会增加