Docker
docker简介:
物理机(平常使用的电脑)是一栋楼,虚拟机(vmware)就是一个套间,docker是套间里面的隔断。
一台虚拟机在物理机里体现为一个进程,docker对于虚拟机来说也是一个进程,进程和进程是没有联系的,即每个docker容器都是独立的,互不影响。
虚拟机和docker的区别
虚拟机起到隔离运行环境的作用,占用的资源较大
docker起到隔离应用程序的作用,占用的资源较小
docker里面运行的是镜像(自带操作系统),也就是说实际应用中需要用到多台电脑的时候,可以使用docker来代替多台电脑,从而在一台电脑中运行多个程序或虚拟机。
docker的版本:
- docker-ce 社区版(一些程序员在维护,免费的)
- stable版
- 稳定版,一个季度更新一次
- edge版
- 非稳定版,一个月更新一次
- stable版
- docker-ee 企业版(收费的)
docker组成
示意图 |
---|
1555225471244.png |
客户端:就是一个终端,由很多指令组成,类似于xshell5来操作linux,xshell5就是一个linux的终端(客户端)
服务器:docker服务器是一个守护进程,没有操作终端,主要是管理docker容器和docker镜像。所谓守护进程,就是不能喝用户进行交互(输入和输出),在后台周期性的执行某些操作,类似于apache服务器,不能用户进行交互,在后台默默的辅助解析PHP代码。
docker容器:通过docker操作命令可以启动磁盘上的镜像启动,启动之后就是docker容器,容器中运行的是一个操作系统。即,运行操作系统的媒介或容器。
docker镜像:所谓镜像就是一些系统磁盘文件,如vmware.vm等文件。用户可以自己制作也可以在官网下载。nginx镜像,意思是有一个操作系统,里面安装了nginx;redis镜像,意思是有一个操作系统,里面安装了redis;ubuntu镜像,意思是纯净的ubuntu操作系统。
镜像仓库:docker hub 是官方提供的镜像仓库。
docker的安装和卸载
安装命令:
# 1.更新软件列表
sudo apt-get update #不会更新软件,是更新本地系统中自带的软件列表,可以让下载的时候下载到最新的软件版本
# 2.安装一些小工具
sudo apt-get install apt-transport-https ca-certificates curl software-properties-commonlrzsz -y # 为后面的安装座准备,-y的意思是碰到提示输入yes或no的时候默认选择yes
# 3.下载阿里云的公钥,通过管道将秘钥添加到本地受信任的数据库(trusted)中
sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/gpg | sudo apt-key add - # curl是一个下载工具
# 4.添加阿里云的docke软件包到apt仓库
sudo add-apt-respository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -ce) stable"
# 5.将阿里云的软件源升级到最新版本
sudo apt-get update
# 6.安装docker
sudo apt-get install docker docker-ce -y
# 7.测试docker
docker version
docker加速器设置:
目的:
docker安装成功以后,启动docker需要镜像,镜像需要从官方下载,配置加速器九尾了提高下载镜像的速度
# 1.访问https://dashboard.daocloud.io网站,登录进去,点击右上角的“小火箭”图标,复制“配置docker加速器”中的linux命令,在中断中执行该命令即可,不同的用户登录会有不同的网址,但是都可以用
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io
# 这个命令会在/etc/docker目录下生成daemon.json文件,写入执行成功的提示命令{"registy-mirrors":["http://f1361db2.m.daocloud.io"]}
# 2.重启docker服务
sudo systemctl restart docker
docker的权限问题:
当安装好docker执行docker version命令,效果如下:
Client:
Version: 18.09.2
API version: 1.39
Go version: go1.10.6
Git commit: 6247962
Built: Sun Feb 10 04:13:47 2019
OS/Arch: linux/amd64
Experimental: false
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.39/version: dial unix /var/run/docker.sock: connect: permission denied
最后的提示是说权限不够,解决方案:
# 方案1:每次执行命令使用sudo
sudo docker version
# 方案2:将当前用户添加到docker组中,设置一次就好了(但重启电脑还不行)
# 使用命令:sudo gpasswd -a 当前用户 组名
sudo gpasswd -a itcast docker
# 这个时候如果还不行的话,再进行组的切换(因为当前用户默认不在docker组,所以现在执行命令虽然也是当前用户,但不属于docker组的操作,所以要进行组的切换),使用命令:newgrp - 组名
newgrp - docker # 如果下次重启,还没权限的话,只需要切换组即可
# 方案3:修改docker文件的权限。文件:/ver/run/docker.sock
sudo chmod 666 docker.sock # 这个命令只需要设置一次即可
docker服务器操作相关指令:
# 重启命令
sudo systemctl restart docker
# 启动命令
sudo systemctl start docker
# 关闭命令
sudo systemctl stop docker
# 查看状态
sudo systemctl status docker
卸载命令:
# 1.卸载软件
sudo apt-get purge docker-ce #删除对应的信息文件+应用程序,如删除人和人的信息,包括姓名,衣服,身份证
# 或者
sudo apt-get remove docker-ce # 只删除应用程序,但是信息还在
# 2.删除两个目录,一个是身份认证目录 /etc/docker,另一个是存储镜像的目录 /var/lib/docker
sudo rm /etc/docker /var/lib/docker
docker镜像管理
查看docker中的所有指令:
docker --help
镜像的搜索:
操作镜像需要知道这个镜像是否存在,也就是需要搜索一下
注意:搜索范围是在docker hub,也就是官方的仓库中搜索
# 使用命令:docker search 镜像名 例:
docker search ubuntu
会搜索很多结果出来,其中有些是官方的,有些是自己制作好上传的,具体结果字段如下:
NAME:镜像的名称
DESCRIPTION:镜像的描述
STARS:镜像的下载量
OFFICIAL:是否为官方出品的镜像
AUTOMATED:会不会启动一些脚本之类的程序
镜像的下载:
# 下载指令:docker pull 镜像名 例:
docker pull ubuntu
下载成功后,会存储到本地的镜像仓库,对应一个本地目录:/var/lib/docker
,这个目录需要root用户才能进去查看,可以使用命令切换到root用户su - root
,使用这个命令切换的root用户,连环境变量也切换到了root用户,如果不加-
那代表虽然用户切换到了root,但使用环境变量还是普通用户的
该目录中有很多文件夹,下载好的镜像不是一个文件,而是由很多小文件组成的,所以是找不到单独的某个镜像文件的,所以在后期需要删除这个镜像的话,就将这个目录删掉就好了。
镜像的查看:
# 查看所有的镜像
docker images
# 或
docker image ls
# 查看某一个镜像
docker image ls 镜像名
# 或
docker images 镜像名
查看的结果中包含很多字段,如下:
REPOSITORY:镜像名称
TAG:镜像的版本(latest代表最新版本)
IMAGE ID:镜像id(类似于身份证,是唯一的)
CREATED:创建时间
SIZe:镜像的大小
通常在描述一个镜像的时候,描述方式如下:
语法:
镜像名:tag
例:
nginx:latest
# 如果tag的值为latest,那么latest可以省略不写,例: nginx == nginx:latest
给docker起别名:
语法:
docker tag 镜像名:tag 别名:tag的别名
例:
docker tag ubuntu:latest uuuu:v1.0
# 这里的别名和tag的别名都可以自定义
当再次查看的时候,会发现列表中多了一个镜像,这个镜像是多出来的一个名字不是复制了一个新的镜像。
删除镜像:
语法:
docker rmi 镜像id/镜像名
# 如果镜像有别名,就不能用镜像id进行删除,因为镜像id不是唯一的,只能使用镜像名来删除,且tag不是latest的话,也必须加上tag,而且删除的只是一个名字,镜像还在的,只是废弃了一个名字,如果用镜像名删除不了的话,可以在后面加一个参数 -f 表示强制删除
镜像的导入导出
由于镜像在使用过程中难免会发生误删的情况,所以镜像需要备份。目的是镜像文件的备份和分发(备份以后传送给别人进行导入使用)。
导出的本质就是将本地仓库中的镜像备份到本地磁盘中。导入的本质就是将本地磁盘中保存的镜像放到本地仓库中。
导出:
导出命令:
docker save -o 目标路径(带名字) 要导出的镜像名带tag
或
docker save --output 目标路径(带名字) 要导出的镜像名带tag
例:
docker save -o /home/itcast/docker-test/ubuntu.img uuuu:v1.0
或
docker save --output /home/itcast/docker-test/ubuntu.img uuuu:v1.0
# 这时候在目标文件夹中就能看到导出的文件了(文件名是自定义的),这个单独的文件就是整个镜像文件
导入:
导入命令:
docker load -i 镜像文件路径
或
docker load --input 镜像文件路径
# 如果这个镜像本身就存在的话,该命令不会进行任何操作
还有另外一种命令:
docker load < 镜像文件路径
查看镜像的历史记录
命令:
docker history 镜像名:tag
# 查看的是镜像制作过程中一些比较重要的步骤
查看镜像的详细信息
命令:
docker inspect 镜像名/镜像id
# 查看的是镜像的属性信息(id,大小,名称等),结果以json格式输出
这个命令还可以查看网络等信息,参考地址:https://yq.aliyun.com/articles/230067
镜像管理总结:
示意图 |
---|
1555249738442.png |
docker容器管理
容器是基于镜像的,镜像(镜像可看做可执行程序)启动之后,就变成了容器。镜像启动之前只占用磁盘空间,当镜像启动之后会占用内存、CPU等资源。
每个容器启动之后,都是一个进程。
查看容器
命令:
docker ps
# 因为容器启动后是进程,所以查看容器和查看进程的指令类似。
命令后面的参数:
docker ps -a/--all # 显示所有的容器,默认只显示running状态的
docker ps -q/--quiet # 直线容器的id
查看结果会有很多字段,如下:
CONTAINER ID:容器启动之后的id,是唯一的
IMAGE:当前容器是基于哪个镜像启动的
COMMAND:容器启动之后,默认执行了什么命令
CREATED:容器的创建时间
STATUS:容器当前的状态
created:容器被创建,但是不能使用的状态
running:运行的状态
pause:暂停的状态
exited:容器终止运行,但是容器还在的状态
PORTS:映射的端口,主机和容器直接的端口映射
NAMES:容器启动之后的名字,如果没有指定,会随机生成一个,这个不能重复(是唯一的)
创建容器:
命令:
docker create -it [--rm] --name 容器名 镜像名:tag commad(执行的命令)
# 其中-i参数,也可以是--interactive,表示给容器关联标准输入,-t参数,也可以是--tty,表示给容器绑定终端,这个位置还可以有-a/--attach list参数,表示给容器关联标准输入输出或错误,--rm参数表示容器终止运行的时候自动删除这个容器,--name参数表示手动指定容器的名字(不指定容器名会自动生成一个),command可以不写,如果必须的写的话,就写bash,所谓bash,就是一个shell命令解析器,没有实际意义
例:
docker create -it --name myubuntu --rm uuuu:v1.0 bash
启动已创建好的容器:
命令:
docker start -ia 容器名/容器id
例:
docker start -ia myubuntu
这时候,操作的用户会发生改变,因为启动容器加了参数后,会进入到容器内部,而容器就是一个微型操作系统,这时候输入exit可以退出容器
启动容器可以不加参数,就不会进入到容器内部,容器正在运行的状态会显示up状态
容器创建并启动:
命令:
docker run -aitd --name 容器名 镜像名:tag command
# 参数意义和用法与docker create一样,多的-d/--detach参数意思是以守护进程的形式运行(在后台运行),并在启动成功以后打印一个容器的id,加了-d参数后不会进入到容器内部了
例:
docker run -itd --name newubun uuuu:v1.0 bash
这时候查看容器的话,可以看到这个容器已经创建好并在运行了,状态是up(正在运行)
暂停容器:
命令:
docker pause 容器名/容器id
例:
docker pause newubun
再次查看容器的时候,在正在运行的容器状态up后面会有一个(Paused),表示这个容器暂停运行了,这个命令可以同时操作多个容器,多个容器名之间使用空格隔开
恢复容器:
命令:
docker unpause 容器名/容器id
例:
docker unpause newubun
容器重启:
命令:
docker restart -t 容器名/容器id
# -t,--time int:延时时间,默认是10s
例:
docker restart -t 5 newubun # 表示容器在5秒钟之后重启
关闭和终止容器:
关闭容器和终止容器都没有删除容器,只是让容器从up状态到了exited状态,关闭容器有延时,终止容器没有延时
关闭命令:
docker stop [-t] 容器名/容器id
# -t,--time int:延时时间,默认为10s
终止命令:
docker kill [-s] 容器名/容器id
# -s.--signal string:指定发出的信号,默认为kill(linux默认有64个信号,实际有62个,sigkill为9号信号(使用kill -l命令可以进行查看所有信号),不能被拦截,只会有一个结果,就是kill),一般不用
例:
docker stop -t 5 newubun # 表示容器在5s之后关闭,容器从up状态变成了exited状态
docker kill newubun # 结果同样是容器关闭
容器的删除:
删除未运行的容器:
命令:
docker rm 容器名/容器id
删除运行的容器:
命令:
docker rm -f 容器名/容器id
# -f参数表示强制删除,也可以加在命令的最末尾
批量删除容器:
命令:
docker rm `docker ps -aq` -f
或
docker rm $(docker ps -aq) -f
进入容器中:
创建并启动并进入容器
命令:
docker run -it [--name 容器名] 镜像名:tag [command]
进入已创建但未启动的容器:
命令:
docker start -ia 容器名/容器id
进入已启动的容器:
命令:
docker exec -it 容器名/容器id command
# -i,--interactive:表示给容器关联标准输入
# -t,--tty:表示给容器绑定终端
# 命令的最后面的command是不能被省略的
# command:shell指令,一般就是用bash
例:
docker exec -it 456b55bb7850 bash # 进入到容器内部,-it两个参数必不可少,且command必须是bash
退出容器:
退出容器,不会影响容器的运行
# 方式1:
exit
# 方式2:
ctrl+D
容器的其他命令:
小知识:我们平常看到的子网掩码为:255.255.255.0,这个代表24位,因为ip地址是32的,四个整数,每个代表8位,其中3个有值,那就24位,如果说子网掩码为16位,那这个子网掩码就是255.255.0.0
查看容器日志:
命令:
docker logs 容器名/容器id
查看容器的详细信息(属性):
命令:
docker inspect 容器名/容器id
# 参考网址: https://yq.aliyun.com/articles/230067
查看容器的端口信息:
命令:
docker port 容器名/容器id
# 查看的是主机和容器的端口映射
容器重命名:
命令:
docker rename 容器名/容器id 新的容器名
例:
docker rename newubun myu
基于容器的进行导出:
命令:
# 方式1
docker export -o 镜像文件名 容器名/容器id
# 方式2
docker export 容器名/容器id > 镜像文件名
例:
docker export -o ~/docker-test/myub.img myu # 将容器中的镜像导入到了本地文件
镜像的导入:
镜像的导入本质是将本地的镜像文件导入到本地的镜像仓库
命令:
cat 镜像文件 | docker import - 新的镜像名:tag
例:
cat myub.img | docker import - ub:1
导入使用的docker import命令,但是在使用的时候,docker import 需要接收数据(数据来源于文件或者url),所以需要使用cat配合管道使用
镜像导出的对比:
save | export | |
---|---|---|
导出方式 | 通过镜像导出 | 通过容器导出 |
是否可以修改 | 不能对镜像进行修改 | 原始镜像可以通过启动的容器进行修改 |
是否丢失数据 | 不会丢失 | 若没有通过容器对进行修改直接导出,会丢失镜像的历史记录 |
大小 | 和原始镜像一样 | 会比原始镜像小(丢失了历史记录) |
镜像导入的对比:
load | import | |
---|---|---|
是否可以修改镜像名 | 无法修改 | 可以修改 |
docker命令总结:
示意图 |
---|
1555477156230.png |
数据卷
容器和宿主机之间的数据拷贝:
宿主机拷贝到容器:
docker cp 宿主机的文件路径 容器名:容器中的文件路径
例:
docker cp ./a.txt myu:/b.txt
# 将当前目录下的a.txt文件拷贝到容器中的根目录下,并改名为b.txt,也可以不改名,即目标之路经中不写文件名
容器拷贝到宿主机:
docker cp 容器:容器中的文件路径 宿主机的文件路径
例:
docker cp myu:/b.txt ./c.html
# 将容器中的根目录下的b.txt拷贝到当前目录下,并改名为c.html,也可以不改名,即目标之路经中不写文件名
数据卷和使用:
所谓数据卷,就是在创建或启动容器的时候,让容器中的某个目录或文件挂载到宿主机上的某个目录或文件,让宿主机和容器之间形成一种数据的映射关系,从而达到宿主机和容器之间数据共享的目的。
挂载命令:
# 创建并启动容器的时候进行挂载
docker run -itd --name 容器名 -v 宿主机路径:容器路径:ro 镜像名:tag command
# 创建容器的时候挂载
docker create -it --name 容器名 -v 宿主机路径:容器路径:ro 镜像名:tag command
# -v,--volume list:list就是路径的意思;ro是容器对于挂载目录是只读的权限,可以不写,默认为读写权限;宿主机路径必须是绝对路径,否则会映射失败,但不会报错;容器路径可以随便定义,不存在会创建
例:
docker run -itd --name myub -v /home/itcast/docker-test/ub:/d-test uuuu:v1.0 bash
# 宿主机/home/itcast/docker-test/ub文件夹和容器/d-test文件夹中的数据可以共享了
文件的挂载和目录的挂载命令一样,同样可以让宿主机和容器共享一个文件,文件名可以重命名,也可以不重命名(不重命名就不写文件名即可)
数据卷容器和宿主机共享目录的示意图 |
---|
1555492695097.png |
数据卷容器和使用:
所谓数据卷容器,本质上是一个容器,只不过这个容器只做一件事情,就是只提供共享目录,只为了共享数据而存在,不做其他任何事情。
如果创建了数据卷和宿主机进行了映射,而且容器什么也不做,也可以叫做数据卷容器。数据卷容器可以不和宿主机进行映射,而只为了和其他容器进行数据共享,创建命令如下:
创建[并启动]数据卷容器:
docker run -itd --name 容器名 -v 数据卷容器的目录 镜像名:tag command
# 除了可以创建并启动,也可以光创建不启动
docker create -it --name 容器名 -v 数据卷容器的目录 镜像名:tag command
# 这个容器可以不启动,目录存在就好
例:
docker create -it --name u1 -v /backup ub:1 bash
创建好以后,关键是和其他容器共享这个目录,其他容器要启动才能用,命令如下:
创建挂载数据卷容器的容器命令:
docker run -itd --name 容器名 --volumes-from 数据卷容器名 镜像名:tag command
例:
docker run -itd --name u2 --volumes-from u1 uuuu:v1.0 bash
# 会在容器内自动生成backup目录,并与数据卷容器共享这个目录
数据卷容器和容器以及宿主机之间的关系有两种,一种是没有宿主机参与,一种是有宿主机参与
有宿主机参与的:
示意图1 |
---|
1555493020066.png |
没有宿主机参与的:
示意图2 |
---|
1555493125532.png |
数据卷容器的数据备份与还原:
-
备份分两种情况:
-
数据卷容器在创建或启动时已经挂载到宿主机上
这种情况基本不用进行任何操作,因为数据卷容器中的数据和宿主机中的数据是共享的,要丢一起丢,要有一起有。如果非要备份的话,就是将宿主机中的数据进行备份到另一个地方即可,或者给宿主机中的共享文件夹创建硬链接。
-
数据卷容器创建并启动时并未挂载到宿主机上
创建或启动时没有挂载宿主机上,到运行一段时间之后再来备份已经来不及了,所以需要另外一个“备份容器”作为宿主机和数据卷容器的媒介来连接宿主机和数据卷容器,以便达到数据卷容器中的数据备份到宿主机的目的。
示意图 1555496756594.png
-
|
例:
```shell
# 1.创建数据卷容器
docker create -it --name container -v /backup ub:1 bash
# 2.创建两个容器共享数据卷容器的数据
docker run -itd --name ub1 --volumes-from container ub:1 bash
docker run -itd --name ub2 --volumes-from container ub:1 bash
# 3.进入容器ub1的共享目录中写入文件数据
docker exec -it ub1 bash
echo aaaaaaaaaaaaaaaaa > /backup/a.txt
# 4.进入容器ub2的共享目录中查看数据
docker exec -it ub2 bash
cat /backup/a.txt # 可以看到数据和前面写进去的一致
# 5.在宿主机上创建本地备份目录
mkdir /home/itcast/docker-test/temp
# 6.创建备份容器,映射到宿主机的备份目录,并共享数据卷容器的数据(注意:这两个目录不要做成一个,否则会有意想不到的错误)
docker run -itd --name tmp -v /home/itcast/docker-test/temp:/test1 --volumes-from container ub:1 bash
# 7.进入备份容器将数据卷容器的数据(/backup文件夹)打包拷贝到和宿主机共享的目录中(/test1)
tar zcvf /test1/backup.tar.gz /backup
# 8.然后可以在宿主机上的temp目录中查看到备份好的数据文件
ls /home/itcast/docker-test/temp
```
命令优化(合并第6~第7):
```shell
docker run -itd --rm --name tmp -v /home/itcast/docker-test/temp:/test1 --volumes-from container ub:1 tar zcvf /test1/backup.tar.gz /backup
# 这个容器创建出来就是为了备份文件,备份以后这个容器就没用了,所以直接加--rm参数;最后的command反正也是shell命令,打包也是shell命令,直接进行替换
```
-
还原
还原的过程其实就是将备份的过程反过来。
第1第5一样,第6第7将压缩换成解压即可
# 1.创建数据卷容器 docker create -it --name container -v /backup ub:1 bash # 2.创建两个容器共享数据卷容器的数据 docker run -itd --name ub1 --volumes-from container ub:1 bash docker run -itd --name ub2 --volumes-from container ub:1 bash # 3.进入容器ub1的共享目录中写入文件数据 docker exec -it ub1 bash echo aaaaaaaaaaaaaaaaa > /backup/a.txt # 4.进入容器ub2的共享目录中查看数据 docker exec -it ub2 bash cat /backup/a.txt # 可以看到数据和前面写进去的一致 # 5.在宿主机上创建本地备份目录 mkdir /home/itcast/docker-test/temp # 创建恢复容器,并将数据放入和数据卷容器共享的文件夹中 docker run -itd --rm --name tmp -v /home/itcast/docker-test/temp:/test1 --volumes-from container ub:1 tar zxvf /test1/backup.tar.gz -C /
端口映射:
示意图 |
---|
1555513504076.png |
命令:
都是创建并启动容器的时候设置
随机端口映射(不推荐):
docker run -itd --name 容器名 -P 镜像名:tag
指定端口映射(推荐):
docker run -itd --name 容器名 -p [宿主机ip:]宿主机端口:容器端口 镜像名:tag
# 指定一个宿主机的空闲端口,容器端口指定一个协议端口,例:http为80,https为443
# 在启动系统自带的容器的时候,在最后面不要加command了,因为涉及到服务的启动,指定command后,服务不能启动
例:
docker run -itd --name myweb -p 8088:80 nginx
容器的网络管理
docker network --help
docker network command
commands:
connect 连接容器到指定的网络中
create 创建一个网络
disconnect 将容器从网络中删除
inspect 查看网络相关的信息
ls 查看现有的所有网络
prune 删除所有的未使用的网络
rm 删除一个或多个指定的网络
docker中的网络
查看所有网络列表:
NETWORK ID NAME DRIVER SCOPE # 头
64d83b763e85 bridge bridge local # 桥接网络,单独生成网卡
89d9ce6dd16d host host local # 主机网络,和宿主机共用网卡
b53a004ffcb7 none null local # 网络一切都需要手动设置
# 查看bridge网络
docker network inspect bridge
# "IPv4Address": "172.17.0.3/16", 表示ip地址和子网掩码,子网掩码是255.255.0.0
"Containers": {
"16a17991c9d7034eba09fdc9a5c90d3121b5607f062002d6e01b7375bd2803b9": {
"Name": "ub2",
"EndpointID": "89b4d01ab4b2be864a4e56fc115b1c6ce8880fdb4842c8c1c4981e4114e79ea8",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16", # 每个容器都由对应的ip地址和子网掩码
"IPv6Address": ""
},
"250c697739db1a291e17a24efccbf88a64de4c600d24e839f14740c22b724c0e": {
"Name": "myweb",
"EndpointID": "52ccff4ef2237641fdbb39557f2a15fc62d1226d510dbf1a49dce654b94114b5",
"MacAddress": "02:42:ac:11:00:05",
"IPv4Address": "172.17.0.5/16",
"IPv6Address": ""
},
# container项,表示在网络中包含了的容器
docker容器默认都在bridge网络中
bridge网络模式
创建网络
docker network create [OPTIONS] NETWORK
Options:
--attachable Enable manual container attachment
--aux-address map Auxiliary IPv4 or IPv6 addresses used by
Network driver (default map[])
--config-from string The network from which copying the configuration
--config-only Create a configuration only network
-d, --driver string # 指定网络的驱动,默认是桥接模式
--gateway strings # 指定网关(一般就是192.168.0.1)
--ingress Create swarm routing-mesh network
--internal Restrict external access to the network
--ip-range strings Allocate container ip from a sub-range
--ipam-driver string IP Address Management Driver (default "default")
--ipam-opt map Set IPAM driver specific options (default map[])
--ipv6 Enable IPv6 networking
--label list Set metadata on a network
-o, --opt map Set driver specific options (default map[])
--scope string Control the network's scope
--subnet strings # 指定网段(一般是192.168.0.255)
例:
docker network create mynetwork # 再次查看网络列表的时候,可以看见网络列表中多了一个自己创建的mynetwork网络
# 查看mynetwork属性信息的时候,可以看到默认的驱动、网关、网段等信息,并且在新创建的这个网络没有容器
创建自定义网段和网关的网络:
docker network create --subnet IP地址/子网掩码 --gateway 自定义网关 网络名
例:
docker network create --subnet 180.17.0.0/16 --gateway 180.17.0.1 mynetwork1
# ip地址自定义,子网掩码参考bridge网络,网关是1
查看容器的属性信息可以看出这个容器处在哪个网络中
docker inspect myweb
"Networks": {
"bridge": { # 网络名称
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "64d83b763e85d40d83381787cc621ace063233e594ab32f95f5b911b331d2d7a",
"EndpointID": "52ccff4ef2237641fdbb39557f2a15fc62d1226d510dbf1a49dce654b94114b5",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.5",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:05",
"DriverOpts": null
}
}
启动并创建容器的时候将容器加入到网络中
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Options:
--network string # 将一个容器添加到网络中
例:
docker run -itd --name nginxnetwork --network mynetwork ub:1 bash
# 查看容器详细信息的时候,可以看到容器的网络是mynetwork,或者查看mynetwork网络的详细信息的时候可以看到container项中会有nginxnetwork容器
从网络中删除容器
命令:
docker network disconnect [OPTIONS] NETWORK CONTAINER
例:
docker network disconnect mynetwork nginxnetwork # 再次查看网络或者容器的详细信息会发现容器已经不在这个网络中
将容器添加到指定网络中
命令:
docker network connect [OPTIONS] NETWORK CONTAINER
例:
docker network connect mynetwork nginxnetwork
删除网络:
命令:
docker network rm NETWORK [NETWORK...] # 可以同时删除多个网络
例:
docker network rm mynetwork1
#删除网络的时候,要确保网络中没有包含容器
容器在启动的时候会加入到默认的网络中;一个容器可以同时加入到多个网络中;容器和容器之间要进行通信的前提是这些容器必须处于同一个网络中;
host网络模式
host网络是和宿主机共享同一个网卡,所以不能重建,也就是说host网络只有一个。操作host网络只能是在容器创建启动或者后期将容器添加到这个网络中。
docker run -itd --network host --name nyweb2 nginx bash # 创建启动容器nyweb2并加入到host网络
docker inspect nyweb2 # 查看nyweb2容器的详细信息
"Networks": {
"host": { # 这个容器已经加入到host网络中了
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "89d9ce6dd16d7808daa82fdada549392e02ba7e0cea496bed5e0ad9091471986",
"EndpointID": "c6f601bb153671834675a5c8c44ca5ce918489ac99ea661075eb6a33c1dd64ed",
"Gateway": "",
"IPAddress": "",
"IPPrefixLen": 0,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "",
"DriverOpts": null
}
}
dockerfile
简介:
shell命令就是linux命令,shell脚本是一个可执行的文件,这个文件写了很多的shell命令以及一些简单的逻辑(判断和循环)。dockerfile也是一个文件,这个文件中写了很多的docker命令,一般情况,里面写的是制作镜像的步骤,以便重复使用和快速制作镜像。
即:一般情况,手动下载镜像,创建容器,在容器中搭建环境或者安装软件 ------>使用dockerfile文件执行即可。也就是将手动操作的步骤,同过dockerfile的规则和命令书写到dockerfile文件中,执行这个文件得到容器并将这个镜像导出。
规则:
- dockerfile文件名首字母大写(例:Dockerfile)
- 尽量将dockerfile放到空目录中
- 每个容器尽量只有一个功能
- dockerfile中要执行的命令越少越好
dockerfile基础指令
dockerfile里面的注释是#
FROM
指定原始镜像,最后制作出来的镜像是从容器中导出的,制作容器是需要原始镜像的
命令:
FROM 镜像名:tag # 这里的镜像名指的是原始镜像
例:
FROM ubuntu
FROM必须写在Dockerfile的第一行(除注释),可以连续写多个FROM原始镜像,如果指定的镜像名在本地镜像仓库中不存在,会自动从远程仓库下载到本地仓库,如果远程仓库中也没指定的镜像,就报错终止执行了
MAINTAINER
维护者信息
命令:
MAINTAINER 维护人员信息
例:
MAINTAINER zhangsan zhangsan@163.com
RUN
构建镜像要执行的shell命令,如果命令中有需要确认的操作,在后面必须有-y;命令太长需要换行,行尾要加\
命令:
RUN shell命令
例:
RUN mkdir /home/itcast/go -p
或:
RUN ["mkdir","/home/itcast/go","-p"]
EXPOSE
设置docker容器对外开放的端口。容器和外部环境是隔离的,要从外部访问到容器内部,需要容器开放端口
命令:
EXPOSE 端口号
例:
EXPOSE 80
# 还可以使用docker命令进行:docker run -itd -p 8888:80
执行dockerfile文件的命令:
docker build [OPTIONS] dockerfile的文件路径或者网上能访问到dockerfile的url
# 后面的路径必须是一个目录,而不能是具体文件
Options:
-t, --tag list 指定最后制作出来的镜像(执行到最后从容器中导出的镜像)的名字
# 最后制作好的镜像在本地镜像仓库中
例:
先创建一个空目录,然后在目录中新建文件名为Dockerfile,写入如下内容
# 构建一个基于ubuntu的docker订制镜像
# 基础镜像
FROM ubuntu
# 镜像作者
MAINTAINER wangjie wangjie.912@163.com
# 执行命令
RUN mkdir hello
RUN mkdir world
RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
# sed的意思是替换下载库地址,后面的/g代表整行替换
RUN apt-get update
RUN apt-get install nginx -y
# 对外开放端口
EXPOSE 80
运行这个文件:
# 运行docker文件
docker build -t mytest:v1.0 . # 在当前文件夹可以使用一个点来表示路径
# 查看制作好的镜像
docker images
运行最后结果:
示意图 |
---|
1555639757579.png |
dockerfile的运行指令
CMD
这个指令是用来执行shell命令的,这个shell命令代表容器启动后默认要执行的命令(CMD就是command的简写)。一个dockerfile只能有一个CMD,如果写多个,以最后一个为准。在后期执行docker run的时候,这个指令会被覆盖。
CMD shell命令
CMD ["shell命令","命令参数1","命令参数2"]
ENTRYPOINT
ENTRYPOINT的用法和意义跟CMD一样,区别只在ENTRYPOINT默认不会被docker run覆盖,若想覆盖,需要在docker run后面加--entrypoint参数
CMD和ENTRYPOINT综合使用:
# 要先写ENTRYPOINT后写CMD,CMD通常作为ENTRYPOINT的参数
ENTRYPOINT mkdir /home/itcast/go
CMD -p
# 意思为:mkdir /homt/itcast/go -p
dockerfile的文件编辑指令
ADD
这个指令是将宿主机的文件拷贝到容器中的。ADD指令在拷贝的同时,如果这个文件是压缩文件,会将宿主机的压缩文件拷贝到容器中进行解压(前提是宿主机中的压缩文件是可识别的压缩包,例:.gz或.bz2)。
命令:
ADD 宿主机文件 容器目录/文件名
ADD ["宿主机文件","容器目录/文件名"]
# 宿主机的文件一般放到和dockerfile所在的目录中
例:
# 文件
ADD ["a.txt","/home/itcast/go/b.txt"] #容器中目录不存在会自动创建;文件存在则覆盖,不存在则拷贝
# 目录 a.tar.gz ---> mytest文件夹
Add ["a.tar.gz","/home/itcast/go"] # 会在/home/itcast/go目录下得到一个mytest录
COPY
COPY的用法和意义跟ADD是一样的,区别只在于COPY不会解压。
VOLUME
这个指令是在镜像中创建挂载点,这样只要通过该镜像创建的容器都由了挂载点(可以是在容器中创建数据卷,也可以把这个容器当做数据卷容器),通过VOLUME指定的挂载点目录是自动生成的。
命令:
VOLUME ["/data"]
例:
VOLUME ["/data","/home/itcast/mytest"]
dockerfile的环境指令
ENV
这个指令是用来设置容器的环境变量的,一般写在RUN指令之前。
命令:
ENV <key> <value> # 设置一个
ENV <key>=<value> <key>=<value> # 设置多个
例:
ENV name zhangsan
ENV name=zhangsan age=12
WORKDIR
这个指令是用来切换工作目录的,类似于shell命令的cd,主要是为后续的RUN、ENTRYPOINT、CMD等指令在指定的目录中执行。可以进行多次切换。
命令:
WORKDIR 目录
例:
WORKDIR /home/itcast/go
RUN a.sh
WORKDIR /home
WORKDIR itcast # 代表相对路径
WORKDIR go
RUM pwd # /home/itcast/go
USER
这个指令用来指定执行命令的用户,默认是root
命令:
USER 用户名
例:
USER root
ARG
这个指令是用来向dockerfile命令传参的。如果在dockerfile中需要用到外部传来的参数,在dockerfile中就用ARG来表示。
命令:
ARG <name>[=value]
例:
FROM ubuntu
ARG myname
ARG index
# 在执行dockerfile的时候
docker build --build-arg myname=zhangsan index=1
dockerfile触发器指令
ONBUILD
ONBUILD指令的意思示意图 |
---|
1555645862355.png |
制作镜像A的时候,设置输出1,但是不会被输出,当使用镜像A作为原始镜像制作镜像B的时候才会输出1。
命令:
ONBUILD [command]
例:
ONBUILD ["echo","1"]
dockerfile案例
用dockerfile来部署一个go的运行环境,并搭建beego框架至可以运行。
步骤:
-
手动搭建go运行环境并搭建beego框架
#1、docker环境配置 #1.1 获取docker镜像 #获取一个ubuntu的模板文件 cat ubuntu-16.04-x86_64.tar.gz | docker import - ubuntu-nimi #1.2 启动docker容器 #启动容器,容器名称叫go-test docker run -itd --name go-test ubuntu-nimi #进入容器 docker exec -it go-test /bin/bash #2、go环境部署 #2.1 基础环境配置 #配置国内源 vim /etc/apt/sources.list #文件内容如下 deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted deb http://mirrors.aliyun.com/ubuntu/ xenial universe deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe deb http://mirrors.aliyun.com/ubuntu/ xenial multiverse deb http://mirrors.aliyun.com/ubuntu/ xenial-updates multiverse deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe deb http://mirrors.aliyun.com/ubuntu/ xenial-security multiverse #如果由于网络环境原因不能进行软件源更新可以使用如下内容 sudo sed -i 's/cn.archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list #更新软件源,安装基本软件 apt-get update apt-get install gcc libc6-dev git vim lrzsz -y #2.2 go环境配置 #安装go语言软件 //apt-get install golang -y 由于软件源问题改使用新版本go 将go1.10.linux-amd64.tar.gz拷贝到容器中进行解压 tar -C /usr/local -zxf go1.10.linux-amd64.tar.gz #配置go基本环境变量 export GOROOT=/usr/local/go export PATH=$PATH:/usr/local/go/bin export GOPATH=/root/go export PATH=$GOPATH/bin/:$PATH #3、go项目部署 #3.1 获取beego代码 #下载项目beego go get github.com/astaxie/beego #3.2 项目文件配置 #创建项目目录 mkdir /root/go/src/myTest cd /root/go/src/myTest #编辑go项目测试文件test.go package main import ( "github.com/astaxie/beego" ) type MainController struct { beego.Controller } func (this *MainController) Get() { this.Ctx.WriteString("hello world\n") } func main() { beego.Router("/", &MainController{}) beego.Run() } #3.3 项目启动 #运行该文件 go run test.go #可以看到: #这个go项目运行起来后,开放的端口是8080 #4、测试 #4.1宿主机测试 #查看容器的ip地址 docker inspect go-test #浏览器查看效果: curl 172.17.0.2:8080
-
修改为dockerfile方案
# 构建一个基于ubuntu 的docker 定制镜像 # 基础镜像 FROM ubuntu # 镜像作者 MAINTAINER panda kstwoak47@163.com # 增加国内源 #COPY sources.list /etc/apt/ RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list RUN sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list # 执行命令 RUN apt-get update RUN apt-get install gcc libc6-dev git lrzsz -y #将go复制解压到容器中 ADD go1.10.linux-amd64.tar.gz /usr/local/ # 定制环境变量 ENV GOROOT=/usr/local/go ENV PATH=$PATH:/usr/local/go/bin ENV GOPATH=/root/go ENV PATH=$GOPATH/bin/:$PATH # 下载项目 RUN go get github.com/astaxie/beego # 增加文件 COPY test.go /root/go/src/myTest/ # 定制工作目录 WORKDIR /root/go/src/myTest/ # 对外端口 EXPOSE 8080 # 运行项目 ENTRYPOINT ["go","run","test.go"] #把sources.list和test.go文件放到这个目录中 #构建镜像 docker build -t go-test:v0.1 . #运行镜像 docker run -p 8080:8080 -itd go-test:v0.1 #访问镜像,查看效果
注意顺序:如果最后的端口开放和运行项目反了就启动不了了;最后这个运行项目是bash命令,且不能够被command覆盖,所以只能使用ENTRYPOINT。
docker-compose
docker-compose是一款管理docker的工具,可以批量操作docker。这款工具是用python开发的。
docker-compose是docker容器进行编排的工具,定义和运行多容器的应用,可以一条命令启动多个容器,使用Docker Compose不再需要使用shell脚本来启动容器。
简单来说,就是使用docker-compose自身的命令来批量操作容器。操作步骤:
- 安装docker-compose工具
- 编写docker-compose配置文件
- 使用命令启动docker-compose
安装
# 安装依赖工具
sudo apt-get install python-pip -y
# 安装编排工具
sudo pip install docker-compose
# 查看编排工具版本(可以用来检测是否安装好)
sudo docker-compose version
# 查看命令帮助
docker-compose --help
如下图所示,则表示docker-compose工具安装成功
示意图 |
---|
1555688569313.png |
YAML文件格式
docker-compose的配置文件格式是yaml或者yml(后缀为yaml或者yml)。
YAM格式文件的基本规则:
- 大小写敏感
- 使用缩进表示层级关系
- 进制使用tab缩进,只能使用空格表达缩进
- 缩进长度没有限制,只要元素对齐就表示这些元素是同一层级
- 使用
#
注释 - 字符串可以不适用引号标注,建议用双引号标注字符串
YAM格式文件的3中数据类型:
-
map-散列表
# 使用冒号标注键值对,相同缩进的键值对属于同一个map 例: age:12 name:zhangsan # age和name属于同一个map
-
list-数组
# 使用连字符表示数组中的元素,相同缩进的元素属于同一个数组 例: - a - b - c - d # a和b属于同一个数组,c和d属于数组b
-
scalar-纯量
# 字符串 "hello" world # 布尔值 true false # 整型 12 # 浮点型 3.14 # null 在YML中使用~来表示空
数据类型示例:
# 例1
Websites:
YAML:yaml.org
Ruby:ruby-lang.org
Python:python.org
Perl:use.perl.org
# 使用json表示:整体上是一个map,这个map的结构如下:
# {"Website":{"YAML":yaml.org","Ruby":"ruby-lang.org","Python":"python.org","Perl":"use.perl.org"}}
# 例2
languages:
- Ruby
- Perl
- Python
- C
# 使用json表示,整体上是一个map,该map结构如下:
# {"languages":["Ruby","Perl","Python","C"]}
# 例3
-
- Ruby
- Perl
- Python
-
- C
- C++
- Java
# 使用json表示,整体上是由两个元素组成的数组,这两个元素也是数组,各有3个字符串元素,具体结构如下:
# [["Ruby","Perl","Python"],["C","C++","Java"]]
# 例4
-
id:1
name:zhangsan
-
id:2
name:lisi
# 使用json表示,整体上是两个map组成的数组,具体结构如下:
# [{"id":1,"name":"zhangsan"},{"id":2,"name":"lisi"}]
YML配置文件的关键字
在docker-compose的配置文件中,有三大部分(是不用缩进的):
-
version
表示docker-compose的版本,一般情况写成固定的2就行,例:
version: '2' # docker-compose的版本
-
services
表示每个docker启动后的在linux中的服务,服务名自定义,每个服务名代表一个docker容器,例:
# common.yaml version: '2' # docker-compose的版本 services: # 服务 webapp environment: # 环境变量 RACK_ENV: development SHOW: 'true' SESSION_SECRET: docker-compose
# test.yaml
services: # 服务
web: # 服务名, 自己起的, 每个服务器名对应一个启动的容器
image: nginx:latest # 容器是基于那个镜像启动 的
container_name: myweb # 容器名字
extends: # 继承自另一个服务
file: common.yml
service: webapp
command: /urs/local/nginx -g daemon off # docker容器启动之后, 执行的命令
networks: # 容器启动之后所在的网络
- network1
ports: # 端口映射
- "6789:8080"
- 12:12 -> yaml解析的时候如果60以下, 解析会有问题
# 6789: 宿主机端口, 8080: 容器端口
extra_hosts:
- "host1:162.242.195.82"
- "host2:50.31.209.229"
# host1: 主机名(域名)
# 域名解析:
- 先查本地hosts文件
- 本地的dns缓存
- 通过dns服务器查询
sql:
image: mysql
volumes:
- /home/test:/root/workdir
ports:
- 9999:3306
networks:
- network1
- network2
depend_on:
- web
- redis
redis:
image: redis
volumes:
- /home/go/redis.conf:/redis/redis.conf
ports:
- 8989:6379
networks:
- network1
多学一招:设置临时的环境变量就是直接是变量名=变量值
,然后在该终端关闭之前都可以用$变量名
来得到变量值。变量名习惯是大写。
-
networks
声名容器会用到的网络,例:
networks: network1: # 网络名 driver: bridge # 网络驱动, 可以省略 network2 # 网络名 driver: bridge
sevices关键字中的具体描述:
-
image
image 则是指定服务的镜像名称或镜像 ID。如果镜像在本地不存在,Compose 将会尝试拉取这个镜像。
-
command
使用 command 可以覆盖容器启动后默认执行的命令。
-
container_name
容器启动之后的名字
-
depends_on
一般项目容器启动的顺序是有要求的,如果直接从上到下启动容器,必然会因为容器依赖问题而启动失败。例如在没启动数据库容器的时候启动了应用容器,这时候应用容器会因为找不到数据库而退出,为了避免这种情况我们需要加入一个标签,就是 depends_on,这个标签解决了容器的依赖、启动先后的问题。例:
version: '2' services: web: image: ubuntu depends_on: # 表示在启动web服务之前,先启动db和redis服务 - db - redis redis: image: redis db: image: mysql
-
evironment
environment 和 Dockerfile 中的 ENV 指令一样会把变量一直保存在镜像、容器中。
-
ports
映射端口的标签。
使用HOST:CONTAINER格式或者只是指定容器的端口,宿主机会随机映射端口,例:# docker run -p 宿主机端口:容器端口 ports: - "3000" # 宿主机的端口是随机分配的, 3000是容器开发的对外端口 // -P - "8000:8000" -> 一般这样写就可以 - "127.0.0.1:8001:8001"
-
volumes
挂载一个目录或者一个已存在的数据卷容器,可以直接使用 [HOST:CONTAINER] 这样的格式,或者使用 [HOST:CONTAINER:ro] 这样的格式,后者对于容器来说,数据卷是只读的,这样可以有效保护宿主机的文件系统。
Compose的数据卷指定路径可以是相对路径,使用 . 或者 .. 来指定相对目录。例:# docker run -v /home/go:/xxx # 宿主机或容器的映射路径如果不存在, 会自动创建出来 volumes: # 这是宿主机目录, 容器的映射目录会自动创建,但是不知道在容器中是哪个目录 - /var/lib/mysql -> 不推荐使用 # 按照绝对路径映射 - /opt/data:/var/lib/mysql # 相对路径的映射 # ./ 目录是docker-compose配置文件所在的目录 # 如果是相对路径, ./是必须要写的, ../ - ./cache:/tmp/cache # 指定容器中对文件的操作权限, 默认rw - /home/go/configs:/etc/configs/:ro # 文件映射 - ../temp/a.txt:/temp/b.sh
-
volumes_from
从其它容器或者服务挂载数据卷,可选的参数是 :ro或者 :rw,前者表示容器只读,后者表示容器对数据卷是可读可写的。默认情况下是可读可写的。例:
# docker run --volumes_from 数据卷容器名 volumes_from: - service_name # 服务名 - service_name:ro - container:container_name # 挂载容器 - container:container_name:rw
-
extends
这个标签可以扩展另一个服务,扩展内容可以是来自在当前文件,也可以是来自其他文件,相同服务的情况下,后来者会有选择地覆盖原有配置。
-
networks
加入指定网络,格式如下:
services: some-service: networks: - some-network - other-network
关于这个标签还有一个特别的子标签aliases,这是一个用来设置服务别名的标签,例如:
services: some-service: networks: some-network: aliases: - alias1 other-network: aliases: - alias2
-
extra_hosts
添加主机映射, 最终被添加到hosts文件中 /etc/hosts,例:
extra_hosts: - "somehost:162.242.195.82" - "otherhost:50.31.209.229"
docker-compose的命令
配置文件的命名自定义,但是推荐使用docker-compose.yaml或docker-compose.yml
服务
服务的启动:
docker-compose -f 配置文件路径 up [-d]
# -d参数表示以守护进程的方式运行
服务的关闭:
docker-compose -f 配置文件路径 down
查看服务:
docker-compose -f 配置文件路径 ps
如果配置文件的名字是docker-compose,那么在服务的所有命令都可以不加-f参数
容器
启动某个容器:
docker-compose start 服务名
关闭某个容器:
docker-compose stop 服务名
删除某个容器:
docker-compose rm 服务名