Docker架构
概念介绍
- 镜像(Image):Docker镜像,就相当于是一个root文件系统。
- 容器(Container):镜像和容器的关系,就像是面向程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体,容器可以被创建、启动、停止、删除、暂停等。
- 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。
概念 | 说明 |
---|---|
Docker 镜像(Images) | Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。 |
Docker 容器(Container) | 容器是独立运行的一个或一组应用,是镜像运行时的实体。 |
Docker 客户端(Client) | Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。 |
Docker 主机(Host) | 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。 |
Docker Registry | Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。 |
Docker Machine | Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。 |
Docker安装
- Docker安装教程参考:https://blog.youkuaiyun.com/qq_43556844/article/details/120604383
- Docker 并非是一个通用的容器工具,它依赖于已存在并运行的 Linux 内核环境。
- Docker 实质上是在已经运行的 Linux 下制造了一个隔离的文件环境,因此它执行的效率几乎等同于所部署的 Linux 主机。
- 因此,Docker 必须部署在 Linux 内核的系统上。如果其他系统想部署 Docker 就必须安装一个虚拟 Linux 环境。
- 在 Windows 上部署 Docker 的方法都是先安装一个虚拟机,并在安装 Linux 系统的的虚拟机中运行 Docker。
常用命令
- 首先我们需要移除所有的环境。方便之后操作。
- 移除所有容器:
docker rm -f $(docker ps -aq)
- 移除所有的镜像:
docker rmi -f $(docker images -aq)
- 把容器指定位置的东西复制出来
docker cp 5eff66eec7e1:/etc/nginx/nginx.conf /data/conf/nginx.conf
- 把外面的内容复制到容器里面
docker cp /data/conf/nginx.conf 5eff66eec7e1:/etc/nginx/nginx.conf
Docker仓库管理
- 仓库(Repository)是集中存放镜像的地方。
- 以下介绍一下 Docker Hub。当然不止 docker hub,只是远程的服务商不一样,操作都是一样的。
- Docker Hub:目前 Docker 官方维护了一个公共仓库 Docker Hub。
- 大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。
- 注册:在 Docker Hub官网 免费注册一个 Docker 账号。
- 登录和退出
- 使用命令进行登录
- 登录成功后,我们就可以从 docker hub 上拉取自己账号下的全部镜像
docker login [options] [server]
options
-- password,-p 密码
-- password-stdin 从stdin获取密码
-- username,-u 用户名
server 不指定的话,默认是Docker Hub
- 退出
docker logout
- 镜像发布
- 查看登录命令:docker login --help
- 进行登录:docker login -u 用户名 回车输出密码
- 可以给镜像给名字:docker tag 镜像id 镜像名:标签
- 上传:docker push 作者名/需要上传的镜像名:版本号
- 退出:docker logout
- 也可以发布到阿里云上:
- 登录阿里云服务器-》找到容器镜像服务-》创建命名空间-》创建镜像仓库-》浏览阿里云命令操作-》上传镜像到阿里云
- 首先退出DockerHub的账号【docker logout】,然后复制自己创建的阿里云镜像仓库中的命令,输入密码登录
- 登录成功之后使用【docker push 镜像名:版本号】上传即可
Docker客户端
- 通过docker来查看所有客户端指令
- 可以使用docker command –help更加深入的了解指定的Docker命令使用方法
- 如:查看stats指令的具体使用方法。
Docker stats –help
Docker镜像的使用
在运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub公共镜像源下载。
-
使用
docker image --help
查看关于镜像的相关命令 -
使用docker images来列出本地主机上的镜像
- 各个选项说明:
- REPOSITORY:表示镜像的仓库源
- TAG:镜像的标签
- IMAGE ID:镜像ID
- CREATED:镜像创建时间
- SIZE:镜像大小
- 同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,如 ubuntu 仓库源里,有 20.04、latest 等多个不同的版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
- 例如:我们如果要使用版本为20.04的ubuntu系统镜像来运行容器时
-
运行镜像,即启动容器
docker run -t -i ubuntu:20.04 /bin/bash
- 参数说明:
- -i: 交互式操作。
- -t: 终端。
- ubuntu:20.04: 这是指用 ubuntu 20.04 版本镜像为基础来启动容器。
- /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash
- 注*:若不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像。
-
查找镜像
- 我们可以从 Docker Hub 网站来搜索镜像
- 也可以使用 docker search 命令来搜索镜像。
- 通过
docker search httpd
命令来寻找合适的httpd镜像。 - 说明
- NAME: 镜像仓库源的名称
- DESCRIPTION: 镜像的描述
- OFFICIAL: 是否 docker 官方发布
- stars: 类似 Github 里面的 star,表示点赞、喜欢的意思。
- AUTOMATED: 自动构建。
-
获取一个新的镜像
- 使用
docker pull
命令来下载 - 通过使用上图中的查询命令来查询 httpd 官方版本的镜像,使用命令 docker pull 来下载镜像
- 使用
-
推送镜像
- 用户登录后,可以通过 docker push 命令将自己的镜像推送到 Docker Hub。
- 以下命令中的 username 请替换为你的 Docker 账号用户名。
docker push ubuntu:18.04 username/ubuntu:18.04
- docker image ls
-
删除镜像
- 镜像删除使用
docker rmi
命令,比如我们删除httpd镜像 docker rmi httpd
- 镜像删除使用
-
自定义自己的镜像
- 当我们从 docker 镜像仓库中下载的镜像不能满足我们的需求时。
- 我们可以通过以下两种方式对镜像进行更改。
- 从已经创建的容器中更新镜像,并且提交这个镜像,以ubuntu为例子进行以下操作
- 更新镜像之前,我们首先需要使用镜像来创建一个容器。
docker run -t -i ubuntu:20.04 /bin/bash
- 在运行的容器内使用
apt update
命令进行更新。 - 在完成操作之后,输入
exit
命令来退出这个容器。 - 若此时更改完成后,例如可以获取容器的ID为
e218edb10161
的容器 - 是按我们的需求更改的容器。这是我们可以通过命令
docker commit
来提交容器副本。 docker commit -m="has update" -a="runoob" e218edb10161 runoob/ubuntu:v2
- 各个参数说明:
- -m: 提交的描述信息
- -a: 指定镜像作者
- e218edb10161:容器 ID
- runoob/ubuntu:v2: 指定要创建的目标镜像名
- 我们可以使用 docker images 命令来查看我们的新镜像 runoob/ubuntu:v2
- 使用我们的新镜像 runoob/ubuntu 来启动一个容器
docker run -t -i runoob/ubuntu:v2 /bin/bash
-
使用 Dockerfile 指令来创建一个新的镜像
- 我们使用命令 docker build , 从零开始来创建一个新的镜像。
- 为此,我们需要创建一个 Dockerfile(后面将会介绍) 文件,其中包含一组指令来告诉 Docker 如何构建我们的镜像。
- 编写Dockerfile文件如下
FROM centos:6.7 MAINTAINER Fisher "fisher@sudops.com" RUN /bin/echo 'root:123456' |chpasswd RUN useradd runoob RUN /bin/echo 'runoob:123456' |chpasswd RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" >/etc/default/local EXPOSE 22 EXPOSE 80 CMD /usr/sbin/sshd -D
- 每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的。
- 第一条FROM,指定使用哪个镜像源
- RUN 指令告诉docker 在镜像内执行命令,安装了什么。。。
- 然后,我们使用 Dockerfile 文件,通过 docker build 命令来构建一个镜像。
docker build -t runoob/centos:6.7 .
- 参数说明:
- -t :指定要创建的目标镜像名
- . :Dockerfile文件所在目录,也可以指定Dockerfile的绝对路径
-
设置镜像标签
-
使用docker tag设置镜像标签
-
docker tag 860c279d2fec runoob/centos:dev
- 说明
- docker tag 镜像ID,这里是 860c279d2fec ,用户名称/镜像源名(repository name):新的标签名(tag)。
容器的使用
-
首先获取镜像
-
若我们本地没有ubuntu镜像,我们可以使用docker pull命令来载入ubuntu镜像:
docker pull ubuntu
默认使用最新的ubuntu镜像
-
启动容器
- 以下命令使用 ubuntu 镜像启动一个容器,参数为以命令行模式进入该容器:
- docker run -it ubuntu /bin/bash
- 参数说明:
- 通过 docker 的两个参数 -i -t,从而让Docker具有交互性
- -i: 交互式操作。允许你对容器内的标准输入 (STDIN) 进行交互。
- -t: 终端。在新容器内指定一个伪终端或终端。
- ubuntu: ubuntu 镜像。指定要运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。
- /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。 在启动的容器里执行的命令
-
要退出终端,直接输入 exit命令或者使用ctrl+D来退出容器。
-
启动已停止运行的容器
- 首先查看所有的容器命令如下
docker ps -a
- 使用 docker start 启动一个已停止的容器
- docker start 容器ID
-
后台运行
- 我们可以过 -d 指定容器进入后台运行模式。
- 注:加了 -d 参数默认不会进入容器,想要进入容器需要使用指令
docker exec
(下面会介绍到)。
-
停止一个容器
- 停止容器的命令如下
docker stop <容器 ID>
- 停止的容器可以通过 docker restart 重启
- docker restart <容器 ID>
-
进入容器
- 在使用 -d 参数时,容器启动后会进入后台。
- 此时想要进入容器,可以通过以下指令进入:
docker attach 容器ID
- 注意: 使用该指令如果从这个容器退出,会导致容器的停止。
docker exec 容器ID
- 推荐大家使用 docker exec 命令,因为此退出容器终端,不会导致容器的停止。
- 具体使用:docker exec -it 容器ID 对应的命令
- 更多参数说明请使用 docker exec --help 命令查看。
-
导出和导入容器
-
镜像保存/载入
-
docker load/docker save
- 将一个镜像导出为文件,再使用docker load命令将文件导入为一个镜像,会保存该镜像的的所有历史记录。
- 比docker export命令导出的文件大,很好理解,因为会保存镜像的所有历史记录。
-
容器导入/导出
- docker import/docker export
- 将一个容器导出为文件,再使用docker import命令将容器导入成为一个新的镜像
- 但是相比docker save命令,容器文件会丢失所有元数据和历史记录,仅保存容器当时的状态,相当于虚拟机快照。
- docker import/docker export
-
导出容器
- 如果要导出本地某个容器,可以使用 docker export 命令
-docker export -o <保存路径> <容器标识>
参数:
-o 通过-o来指定到处的tar文件名,也可以使用重定向来实现。
容器标识:这里可以填容器的name ,也可以填容器id的前三位,也可以使用 <镜像名称:标签>
这样将导出容器快照到本地文件。
具体使用(保存到当前目录下):
docker export -o ./ubuntu.tar ubuntu:20.04
另一种到处方法:docker export 容器id/name >文件名.tar
- 如果要导出本地某个容器,可以使用 docker export 命令
-
导入容器快照
docker import <文件路径> <容器名>
- 可以使用 docker import 从容器快照文件中再导入为镜像
- 以下实例将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1:
cat docker/ubuntu.tar | docker import - test/ubuntu:v1
- 此外,也可以通过指定 URL 或者某个目录来导入,例如:
docker import http://example.com/exampleimage.tgz example/imagerepo
-
-
删除容器
- 使用
docker rm
命令删除容器 docker rm -f 容器ID
- 注意*:在删除容器的时候必须是停止状态,否则会报错。
- 下面的命令可以清理掉所有处于终止状态的容器。
docker container prune
- 使用
-
具体例子
-
运行一个Web应用
-
接下来让我们尝试使用 docker 构建一个 web 应用程序。
-
我们将在docker容器中运行一个 Python Flask 应用来运行一个web应用。
-
docker pull training/webapp
# 载入镜像
-
docker run -d -P training/webapp python app.py
#运行镜像- 参数说明:
- -d:让容器在后台运行。
- -P:将容器内部使用的网络端口随机映射到我们使用的主机上。
-
运行后访问:
-
我们也可以通过 -p 参数来设置不一样的端口:
docker run -d -p 5000:5000 training/webapp python app.py
-
以上是将容器内部的 5000 端口映射到我们本地主机的 5000 端口上。
-
使用
docker port 容器ID
-
可以查看容器端口的映射情况和容器内部的内容
docker logs [ID或者名字]
- -f: 让 docker logs 像使用 tail -f 一样来输出容器内部的标准输出。
- -f: 让 docker logs 像使用 tail -f 一样来输出容器内部的标准输出。
-
从上面,我们可以看到应用程序使用的是 5000 端口并且能够查看到应用程序的访问日志。
-
查看WEB应用程序容器的进程
docker top [ID或者名字]
-
检查 WEB 应用程序,可以查看 Docker 的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息。
-
docker inspect [ID或者名字]
-
查询最后一次创建的容器
-
docker ps -l
-
-
通过
docker container ls
或docker ps
(该操作首先需要确定有容器在运行)来查看那些容器在运行- 输出的详细介绍
- CONTAINER ID: 容器 ID。
- IMAGE: 使用的镜像。
- COMMAND: 启动容器时运行的命令。
- CREATED: 容器的创建时间。
- STATUS: 容器状态。
- 状态有7种:
- created(已创建)
- restarting(重启中)
- running 或 Up(运行中)
- removing(迁移中)
- paused(暂停)
- exited(停止)
- dead(死亡)
- PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。
- NAMES: 自动分配的容器名称。
-
通过
docker logs命令(后面跟的是容器ID或者容器名)
,可以查看容器内的标准输出。
-
Docker容器连接
- 容器中可以运行一些网络应用,要让外部也可以访问这些应用,
- 可以通过 -P 或 -p 参数来指定端口映射。
- 我们创建了一个 python 应用的容器
docker run -d -P training/webapp python app.py
- 另外,我们可以指定容器绑定的网络地址,比如绑定 127.0.0.1。
-
我们使用 -P 绑定端口号,使用 docker ps 可以看到容器端口 5000 绑定主机端口 32768。
我们也可以使用 -p 标识来指定容器端口绑定到主机端口。- 两种方式的区别是:
- -P :是容器内部端口随机映射到主机的高端口。
- -p : 是容器内部端口绑定到指定的主机端口。
docker run -d -p 5000:5000 training/webapp python app.py
- 另外,我们可以指定容器绑定的网络地址,比如绑定 127.0.0.1。
docker run -d -p 127.0.0.1:5001:5000 training/webapp python app.py
- 这样我们就可以通过访问 127.0.0.1:5001 来访问容器的 5000 端口。
- 上面的例子中,默认都是绑定 tcp 端口,如果要绑定 UDP 端口,可以在端口后面加上 /udp。
docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
docker port
命令可以让我们快捷地查看端口的绑定情况。
- 两种方式的区别是:
-
Docker容器互联
- 端口映射并不是唯一把 docker 连接到另一个容器的方法。
- docker 有一个连接系统允许将多个容器连接在一起,共享连接信息。
- docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息。
- 容器命名
- 当我们创建一个容器的时候,docker 会自动对它进行命名。
- 另外,我们也可以使用 --name 标识来命名容器
- 例如:
docker run -d -P --name runoob training/webapp python app.py
- 我们可以使用 docker ps 命令来查看容器名称。
docker ps -l
- 创建网络
- docker network create -d bridge test-net
- 参数说明:
- -d:参数指定 Docker 网络类型,有 bridge、overlay。
- 其中 overlay 网络类型用于 Swarm mode,在这里可以忽略
- docker network create -d bridge test-net
- 通过docker network ls参看网络信息
- 连接容器
- 运行一个容器并连接到新建的 test-net 网络:
docker run -itd --name test1 --network test-net ubuntu /bin/bash
- 打开新的终端,再运行一个容器并加入到 test-net 网络:
docker run -itd --name test2 --network test-net ubuntu /bin/bash
- 下面通过 ping 来证明 test1 容器和 test2 容器建立了互联关系。
- 如果 test1、test2 容器内中无 ping 命令,则在容器内执行以下命令安装 ping
- (即学即用:可以在一个容器里安装好,提交容器到镜像,在以新的镜像重新运行以上俩个容器)。
- apt update
- apt install iputils-ping
- 之后在test1容器中使用docker exec -it test1 /bin/bash 进入容器后,执行ping test2命令
- 也可以在test2容器中使用docker exec -it test2 /bin/bash 进入容器后,执行ping test1命令
- 若多个容器之间需要互相连接,推荐使用 Docker Compose,后面介绍。
- 配置 DNS
- 我们可以在宿主机的 /etc/docker/daemon.json 文件中增加以下内容来设置全部容器的 DNS
{ "dns" : [ "114.114.114.114", "8.8.8.8" ] }
- 设置后,启动容器的 DNS 会自动配置为 114.114.114.114 和 8.8.8.8
- 配置完,需要重启 docker 才能生效
- 查看容器的 DNS 是否生效可以使用以下命令,它会输出容器的 DNS 信息
docker run -it --rm ubuntu cat etc/resolv.conf
- 手动指定容器的配置
- 如果只想在指定的容器设置 DNS,则可以使用以下命令
docker run -it --rm -h host_ubuntu --dns=114.114.114.114 --dns-search=test.com ubuntu
- 参数说明:
- -rm:容器退出时自动清理容器内部的文件系统。
- -h HOSTNAME 或者 --hostname=HOSTNAME: 设定容器的主机名,它会被写到容器内的 /etc/hostname 和 /etc/hosts。
- –dns=IP_ADDRESS: 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。
- –dns-search=DOMAIN: 设定容器的搜索域,当设定搜索域为 .example.com 时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 host.example.com。
- 如果在容器启动时没有指定 --dns 和 --dns-search,Docker 会默认用宿主主机上的 /etc/resolv.conf 来配置容器的 DNS。
Docker容器卷
- 概念
- docker的原理是将所使用的应用和环境打包成一个镜像,最终以容器的方法运行。
- 而当容器产生了数据,而如果我们不通过docker commit生成新的镜像,来使得数据作为容器的一部分保存下来的话,因为数据是存储在容器中,那么当容器删除的时候,数据也就丢失了。所以我们需要将数据持久化,故需要在docker容器中使用卷。
- Docker的数据可以存储在类似于虚拟机磁盘的介质中,在Docker中称为数据卷(Data Volume)。
- 数据卷在Docker容器的形式就是一个目录,支持多个容器间共享,修改并不会影响镜像,使用Docker数据卷,类似在系统中使用mount挂载一个文件系统。
- 可以在Docker容器间进行共享和重用数据
- 可以使数据持久化,完全独立与容器的生命周期,故Docker不会在容器删除时删除其挂载的数据卷
- 数据卷的生命周期会一直持续到没有容器使用为止
- 卷的更改可以直接生效
- 数据卷的更改不会包含在镜像的更新中
- 实际使用
- 如果MySQL数据中,容器删除了,数据库内的数据就会丢失,故我们需要将MySQL的数据存储在本地。
- 数据卷使用
- 直接使用命令来挂载
docker run -it -v 主机目录:容器目录
- 几种:
- -v 容器内路径 #匿名挂载
- -v 卷名:容器内路径 #具体挂载
- -v /宿主机路径:容器内路径 #指定路径
- 可以使用-v 容器内路径,ro(readonly) rw(readwrite)改变容器对数据卷读写权限
docker run -d -P --name ubunut01 -v /home/demo:/home:ro ubuntu
docker run -d -P --name ubunut02 -v /home/demo:/home:rw ubuntu
- 详细使用
docker run -it -v /home/demo:/home ubuntu /bin/bash
- 解释:该操作执行后,会将Linux下的demo目录和容器内的home目录连接,两者内容会同步。之后我们就可以直接在Linux目录下进行数据操作,容器内会同步。
- 在容器启动,通过在Linux主机的终端中使用
docket inspect 容器id
来查看卷的挂载信息(找到Mounts字段,其Source就是主机目录,Destination就是容器目录),若没有该字段,说明挂载失败,需要重新挂载
- 查看卷的帮助文档
- docker volume --help来查看关于卷的帮助文档
- 说明:
- create :创建卷
- inspect :查看卷
- ls :列出所有卷
- prune:移除卷
- rm:移除卷
- 通过使用–volumes-from来指定父容器实现容器间数据的同步。
- 具体使用
docker run -it --name docker02 --volumes-from docker01 demo/ubunut:0.1
- 这样的话新创建的docker02容器里就有了docker01的数据。
Docker网络总结
-
查看容器内部网络的ip地址命令:ip addr 【或者 ifconfig】
-
Docker关于网络的处理。
-
一个网络模型图
-
-
Docker使用的是Linux的桥接模式,宿主机中是一个Docker容器的网桥docker0,所有东西都是经过这个docker0的,只要你启动一个容器,不指定一个网络它就会往docker0这里给你分配一个IP,最多能分配65535个。
-
Docker中的所有的网络接口都是虚拟的。虚拟的转发效率高!(内网传递文件!)
-
如果是容器之间需要通信,那么就通过Veth-pair给转发连接过去,如下图所示。核心就是利用了Linux的虚拟化网络技术,在容器内和Docker0分别创建了一个虚拟网卡,通过Veth-pair进行一个连接。
-
为什么是65535个的原因:
-
因为docker0分配的ip后面有16,我们拿255.255.0.1/16为例,因为原有的为00000000.00000000.00000000.00000000,转化为十进制【255.255.255.255】而16表示的是截止到前面的第二个255,也就是【255.255.0.0】,而每位的范围是0~255个数,那么能存储的个数就为后面的位数相乘,也就是255*255=65535个。假如是255.255.0.1/24,那么就代表255.255.255.0,也就是只有最后的0-255个,也就是可分配255个。而我们的docker0课分配的个数就是65535个
-
容器互联 --link 【了解即可】
- 当我们编写微服务的时候,database url=ip,项目不重启,而数据库ip换掉了,因此我们希望用名字来进行容器的访问。
- 我们通过名字是无法ping通的。如ping tomcat01
- 当然我们可以使用–link可以解决网络连通问题
- 使用
docker run -d -P --name tomcat03 --link tomcat02 tomcat
运行tomcat03并且连通tomcat02是可以的,并且通过docker exec -it tomcat03 ping tomcat02
可以ping通。 - 但是反向就不能ping通了
docker exec -it tomcat02 ping tomcat03
就会ping失败 - 原理:这项技术实际就是在hosts配置文件添加了一个域名解析,故不能反向,因为上述只在tomcat 03加入了tomcat02的域名解析。
- 现在不推荐使用–link,现在的容器互联使用的是自定义网路来实现的。
-
通过docker network --help查看网络的相关命令
-
网络模式
- bridge:桥接docker(默认,自己创建也使用bridge模式);
- none:不配置网络;
- host:和宿主机共享网络;
- container:容器网络连通!(用的少,局限很大);
-
直接使用–net bridge,而这个就是我们的docker0
docker run -d -P --name tomcat01 tomcat
-
以上命令就相当于
docker run -d -P --name tomcat01 --net bridge tomcat
-
docker0特点:默认,域名不能访问。 --ling可以打通,不建议使用
-
创建自定义网络
-
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mytestnet
-
参数说明:
-
–driver bridge # 桥接模式
-
–subnet 192.168.0.0/16 # 配制一个子网,65535个字段 192.168.0.2——192.168.255.255
-
–gateway 192.168.0.1 # 配制默认的路由网关
-
mytestnet #表示自定义的网络名
-
查看一下:docker network ls
-
查看一下mynet的详情:docker network inspect mynet
-
使用我们自定义的网络启动两个tomcat,然后查看一下信息。
-
启动tomcat-mytestnet-01
docker run -d -P --name tomcat-mytestnet-01 --net mytestnet tomcat
-
启动tomcat-net-02
-
docker run -d -P --name tomcat-mytestnet-02 --net mytestnet tomcat
-
查看一下
docker network inspect mytestnet
-
tomcat01 ping一下02的IP地址
-
docker exec -it tomcat-mytestnet-01 ping 192.168.0.3
-
tomcat02 ping一下01的IP地址
-
docker exec -it tomcat-mytestnet-02 ping 192.168.0.2
-
tomcat01 ping一下02的name
-
docker exec -it tomcat-mytestnet-01 ping tomcat-mytestnet-02
-
tomcat02 ping一下01的IP地址
-
docker exec -it tomcat-mytestnet-02 ping tomcat-mytestnet-01
-
发现可以ping通
-
网络联通connect
-
查看帮助命令:docker network connect --help
-
查看两个网段是否可以ping通
-
启动tomcat01,使用的是docker0路由
-
docker run -d -P --name tomcat01 tomcat
-
启动tomcat02,使用的是docker0路由
-
docker run -d -P --name tomcat02 tomcat
-
查看一下启动的容器
-
docker ps
-
测试tomcat01是否能ping通tomcat-net-01
docker exec -it tomcat01 ping tomcat-mytestnet-01
结果是不可以ping通
我们通过connect将两个不同网段的容器来ping通 -
docker network connect mytestnet tomcat01
-
然后再去ping
-
docker exec -it tomcat01 ping tomcat-mytestnet-01
-
这下就能ping通了,这里连通之后就是将tomcat01放到了mynet下【注意:tomcat-02依旧是打不通的】,就相当于下图所示。
-
使用connect就是将tomcat01放到了mynet下,如果我们以后想要跨网络操作别人的容器,就需要使用
docker network connect
连通。 -
可以在Linux中ping通tomcat01容器,而且容器与容器之间是可以互相ping通的。
-
启动一个tomcat
docker run -d -P --name tomcat01 tomcat
- 使用以下命令进入容器并查看容器内部ip addr,可以得到一个eth0@if262 ip地址,这个是docker分配的。
docker exec -it tomcat01 ip addr
- docker容器内查看
-
宿主机查看
-
经过测试,发现当我们启动一个容器的时候,会多一对网卡,上图中的8和容器的7是对应的。
启动容器带来的网卡是一对对的,这就是evth-pair,是一对虚拟设备接口,它们是成对出现的,一端连着协议,一端彼此连接。正是因为有这个特性,evth-pair才能充当一个桥梁,连接着各种虚拟网络设备。OpenStac,Docker容器之间的连接,OVS的连接,都是使用evth-pair技术。同时发现Linux是可以ping通容器内部的。 -
原理:我们每启动一个docker容器,docker就会给容器分配一个ip地址,我们只要安装了docker就会有一个docker0的网卡,使用的是桥接模式bridge,使用的技术就是evth-pair技术。
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mytestnet
docker run -d -P --name tomcat-testnet-01 --net mytestnet tomcat
docker run -d -P --name tomcat-testnet-02 --net mytestnet tomcat
Dockerfile
- Dockerfile 是一个用来构建镜像的文本文件,相当于命令脚本,文本内容包含了一条条构建镜像所需的指令和说明。
- 每个保留关键字(指令)都必须是大写字母;执行顺序是从上往下依次执行;
- 可以使用 Dockerfile 定制镜像
- 使用Dockerfile 文件来定制一个镜像,具体 Dockerfile 文件内指令详解
- 定制一个 nginx 镜像(构建好的镜像内会有一个 /usr/share/nginx/html/index.html 文件)
- 在一个空目录下,新建一个名为 Dockerfile 文件,并在文件内添加以下内容:
- 初体验
# 创建一个dockerfile文件,名字可以随意,建议Dockerfile
# 编写dockerfile脚本
# 文件中的内容,指令需要大写
FROM ubuntu # 基础镜像
VOLUME ["volume01","volume02"] # 挂载卷的目录,这里没有指定
CMD echo "-------hello-------" # 生成完之后发一段消息
CMD /bin/bash # 生成完之后执行的命令
# 这里的每个命令就是镜像的一层
- 编写完成后使用以下命令来构建镜像
docker build -f /home/dockerfile -t demo/ubuntu:1.0 .
-f(from) 通过什么文件来构建,后面接构建文件的地址
-t 生成文件的版本
- 启动自己构建的容器
- 使用docker image ls查看镜像
- 使用以下命令启动自己的容器
docker run -it --name docker01 demo/ubuntu:1.0
- 启动后可以看到volume01和volume02两个目录,这两个就是容器内同步的卷目录。
- 同步操作的验证:
- 首先在容器的卷目录中写一个文件。
- 在容器中使用以下命令查看卷挂载的路径(在linux终端执行)
- #查看容器id
- docker ps
- #根据容器id查看容器信息
- docker inspect 容器id
- 进入该路径查看可以看到文件已经进行了同步。
FROM nginx
RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html
- FROM 和 RUN 指令的作用
- FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。
- RUN:用于执行后面跟着的命令行命令。有以下俩种格式:
- shell 格式
- RUN <命令行命令>
- <命令行命令> 等同于,在终端操作的 shell 命令。
- exec 格式:
- RUN [“可执行文件”, “参数1”, “参数2”]
- 例如:
- RUN [“./test.php”, “dev”, “offline”] 等价于 RUN ./test.php dev offline- 注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
FROM centos RUN yum install wget RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" RUN tar -xvf redis.tar.gz # 以上执行会创建 3 层镜像。可简化为以下格式: # 以 && 符号连接命令,这样执行后,只会创建 1 层镜像。 FROM centos RUN yum install wget \ && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \ && tar -xvf redis.tar.gz
- 注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
- 开始构建镜像
- 在 Dockerfile 文件的存放目录下,执行构建动作。
- 以下示例,通过目录下的 Dockerfile 构建一个 nginx:v3(镜像名称:镜像标签)。
- 注:最后的 . 代表本次执行的上下文路径
docker build -t nginx:v3 .
- 上下文路径
- 上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。
- 解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。
- 如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。
- 注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。
- Dockerfile指令详解
指令 | 解释 |
---|---|
FROM | 基础镜像,在此基础上开始构建 |
MAINTAINER | 指定维护者信息 姓名+邮箱 |
RUN | 构建镜像需要运行的命令 |
ADD | 步骤,添加内容 |
WORKDIR | 镜像的工作目录 |
VOLUME | 挂载的目录 |
EXPOSE | 保留端口配置 |
CMD | 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代 |
ENTRYPOINT | 指定这个容器启动的时候要运行的命令,可以追加命令 |
ONBUILD | 当构建一个被继承,DockerFile 这个时候就会运行 ONBUILD 的指令,触发指令 |
COPY | 基类似ADD,将我们文件拷贝到镜像中 |
ENV | 构建的时候设置环境变量 |
- COPY
- 复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
- 格式:
-COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
-COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
- [–chown=:]:可选参数,用户改变复制到容器内文件的拥有者和属组。
- <源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:
- COPY hom* /mydir/
- COPY hom?.txt /mydir/
- <目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。- ADD
- ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似
- 不同之处如下:
- ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
- ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
- CMD
- 类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:
- CMD 在docker run 时运行。
- RUN 是在 docker build。
- 作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
- 注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。
- 格式:
- CMD <shell 命令>
- CMD [“<可执行文件或命令>”,“”,“”,…]
- CMD [“”,“”,…] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。
- ADD
- ENTRYPOINT
- 类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。
- 但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 CMD 指令指定的程序。
- 优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。
- 注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
- 格式:
- ENTRYPOINT [“”,“”,“”,…]
- 可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。
- 示例:
- 假设已通过 Dockerfile 构建了 nginx:test 镜像:
FROM nginx ENTRYPOINT ["nginx", "-c"] # 定参 CMD ["/etc/nginx/nginx.conf"] # 变参 # 不传参运行 docker run nginx:test # 容器内会默认运行以下命令,启动主进程。 nginx -c /etc/nginx/nginx.conf # 传参运行 docker run nginx:test -c /etc/nginx/new.conf # 容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件) nginx -c /etc/nginx/new.conf
- ENV
- 设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
- 格式:
- ENV
- ENV = =…
- 以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过
$NODE_VERSION
引用:
ENV NODE_VERSION 7.2.0 RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \ && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
- ARG
- 构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
- 构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。
- 格式:
- ARG <参数名>[=<默认值>]
- VOLUME
- 定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
- 作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
- 格式:
- VOLUME [“<路径1>”, “<路径2>”…]
- VOLUME <路径>
- 在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
- EXPOSE
- 仅仅只是声明端口。
- 作用:
- 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
- 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
- 格式:
- EXPOSE <端口1> [<端口2>…]
- WORKDIR
- 指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。
- docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
- 格式:
- WORKDIR <工作目录路径>
- USER
- 用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。
- 格式:
- USER <用户名>[:<用户组>]
- HEALTHCHECK
- 用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
- 格式:
- HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
- HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
- HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
- ONBUILD
- 用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。
- 格式:
- ONBUILD <其它指令>
- LABEL
- LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:
- LABEL = = = …
- 比如我们可以添加镜像的作者:
- LABEL org.opencontainers.image.authors=“runoob”
- 实战
- 构建自己的centos镜像,官方的centos基础镜像没有vim 、ifconfig命令,故在官方的基础上增加这几个命令。
- 编写dockerfile文件
# 书写内容
FROM centos # 首先会从本地查找该镜像,若没有会在网上下载
MAINTAINER 名字<邮箱> # 写作者,邮件
ENV MYPATH /usr/local # 设置环境变量
WORKDIR $MYPATH # 配置登录进行的路径,引用上面配置的
RUN yum -y install vim # 安装vim
RUN yum -y install net-tools # 安装网络工具
EXPOSE 80 # 暴露80端口
# 打印信息
CMD echo $MYPATH
CMD echo "--------END---------"
CMD /bin/bash
- 通过命令构建镜像
docker build -f dockerfile 文件路径 -t 镜像名:[tag]
- 具体:
docker build -f dockerfile -t mycentor:0.1 .
- 查看镜像docker images
- 运行自己镜像 docker run -it mycentor:0.1
- 可以使用docker history 镜像id 来查看变更历史,也可以使用其查看官方的变更历史
参考网址:
https://blog.youkuaiyun.com/weixin_43246215/article/details/108934216
https://www.bilibili.com/video/BV1og4y1q7M4
https://www.bilibili.com/video/BV1kv411q7Qc