1、简介
2、安装
3、常用命令
4、数据管理
5、Dockerfile
6、网络连接
7、仓库管理
8、图形界面
9、镜像原理
10、Compose
11、Swarm
12、拓展
Docker 是基于Go语言开发的一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
对于开发和运维人员来说,最希望的效果就是一次创建或者配置后,可以在任意地方、任意时间让应用正常运行,对于算法研究人员来说,可能不同的算法需要不同版本的软件,那么在同一个环境中就会存在冲突,docker 的环境隔离就可以很方便的用于不同环境的配置。具体来说,docker优势主要有以下几个方面:
快速交付和部署
使用docker,开发人员可以使用镜像快速构建一套标准的开发环境;开发完成后,测试和运维人员可以使用完全相同的环境部署代码,只要是开发测试过的代码就可以确保在生产环境无缝运行。docker可以快速创建和删除容器,实现快速迭代。
高效的资源利用
运行docker容器不需要额外的虚拟化管理程序的支持,docker是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低。
轻松的迁移和扩展
docker容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、服务器等,同时支持主流的操作系统发行版本,这种兼容性让用户可以在不同平台间轻松的迁移应用。
简单的更新管理
使用Dockerfile生成镜像的方式,只需要小小的配置修改,就可以替代以往大量的更新工作,所有的修改都以增量的方式进行分发和更新,从而实现自动化且高效的容器管理。
2010年几个年轻人成立了一个做PAAS平台的公司dotCloud。起初公司发展的不错,不但拿到过一些融资,还获得了美国著名孵化器YCombinator的支持,后来微软谷歌亚马逊这样的大厂商也纷纷加入PAAS平台,竞争十分激烈,dotCloud举步维艰。
2013年可能是公司发展的不是很好,工程师又不想自己的努力付之东流,于是他们决定将他们的核心技术开源。这项技术就是docker。当时docker的功能就是将linux容器中的应用代码打包,可以轻松的在服务器之间进行迁移。
无心插柳柳成荫,docker技术风靡全球,于是dotCloud公司改名为docker Inc,并全面投入到docker的开发之中。
2014年 Docker 发布1.0版本,2015年Docker 提供 Docker-machine,支持 windows 平台。
在此期间,Docker 项目在开源社区大受追捧,同时也被业界诟病的是 Docker 公司对于 Docker 发展具有绝对的话语权,比如 Docker 公司推行了 libcontainer 难以被社区接受。
为了防止 Docker 这项开源技术被Docker 公司控制,在几个核心贡献的厂商,诸如 Redhat,谷歌的倡导下,成立了 OCI 开源社区。
OCI 开源社区旨在于将 Docker 的发展权利回归社区,当然反过来讲,Docker 公司也希望更多的厂商安心贡献代码到Docker 项目,促进 Docker 项目的发展。
于是通过OCI建立了 runc 项目,替代 libcontainer,这为开发者提供了除 Docker 之外的容器化实现的选择。
OCI 社区提供了 runc 的维护,而 runc 是基于 OCI 规范的运行容器的工具。换句话说,你可以通过 runc,提供自己的容器实现,而不需要依赖 Docker。当然,Docker 的发行版底层也是用的 runc。在 Docker 宿主机上执行 runc,你会发现它的大多数命令和 Docker 命令类似,感兴趣的读者可以自己实践如何用 runc 启动容器。
至2017年,Docker 项目转移到 Moby 项目,基于 Moby 项目,Docker 提供了两种发行版,Docker CE 和 Docker EE, Docker CE 就是目前大家普遍使用的版本,Docker EE 成为付费版本,提供了容器的编排,Service 等概念。Docker 公司承诺 Docker 的发行版会基于 Moby 项目。这样一来,通过 Moby 项目,你也可以自己打造一个定制化的容器引擎,而不会被 Docker 公司绑定。
Docker的主要思想就是集装箱思想,就是说当我们把项目从一个地方搬到另一个地方,难免会丢失某些配置或数据导致项目无法运行,而有个集装箱,就可以把项目的所有东西都丢到集装箱里面,这样自然不会出现项目移植到另一个环境就跑不起来的情况。
Docker还简化了部署过程,Docker运输东西有一个超级码头(仓库),任何地方需要货物都由鲸鱼先送到超级码头,然后再由鲸鱼从超级码头把货物送到目的地去。比如把A电脑的项目搬到B电脑上,那么直接执行一条命令让鲸鱼将货物搬过来即可。
同时,由于Docker是一个集装箱,那么我们自然可以设定它的大小,这样就不会因为死循环疯狂吃内存,导致全部崩盘,最多只是集装箱出问题罢了。
镜像(image):镜像就好比一个模板,可以通过这个模板创建多个容器,通过镜像可以创建多个容器。
容器(container):Docker利用容器技术独立运行一个或者一个组应用,可以把容器理解成一个简陋版的Liunx系统。
仓库(repository):仓库就是存放镜像的地方,分为公有仓库和私有仓库,类似于maven的中央仓库和私服。
官网:https://www.docker.com/
官方文档:https://docs.docker.com/get-started/
Docker Hub: https://hub.docker.com/
# Linux服务器一台,且上面的安装的Centos系统内核要不低于3.10。你可以通过 uname -r 来查询当前内核版本。
uname -r
# 清除系统残余项
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine
#安装下载Docker依赖的工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
#添加阿里云的软件源
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#更新yum缓存(为了保证能更新和下载需要的服务:如docker)
sudo yum makecache fast
#安装Docker(Docker版本分为CE(社区免费版)和EE(企业版,安全CE)
sudo yum -y install docker-ce
#启动Docker
sudo systemctl start docker
#查看Docker是否成功
docker info
sudo docker run hello-world
#设置开机自启
systemctl enable docker
#移除Docker-ce服务
yum remove docker-ce
#删除Docker依赖项
rm -rf /var/lib/docke
docker info #显示docker的系统信息,包括镜像和容器的数量
docker version #docker的版本信息
docker 命令 --help #帮助命令,查看命令的用法
docker images
各个选项说明:
#可选项,可组合使用
-a, --all # 列出全部镜像
-q, --quiet # 只列出镜像id
我们可以从 Docker Hub 网站来搜索镜像,Docker Hub 网址为: https://hub.docker.com/
也可以使用docker search
命令来搜索镜像
docker search 镜像名
#可选项
-f, --filter #通过搜索来过滤
[root@VM-12-10-centos ~]# docker search mysql -f=STARS=3000 #搜索STARS大于3000的
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 12693 [OK]
mariadb MariaDB Server is a high performing open sou… 4871 [OK]
各个选项说明:
docker pull 镜像名
docker rmi -f 镜像的id或者名称 #删除一个镜像
docker rmi -f $(docker images -aq) #删除全部镜像
当我们从 docker 镜像仓库中下载的镜像不能满足我们的需求时,可以通过以下两种方式对镜像进行更改。
这里进行第一种方式的讲解,关于Dockerfile创建镜像,将在以后的章节进行讲解。
#这里先这样写,下一节将会讲解容器的相关知识
[root@VM-12-10-centos ~]# docker run -itd --name tomcat01 tomcat #创建容器
f57398ba1d274a542ac518f58d35b363b21827a1c9d9f9c4ec02abfc78ee80fa
[root@VM-12-10-centos ~]# docker ps #查看运行中的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f57398ba1d27 tomcat "catalina.sh run" 22 seconds ago Up 21 seconds 8080/tcp tomcat01
[root@VM-12-10-centos ~]# docker exec -it f57398ba1d27 /bin/bash #进入容器内部
root@f57398ba1d27:/usr/local/tomcat#
# 由于是精简版的tomcat,很多命令是无法执行的,这里安装一些东西,将tomcat改造成我们需要的tomcat
# 执行更新命令:
apt-get update -y
# 执行下载 iproute2 命令:
apt install -y iproute2
#执行下载 iputils-ping 命令,让ping命令生效:
apt install iputils-ping
#下载完毕后,退出容器
Ctrl+P+Q
#进行提交
docker commit -m="hello.java" -a="thl" f57398ba1d27 tomcat:v1
各个参数说明:
查看镜像
[root@VM-12-10-centos ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat v1 747d384aa76e 24 hours ago 705MB
tomcat latest c795915cb678 13 days ago 680MB
测试
#首先查看使用精简版tomcat创建的容器
[root@VM-12-10-centos ~]# docker run -itd --name simpletomcat tomcat #创建容器
daef93c8f774487a6134083a0bd748f0e6354cd4ecf039a0c2c37cca0c069d20
[root@VM-12-10-centos ~]# docker exec -it simpletomcat ip addr #查看该容器的ip
OCI runtime exec failed: exec failed: unable to start container process: exec: "ip": executable file not found in $PATH: unknown
#精简版是不支持命令的,接下来用我们自己的镜像来创建容器
[root@VM-12-10-centos ~]# docker run -itd --name mytomcat tomcat:v1 #创建容器
daef93c8f774487a6134083a0bd748f0e6354cd4ecf039a0c2c37cca0c069d20
[root@VM-12-10-centos ~]# docker exec -it mytomcat ip addr #查看该容器的ip
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
50: eth0@if51: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
docker tag <容器 ID> 用户名称、镜像源名:新的标签名
新建容器之前,必须要有镜像,如果没有镜像,直接创建容器,那么docker会自动帮我们到远程仓库拉取镜像,如果远程仓库没有就会报错。
docker run [可选参数] image 命令
#可选参数
--name="Name" #容器名称 如mysql1,mysql2,用来区分容器
-d #后台方式运行
-t #在新容器内指定一个伪终端或终端。
-i #允许你对容器内的标准输入 (STDIN) 进行交互。
-p #指定容器的端口 -p 8080:8080
-p ip:主机端口:容器端口
-p 主机端口:容器端口(常用)
-p 容器端口
-P #随机指定端口
-v #指定卷的路径
--volumes-from list #从指定容器装载卷
测试
[root@VM-12-10-centos ~]# docker images #查看镜像,这里只有mysql的镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.7 2a0961b7de03 10 days ago 462MB
[root@VM-12-10-centos ~]# docker run -it centos /bin/bash #运行并进入centos容器
Unable to find image 'centos:latest' locally #没有centos镜像
latest: Pulling from library/centos #这里在自动拉取
a1d0c7532777: Pull complete
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
[root@d176336c8383 /]# ls #这里已经进入了容器,ls列出查看目录
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@d176336c8383 /]# exit #退出容器
exit
[root@VM-12-10-centos ~]# cd / #已经回到主机,切换到根目录
[root@VM-12-10-centos /]# ls #查看主机的目录,发现与容器内部有些不同
bin boot data dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@VM-12-10-centos /]# docker images #查看镜像,多了一个centos镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql 5.7 2a0961b7de03 10 days ago 462MB
centos latest 5d0da3dc9764 8 months ago 231MB
#列出正在运行的容器
docker ps [可选参数]
#可选参数
-a #列出当前正在运行的容器和历史运行过的容器
-n=? #显示最近创建的容器,问号代表的是需要显示的条数,如 -n=1 -n=2等
-q #只显示容器的编号
输出详情介绍:
CONTAINER ID: 容器 ID。
IMAGE: 使用的镜像。
COMMAND: 启动容器时运行的命令。
CREATED: 容器的创建时间。
STATUS: 容器状态。
状态有7种:
1、created(已创建)
2、restarting(重启中)
3、running 或 Up(运行中)
4、removing(迁移中)
5、paused(暂停)
6、exited(停止)
7、dead(死亡)
PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。
NAMES: 自动分配的容器名称。
exit #退出容器且停止运行
Ctrl+D #退出容器且停止运行
Ctrl+P+Q #退出容器不停止运行
docker rm -f <容器 ID> #强制删除一个容器,如果不加 -f,则正在运行的容器无法删除
docker rm -f $(docker ps -aq) #删除全部容器
docker ps -a -q|xargs docker rm #删除全部容器
docker container prune #清理掉所有处于终止状态的容器
docker start <容器 ID> #启动容器
docker restart <容器 ID> #重启容器
docker stop <容器 ID> #停止正在运行的容器
docker kill <容器 ID> #强制停止当前容器
在大部分的场景下,我们希望 docker 的服务是在后台运行的,可以过 -d 指定容器的运行模式
docker run -itd --name centos-test centos /bin/bash
**注:**加了 -d 参数默认不会进入容器,想要进入容器需要使用指令 docker exec(下面会介绍到)。
在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:
#输入exit命令从容器退出,会导致容器的停止,但是Ctrl+P+Q不会,不过attach有些问题,有可能无法进入到容器内部
docker attach <容器 ID>
#输入exit命令从容器退出,不会导致容器的停止,更推荐使用
docker exec -it <容器 ID> /bin/bash
#将docker内的文件拷贝到主机上
docker cp <容器 ID>:容器内文件路径 主机路径
如果要导出本地某个容器,可以使用 docker export 命令。
docker export <容器 ID> > 文件
测试
#导出容器 daef93c8f774 快照到本地文件 tomcat.tar
[root@VM-12-10-centos ~]# docker export daef93c8f774 > tomcat.tar
[root@VM-12-10-centos ~]# ls
tomcat.tar
可以使用 docker import 从容器快照文件中再导入为镜像
docker import 快照文件路径 Repository:tag
测试
[root@VM-12-10-centos ~]# docker import tomcat.tar tomcat:v1.2
sha256:e9540b2102f62605925dc1ef7769a281277987c354c3f47a40c374f38ae71751
[root@VM-12-10-centos ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat v1.2 e9540b2102f6 8 seconds ago 694MB
tomcat v1 747d384aa76e 25 hours ago 705MB
tomcat v1.1 747d384aa76e 25 hours ago 705MB
此外,也可以通过指定 URL 或者某个目录来导入,例如:
docker import http://example.com/exampleimage.tgz example/imagerepo
#查看容器的进程信息
docker top <容器 ID>
#查看容器的元数据
docker inspect <容器 ID>
docker logs [可选参数] <容器 ID>
#可选参数
-f #日志格式
-t #显示时间戳
--tail #要显示的条数
测试
#示例,创建一个容器,并编写一段shell脚本,打印信息
docker run -itd centos /bin/sh -c "while true;do echo thl;sleep 1;done"
#查看
docker logs -ft aa460ba02cd0
docker logs -ft --tail=10 aa460ba02cd0
在生产环境中使用 Docker ,往往需要对数据进行持久化,或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作,容器中的数据管理主要有两种方式:
数据卷是一个可供一个或多个容器使用的特殊目录,它将主机操作系统目录直接映射进容器,它可以提供很多有用的特性:
docker run -it -v 主机目录:容器内目录 镜像 命令
-v 宿主机路径:容器内路径 #指定路径挂载
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
#拓展:
宿主机路径:容器内路径 : ro #只读
宿主机路径:容器内路径 : rw #可读可写
#如果是ro说明这个路径只能通过宿主机来操作,容器内部无法操作!
#数据卷
docker run -it --name="centos01" -v /home/test:/home centos /bin/bash
#查看容器信息
docker inspect centos01
在容器中的home目录创建hello.java
,在主机的home/test
文件夹中会出现hello.java
,反之亦然。
[root@VM-12-10-centos ~]# docker volume ls #查看挂载的卷
DRIVER VOLUME NAME
[root@VM-12-10-centos ~]# docker run -d -P -v /etc/nginx nginx #匿名挂载
c95a97b3f6f133b18365ea0a0791782b931c087aae3a42d1a7aadd8dd7bdffc1
[root@VM-12-10-centos ~]# docker volume ls #再次查看挂载的卷
DRIVER VOLUME NAME
local 5773f76bb70293141701976761b29c1db3caf627e10679c6587b0270f2b5677e #卷名称是匿名的,不易分辨
[root@VM-12-10-centos ~]# docker inspect 5773f76bb70293141701976761b29c1db3caf627e10679c6587b0270f2b5677e
[
{
"CreatedAt": "2022-06-08T18:45:21+08:00",
"Driver": "local",
"Labels": null,
#宿主机映射的数据卷路径
"Mountpoint": "/var/lib/docker/volumes/5773f76bb70293141701976761b29c1db3caf627e10679c6587b0270f2b5677e/_data",
"Name": "5773f76bb70293141701976761b29c1db3caf627e10679c6587b0270f2b5677e",
"Options": null,
"Scope": "local"
}
]
[root@VM-12-10-centos ~]# docker run -d -P -v juming-nginx:/etc/nginx nginx #具名挂载
81f727086d846ba719a564ae1e934fbfbd68dcdf5dd49036a855560d63b354e1
[root@VM-12-10-centos ~]# docker volume ls #查看卷
DRIVER VOLUME NAME
local 5773f76bb70293141701976761b29c1db3caf627e10679c6587b0270f2b5677e
local juming-nginx #这里是有名字的,更方便分辨卷
[root@VM-12-10-centos ~]# docker volume inspect juming-nginx #查看信息
[
{
"CreatedAt": "2022-06-08T18:49:19+08:00",
"Driver": "local",
"Labels": null,
#宿主机映射的数据卷路径
"Mountpoint": "/var/lib/docker/volumes/juming-nginx/_data",
"Name": "juming-nginx",
"Options": null,
"Scope": "local"
}
]
docker run -d -P -v nginx01:/etc/nginx:ro nginx #只读
docker run -d -P -v nginx02:/etc/nginx:rw nginx #可读可写
如果需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但是它的目的是专门提供数据卷给其他容器挂载。
#创建一个数据卷容器,这种挂载的方式是匿名挂载
docker run -itd --name="t1" -v /docker01 centos
#与数据卷容器绑定
docker run -itd --name t2 --volumes-from t1 centos
#由于t2和t1绑定了,所以t3和t2绑定也可以将数据卷挂载上去
docker run -itd --name t3 --volumes-from t2 centos
其实数据卷容器就是容器绑定数据卷的一种方式,比如我们创建t1容器,然后创建t2容器,数据卷挂载的路径指定t1挂载的路径,这样t1和t2就绑定了同一个数据卷,它们之间就能实现数据共享。而数据卷容器就是让我们在创建t2容器的时候,不必指定t1数据卷的挂载路径,而是直接指定t1容器就可以了,这避免了我们在指定路径时可能会写错路径的情况。
前面提到过构建镜像的方式有两种,一种是从已经创建的容器中更新镜像,并且提交这个镜像,另一种就是Dockerfile了。Dockerfile是用来构建docker镜像的文件,是命令脚本,通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个一个的命令,每个命令都是一层。
每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的,执行从上到下顺序执行,#
表示注释。
指令 | 作用 |
---|---|
FROM | 指定基础镜像 |
MAINTAINER | 指定镜像的维护者信息,一般为名字+邮箱 |
RUN | 镜像构建时需要执行的命令 |
ADD | 增加文件,会自动解压 |
WORKDIR | 设置当前工作目录 |
VOLUME | 挂载主机目录 |
EXPOSE | 暴露端口,注意这里指仅暴露容器的端口,并不会将容器端口与宿主机端口映射。也就是说在使用docker run的时候仍然需要继续使用-p进行端口映射,换言之,EXPOSE更多的作用在于给Dockerfile开发者提供开发端口的提示提示作用 |
CMD | 指定容器启动的时候需要执行的命令,注意CMD只有最后一个命令会生效,可被替换 |
ENTRYPOINT | 指定容器启动时需要运行的命令,注意ENTRYPOINT命令可以追加命令,在docker run时,追加命令会生效 |
ONBUILD | 当构建一个被继承Dockerfile,这个时候就会运行ONBUILD指令 |
COPY | 类似ADD命令,将文件拷贝到镜像中 |
ENV | 构建的时候设置环境变量 |
FROM centos
MAINTAINER thl
ENV JAVA_HOME /usr/local/jdk_1.8/
WORKDIR /usr/local
RUN yum install -y vim
RUN yum install -y net-tools
EXPOSE 80
CMD echo $JAVA_HOME
CMD echo "---end---"
CMD /bin/bash
docker build -f dockerfile -t mycentos:1.0 .
参数说明:
如果失败了,将dockerfile第一行改为:FROM centos:7即可。因为Centos8不再维护,2022年1月31日,Centos团队从官方镜像中移除了CentOS8的所有包。
[root@VM-12-10-centos ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 1.0 95f3a2a6b615 2 minutes ago 601MB
[root@VM-12-10-centos ~]# docker run -it mycentos:1.0 #可以发现这里运行时没有追加 /bin/bash
[root@f409fdad662f local]# pwd
/usr/local
进入容器后,输入pwd会发现目录是==/usr/local==,输入clear
发现能够清屏了。
语法
docker history 镜像名或镜像ID
测试
[root@VM-12-10-centos ~]# docker history mycentos:1.0
IMAGE CREATED CREATED BY SIZE COMMENT
95f3a2a6b615 6 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin… 0B
dd3bc424a7ce 6 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B
bf2e41afb395 6 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B
2e8082a693b5 6 minutes ago /bin/sh -c #(nop) EXPOSE 80 0B
75d2a8078746 6 minutes ago /bin/sh -c yum install -y net-tools 171MB
bfd024d04b70 6 minutes ago /bin/sh -c yum install -y vim 226MB
cf1a5b2b0118 8 minutes ago /bin/sh -c #(nop) WORKDIR /usr/local 0B
c53da378573d 8 minutes ago /bin/sh -c #(nop) ENV JAVA_HOME=/usr/local/… 0B
fd3d5b1df6d9 8 minutes ago /bin/sh -c #(nop) MAINTAINER thl
eeb6ee3f44bd 9 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 9 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 9 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
可以看到指令是一条一条执行的
#CMD
#dockerfile-cmd
FROM centos
CMD ["ls","-a"]
#编译
docker build -f dockerfile-cmd -t cmd .
#在后方追加-l,会报错
[root@VM-12-10-centos home]# docker run f3c1c8b34c72 -l
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "-l": executable file not found in $PATH: unknown.
ERRO[0000] error waiting for container: context canceled
#ENTRYPOINT
#dockerfile-entrypoint
#编译
docker build -f entry -t enrty .
#在后方追加-l,正确显示
[root@VM-12-10-centos home]# docker run a3cc724a748e -l
total 56
drwxr-xr-x 1 root root 4096 Jun 9 06:41 .
drwxr-xr-x 1 root root 4096 Jun 9 06:41 ..
-rwxr-xr-x 1 root root 0 Jun 9 06:41 .dockerenv
lrwxrwxrwx 1 root root 7 Nov 3 2020 bin -> usr/bin
drwxr-xr-x 5 root root 340 Jun 9 06:41 dev
drwxr-xr-x 1 root root 4096 Jun 9 06:41 etc
drwxr-xr-x 2 root root 4096 Nov 3 2020 home
lrwxrwxrwx 1 root root 7 Nov 3 2020 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 2020 lib64 -> usr/lib64
drwx------ 2 root root 4096 Sep 15 2021 lost+found
drwxr-xr-x 2 root root 4096 Nov 3 2020 media
drwxr-xr-x 2 root root 4096 Nov 3 2020 mnt
drwxr-xr-x 2 root root 4096 Nov 3 2020 opt
dr-xr-xr-x 133 root root 0 Jun 9 06:41 proc
dr-xr-x--- 2 root root 4096 Sep 15 2021 root
drwxr-xr-x 11 root root 4096 Sep 15 2021 run
lrwxrwxrwx 1 root root 8 Nov 3 2020 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Nov 3 2020 srv
dr-xr-xr-x 13 root root 0 Jun 8 11:52 sys
drwxrwxrwt 7 root root 4096 Sep 15 2021 tmp
drwxr-xr-x 12 root root 4096 Sep 15 2021 usr
drwxr-xr-x 20 root root 4096 Sep 15 2021 var
使用Dockerfile构建镜像时,也可以挂载数据卷。
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "===end==="
CMD /bin/bash
构建镜像
docker build -f dockerfile -t thl-centos:1.0 .
使用镜像创建一个容器,不挂载数据卷,然后查看目录。
这个卷是匿名挂载,与主机有一个关联的目录
使用dockerfile创建镜像的时候,可以设定挂载卷,但是这个卷是匿名的,通常情况下是在创建容器的时候挂载卷,因为这样更加灵活。
到目前为止,我们的所有Docker容器都是公开端口并绑定到本地网络接口的,这样可以把容器里的服务在本地Docker宿主机所在的外部网络上(比如 docker run -p 81:80 nginx, 就是把容器里的80端口公开给宿主机的81端口)公开。除了这种用法外,还有一种就是内部网络。
在安装Docker时,会在宿主机上创建一个新的网络接口,名字是docker0,网络接口docker0是一个虚拟的以太网桥,它专门用于连接容器和本地宿主机网络,每个Docker容器都会在这个接口上分配一个IP地址,接口本身的地址是172.17.0.1,子网掩码是255.255.0.0,也就是说Docker会默认使用172.17.X.X作为子网地址。
#运行一个容器
docker run -d -P --name tomcat01 tomcat
#由于是精简版的tomcat,很多命令是无法执行的,需要安装一些东西
# 执行一下更新命令:
apt-get update -y
# 执行下载 iproute2命令:
apt install -y iproute2
#执行下载 iputils-ping命令,让ping命令生效:
apt install iputils-ping
#下载完需要的东西之后,可以将其提交为镜像,之后创建的容器就可以使用自己改造过后的镜像创建tomcat容器了
#查看容器 ip addr
[root@VM-12-10-centos ~]# docker exec -it tomcat01 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
#看看是否能ping通容器
[root@VM-12-10-centos ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.036 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.050 ms
#按照上面的步骤再创建一个容器tomcat02,然后尝试能否ping通tomcat01
docker exec -it tomcat02 ping 172.17.0.2
--link
是一项比较古老的技术,在实际中不建议使用
[root@VM-12-10-centos ~]# docker run -d --name="tomcat03" -P --link tomcat01 tomcat:v2
ef4d2ecf0ae9e64ae41048032cb32f8e0806eb16d968bca5a8e1ff79c69f48cc
[root@VM-12-10-centos ~]# docker exec -it tomcat03 ping tomcat01 #直接ping容器名就可以ping通
PING tomcat01 (172.17.0.2) 56(84) bytes of data.
64 bytes from tomcat01 (172.17.0.2): icmp_seq=1 ttl=64 time=0.101 ms
#查看docker网络
docker network ls
#测试
[root@VM-12-10-centos ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
253c657ee003 bridge bridge local
7383cb2c4079 host host local
b5e4aa2a23b3 none null local
#解析
bridge:桥接docker(默认)
host:和宿主机共享网络
none:不配置网络
container:容器网络连通(用的少,局限大)
#自定义网络
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
测试
#创建两个容器,指定我们自定义的网络
[root@VM-12-10-centos ~]# docker run -d -P --name tomcat-mynet-01 --net mynet tomcat:v2
f6d15950a157f0824eed450a45e58a26204b52b307691176a0500f47705c5f21
[root@VM-12-10-centos ~]# docker run -d -P --name tomcat-mynet-02 --net mynet tomcat:v2
8c22d4633a19d478a5073eb4c3b6d1b5827e83b3768095f03638e95ceae56b09
#使用ip地址去ping,可以ping通
[root@VM-12-10-centos ~]# docker exec -it tomcat-mynet-01 ping 192.168.0.3
PING 192.168.0.3 (192.168.0.3) 56(84) bytes of data.
64 bytes from 192.168.0.3: icmp_seq=1 ttl=64 time=0.078 ms
#使用容器名去ping,也可以ping通
[root@VM-12-10-centos ~]# docker exec -it tomcat-mynet-01 ping tomcat-mynet-02
PING tomcat-mynet-02 (192.168.0.3) 56(84) bytes of data.
64 bytes from tomcat-mynet-02.mynet (192.168.0.3): icmp_seq=1 ttl=64 time=0.049 ms
结论
把一个容器连接到一个网络上
#测试打通tomcat01和mynet
docker network connect mynet tomcat01
#连通之后就是将tomcat01放到了mynet网络下
#官网:一个容器两个ip
#测试
[root@VM-12-10-centos ~]# docker exec -it tomcat01 ping tomcat-mynet-01
PING tomcat-mynet-01 (192.168.0.2) 56(84) bytes of data.
64 bytes from tomcat-mynet-01.mynet (192.168.0.2): icmp_seq=1 ttl=64 time=0.084 ms
#tomcat01是docker0网卡下的,但是可以连通tomcat-mynet-01,就是因为tomcat01打通了mynet
#但是与tomcat01相连的tomcat02却无法连通tomcat-mynet-01,因为它没有打通mynet
[root@VM-12-10-centos ~]# docker exec -it tomcat02 ping tomcat-mynet-01
ping: tomcat-mynet-01: Name or service not known
端口映射并不是唯一把 docker 连接到另一个容器的方法。
docker 有一个连接系统允许将多个容器连接在一起,共享连接信息。
docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息。
仓库(Repository)是集中存放镜像的地方。目前 Docker 官方维护了一个公共仓库 Docker Hub。大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。当然不止 docker hub,国内如阿里云,腾讯云也有镜像仓库。
在 https://hub.docker.com 免费注册一个 Docker 账号。
#登录
docker login
#退出
docker logout
用户登录后,通过docker push
命令将镜像推送到 Docker Hub。以下命令中的 username 请替换为你的 Docker 账号用户名。
#修改镜像的tag,这一步至关重要的,原因和Git push代码一样,为了安全起见,在Docker Hub无法确定操作者的情况下,是无法完成push操作的。将tag改为用户名开头,则可以避免出现denied: requested access to the resource is denied异常
docker tag mycentos:0.1 username/mycentos:0.1
#发布到Docker Hub中
docker push username/mycentos:0.1
使用腾讯的容器服务,其实与Docker Hub是一样的。首先找到容器服务。
如果是第一次,这里会让我们授予权限,同意即可
授权之后,找到镜像仓库
开启服务
继续授权
新建一个实例
这里进行测试,所以使用免费的。
会让注册一个容器账号,类似于Docker Hub账号
要新建命名空间
接下来就是创建镜像仓库了
点击进入t1仓库
按照它的指引操作即可
#上传
sudo docker login --username=100025691051 ccr.ccs.tencentyun.com
sudo docker tag 9b9cb95443b5 ccr.ccs.tencentyun.com/thlyj/t1:v0.1
sudo docker push ccr.ccs.tencentyun.com/thlyj/t1:v0.1
#拉取
sudo docker pull ccr.ccs.tencentyun.com/thlyj/t1:v0.1
以下是两种docker图形化界面。
docker的镜像是由多个只读的文件系统叠加在一起形成的。当启动一个容器的时候,docker会加载这些只读层并在这些只读层的上面(栈顶)增加一个读写层。这时如果修改正在运行的容器中已有的文件,那么这个文件将会从只读层复制到读写层。该文件的只读版本还在,只是被上面读写层的该文件的副本隐藏。当删除docker,或者重新启动时,之前的更改将会消失。在Docker中,只读层及在顶部的读写层的组合被称为Union File System(联合文件系统)。
联合文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。
联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。
bootfs(boot file system) 主要包含bootloader和kernel, bpotloader 主要是引导加载kernel,当我们加载镜像的时候,会通过bootloader加载kernal,Docker镜像最底层是bootfs,当boot加载完成后整个kernal内核都在内存中了,bootfs也就可以卸载,值得注意的是,bootfs是被所有镜像共用的,许多镜像images都是在base image(rootfs)基础上叠加的
rootfs (root file system),在bootfs之 上.包含的就是典型Linux系统中的/dev, /proc, /bin, /etc等标准目录和文件。rootfs就是 各种不同的操作系统发行版,比如Ubuntu, Centos等等 。
当我们运行一个新的容器的时候,实际上是在镜像分层的基础上新添加了一层:container layer(容器层)。之后所有容器运行时对文件系统产生的修改实际都只影响这一层。并且针对这一层所作的修改(写操作),在容器重启之后会全部丢失。所以说在使用docker的过程中,在需要修改运行时容器文件数据的时候,尽量去重新构建镜像而不是直接修改容器内文件。如果重构镜像解决不了的问题,使用数据卷。
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
Compose 使用的三个步骤:
#使用国内的地址下载,官方的下载太慢
curl -L https://get.daocloud.io/docker/compose/releases/download/v2.4.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
#授权
chmod +x /usr/local/bin/docker-compose
#查看是否安装成功,出现版本号就是安装成功
docker-compose --version
1、为项目创建一个目录
mkdir composetest
cd composetest
2、部署的项目,这里以官网的python为例,这个简单的python项目仅只有两个文件
app.py
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
requirements.txt
flask
redis
3、接下来需要一个dockerfile文件来创建镜像
Dockerfile
# syntax=docker/dockerfile:1
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
这告诉 Docker:
/code
flask
requirements.txt
.``.
flask run
4、创建docker-compose.yml
文件,定义服务
version: "3.9"
services:
web:
build: .
ports:
- "8000:5000"
redis:
image: "redis:alpine"
这个compose文件定义了两个服务:web
和redis
。
5、最好我们就可以启动项目了
docker-compose up
Compose 会拉取 Redis 镜像,为代码构建镜像,然后启动定义的服务。由于是从国外的网站进行下载镜像,所以会很慢,稍微等待一下即可。
6、启动完毕后,可在浏览器输入ip地址:8000服务项目了!这个项目的就是刷新页面计数。
7、按Ctrl+C
或者输入docker-compose down
停止应用程序。然后修改Compose文件。
version: "3.9"
services:
web:
build: .
ports:
- "8000:5000"
volumes:
- .:/code
environment:
FLASK_ENV: development
redis:
image: "redis:alpine"
修改过后,修改代码就无需重新运行了,类似于热部署。此模式应仅在开发中使用。
8、现在重新启动docker-compose up
,启动后访问浏览器,紧接着再修改app.py
文件,这个时候刷新,会发现浏览器打印的内容改变了,变成了我们修改的内容。
return 'Hello from Docker! I have been seen {} times.\n'.format(count)
9、其他命令
#后台启动项目
docker-compose up -d
#查看后台进程
docker-compose ps
#为服务运行一次性命令
docker-compose run web
#查看帮助
docker-compose --help
#如果使用后台启动服务,可用以下命令停止服务
docker-compose stop
#关闭所有内容,完全删除容器。
docker-compose down --volumes
3层配置,第一层是版本,第二层是服务,第三层是其他配置
如果项目出现问题,要重新部署
docker-compose up --build #重新构建
Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机。 Docker Swarm 提供了标准的 Docker API,所有任何已经与 Docker 守护程序通信的工具都可以使用 Swarm 轻松地扩展到多个主机。
支持的工具包括但不限于以下各项:
如下图所示,swarm 集群由管理节点(manager)和工作节点(work node)构成。
docker-machine
已经被官方弃用!不再维护更新!作为拓展知识,只需要知道有这么个东西就可以了!