docker是什么?
docker 🐳 作为容器化技术的代言人。 由于应用程序的运行被隔离在了一个独立的运行环境之中,这个独立的运行环境就好似一个容器,包裹住了应用程序,这就是容器技术名字的由来。 而docker相比于虚拟机有几个特点:
-
启动速度快
-
更轻量
docker内部组件
Namespace 命名空间,提供一种对进程隔离的一种机制,例如进程,网络、挂载等资源
ControlGroups 资源控制组的作用就是控制计算机资源的,与namespace不同CGroups 主要做的是硬件资源的隔离。
Union File System 联合文件系统,支持将不同位置的目录挂载到同一个虚拟文件系统,形成一种分层的模型
docker的核心组成
在docker体系中,有四个不得不介绍的,它们分别是: 镜像 ( Image ) 、 容器 ( Container ) 、仓库(Registry) 。
镜像
镜像是一个特殊的文件系统,可以理解为一个只读包,甚至可以理解为类与实例中的类。 每个镜像可能有多个镜像组成。 它是一种层级结构,每次对镜像的修改,docker都会铸造成一个镜像层。
容器
容器可以理解为类与实例中的实例,镜像是死的是不可变的。 而容器却是一个活的空间。 每次启动容器都是通过镜像启动一个新的容器。
仓库
远端中的镜像仓库,例如npm仓库
安装docker
在安装 docker 之前,我们先来了解一下docker的版本定义,这有利于我们在之后的开发中选择和使用合适的 Docker 版本。 对于docker来说,它分为两个系列:
-
社区版(ce)
-
企业版(ee)
社区版和企业版的区别无非就是企业版收费,提供额外的服务。
sudo yum install yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo
https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce 复制代码
不出意外的话 输入docker -v出现图下页面就代表成功了
docker的运行过程
docker的运行过程可以简单的理解为,从远端仓库中拉取合适的镜像到本地-->通过镜像创建容器-->启动容器
使用docker
docker search (查看远端库的镜像)
跟 npm search 类似,用来查看远端中的镜像,例如:
docker search ubuntu复制代码
会出现如上图,他有几个参数:
NAME | 镜像名字 |
DESCRIPION |
描述 |
STARS |
星星数量 |
OFFICIAL |
是否官方版本 |
AUTOMATED |
是否是自制的 |
docker pull (拉取镜像)
从远端仓库中拉取镜像到本地,这里以 centos 镜像为例
docker pull centos
复制代码
等到拉取成功后会出现下图所示:
当你不指定任何标签的时候,docker会默认拉取最新的tag,指定拉取 : + tag 例如 : docker pull centos:7 。 每一个镜像都是由一组64位长度的hash码组成,这种组成的方式保证了全球的唯一性。
docker images(查看镜像)
从远端拉取镜像成功后我们可以通过docker images 来列出本地所有的镜像
docker images
复制代码
如图下所示:
这边的image id 为12位和上方说的64位长度并不冲突,只是官方为了显示在控制台上好看一些。 将后方的位数省略了。
docker create (创建容器)
如果说镜像是个类,那么我们需要创建一个实例来让我们操作。 通 过
docker create centos
复制代码
来创建一个centos的容器,创建成功后会生成一个64位的hash值,如图下:
如果当你本地没有centos的镜像时候,会默认从远端仓库中的拉取对应的版本。 我们还可以通过 --name 来指定容器的别名 。
docker ps (查看容器)
通过docker ps可以查看当前所有正在运行的容器,但是由于上方容器没有运行,在执行操作时,需要在后面加一个 -a 参数。 代表所有容器。
docker ps -a
复制代码
docker start stop reset(启动/停止/重启容器)
通过 docker create 创建的容器,是处于 Created 状态的,其内部的应用程序还没有启动,所以我们需要通过 docker start 命令来启动它。
docker start 8c784b9b2118复制代码
通过 docker start + 容器id 来启动容器,如果给容器配置了别名,也可以通过别名来启动容器。 启动容器后通过 docker ps 。 如图下所示:
你会发现空空如也。 这是为什么呢,执行 docker ps -a
你会发现容器处于 Exited 状态。 这是因为如果容器内部没有进程正在运行,那么容器在 start 之后会停止。 如果存在进程的容器,例如nginx,mysql,你在启动后就会变成up状态。
docker run (创建并启动容器)
docker run 命令是 docker create 命令和 docker start 命令的合成,可是说是我们最常用的命令之一。 docker run 命令有很多参数,这里我例举一些常用的参数
- d |
后台运行容器,并返回容器ID |
- i | 以交互模式运行容器,通常与 -t 同时使用; |
- p |
端口映射,格式为: 主机(宿主)端口:容器端口 |
- t |
为容器重新分配一个伪输入终端,通常与 -i 同时使用 |
- v |
绑定数据卷 |
--name | 为容器指定一个名称 |
--net | 指定容器的网络连接类型 |
举个例子
docker run -p 80:80 -v nginx-html:/usr/share/nginx/html -d --name nginx nginx:latest复制代码
使用镜像 nginx:latest,以后台模式启动一个容器,将容器的 80 端口映射到主机的 80 端口,将容器的/usr/share/nginx/html目录映射到主机目录下的docker中的nginx-html数据卷中
。
并取名为nginx。
可以看到容器的状态变成了up。
每个docker容器和我们宿主机之间存在隔离关系,假设有一个nginx服务,内部容器监听的端口号是80,这时候如何将外面访问宿主机80端口号的时候,能够访问到nginx服务呢? 所以 我们需要作出映射通过 -p 将宿主机上的80端口和 nginx 端口 进行映射 。 -v 将宿主机中的目录挂载到容器的目录中 ,便于以后数据的备份 和防止容器删除后数据的丢失。 网络和数据卷会在后文有专门提到。
docker exec (在运行的容器中执行命令)
很多时间,我们需要的操作并不仅仅是按镜像所给出的命令启动容器而已,我们还会希望进一步了解容器或操作容器,这时候最佳的方式就是让我们进入到容器了。 这里以上方nginx容器为例。docker exec -it nginx bash
复制代码
你会发现前缀变成一串容器的hash了,说明你已经成功进入的容器内部。 这里我是以bash的方式进去,当然你也可以以其他的交互方式进入。 -it 命令和上方的 docker run 中参数一样,在run中 代表着创建一个新的容器并启动并进入容器内部 。
docker rmi? (删除容器或者镜像)
docker rm 容器id复制代码
docker rmi 镜像id 复制代码
需要注意的是,如果容器正在运行中,需要先将容器停止后方能删除。
docker inspect (获取容器/镜像的元数据)
docker inspect [容器id/镜像id]
复制代码
通过上述命令可以获取容器或者镜像的相关信息,如图
包含端口号映射情况,数据卷挂载情况,网络情况等,反正只要想看容器或者镜像的具体信息时候,敲这个命令准没错。
docker save load (导出镜像/导入镜像)
将容器导出成一个tar文件 -o 指定为指定文件中。
docker save -o nginx.tar [镜像id]
复制代码
导入镜像
docker load -i nginx.tar
复制代码
docker export import (导出容器/导入容器)
将容器导出成一个tar文件
docker export -o nginx.tar [容器id]
复制代码
导入容器,这里需要注意的是,使用 docker import
并非直接将容器导入,而是将容器运行时的内容以镜像的形式导入。 所以导入的结果其实是一个镜像,而不是容器。
docker import nginx.tar
复制代码
docker cp (用于容器与主机之间的数据拷贝)
在主机目录下创建一个abc.txt文件
将目录下的abc.txt文件移到容器中的/data目录下
docker cp ./abc.txt a175b4a2fd94:/data
复制代码
进入容器内部
docker exec -it a175b4a2fd94 bash
复制代码
会发现/data目录下存在了abc.txt文件,反之,容器内容的文件或者目录也可以复制到主机内,只要将两者调换顺序即可
docker cp a175b4a2fd94:/data /data/
复制代码
其他命令
docker logs |
获取容器的日志 |
docker port |
查看容器映射端口情况 |
docker volume ls | 列出当前已经创建的数据卷 |
docker history |
查看镜像的创建历史 |
docker diff |
检查容器里文件结构的更改 |
docker kill |
杀掉一个运行中的容器 |
docker login |
登陆远端镜像仓库 |
docker push |
将本地镜像上传到远端仓库 |
可以去捣鼓捣鼓看看,把命令都敲个遍,玩不下去就删容器,删镜像。
制作镜像
当公共仓库中的镜像不能满足我们的需求时,或者对镜像进行个性化的定制时,我们需要制定出自己的镜像,方面以后经常性的使用。
通过docker commit制作镜像
假设我现在在nginx镜像构建出的一个容器中新建了一个abc.txt文件,那我如何在每次构建nginx镜像时都有这个abc.txt文。 这时直接将这个容器制作成镜像就可以解决。 具体命令如下
docker commit -m'我的nginx' -a'yalewan' a175b4a2fd94 mynginx:1.0
复制代码
效果如下图所示
执行docker im ages,你会发现多出来了一个镜像
-m | 镜像提交的信息 |
-a |
提交镜像的作者 |
-p |
在commit时,将容器暂停。 |
通过Dockerfile制作镜像
Dockerfile 是 Docker 中用于定义镜像自动化构建流程的配置文件,能够明确的给定 Docker 镜像的制作过程。 假设这边我们以一个node项目为例(项目在宿主机中的nodeapp目录中,基于koa2中的项目 )如图:
-
编写dockerfile
dockerfile具有以下几个参数
FROM |
继承的镜像文件 |
COPY |
拷贝数据 |
WORKDIR |
工作路径 |
RUN |
编译打包阶段运行命令 |
EXPOSE |
暴露的端口号 |
CMD |
容器运行阶段的命令 |
在nodeapp目录同级新建一个dockerfile文件,没有后缀名
FROM node # 基于node镜像
COPY ./nodeapp /nodeapp # 将nodeapp目录下d的文件移到容器中
WORKDIR /nodeapp # 工作目录nodeapp,类似移到nodeapp目录中
RUN npm install # 安装依赖
EXPOSE 3000 # 因为容器是隔离的,所以需要暴露端口 复制代码
新建完成后大家可以看一下我现在的目录结构,
在home目录下执 行
docker build -t nodeapp .
复制代码
-t 表示镜像的名字,不要忘记后面的 . ,dockerfile文件的相对路径, . 表示在当前目录下。 运行结果如下
等到安装完毕后,查看镜像,会发现多出一个nodeapp的镜像
创建并启动容器,同时进入到容器内部,容器中已经存在了我们的node项目
docker run -p 3000:3000 -it nodeapp bash
复制代码
npm start 启动nodeapp,并且浏览器访问
修改D ocker file 在最后增加一句
CMD npm start复制代码
复制代码
删除容器重新启动一遍,现在我们连启动的一步也省略了。 看到这边,相信你也对docker有了一定的认识,但相信我这仍然不是最佳选择,继续往下 读 。
数据卷
因为容器内部的文件系统是随着容器内部的生命周期所创建和移除的,并且容器隔离,我们很难从外部获得或者操作容器内部文件中的数据。 所以docker为了解决这个问题,提出了三种文件系统的挂载方式,分别为: Bind Mount 、 Volume 和 Tmpfs Mount 。
Volume
volumes 是docker管理宿主机文件系统的一部分,在 /var/lib/docker/volumes 目录 下,当你创建一个数据卷的时候,会默认放在 volumes 目录。 创建命令
docker volume create nginx-html
复制代码
可以通过 docker volume ls 查看
通过 docker volume inspect nginx-html 来查看具体信息
我们来创建一个新的nginx容器来和数据卷进行挂载,命令如下图
docker run -d --name nginx -v nginx-html:/usr/share/nginx/html nginx
复制代码
挂载成功后我们进入宿主机中
cd /var/lib/docker/volumes/nginx-html/_data
复制代码
你会发现宿主机中的nginx-html目录中多了两个文件
同时我们进入到容器内部
你会发现容器内部的文件和挂载的那个目录文件是一样的,说明我们挂载成功了docker exec -it 7454e37763d0 bash复制代码
cd /usr/share/nginx/html 复制代码
当然,无论你在容器内部文件系统中,还是在挂载的docker volumes目录中增加或者修改文件,互相关联的另一个都会随之改变
Bind Mount
bind mount相对于volumn唯一的区别就是将容器内的目录映射到宿主机中的任意一个位置。
docker run -d -v /mnt:/mnt -name logs centos
复制代码
唯一区别的就是,volume对应的是文件名(nginx-html),而bindMount则是一个相对路径(/mnt)
Tmpfs Mount
Tmpfs Mount是临时挂载到系统内存中,存储不是永久的,会随着容器的停止而消失。 适用于不需要持久保存的数据。 挂载时需要用--tmpfs来指定。
docker run -d --name webapp --tmpfs /webapp/cache webapp:latest复制代码
网络
一个完整的项目可能存在很多容器,比如node,mysql,redis,webapp等,它们彼此之间可能存在通信问题,比如node容器如何连接mysql的服务等。 为此,docker提供了网络驱动。 常用的网络驱动有3种类型: Bridge Driver 、 Host Driver 、 None Driver
可以通过 docker network ls 来查看网络驱动
如果想看网络驱动的具体信息和对应的容器,使用 docker network inspect [网络驱动]
docker network inspect bridge
复制代码
如图下所示:
Bridge Driver
会在主机上创建一个虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。 如上图显示所示,bridge的ip地址都是以172.17开头显示。 不指定网络默认为bridge模式。
Host Driver
通过--net host来使用host模式,host模式是宿主机公用一个network,使用宿主机的IP和端口。
创建一个新的nginx3的容器,通过--net host来指定网络驱动
docker run -d --name nginx3 --network host nginx复制代码
启动完毕,进入到host详情,会发现多出了一个容器,并且没有ip地址,如图下:
None Driver
不为Docker容器进行任何网络配置。通过 --net none
创建自定义网络
docker network create -d bridge mynetwork复制代码
执行查看 d ocker network ls
容器之间的link
通常由于容器之前隔离,两个容器之间的网络是无法进行通信的,通常我们需要通过link来建立容器之间的连接。
docker run -d --name nodeapp --link mysql node复制代码
或者说两个容器同时加入自定义的网络中也是可行的
docker run -d --name mysql --network mynetwork mysql复制代码
docker run -d --name nodeapp --network mynetwork node 复制代码
docker-compose编排容器
往往一个完整的项目可能通过很多容器组成,为每个容器挂载网络,指定数据卷会变非常的麻烦,幸好docker-compose为我们解决了这个问题。 安装docker-compose。
sudo curl -L
"https://github.com/docker/compose/releases/download
/1.24.0/docker-compose-$(uname -s)-$(uname -m)"
-o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
复制代码
下面我以nginx容器为例
version: "3"
networks:
my-network:
driver: bridge
services:
nginx:
image: nginx
container_name: nginx
ports:
- 80:80
- 443:443
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./logs/nginx:/var/log/nginx
restart: always
networks:
- my-network复制代码
versi on |
版本 号 |
b uild | 从dockfile构建 |
image | 从哪个镜像构建 |
por ts | 映射的端口号 |
depends_on | 依赖 的 启动 顺序 |
volumes | 挂载 的 数据 卷 |
net works | 网络 |
restart | 重 启 |
通过 docker-compose up -d 启动容器 如果有重名的容器记得先删除哦!
你会发现容器已经创建完毕,当有很多个容器时,只要往下继续补充即可。 当然,容器编排技术不知docker-compose这一种,k8s也是一种不错的选则,这里就不在赘述了,有兴趣的话可以研究一下。
tips
-
如何镜像加速(从远端拉镜像国内会很慢)
# /etc/docker/daemon.json
{
"registry-mirrors": [
"https://dockerhub.azk8s.cn",
"https://reg-mirror.qiniu.com"
]
}
# 找到 /etc/docker/daemon.json文件,添加上述文件
# 如果没有该文件,创建一个即可
sudo systemctl daemon-reload
# 重启服务
sudo systemctl restart docker复制代码
感谢大家
1.如果文章对你有帮助,请动动你的小手指点个赞👍吧,你的赞是我创作的动力。
2.关注公众号「前端精英」! 不定期推送高质量文章哦。
来源:oschina
链接:https://my.oschina.net/u/4390903/blog/3225312