一.虚拟化技术
1.1 虚拟化介绍
操作系统层虚拟化是指通过划分一个宿主操作系统的特定部分,产生一个个隔离的操作执行环境。操作系统层的虚拟化是操作系统内核直接提供的虚拟化,虚拟出的操作系统之间共享底层宿主操作系统内核和底层的硬件资源。操作系统虚拟化的关键点在于将操作系统与上层应用隔离开,将对操作系统资源的访问进行虚报化,使上层应用觉得自己独占操作系统。操作系统虚拟化的好处是实现了虚拟操作系统与物理操作系统的隔离并且有效避免物理操作系统的重复安装。比较有名的操作系统虚报化解决方案有Virtual Server、Zone、Virtuozzo 及虚拟专用服务器(Vital Pnvate Sever,VPS)。VPS是利用虚拟服务器软件在一台物理机上创建多个相互隔离的小服务器。这些小服务器本身就有自己的操作系统,其运行和管理与独立主机完全相。其可以保证用户独享资源,且可以节约成本。
1.2 虚拟化分类
- 仿真虚拟化 [对系统硬件没有要求,性能最低] VMware
- 半虚拟化 [虚拟机可以使用真机物理硬件,性能高,需要改内核] xen
- 硬件辅助虚拟化 vmware kvm
- 需要硬件支持 【cpu 主板】
- 不需要改内核
- 可以直接使用真机硬件,性能最贴近宿主机
- 容器虚拟化 lxc docker
1.3 主机虚拟化和容器虚拟比较
主机虚拟化
- 应用程序运行环境强隔离
- 虚拟机操作系统与底层操作系统无关化
- 虚拟机内部操作不会影响到物理机
- 拥有操作系统会占用部署资源及存储
- 网络传输效率低
- 当应用程序需要调用硬件响应用户访问时间延迟大
容器虚拟化
- 可以实现应用程序的隔离
- 直接使用物理机的操作系统可以快速响应用户请求
- 不占用部署时间
- 占用少量磁盘空间
容器虚拟化缺点:学习成本增加、操作控制麻烦、网络控制与主机虚拟化有所区别、服务治理。
二.docker 介绍
2.1 Docker 开源项目的背景
docker 是基于Go语言编写的开源容器项目。诞生于2013年初,最初的发起者是dotCloud 公司,目前docker 已经全球最大的容器服务提供商。docker 项目已加入Linux 基金会,并遵循Apache 2.0协议,全部开源代码均在 https: // github com/docker 项目仓库进行维护.
LXC 是早期得容器技术 发布于2008年是第一套完整的容器管理解决方案,不需要任何补丁直接运行在linux内核之上管理容器
2.2 Linux 容器技术
docker 算得上是linux 容器的技术的代表,目前市面上使用的比较多的就是linux 容器技术就是docker。具体docker的发展之路,我这里就不说了。
什么是容器技术呢?容器有效地将由单个操作系统管理的 资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资惊使用需求 与虚拟化相 比,这样既不需要指令级模拟,也不需要即时编译 容器可以在核心 CPU 本地运行指令,而不需要任何专门的解释机制此外,也避免了准虚拟化( para-virtualization )和系统调用替换 中的复杂性。
简单的说容器就是:更加轻量且耦合性更低的沙盒(sendbox),每个容器内运行着一个应用,不同容器之间相互隔离,容器之间也可以通过网络互相通信。容器的创建和停止十分快速,几乎跟创建和终止原生应用一致;另外,容器自身对系统资源的额外需求也十分有限,远远低于传统虚拟机。很多时候,甚至直接把容器当作应用本身也没有任何问题。
2.3 为什么要使用docker
在开发和运维过程中,Docker 具备如下几个方面的优势:
更快速的交付和部署:使用docker 运维人员可以使用镜像来快速构建一套标准的软件运行环境,当开发完成代码编写后,运维人员可以直接使用相同的环境来部署代码。只要开发测试过代码,就可以确保在生产环境无缝运行。Docker可以快速的创建和删除容器,实现快速的迭代,节约开发、测试、部署的大量时间。并且,整个过程全程可见,使团队更容易理解应用的创建和工作过程。
更高效的资源利用:运行Docker容器不需要额外的虚拟化管理程序的支持,Docker 是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。与传统虚拟化方式相比,Docker 的性能要高1~2个量级。
更轻松迁移和扩展:运行Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器,同事支持主流的操作系统发行版本。这种兼容让用户可以在不同平台之间轻松的迁移应用。
更简单的更新管理:使用Dockerfile ,只需要小小的配置修改,就可以代替以往大量的更新工作。所有修改都以增量的方式被分配和更新,从而实现自动化并且高效的容器管理。
对比传统虚拟机总结:
特性 | 容器 | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为 MB | 一般为 GB |
性能 | 接近原生 | 弱于 |
系统支持量 | 单机支持上千个容器 | 一般几十个 |
docker 基本架构:
Docker 采用了 C/S架构,包括客户端和服务端。 Docker daemon 作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。 客户端和服务端既可以运行在一个机器上,也可通过 socket 或者 RESTful API 来进行通信。
docker daemon 一般在宿主主机后台运行,等待接收来自客户端的消息。 Docker 客户端则为用户提供一系列可执行命令,用户用这些命令实现跟 Docker daemon 交互。
容器 — 镜像 — 仓库 — daemon — client 之间的关系
2.4 Docker的名字空间
名字空间是 Linux 内核一个强大的特性。每个容器都有自己单独的名字空间,运行在其中的应用都像是在独立的操作系统中运行一样。名字空间保证了容器之间彼此互不影响。
pid 名字空间:不同用户的进程就是通过 pid 名字空间隔离开的,且不同名字空间中可以有相同 pid。所有的 LXC 进程在 Docker 中的父进程为Docker进程,每个 LXC 进程具有不同的名字空间。同时由于允许嵌套,因此可以很方便的实现嵌套的 Docker 容器。
net 名字空间:有了 pid 名字空间, 每个名字空间中的 pid 能够相互隔离,但是网络端口还是共享 host 的端口。网络隔离是通过 net 名字空间实现的, 每个 net 名字空间有独立的 网络设备, IP 地址, 路由表, /proc/net 目录。这样每个容器的网络就能隔离开来。Docker 默认采用 veth 的方式,将容器中的虚拟网卡同 host 上的一 个Docker 网桥 docker0 连接在一起。
ipc 名字空间:容器中进程交互还是采用了 Linux 常见的进程间交互方法(interprocess communication - IPC), 包括信号量、消息队列和共享内存等。然而同 VM 不同的是,容器的进程间交互实际上还是 host 上具有相同 pid 名字空间中的进程间交互,因此需要在 IPC 资源申请时加入名字空间信息,每个 IPC 资源有一个唯一的 32 位 id。
mnt 名字空间:类似 chroot,将一个进程放到一个特定的目录执行。mnt 名字空间允许不同名字空间的进程看到的文件结构不同,这样每个名字空间 中的进程所看到的文件目录就被隔离开了。同 chroot 不同,每个名字空间中的容器在 /proc/mounts 的信息只包含所在名字空间的 mount point。
uts 名字空间:UTS(“UNIX Time-sharing System”) 名字空间允许每个容器拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 主机上的一个进程。
user 名字空间:每个容器可以有不同的用户和组 id, 也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。
三.docker 安装
3.1 卸载旧版本
较旧的Docker版本称为docker
或docker-engine
。如果已安装这些程序,请卸载它们以及相关的依赖项。
rpm -qa|grep -i docker 查询已经安装的docker
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
如果yum报告未安装这些软件包,则可以。
的内容(/var/lib/docker/包括图像,容器,卷和网络)被保留。现在将Docker Engine软件包称为docker-ce。
3.2 安装方法 yum
您可以根据需要以不同的方式安装Docker>您可以根据需要以不同的方式安装Docker Engine:
- 大多数用户会 设置Docker的存储库并从中进行安装,以简化安装和升级任务。这是推荐的方法。
- 一些用户下载并手动安装 RPM软件包, 并完全手动管理升级。这在诸如在无法访问互联网的空白系统上安装Docker的情况下非常有用。
- 在测试和开发环境中,一些用户选择使用自动 便利脚本来安装Docker。
3.2.1使用存储库安装
在新主机上首次安装Docker Engine之前,需要设置Docker存储库。之后,您可以从存储库安装和更新Docker。
设置存储库
安装yum-utils
软件包(提供yum-config-manager
实用程序)并设置稳定的存储库。
$ sudo yum install -y yum-utils
官网的yum源,国外
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
国内阿里的yum源
https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
3.3安装DOCKER引擎
安装最新版本的Docker Engine和容器,或转到下一步以安装特定版本:
$ sudo yum install docker-ce docker-ce-cli containerd.io
如果提示您接受GPG密钥,请验证指纹是否匹配
060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35,如果是,则接受它。
有多个Docker存储库?
如果启用了多个Docker存储库,则在未在yum install
or yum update
命令中指定版本的情况下进行安装或更新将始终安装可能的最高版本,这可能不适合您的稳定性需求。
启动Docker
$ sudo systemctl start docker
通过运行hello-world
映像来验证是否正确安装了Docker Engine 。
此命令下载测试图像并在容器中运行它。容器运行时,它会打印参考消息并退出。
Docker Engine已安装并正在运行。您需要使用sudo
来运行Docker命令。
四.docker镜像
4.1 docker 镜像原理
如果只考虑 Docker 容器的操作系统属性,那么镜像=轻量级操作系统安装包。
如果需考虑 Docker 容器的应用软件属性,那么镜像=(轻量级操作系统+应用)安装包
镜像是怎么产生的?
镜像从逻辑上可以简单理解是一个文件,但实际上是多层文件的组合。
所以,镜像虽然不是一个单独的文件,但可以被导出成为一个压缩文件:
# 镜像导出成一个tarball文件
docker save image
# 加载一个 tarball 镜像文件
docker load image
镜像存放在哪里?运行容器时,Docker 会从 /var/lib/docker/image 目录下寻找是否镜像文件。
镜像可以看成是由多个镜像层叠加起来的一个文件系统(通过UnionFS与AUFS文件联合系统实现),镜像层也可以简单理解为一个基本的镜像,而每个镜像层之间通过指针的形式进行叠加。
根据上图,镜像层的主要组成部分包括镜像层 ID、镜像层指针 「指向父层」、元数据「 Layer Metadata,包含了 Docker 构建和运行的信息和父层的层次信息」。只读层和读写层「Top Layer」的组成部分基本一致,同时读写层可以转换成只读层「 通过docker commit 操作实现」。
元数据(metadata)就是关于这个层的额外信息,它不仅能够让Docker获取运行和构建时的信息,还包括父层的层次信息。需要注意,只读层和读写层都包含元数据。
每一层都包括了一个指向父层的指针。如果一个层没有这个指针,说明它处于最底层。
在docker主机中镜像层(image layer)的元数据被保存在名为”json”的文件中,一个容器的元数据好像是被分成了很多文件,但或多或少能够在/var/lib/docker/containers/目录下找到,就是一个可读层的id。这个目录下的文件大多是运行时的数据,比如说网络,日志等等。
镜像是一堆只读层的统一视角,除了最底层没有指向外,每一层都指向它的父层。统一文件系统( Union File System)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在。在用户的角度看来,只存在一个文件系统。镜像每一层都是不可写的,都是只读层。
我们可以看到镜像包含多个只读层,它们重叠在一起。除了最下面一层,其它层都会有一个指针指向下一层。这些层是Docker内部的实现细节,并且能够在docker主机的文件系统上访问到。统一文件系统(union file system,升级版为AUFS)技术能够将不同的层整合成一个文件系统,为这些层提供了一个统一的视角,这样就隐藏了多层的存在,在用户的角度看来,只存在一个文件系统。
4.2docker镜像管理
镜像搜索-search
从docker镜像仓库模糊搜索镜像
用法:
------------
docker search 镜像关键字
[root@docker~]# docker search centos
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
centos The official build of CentOS. 5674 [OK]
#字段说明:
NAME:镜像名称
DESCRIPTION:镜像描述
STARS:镜像星级,数字越大表示用的人越多
OFFICIAL:是否为官方 跟[OK]说明是官方
AUTOMATED: 是否为自动化构建的镜像
镜像下载-pull命令
从docker指定的仓库下载镜像到本地命令
docker pull 镜像名称
[root@docker~]# docker pull centos
Using default tag: latest
latest: Pulling from library/centos
729ec3a6ada3: Pull complete
Digest: sha256:f94c1d992c193b3dc09e297ffd54d8a4f1dc946c37cbeceb26d35ce1647f88d9
Status: Downloaded newer image for centos:latest
docker.io/library/centos:latest
本地镜像查看-images命令
查看本地存储的镜像
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/gitlab/gitlab-ce latest 515ad1a75677 7 weeks ago 1.9 GB
docker.io/redis latest 1319b1eaa0b7 7 weeks ago 104 MB
#字段说明:
REPOSITORY:镜像的名字
TAG:镜像的标签
IMAGE ID:镜像的ID号
CREATED:镜像建立时间
SIZE: 镜像大小
镜像详细信息-inspect命令
显示镜像的详细导入由save保存出来的压缩文件镜像
docker load -i 镜像压缩文件名称 [镜像名称或者ID]
[root@docker~]# docker load -i centos_base.tar
Loaded image: centos:latest信息
用法:
docker inspect [镜像名称或者ID]
[root@docker~]# docker inspect 0f3e07c0138f
[
{
"Id": "sha256:0f3e07c0138fbe05abcb7a9cc7d63d9bd4c980c3f61fea5efa32e7c4217ef4da",
"RepoTags": [
"centos:latest"
],
"RepoDigests": [
"centos@sha256:f94c1d992c193b3dc09e297ffd54d8a4f1dc946c37cbeceb26d35ce1647
.................此除省略
本地镜像删除-rmi命令
删除本地镜像库中的某个镜像命令:
docker rmi [镜像名称或者ID]
[root@docker~]# docker rmi centos
Untagged: centos:latest
Untagged: centos@sha256:f94c1d992c193b3dc09e297ffd54d8a4f1dc946c37cbeceb26d35ce1647f88d9
Deleted: sha256:0f3e07c0138fbe05abcb7a9cc7d63d9bd4c980c3f61fea5efa32e7c4217ef4da
Deleted: sha256:9e607bb861a7d58bece26dd2c02874beedd6a097c1b6eca5255d5eb0d2236983
镜像保存-save命令
保存镜像为压缩文件命令:
docker save -o 压缩文件名称 [镜像名称或者ID
[root@docker~]# docker save -o centos_base.tar centos
[root@docker~]# ls
anaconda-ks.cfg centos_base.tar
镜像载入-load命令
导入由save保存出来的压缩文件镜像命令:
docker load -i 镜像压缩文件名称 [镜像名称或者ID]
[root@docker~]# docker load -i centos_base.tar
Loaded image: centos:latest
镜像管理命令-image命令
镜像管理命令,和上面的命令相似
[root@docker~]# docker image --help
Usage: docker image COMMAND
Manage images
Commands:
build Build an image from a Dockerfile
history Show the history of an image
import Import the contents from a tarball to create a filesystem image
inspect Display detailed information on one or more images
load Load an image from a tar archive or STDIN
ls List images
prune Remove unused images
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rm Remove one or more images
save Save one or more images to a tar archive (streamed to STDOUT by default)
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
五.docker容器
5.1 容器概念
容器是 Docker 最重要的组件,容器就是一个轻量级虚拟机。
5.2容器管理
5.2.1 docker ps
显示本地容器列表,但是默认不显示关闭的容器,只显示运行中的容器,除非加上命令选项 -a
docker ps [-a 显示所有容器,默认只显示运行的]
root@docker~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8f4c3f823843 centos "/bin/bash" 3 seconds ago Exited(0) 3 seconds ago centos7_6
5.2.2 docker inspect
显示容器的详细信息
docker inspect [容器名称或者ID]
[root@docker~]# docker inspect centos
[
{
"Id": "sha256:0f3e07c0138fbe05abcb7a9cc7d63d9bd4c980c3f61fea5efa32e7c4217ef4da",
"RepoTags": [
"centos:latest",
"docker_centos:v1"
],
"RepoDigests": [],
"Parent": "",
"Comment": "",
"Created": "2019-10-01T23:19:57.105928163Z",
"Container": "711572e3c0c1ac06d5c13c4e668ec170b8ad8786b5f0949f884a5f7fd350d856",
"ContainerConfig": {
"Hostname": "711572e3c0c1",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
.........此处省略
5.2.3 docker run
容器创建命令
docker run [options] 镜像名称
#后台执行容器
[root@docker~]# docker run -d --name centos7_6 centos
#前台执行的容器
[root@docker~]# docker run -it --name centos7_5 centos /bin/bash
[root@5a1f02b4041c /]#
-i 交互式创建
-t 创建一个伪终端
-d 后台执行
--name 容器名称
/bin/bash 在伪终端中执行的命令
5.2.4 docker rm
删除一个本地容器
docker rm [容器名称或者ID] [–force]
[root@docker~]# docker rm centos7_5
centos7_5
默认删除的容器必须是关闭状态,建议如果希望删除一个运行的容器,可以先关闭在删除。
当然也可以在后面直接加上--force 强制删除一个运行中的容器
容器执行命令-exec命令
在运行容器中执行一个命令,如果想在容器中执行一个命令,那么这个exec命令就很有用了。
docker exec [容器名称或者ID] 命令
[root@docker~]# docker exec centos7_6 ls /
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
容器信息输出-attach命令
将一个运行容器的标准输出、错误输出、标准输入调入前台
默认容器都会在后台运行,如果你想进入容器内,就可以使用该命令。这样你就可以交互式的在容器中执行命令了。
docker attach [容器名称或者ID]
[root@docker~]# docker attach centos7_6
[root@128dc0ffc489 /]#
容器启动-start命令
启动一个容器
docker start [容器名称或者ID]
[root@docker~]# docker start centos7_6
centos7_6
停止一个容器-stop命令
关闭一个容器
docker stop [容器名称或者ID]
[root@docker~]# docker stop centos7_6
centos7_6
重启一个容器-restart命令
重启一个容器
docker restart [容器名称或者ID]
[root@docker~]# docker restart centos7_6
centos7_6
容器挂起-pause命令
挂起运行中的容器
docker pause [容器名称或者ID]
[root@docker~]# docker pause centos7_6
centos7_6
[root@docker~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
128dc0ffc489 centos "/bin/bash" 19 minutes ago Up 14 minutes (Paused) centos7_6
容器恢复-unpause命令
恢复挂起容器
docker unpause [容器名称或者ID]
[root@docker~]# docker unpause centos7_6
centos7_6
容器重命名-rename命令
重命名容器
docker rename 容器名称 容器新名称
[root@docker~]# docker rename centos7_6 centos76
容器端口映射信息-port命令
显示容器与宿主机的端口隐射信息
docker port [容器名称或者ID]
[root@docker~]# docker port 32fd02f05446
5000/tcp -> 0.0.0.0:5000
容器的TCP 5000端口与宿主机的所有IP的5000端口绑定
杀死一个或多个容器-kill命令
杀死运行的容器
docker kill [镜像名称或者ID]
[root@docker~]# docker kill centos76
centos76
容器导出-export命令
将一个容器导出一个镜像为压缩文件
docker export -o 导出后镜像文件名 [容器名称或者ID]
[root@docker~]# docker export -o docker_centos.tar centos76
[root@docker~]# ls
anaconda-ks.cfg centos_base.tar Docker docker_centos.tar
容器镜像导入到镜像库-import命令
将容器镜像导入到镜像库
docker import 镜像文件名 镜像名:tag
[root@docker ~]# docker import docker_centos.tar docker/centos7_6:latest
sha256:659fb2fca656430822627685ba4f29d09ae619cd9f2b42ef52d47003c8af8d11
将容器生成镜像-commit命令
将改变后的容器直接变成镜像,一般指的是封装好业务的容器,直接封装成镜像
docker commit [容器名称或者ID] 导出后镜像的名字:tag
[root@docker~]# docker commit centos76 docker/centos_7_6:v1
sha256:1f078c1d94dd641c65495bd91d3e471593c5ec60ecbb4492cfa18a161448dd3a
六.docker 网络
由于容器是用于部署应用的,因此它需要频繁的被其他服务所访问,深刻理解 Docker 网络的概念和原理就显得至关重要。
6.1 docker 网络介绍
组网
对于Docker系统来说,默认有一个容器路由功能,简单的说,Docker会给每个部署好的Container生成一个内网IP地址。例如,Docker下运行了容器,Docker就自动分配了3个内网地址:
容器1 172.18.0.1
容器2 172.18.0.2
容器3 172.18.0.23
对于其中任何Container来说,都可以通过IP地址作为访问通道
端口
每个Container,都可以映射到服务器的一个端口上,以便于外部访问这个Container。 例如:172.18.0.1 上运行了MySQL,且MySQL本身开启了外部访问。这个时候,如何通过服务器的IP地址来访问这个MySQL呢?
- 首先,将容器1的做一个端口映射,加入映射到都服务器的3306端口
- 然后,通过 服务器IP:3306 就可以访问MySQL
问题:Container中的应用为什么有端口号?Container是带最简的操作系统的,有操作系统就一定会通过端口访问程序
6.2 docker network 网络管理
[root@docker~]# docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.
6.3 docker网络类型
创建容器的时候可以通过—network命令来指定容器的网络,网络类型有以下四种
- bridge
- host
- none
- 容器网络或联盟网络
bridge
桥接网络是指容器通过桥接的方式将容器网卡桥接到宿主机的docker0网桥,然后在通过宿主机防火墙的NAT表实现与外网的联系。
宿主机docker0网桥
[root@docker~]# ifconfig
#docker0网桥
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:c7ff:fe37:8e8 prefixlen 64 scopeid 0x20<link>
ether 02:42:c7:37:08:e8 txqueuelen 0 (Ethernet)
RX packets 6618 bytes 277975 (271.4 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8152 bytes 24675021 (23.5 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
.....省略了本机的网卡信息
#容器网卡,每创建一个桥接网络的容器就会生成一个对应的网卡
vethf75a942: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::9085:f5ff:fe34:77b5 prefixlen 64 scopeid 0x20<link>
ether 92:85:f5:34:77:b5 txqueuelen 0 (Ethernet)
RX packets 2850 bytes 158484 (154.7 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3397 bytes 11613136 (11.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
如果想看更清楚一下 可以使用 ip add show命令
[root@docker~]# ip add show
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:c7:37:08:e8 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:c7ff:fe37:8e8/64 scope link
valid_lft forever preferred_lft forever
容器网卡
14: vethf75a942@if13: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 92:85:f5:34:77:b5 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::9085:f5ff:fe34:77b5/64 scope link
valid_lft forever preferred_lft forever
注意:
这里的vethf75a942@if13指的就是容器网卡,V代表虚拟网卡的意思,eth 以太网卡,f75a942网卡编号,if13指的是宿主机网桥(docekr0)的一个端口,对应容器的网卡编号加一。
所以容器内的网卡编号应该是 eth0@if14
通过在容器中执行命令 ip add show 也可以看到
[root@docker~]# docker exec centos1 ip add show
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
13: eth0@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
防火墙的NAT表内容
[root@docker~]# iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER all -- anywhere anywhere ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER all -- anywhere !loopback/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 anywhere
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- anywhere anywhere
docker0 与容器网卡桥接
通过brctl show命令可以看到容器网卡和docker0网卡的桥接信息
[root@docker~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242c73708e8 no vethf75a942
创建一个网络为bridge类型的容器,不指定默认也是这个类型
[root@docker~]# docker run -d --network bridge --name centos1 baishuming2020/centos_nginx
host
容器和真机共用网卡及对应的端口,缺点就是同一个端口只能宿主机或者某个容器使用,其他容器不能用。
创建一个网络类型host的容器
[root@docker~]# docker run -d --network host --name centos2 baishuming2020/centos_nginx
none
容器仅有lo网卡,是一个不能联网的本地容器
创建一个网络类型为lo的容器
[root@docker~]# docker run -d --network none --name centos3 baishuming2020/centos_nginx
6.4 实现网桥网络
目的:不同的服务容器组应用不同的网桥,避免同一网络内容器太多,保持容器网络独立性。
关于新网桥联网问题:创建网桥后,宿主机会自动帮你做NAT,所以不用担心联网问题
查看网络-ls
[root@docker ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
80982d2613cd bridge bridge local
40c179ab420a docker1 bridge local
04aadb7475c0 docker100 bridge local
ce79e9d7525a host host local
8f0358469e57 none null local
NETWORK ID 网桥ID
NAME 名称
DRIVER 网络类型
SCOPE 作用范围
创建网桥-create
[root@docker~]# docker network create -d bridge --subnet 192.168.1.0/24 --gateway 192.168.1.1 mydocker0
6a410e27b66ea587142d967f7dff6f36c04ced3c27116a79831412f3743aba56
[root@docker~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
6ee1e928b710 bridge bridge local
ce79e9d7525a host host local
6a410e27b66e mydocker0 bridge local
8f0358469e57 none null local
修改docker网桥名字
1、关闭新建网桥
[root@docker~]# ip link set dev br-6a410e27b66e down
2、修改名字
[root@docker~]# ip link set dev br-6a410e27b66e name mydocker0
3、启动网桥
[root@docker~]# ip link set dev mydocker0 up
4、重启docker服务
[root@docker~]# systemctl restart docker
删除未使用的网桥-prune
[root@docker~]# docker network prune
WARNING! This will remove all networks not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Networks:
docker1
删除某个网桥-rm
[root@docker~]# docker network rm docker100
docker100
注意:
不能被活动容器占用
容器连接到网桥
前提是该容器是桥接网络
[root@docker~]# docker network connect docker1 centos1
[root@docker~]# docker exec centos1 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 8 bytes 656 (656.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
发现centos1容器多了一块网卡,使用的正是docker1的网段
eth2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.2 netmask 255.255.255.0 broadcast 192.168.1.255
ether 02:42:c0:a8:01:02 txqueuelen 0 (Ethernet)
RX packets 16 bytes 1312 (1.2 KiB)
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
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
容器断开网桥
将centos1容器的网络从docker1网桥断开
[root@docker~]# docker network disconnect docker1 centos1
6.5 docker 网络常见故障
FAQ1:使用改名后的新网桥的容器可能无法解析域名
原因:没有配置新网桥的DNS
解决方法:为容器手动配置一个DNS地址即可
FAQ2:Networking will not work
[root@docker~]# docker run -d --network docker100 --name centos4 baishuming2020/centos_nginx
WARNING: IPv4 forwarding is disabled. Networking will not work.
67f2c276123c993cd66b9d7a99ba22402331a13f9ea8817e57324a934896b805
解决方案
1、打开转发
[root@docker~]# echo "net.ipv4.ip_forward=1" >> /usr/lib/sysctl.d/00-system.conf
2、重启网络
[root@docker~]# systemctl restart network
6.6 docker 不通主机之间通信
macvlan
在 Docker 中,macvlan 是众多 Docker 网络模型中的一种,并且是一种跨主机的网络模型,作为一种驱动启用,Docker macvlan 只支持 bridge 模式
#macvlan 需要一块独立的网卡来进行使用,所以我们需要新添加一块网卡
docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=ens224 mtacvlan-1
-o parent=网卡名称 指定用来给 macvlan 网络使用的物理网卡
注意,要在所有需要运行 macvlan 的主机上执行这条命令,但是要记得更改网关的地址,避免造成IP冲突
docker run -itd --network macvlan-1 centos /bin/bash
overlay
在 Docker 中,overlay 是众多 Docker 网络模型中的一种,并且是一种跨主机的全局网络模型,有一个数据库专门的来存储网络分配信息,避免 IP 冲突,同时内部还有一个小型的 DNS 我们可以直接通过主机名进行访问
consul 服务端:
docker run -itd -h consul --name consul --restart=always -p 8500:8500 progrium/consul -server -bootstrap
-h 主机名
–name 容器名
–restart=always 重启策略
progrium/consul 镜像名称
-server 以服务节点启动
-bootstrap 预期的启动节点数:自举
在浏览器内输入 IP地址+端口号 可以看到 web 页面
在所有主机上编辑 daemon.json 文件:
{
"hosts": ["tcp://0.0.0.0:2375","unix:///var/run/docker.sock"], 监听相关端口
"cluster-store":"consul://192.168.1.150:8500", 集群的主机地址
"cluster-advertise":"192.168.1.150:2375” 宣告自己的地址
}
重启 docker 服务
创建 overlay 网络(全局网络):一台主机上创建自动同步
docker network create -d overlay overlay-1
启动容器测试:
docker run -it --name docker-1 --network=overlay-1 centos /bin/bash
docker run -it --name docker-2 --network=overlay-1 centos /bin/bash
验证:ping docker-1
七.dockerfile
7.1 什么是Dockerfile
Dockerfile 是由一系列命令和参数构成的脚本,这些命令应用于基础镜像并最终创建一个新的镜像。它们简化了从头到尾的流程并极大的简化了部署工作。Dockerfile 从 FROM 命令开始,紧接着跟随着各种方法,命令和参数。其产出为一个新的可以用于创建容器的镜像。
Dockerfile 语法由两部分构成,注释和命令+参数,注释是不能少的,因为明天可能就忘记写的是什么了。说白了, Dockerfile 是告诉 docker 怎么样制作一个镜像,就像我们写代码告诉应用怎么执行一条逻辑,这样应该好理解了,所以可以在 Dockerfile 中写明,我们需要怎么个执行方式的某个镜像,最后执行 docker build 命令构建写好的Dockerfile 成镜像。
7.2 Dockerfile基础命令
FROM:
#功能为指定基础镜像,并且必须是第一条指令,如果没有选择,那么默认值为latest
MAINTAINER:
#指定作者
LABEL
#功能是为镜像指定标签
一个Dockerfile种可以有多个LABEL,如下:
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
但是并不建议这样写,最好就写成一行,如太长需要换行的话则使用\符号
如下:
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
注意:LABEL会继承基础镜像种的LABEL,如遇到key相同,则值覆盖
RUN
##功能为运行指定的命令
RUN命令有两种格式,两种写法比对:
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME
RUN ["/bin/bash", “-c”, “echo hello”]
注意:多行命令不要写多个RUN,原因是Dockerfile中每一个指令都会建立一层. RUN书写时的换行符是 \ 多少个RUN就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错。
ADD
##一个复制命令,把文件复制到镜像中
##如果把虚拟机与容器想象成两台linux服务器的话,那么这个命令就类似于scp,只是scp需要加用户名和密码的权限验证,而ADD不用
语法如下:
ADD <src>... <dest>
<src>可以是一个本地文件或者是一个本地压缩文件,还可以是一个url
<dest>路径的填写可以是容器内的绝对路径,也可以是相对于工作目录的相对路径
ADD test1.txt test1.txt
ADD test1.txt test1.txt.bak
ADD test1.txt /mydir/
ADD data1 data1
ADD zip.tar /myzip
有如下注意事项:
1、如果源路径是个文件,且目标路径是以 / 结尾, 则docker会把目标路径当作一个目录,会把源文件拷贝到该目录下。如果目标路径不存在,则会自动创建目标路径。
2、如果源路径是个文件,且目标路径不是以 / 结尾,则docker会把目标路径当作一个文件。
3、如果目标路径不存在,会以目标路径为名创建一个文件,内容同源文件;
4、如果目标文件是个存在的文件,会用源文件覆盖它,当然只是内容覆盖,文件名还是目标文件名。
5、如果目标文件实际是个存在的目录,则会源文件拷贝到该目录下。 注意,这种情况下,最好显示的以 / 结尾,以避免混淆。
6、如果源路径是个目录,且目标路径不存在,则docker会自动以目标路径创建一个目录,把源路径目录下的文件拷贝进来。如果目标路径是个已经存在的目录,则docker会把源路径目录下的文件拷贝到该目录下。
7、如果源文件是个归档文件(压缩文件),则docker会自动帮解压。尽量不要把<scr>写成一个文件夹,如果<src>是一个文件夹了,复制整个目录的内容,包括文件系统元数据
VOLUME
可实现挂载功能,可以将内地文件夹或者其他容器种得文件夹挂在到这个容器种
语法为:
VOLUME ["/data"]
说明:
["/data"]可以是一个JsonArray ,也可以是多个值。所以如下几种写法都是正确的
VOLUME ["/var/log/"]
VOLUME /var/log
VOLUME /var/log /var/db
一般的使用场景为需要持久化存储数据时, 容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失,所以当数据需要持久化时用这个命令。
EXPOSE
##功能为暴漏容器运行时的监听端口给外部,但是EXPOSE并不会使容器访问主机的端口
如果想使得容器与主机的端口有映射关系,必须在容器启动的时候加上 -P参数
WORKDIR
设置工作目录
WORKDIR /usr/bin/
ENV
功能为设置环境变量
CMD
功能为容器启动时要运行的命令
CMD [ “echo”, “$HOME” ]
注意:
1、这里边包括参数的一定要用双引号,就是 " 不能是单引号, 原因是参数传递后,docker解析的是一个JSON Array
2、不要把RUN和CMD搞混了。
RUN:是构件容器时就运行的命令以及提交运行结果
CMD:是容器启动时执行的命令,在构件时并不运行
ENTRYPOINT
功能是启动时的默认命令
语法如下:
ENTRYPOINT [“executable”, “param1”, “param2”]
ENTRYPOINT command param1 param2
如果从上到下看到这里的话,那么你应该对这两种语法很熟悉啦。
第一种就是可执行文件加参数
第二种就是写shell
与 CMD 比较说明:
相同点:
只能写一条,如果写了多条,那么只有最后一条生效,容器启动时才运行,运行时机相同
不同点:
ENTRYPOINT 不会被运行的 command 覆盖,而 CMD 则会被覆盖
如果我们在 Dockerfile 时同时写了 ENTRYPOINT 和 CMD ,并且 CMD 指令不是一个完整的可执行命令,那么CMD 指定的内容将会作为 ENTRYPOINT 的参数, 如下:
FROM centos
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
如果我们在 Dockerfile 种同时写了 ENTRYPOINT 和 CMD ,并且 CMD 是一个完整的指令,那么它们两个会互相覆盖,谁在最后谁生效, 如下:
FROM centos
ENTRYPOINT ["top", "-b"]
CMD ls -al
那么将执行 ls -al , top -b 不会执行
7.2 Dockerfile 案例
1、创建目录,用于存放 dockerfile 所使用的文件
2、在此目录中创建 dockerfile 文件
3、在此目录中使用 docker build 创建镜像
4、使用创建的镜像启动容器
准备启动文件:
vim httpd-run.sh
#!/bash
rm -rf /run/httpd/*
exec /usr/sbin/httpd -D FOREGROUND
准备网页测试文件
vim index.html
hello welcome to zutuanxue!!!
准备 dockerfile 文件
FROM centos:latest
MAINTAINER "zutuanxue admin@163.com"
ADD httpd-run.sh /httpd-run.sh
ADD index.html /var/www/html/index.html
RUN yum -y install httpd && chmod -v +x /httpd-run.sh
EXPOSE 80
WORKDIR /
CMD ["/bin/bash","/httpd-run.sh"]
创建镜像:
docker build -t centos-httpd:v1 .
-t: 镜像的名字及标签,通常 name:tag 或者 name 格式
#定义基础镜像 FROM
FROM centos
#定义作者 MAINTAINER
MAINTAINER test_123
#上传文件到容器 COPY or ADD
#COPY 从当前目录复制文件到容器. 只是单纯地复制文件. 格式为 COPY <src> <dest>。
#ADD 从当前目录复制文件到容器. 会自动处理目录, 压缩包等情况.格式为 ADD <src> <dest>。
ADD nginx-1.17.6.tar.gz /root
#生成镜像时运行的命令 RUN
#shell 写法
RUN yum -y install pcre-devel zlib-devel openssl lsof iproute net-tools gcc make
#exec写法
#["命令","命令选项","参数"]
#解压压缩文件
#RUN ["tar","xf","nginx-1.17.6.tar.gz"]
#创建管理用户www
RUN useradd -r -s/sbin/nologin -M www
#进入nginx源码文件WORKDIR
WORKDIR /root/nginx-1.17.6
#安装nginx
RUN ./configure --prefix=/usr/local/nginx --user=www --group=www && make && make install
#定义变量 ENV
ENV PATH /usr/local/nginx/sbin:$PATH
#业务初始化
#COPY 从当前目录复制文件到容器. 只是单纯地复制文件. 格式为 COPY <src> <dest>。
COPY nginx.conf /usr/local/nginx/conf
COPY index.html /usr/local/nginx/html
#输出端口 EXPOSE
EXPOSE 80
#挂载本地目录VOLUME
#创建一个可以从本地主机或其他容器挂载的挂载点
#一般用来存放数据库和需要保持同步的数据
VOLUME ["/data"]
#容器启动后执行的命令 CMD
#只能执行一个,如果有多个,同一时间只有最后一个生效
CMD ["nginx","-g","daemon off;"]
八.docker Compost
8.1 什么是Docker Compose
Compose 项目是 Docker 官方的开源项目,负责实现 Docker 容器集群的快速编排,开源代码在 https://github.com/docker/compose 上
我们知道使用 Dockerfile 模板文件可以让用户很方便的定义一个单独的应用容器,其实在工作中,经常会碰到需要多个容器相互配合来完成的某项任务情况,例如工作中的 web 服务容器本身,往往会在后端加上数据库容器,甚至会有负责均衡器,比如 LNMP 服务
Compose 就是来做这个事情的,它允许用户通过一个单独的 docker-compose.yml 模板文件 YAML格式 来定义一组相关联的应用容器为一个项目 project
Compose 中有两个重要的概念:
服务 service :一个应用的容器,实际上可以包括若干运行相同镜像的容器实例
项目 project :由一组关联的应用容器组成的一个完整业务单元,在docker-compose.yml中定义
8.2 安装
# docker-compose版本选择:https://github.com/docker/compose/releases
# curl -L https://github.com/docker/compose/releases/download/1.25.4/docker-compose-uname -s
-uname -m
-o /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
8.3 命令
Compose 大部分命令的对象即可以是项目的本身,也可以是指定为项目中的服务或者容器
执行docker-compose [COMMAND] --help 或者docker-compose help [COMMAND]可以查看命令的帮助信息
具体的使用格式
docker-compose [-f=<arg>...] [options] [COMMAND] [ARGS]
参数选项
-f,--file file指定模板文件,默认是docker-compose.yml模板文件,可以多次指定
-p,--project-name name指定项目名称,默认使用所在目录名称作为项目名称
--x-networking 使用Docker的后端可插拔网络特性
--x-networking-driver driver指定网络的后端驱动,默认使用bridge
--verbose 输入更多的调试信息
-v,--version 输出版本信息
Compose所支持的命令:
build 构建项目中的服务容器
bundle 从Compose文件生成分布式应用程序包
config 验证并查看Compose文件
create 为服务创建容器
down 停止容器并删除由其创建的容器,网络,卷和图像up
events 为项目中的每个容器流式传输容器事件
exec 这相当于docker exec。
help 获得一个命令的帮助
kill 通过发送SIGKILL信号来强制停止服务容器
logs 查看服务容器的输出
pause 暂停一个容器
port 打印某个容器端口所映射的公共端口
ps 列出项目中目前所有的容器
pull 拉取服务依赖镜像
push 推送服务镜像
restart 重启项目中的服务
rm 删除所有停止状态的服务容器
run 在指定服务上执行一个命令
scale 设置指定服务执行的容器个数
start 启动已存在的服务容器
stop 停止已存在的服务容器
top 显示容器正在运行的进程
unpause 恢复处于暂停状态的容器
up 自动完成包括构建镜像、创建服务、启动服务并关联服务相关容器的一系列操作
version 输出版本
1.4 模板文件
排版问题,请看单独的文件。
官网链接:https://docs.docker.com/compose/compose-file/#compose-file-structure-and-examples
八.docker 镜像私有仓库
8.1 harbor镜像仓库
Harbor离线安装包下载地址:https://github.com/goharbor/harbor
docker-compose版本选择:https://github.com/docker/compose/releases
8.1 docker-compose 下载安装
容器编排工具,执行./install.sh时需要。如果不安装,一会重启docker服务,相关的harbor容器会死掉,安装后就会被随着docker重启
#####由于github在国外服务器,推荐是本地下载后上传服务器
wget https://github.com/docker/compose/releases/download/v2.2.2/docker-compose-linux-x86_64
mv docker-compose-linux-x86_64 /usr/local/bin/docker-compose
[root@docker-harbor harbor]# docker-compose -v
Docker Compose version v2.2.2
8.2 harbor下载安装
#####由于github在国外服务器,推荐是本地下载后上传服务器
[root@docker-harbor harbor]# tar -zxvf harbor-offline-installer-v2.4.1.tgz
[root@docker-harbor harbor]# mv harbor /opt/
mv harbor.yml.tmpl harbor.yml
####修改hostname 内网ip
cat /opt/harbor/harbor.yml
hostname: 192.168.232.60
###将harbor.yml 文件中 ssl 证书部分注释掉
#https:
# https port for harbor, default is 443
#port: 443
# The path of cert and key files for nginx
#certificate: /your/certificate/path
#private_key: /your/private/key/path
[root@docker-harbor harbor]# /opt/harbor/prepare
.......
✔ ----Harbor has been installed and started successfully.----
2.3 docker设置仓库为harbor
创建docker守护进程配置文件
[root@centos8_manage01 harbor]# cat /etc/docker/daemon.json
{
"insecure-registries": ["http://192.168.232.60"]
}
修改
8.4 镜像上传到harbor
#登陆harbor
[root@centos8_manage01 harbor]# docker login http://192.168.232.60 -u admin -p Harbor12345
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
#修改镜像name:tag为harbor仓库名
[root@docker_harbor ~]# docker pull nginx
##打标签
[root@docker_harbor ~]# docker tag nginx:latest 192.168.232.60/jyl/jyl_nginx:v1
#上传镜像
[root@centos8_manage01 harbor]# docker push 192.168.232.60/jyl/jyl_nginx:v1
8.5 问题说明:
Comments | NOTHING