docker的基本操作,指令加操作过程,适合新手快速上手
查看导入的镜像 |
docker images |
运行docker |
systemctl start docker |
使用标签删除镜像 |
docker rmi myubuntu:latest |
使用ID删除镜像 |
docker rmi ID号 |
当使用docker rmi命令,并且后面跟上镜像的ID时,会先尝试删除所有指向该镜像的标签,然后删除该镜像文件本身。 删除镜像一般先删除依赖该镜像的所有容器,再来删除镜像。 |
|
清理镜像 |
docker image prune -f |
该命令会自动清理临时的遗留镜像文件层,最后会提示释放的存储空间。 |
|
基于已有容器创建镜像 |
docker commit -m “Added a new file” -a “Docker Newbee” 容器ID号 test:0.1 |
查看镜像信息 |
docker inspect 镜像ID号 |
获得inpect信息中部分内容的方法 |
docker inspect -f {{.Author}} test:0.1 docker inspect -f {{}.ContainerConfig.Tty} test:0.1 |
利用镜像创建一个容器并运行 |
docker run -it test:0.1 /bin/bash test:0.1就是镜像名称 |
基于本地模板导入创建镜像 |
docker import name.tar ubuntu:v4 |
将容器存储镜像 |
docker save -e jason.tar test:0.1 |
从指定文件中读入镜像 -i 是import |
docker load -i ubuntu_18.04.tar |
创建容器 |
docker create -it ubuntu:latest |
使用docker create命令新建的容器处于停止状态,可以使用docker start命令启动它。 -i 保持标准输入打开,默认为false。 -t 是否分配一个伪终端,默认为false。 |
|
启动容器 |
docker start 容器ID号 |
新建并启动容器 |
docker run -it ubuntu16.04:develop /bin/bash |
docker run等价于先执行docker create 命令,再执行docker start命令。 docker create,docker start后,并没有进入容器的bash输入界面,使用docker attach 容器ID号就可以进入bash输入界面。 |
|
等待容器退出,并打印退出返回结果 |
docker wait 容器ID号 |
列出各层的创建信息 |
docker history ubuntu16.04:develop docker history ubuntu16.04:develop --no-trunc 列出的信息未被截断。
|
暂停容器 |
docker run --name test --rm -t ubuntu bash --rm容器退出后是否自动删除,不能跟-d同时使用。 -d 是否在后台运行容器,默认为否。 docker pause test |
停止容器 |
docker stop 容器ID号 |
该命令会首先向容器发送SIGTERM信号,等待一段超时时间后(默认为10秒),再发出SIGKILL信号来终止容器。 此时执行docker container prune命令,会自动清除掉所有处于停止状态的容器。 此外,还可以通过docker kill直接发送SIGKILL信号来强行终止容器。 当docker容器中指定的应用终结时,容器也会自动停止。 |
|
查看所有容器的ID号 |
docker ps -qa |
处于终止状态的容器,可以通过docker start命令来重新启动。 docker restart 会将一个运行状态的容器先终止,然后再重新启动。 |
|
docker attach 容器ID号 |
当多个窗口同时attach到同一个容器的时候,所有窗口都会同步显示,当某一个窗口因命令阻塞时,其它窗口也无法执行操作了。 exec是推荐方式。 |
docker exec -it 容器ID号 /bin/bash |
|
导出一个已创建的容器到一个文件 |
docker export -o test_jason.tar 8f 不管此时这个容器是否处于运行状态。 导出的文件可以使用docker import 命令导入变成镜像。 |
docker import test_jason.tar - test/jason:v0.1 既可以使用docker load命令导入镜像存储文件到本地镜像库,可以使用docker import命令来导入容器快照到本地镜像库。 |
|
查看容器的详情,也可以查看镜像的详情。 |
docker inspect test_jason |
查看容器内进程 |
docker top test_jason |
查看统计信息 |
docker stats |
|
docker stats --no-stream 不持续更新,只显示最新的结果。 |
从本地复制文件到test_jason容器的指定目录下 |
docker cp test.txt test_jason:/home/ |
查看变更 |
docker diff test_jason |
查看端口映射 |
docker port 容器名称 |
本地和容器的数据共享 |
|
数据卷: docker volume create -d local jason_volume 在本地创建一个数据卷, 此时在/var/lib/docker/volumes路径下,会发现所创建的数据卷位置。 docker run -it --name test_jason1 --mount type=volume,source=jason_volume,target=/home/ ubuntu16.04:develop /bin/bash 把本地创建的数据卷挂载到容器的/home下,对jason_volume里_data的文件操作,容器内也可以看到相应的变化,实现了数据共享。 docker run -it --name u1 -v jason_volume:/data ubuntu16.04:develop 在容器内创建一个数据卷,则在容器内/data目录下与jason_volume共享数据。 数据卷容器: docker run -it -v /dbdata --name dbdata ubuntu16.04:develop 创建一个数据卷容器dbdata,并在其中创建一个数据卷挂载到/dbdata: docker run -it --volumes-from dbdata --name db1 ubuntu16.04:develop 则db1容器/dbdata目录下可以与其他容器共享数据。 |
|
使用--volumes-from参数所挂载数据卷的容器自身并不需要保持在运行状态,如果删除了挂载的容器,数据卷并不会自动删除,如果要删除一个数据卷,必须在删除最后一个挂着它的容器时显示使用docker rm -v 命令来指定同时删除关联的容器。 |
|
查看详细信息 |
docker volume inspect |
列出已有数据卷 |
docker volume ls |
清理无用数据卷 |
docker volume prune |
删除数据卷 |
docker volume rm |
DOCKER
如果说主机时代比拼的是单个服务器物理性能(如CPU主频和内存)的强弱,那么在云时代,最为看重的则是凭借虚拟化技术所构建的集群处理能力。
Docker是基于Go语言实现的开源容器项目。它诞生于2013年年初,最初发起者是dotCloud公司。
可以将Docker容器理解为一种轻量级的沙盒(sandbox)。每个容器内运行着一个应用,不同的容器相互隔离,容器之间也可以通过网络互相连通。容器的创建和停止十分快速,几乎跟创建和终止原生应用一致;另外自身对系统资源的额外需求也十分有限,远远低于传统虚拟机。很多时候,甚至直接把容器当作应用本身也没有任何问题。
Docker与虚拟机比较
- Docker容器很快,启动和停止可以在秒级实现,这相比传统的虚拟机方式(数分钟)要快得多。
- Docker容器对系统资源需求很少,一台主机可以同时运行数千个Docker容器(在IBM服务器上已经实现了同时运行10K量级的容器实例)。
- Docker通过类似Git设计理念的操作来方便用户获取、分发和更新应用镜像,存储复用,增量更新。
- Docker通过Dockerfile支持灵活的自动化创建和部署,以提高工作效率,并标准化流程。
在隔离性方面,传统的虚拟机方式提供的是相对封闭的隔离。但这并不意味着Docker不安全。Docker利用Linux系统上的多种防护技术实现了严格的隔离可靠性,并且可以整合众多安全工具。从1.3.0版本开始,Docker重点改善了容器的安全控制和镜像的安全机制,极大地提高了使用Docker的安全性。在已知的大规模应用中,目前尚未出现值得担忧的安全隐患。
- 核心概念与安装配置
1.1 核心概念
1. Docker镜像
Docker镜像类似于虚拟机镜像,可以将它理解为一个只读的模板。
例如一个镜像可以包含一个基本的操作系统环境,里面仅安全了Apache应用程序(或用户需要的其他软件)。可以把它称为一个Apache镜像。
镜像是创建Docker容器的基础。
- Docker容器
Docker容器类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用。
容器是从镜像创建的应用实例。它可以启动、开始、停止、删除,而这些容器都是彼此相互隔离,互不可见的。
可以把容器看做一个简易版的Linux系统环境(包括root用户权限、进程空间、用户空间和网络空间等)以及运行在其中的应用程序打包而成的盒子。
- Docker仓库
Docker仓库类似于代码仓库,是Dokcer集中存放镜像文件的场所。
二 使用Docker镜像
2.1 获取镜像
镜像是运行容器的前提,官方的Docker Hub网站已经提供了数十万个镜像供大家开放下载。
可以使用docker [image] pull命令直接从Docker Hub镜像源来下载镜像。该命令的格式为docker [image] pull NAME[:TAG]。
其中,NAME是镜像仓库名称(用来区分镜像),TAG是镜像的标签(往往用来表示版本信息)。通常情况下,描述一个镜像需要包括“名称+标签”信息。
例如:docker pull ubuntu:18.04
对于Docker镜像来说,如果不显式指定TAG,则默认会选择latest标签,这会下载仓库中最新版本的镜像。
注:一般来说,镜像的latest标签意味着该镜像的内容会跟踪最新版本的变更而变化,内容是不稳定的。因此从稳定性上考虑,不要在生产环境中忽略镜像的标签信息或使用默认的latest标记的镜像。
下载过程中可以看出,镜像文件一般由若干层(layer)组成,层的唯一id包括256比特,一般只显示部分比特。使用docker pull命令下载中会获取并输出镜像的各层信息。当不同的镜像包括相同的层时,本地仅存储了层的一份内容,减小了存储空间。
1.使用images命令列出镜像
使用docker images或docker image ls命令可以列出本地主机已有镜像的基本信息。
a.来自于那个仓库,比如ubuntu表示Ubuntu系列的基础镜像。
b.镜像的标签信息,比如18.04、latest表示不同的版本信息。标签只是标记,并不能标识镜像内容。
c.镜像的ID(唯一标识镜像),如果两个镜像的ID相同,说明它们实际上指向了同一个镜像,只是具有不同标签名称而已。
d.创建时间,说明镜像最后的更新时间。
e.镜像大小,优秀的镜像往往体积都比较小。
镜像大小信息只是表示了该镜像的逻辑体积大小,实际上由于相同的镜像层本地只会存储一份,物理上占用的存储空间会小于各镜像逻辑体积之和。
2.2 创建镜像
创建镜像的方法有三种:基于已有镜像的容器创建、基于本地模板导入、基于Dockerfile创建。
1、基于已有容器的创建
首先,启动一个镜像,并在其中进行修改操作。例如创建一个test文件,之后退出。记住该容器的ID为6d972f1990a7。
此时该容器与原ubuntu16.04镜像相比,已经发生了变化,可以使用docker commit 命令来提交为一个新的镜像。提交时可以使用ID或名称来指定容器。
[[email protected] jason]# docker inspect 57 [ { "Id": "sha256:57ec9e898fb712801d1d3e2ac6528385ae0e8d2f90a8a0e079d563569e3394d3", "RepoTags": [ "test:0.1" ], "RepoDigests": [], "Parent": "sha256:5162ec8ad9b429d2a7ae8ab97d551c8b7f7433d28fe3bfec041a9657dc7bd568", "Comment": "Added a new file", "Created": "2020-03-07T03:53:39.226860391Z", "Container": "6d972f1990a7c2cf09440c018d6857d226958c866fef4e5f196537e6f0b538d5", "ContainerConfig": { "Hostname": "6d972f1990a7", "Domainname": "", "User": "", "AttachStdin": true, "AttachStdout": true, "AttachStderr": true, "Tty": true, "OpenStdin": true, "StdinOnce": true, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/bash" ], "Image": "ubuntu16.04:develop", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": {} }, "DockerVersion": "18.09.6", "Author": "Docker Newbee", "Config": { "Hostname": "6d972f1990a7", "Domainname": "", "User": "", "AttachStdin": true, "AttachStdout": true, "AttachStderr": true, "Tty": true, "OpenStdin": true, "StdinOnce": true, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/bash" ], "Image": "ubuntu16.04:develop", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": {} }, "Architecture": "amd64", "Os": "linux", "Size": 757021543, "VirtualSize": 757021543, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/ddc07e164135f26e20b4360ea9eed78ff1f2bf6216bdbe078c347d435fb2173d/diff:/var/lib/docker/overlay2/9ebbe2d2ffadfca0b693b49937c262c2445616ce480f8efb143098206113e879/diff:/var/lib/docker/overlay2/d4437ad04f0349ad865543b764ced523d9f08031346fa97afafd6d06a9284057/diff:/var/lib/docker/overlay2/34cee52b9933779678b6ea280a37f693980dca550b98c78df216fe1ce0cfa563/diff:/var/lib/docker/overlay2/bf193b7222266e376735f8a7b97d44ca0bb3a5aaaea81f02d7cbba9c4413f050/diff", "MergedDir": "/var/lib/docker/overlay2/ca304160feea312ccb2a7d5ec7c4f3a1b94a10eb50e7f1aac5dad8830119f3b3/merged", "UpperDir": "/var/lib/docker/overlay2/ca304160feea312ccb2a7d5ec7c4f3a1b94a10eb50e7f1aac5dad8830119f3b3/diff", "WorkDir": "/var/lib/docker/overlay2/ca304160feea312ccb2a7d5ec7c4f3a1b94a10eb50e7f1aac5dad8830119f3b3/work" }, "Name": "overlay2" }, "RootFS": { "Type": "layers", "Layers": [ "sha256:a0c1e01578b7e57d891b82a53a9debdb52dc642c581de3e9231d395989d39a03", "sha256:89ec57aea3bfda4030b9046bd998a74dd64bb8a7fcecca13ceafdc126d9d3dba", "sha256:7ccfaa7554e3812178273aa374570a24ee1fca986c44df2bf29681d9b971f525", "sha256:d908c11b1a82a8e558053856d5092771a5ce72c47b2942ed64f6d7debefe5a1c", "sha256:f351c8af0e79146b9250c3068f4a8828856f9c912862d40b5522ac4eecdf0a6f", "sha256:d65ba27f96d71c6c7573f386ca275dcfa86488dcb0abe973365ef210aeb55df6" ] }, "Metadata": { "LastTagTime": "2020-03-07T11:53:39.320029459+08:00" } } ]
|
|
|
2、基于本地模板导入
docker import name.tar ubuntu:v4
3、基于Dockerfile创建
基于dockerfile创建是最常见的方式。Dockerfile是一个文本文件,利用给定的指令描述基于某个父镜像创建新镜像的过程。
2.3 存出和载入镜像
1、存出镜像
如果要导出镜像到本地文件,可以使用docker save命令。
载入镜像
docker load,从指定文件中读入镜像内容。
docker load -i ubuntu_18.04.tar
-i input的意思。
三 操作Docker容器
容器是Docker的另外一个核心概念。简单来说,容器是镜像的一个运行实例。所不同的是,镜像是静态的只读文件,而容器是带有运行时需要的可写文件层,同时,容器中的应用进程处于运行状态。
如果认为虚拟机是模拟运行的一整套操作系统(包括内核、应用运行态环境和其他系统环境)和跑在上面的应用。那么Docker容器就是独立运行的一个(或一组)应用,以及它们必须的运行环境。
-
- 创建容器
- 新建容器
docker create -it ubuntu:latest
使用docker create命令新建的容器处于停止状态,可以使用docker start命令来启动它。
-i 保持标准输入打开,默认为false。
-t 是否分配一个伪终端,默认为false。
2、启动容器
3、新建并启动容器
docker run,等价于先执行docker create命令,再执行docker start命令。
上图为分开创建,但是没有进入容器的bash输入界面。
使用docker attch就可以进入bash输入界面。
在容器内ps -ef查看进行,只运行了bash应用,并没有其他无关的进程。
用docker wait 容器ID可以等待容器退出,并打印退出返回结果。
docker history命令将列出各层的创建信息。
[[email protected] /]# docker history ubuntu16.04:develop --no-trunc
IMAGE CREATED CREATED BY SIZE COMMENT sha256:5162ec8ad9b429d2a7ae8ab97d551c8b7f7433d28fe3bfec041a9657dc7bd568 9 months ago /bin/sh 638MB <missing> 10 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 10 months ago /bin/sh -c mkdir -p /run/systemd && echo 'docker' > /run/systemd/container 7B <missing> 10 months ago /bin/sh -c rm -rf /var/lib/apt/lists/* 0B <missing> 10 months ago /bin/sh -c set -xe && echo '#!/bin/sh' > /usr/sbin/policy-rc.d && echo 'exit 101' >> /usr/sbin/policy-rc.d && chmod +x /usr/sbin/policy-rc.d && dpkg-divert --local --rename --add /sbin/initctl && cp -a /usr/sbin/policy-rc.d /sbin/initctl && sed -i 's/^exit.*/exit 0/' /sbin/initctl && echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup && echo 'DPkg::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' > /etc/apt/apt.conf.d/docker-clean && echo 'APT::Update::Post-Invoke { "rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true"; };' >> /etc/apt/apt.conf.d/docker-clean && echo 'Dir::Cache::pkgcache ""; Dir::Cache::srcpkgcache "";' >> /etc/apt/apt.conf.d/docker-clean && echo 'Acquire::Languages "none";' > /etc/apt/apt.conf.d/docker-no-languages && echo 'Acquire::GzipIndexes "true"; Acquire::CompressionTypes::Order:: "gz";' > /etc/apt/apt.conf.d/docker-gzip-indexes && echo 'Apt::AutoRemove::SuggestsImportant "false";' > /etc/apt/apt.conf.d/docker-autoremove-suggests 745B <missing> 10 months ago /bin/sh -c #(nop) ADD file:eb81ec6d9e1940968c44e3fe988a8d07474c05b5b0ea60ace0bd2e4fbf180f3b in / 119MB
|
3.2 停止容器
1、暂停容器
docker run --name test --rm -it ubuntu bash
docker pause test
docker ps
--rm 容器退出后是否自动删除,不能跟-d同时使用。
-d 是否在后台运行容器,默认为否。
- 终止容器
该命令会首先向容器发送SIGTERM信号,等待一段超时时间后(默认为10s),再发出SIGKILL信号来终止容器。
docker stop 容器ID
此时执行docker container prune命令,会自动清除掉所有处于停止状态的容器。
此外,还可以通过docker kill直接发送SIGKILL信号来强行终止容器。
当Docker容器中指定的应用终结时,容器也会自动终止。
用docker ps -qa命令可以看到所有容器的ID。
处于终止状态的容器,可以通过docker start命令来重新启动。
docker start 容器ID
docker restart命令会将一个运行态的容器先终止,然后再重新启动。
3.3 进入容器
1. attach命令
在使用-d参数时,容器启动后会进入后台,用户无法看到容器的信息,也无法进行操作。
这个时候如果需要进入容器进行操作,推荐使用官方的attach或exec命令。
上面有进入容器的attach命令。
然后使用attach命令有时候并不方便。当多个窗口同时attach到同一个容器的时候,所有窗口都会同步显示;当某一个窗口因命令阻塞时,其他窗口也无法执行操作了。
2.exec命令
docker exec -it 容器ID /bin/bash
可以看到会打开一个新的bash终端,在不影响容器内其他应用的前提下,用户可以与容器进行交互。
注:通过指定-it参数来保持标准输入打开,并且分配一个伪终端。通过exec命令对容器执行操作是最为推荐的方式。
3.4 删除容器
docker rm 容器ID
-f 是否强行终止并删除一个运行中的容器。
-l 删除容器的连接,但保留容器。
-v 删除容器挂在的数据卷。
默认情况下,docker rm命令只能删除已经处于终止或退出状态的容器,并不能删除还处于运行状态的容器。
如果想要删除一个运行中的容器,可以添加-f参数,Docker会先发送SIGKILL信号给容器,终止其中的应用,之后强行删除。
3.5 导入和导出容器
某些时候,需要将容器从一个系统迁移到另外一个系统,此时可以使用Docker的导入和导出功能,这也是Docker自身提供的一个重要特性。
- 导出容器
导出容器指,导出一个已经创建的容器到一个文件,不管此时这个容器是否处于运行状态。可以使用docker export 命令。
- 导入容器
导出的文件又可以使用docker imort命令导入变成镜像。
既可以使用docker load命令来导入镜像存储文件到本地镜像库,也可以使用docker import命令来导入一个容器快照到本地镜像库。
这两者的区别在于:容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积更大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。
3.6 查看容器
1、查看容器的详情
查看某容器的具体信息,会以json格式返回包括容器ID、创建时间、路径、状态、镜像、配置等在内的各项信息。
2、查看容器内进程
- 查看统计信息
docker stats会持续更新,docker stats --no-stream只显示最新的结果。
3.7 其他容器命令
1.复制文件
从计算机复制文件到test_jason容器的指定目录下。
2.查看变更
3.查看端口映射
docker port 容器名
test_jason容器内没有ifconfig等IP相关的,所以没打印。
四 Docker数据管理
在生产环境中使用Docker,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作。
容器中的管理数据主要有两种方式:
1、数据卷(Data Volumes):容器内数据直接映射到本地主机环境。
2、数据卷容器(Data Volume Containers):使用特定容器维护数据卷。
4.1 数据卷
数据卷:是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类似于Linux中的mount行为。
数据卷可以提供很多有用的特性:
(1)数据卷可以在容器之间共享和重用,容器间传递数据将变得高效与方便。
(2)对数据卷内数据的修改会立马生效,无论是容器内操作还是本地操作。
(3)对数据卷的更新不会影响镜像,解耦开应用和数据。
(4)卷会一直存在,直到没有容器使用,可以安全地卸载它。
1.创建数据卷
在本地创建一个数据卷: docker volume create -d local test
此时在/val/lib/docker/volumes路径下,会发现所创建的数据卷位置:
docker volume inspect查看详细信息。
docker volume ls列出已有数据卷。
docker volume prune 清理无用数据卷。
docker volume rm 删除数据卷。
2.绑定数据卷
除了使用volume子命令来管理数据卷外,还可以在创建容器时将主机本地的任意路径挂在到容器内作为数据卷,这种形式创建的数据卷称为绑定数据卷。
在用docker run命令的时候,可以使用-mount选项来使用数据卷。
-mount支持三种类型的数据卷。
(1)volume:普通数据卷,映射到主机/var/lib/docker/volumes/路径下。
(2)bind:绑定数据卷,映射到主机指定路径下。
(3)tmpfs:临时数据卷,只存在于内存中。
容器命令-P选项:通过NAT机制将容器标记暴露的端口自动映射到本地主机的临时端口。
上述命令相当于把在本地创建的数据卷挂载到容器的/home下,对jason_volume里_data的数据操作就等于在容器内的操作。
jason202003072212.txt是在本机下创建的文件,在容器内也可以看到本机下创建的该文件,实现了数据共享。
下面是在容器内也创建一个数据卷,方便数据的管理。
4.2数据卷容器
如果用户需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但是它的目的是专门提供数据卷给其他容器挂载。
创建一个数据卷容器dbdata,并在其中创建一个数据卷挂载到/dbdata:
docker run -it -v /dbdata --name dbdata ubuntu
注:使用--volumes-from参数所挂载数据卷的容器自身并不需要保持在运行状态。
如果删除了挂载的容器,数据卷并不会被自动删除,如果要删除一个数据卷,必须在删除最后一个还挂在着它的容器时显式使用docker rm -v命令来指定同时删除关联的容器。
附件:docker容器设置IP地址与外界通信。
使用pipework为docker容器配置独立IP
安装pipework
wget https://github.com/jpetazzo/pipework/archive/master.zip
unzip master.zip
cp pipework-master/pipework /usr/local/bin/
chmod +x /usr/local/bin/pipework
创建两个容器实例,并不需要默认docker0网桥分配的172.17.0.1网段,设置为–net=none
docker run -itd –name test1 –net=none -h test1 centos /bin/bash
docker run -itd –name test2 –net=none -h test2 centos /bin/bash
接下来,使用pipework命令为容器设置固定IP
[[email protected] ~]# pipework br0 test1 192.168.1.52/[email protected]
[[email protected] ~]# pipework br0 test2 192.168.1.53/[email protected]
pipework包含了200多行的shell脚本
通过network namespace,veth pair以及linux bridge完成容器网络的设置,执行过程大概包括:
查看主机是否包含br0网桥,如果不存在就创建,向容器实例test1添加一块网卡,并配置固定IP:192.168.1.53,若test1已经有默认的路由,则删除掉,将@后面的192.168.1.1设置为默认路由的网关,将test1容器实例连接到创建的br0上。
进入test1容器中,测试与test2容器和网关的连通性
[[email protected] ~]# ping 192.168.1.53
PING 192.168.1.53 (192.168.1.53) 56(84) bytes of data.
64 bytes from 192.168.1.53: icmp_seq=1 ttl=64 time=0.296 ms
64 bytes from 192.168.1.53: icmp_seq=2 ttl=64 time=0.131 ms
[[email protected] ~]# ping 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.762 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.209 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.238 ms
说明上面的配置没有问题
但是这时,还没有完,宿主机是ping不通容器的
宿主机有两个网卡,em1和em2,em1作为管理口192.168.1.50,em2没有使用,现在,我们只需要将宿主机的em2网卡添加到br0网桥即可
[[email protected] ~]# brctl addif br0 em2
[[email protected] ~]# brctl show
bridge name bridge id STP enabled interfaces
br0 8000.02d111808f50 no em2
veth1pl18006
veth1pl184096
veth1pl184872
docker0 8000.0242a42ada41 no
然后再进行相关的测试
使用宿主机去ping 52/53
[[email protected] ~]# ping 192.168.1.52
PING 192.168.1.52 (192.168.1.52) 56(84) bytes of data.
64 bytes from 192.168.1.52: icmp_seq=1 ttl=64 time=0.109 ms
64 bytes from 192.168.1.52: icmp_seq=2 ttl=64 time=0.114 ms
64 bytes from 192.168.1.52: icmp_seq=3 ttl=64 time=0.111 ms
[[email protected] ~]# ping 192.168.1.53
PING 192.168.1.53 (192.168.1.53) 56(84) bytes of data.
64 bytes from 192.168.1.53: icmp_seq=1 ttl=64 time=0.119 ms
64 bytes from 192.168.1.53: icmp_seq=2 ttl=64 time=0.128 ms
64 bytes from 192.168.1.53: icmp_seq=3 ttl=64 time=0.131 ms
进入容器去ping宿主机
[[email protected] ~]# ping 192.168.1.50
PING 192.168.1.50 (192.168.1.50) 56(84) bytes of data.
64 bytes from 192.168.1.50: icmp_seq=1 ttl=64 time=0.035 ms
64 bytes from 192.168.1.50: icmp_seq=2 ttl=64 time=0.049 ms
64 bytes from 192.168.1.50: icmp_seq=3 ttl=64 time=0.024 ms
[[email protected] ~]# ping 192.168.1.50
PING 192.168.1.50 (192.168.1.50) 56(84) bytes of data.
64 bytes from 192.168.1.50: icmp_seq=1 ttl=64 time=0.037 ms
64 bytes from 192.168.1.50: icmp_seq=2 ttl=64 time=0.030 ms
64 bytes from 192.168.1.50: icmp_seq=3 ttl=64 time=0.033 ms
再使用window主机去测试
正在 Ping 192.168.1.52 具有 32 字节的数据:
来自 192.168.1.52 的回复: 字节=32 时间=18ms TTL=64
来自 192.168.1.52 的回复: 字节=32 时间=1ms TTL=64
来自 192.168.1.52 的回复: 字节=32 时间=4ms TTL=64
192.168.1.52 的 Ping 统计信息:
数据包: 已发送 = 3,已接收 = 3,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 1ms,最长 = 18ms,平均 = 7ms
正在 Ping 192.168.1.53 具有 32 字节的数据:
来自 192.168.1.53 的回复: 字节=32 时间=20ms TTL=64
来自 192.168.1.53 的回复: 字节=32 时间=7ms TTL=64
来自 192.168.1.53 的回复: 字节=32 时间=11ms TTL=64
来自 192.168.1.53 的回复: 字节=32 时间=2ms TTL=64
192.168.1.53 的 Ping 统计信息:
数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 2ms,最长 = 20ms,平均 = 10ms
注意:pipework目前还有缺陷,容器重启后IP设置会自动消失,需要重新设置。