Docker简介
docker是docker inc公司开源的一项基于Ubuntu LXC技术之上构建的应用打包运行时引擎。源代码托管在github上,完全基于Go语言开发并遵守Apache License2.0协议。Docker是一个解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。
docker技术解决的问题
- 复杂的环境配置:从各种操作系统环境到各种中间件以及应用环境。
- AWS的成功将开发者应用引导在云上,解决了硬件管理功能,然后软件配置和管理相关的问题依然存在。docker的出现可以帮助开发者扩展思路。
- 虚拟化手段的变化:云时代采用标配硬件来降低成本,采用虚拟化手段来满足用户按需分配的资源需求以及保证可用性和隔离性。然而无论是 KVM 还是 Xen,在 Docker 看来都在浪费资源,因为用户需要的是高效运行环境而非 OS,GuestOS 既浪费资源又难于管理,轻量级的 LXC 更加灵活和快速。
- 容器技术的便携性:LXC在linux2.6的内核里已经存在,但是其设计之初并非为云计算考虑,缺少标准化的描述手段和容器的可便携性,决定其构建出的环境难于分发和标准化管理。Docker就在这个问题上做出了创新。
Docker和传统虚拟机的不同之处
- 传统虚拟机技术是虚拟一套硬件后,在一个完整的操作系统上运行所需的应用程序。
- 容器内的应用进程直接运行在宿主的内核,容器内没有自己的内核且没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
- 每个容器之间互相隔离,每个容器都有自己的文件系统,容器之间进程不会互相影响,能区分资源。
Docker的基本组成
- 镜像
- 容器
- 仓库
从面向对象的角度来讲,Docker是利用容器Container独立运行一个或一组应用。容器就是一个虚拟化的运行环境,容器之间相互隔离。镜像是静态的定义,容器是镜像运行时的实体。仓库是集中存放镜像文件的场所。类似于github,maven仓库,存放各种jar包的地方。仓库分为公有和私有,最大的仓库是Docker Hub,存放了数量庞大的镜像用户下载。国内公开的仓库包括阿里云。
Docker的运行流程
- 用户使用Docker Client与Docker Daemon建立通信,并发送请求。
- Docker Daemon作为Docker架构中的主体部分,首先提供Docker Server的功能使其可以接受Docker Client请求。
- Docker Engine执行Docker内部的一系列工作,每项工作都是以一个Job的形式存在。
- Job运行过程中,如果需要镜像,就会从Docker Registry中下载镜像,并通过镜像管理驱动Graph driver将下载镜像以Graph的形式存储。
- 当需要为Docker创建网络环境时,通过网络管理驱动NetWork driver创建并配置Docker容器网络环境。
- 当需要限制用户指令或容器的运行资源时,通过Exec driver完成。
- Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作。
Docker安装
[参考官网](Install Docker Engine | Docker Documentation)
Docker 加速镜像
登录阿里云官网,选择容器镜像服务,点击镜像工具下的镜像加速器,然后选择自己的操作系统进行配置。
1. 安装/升级Docker客户端
推荐安装1.10.0以上版本的Docker客户端,参考文档docker-ce
2. 配置镜像加速器
针对Docker客户端版本大于 1.10.0 的用户
您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://w4zxu525.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
docker run命令
首先检查本机是否有该镜像,如果有以本地镜像为模板创建容器实例运行,否则就去Docker Hub上查找该镜像,Hub如果找到后,就下载到该镜像到本地,以该镜像为模板创建实例运行。如果Hub上没找到该镜像,就返回失败。
Docker与VM的对比
Docker | 虚拟机 | |
---|---|---|
操作系统 | 与宿主机共享OS | 宿主机上运行虚拟机OS |
存储大小 | 镜像小,便于存储和传输 | 镜像庞大 |
运行速度 | 无额外性能损失 | 操作系统额外的CPU,内存消耗 |
移植性 | 轻便,灵活,适用于Linux | 笨重,虚拟化技术耦合度高 |
硬件亲和力 | 面向开发者 | 面向硬件运维 |
部署速度 | 快速 | 较慢 |
Docker命令
启动类命令
- 启动docker:
systemctl start docker
- 停止docker:
systemctl stop docker
- 重启docker:
systemctl restart docker
- 查看状态:
systemctl status docker
- 开机启动:
sysetmctl enable docker
- 概要信息:
docker info
- 帮助文档:
docker --help
,docker 具体命令 --help
镜像命令
- 列出所有镜像:
docker images
- Repository:表示镜像的仓库源
- TAG :镜像版本号
- IMAGE ID:镜像ID
- CREATED:镜像创建时间
- SIZE:镜像大小
同一个镜像可以有多个版本,因此通过Repository:TAG来确定一个镜像。如果不指定TAG,默认使用最新版latest。
- 搜索镜像:
docker search [-- option] xxx
,可选参数:–limit 5表示只展示前5个镜像。
- 从远程仓库拉取镜像:
docker pull 镜像名称:TAG
- 删除镜像:
docker rmi 镜像ID
;强制删除多个镜像:docker rmi -f 镜像名1:TAG 镜像名2:TAG
;强制删除所有镜像:docker rim -f $(docker images -qa)
- 查看镜像所占空间:
docker system df
虚悬镜像:仓库名和标签都是的镜像。
容器命令
1、查看正在运行的容器:docker ps [option]
可选参数
-a:列出正在运行+历史运行过的容器
-l:显示最近创建的容器
-n:显示最近创建的n个容器
-q:静默模式,只显示容器id
2、新建+运行容器:docker run [OPTIONS] 镜像名称
option参数:-it返回交互界面 ;-d:后台运行,-p:本地映射端口;–name=xxx:指定容器名称,没有指定系统会随机生成。
3、退出容器
exit:停止容器并退出
ctrl+p+q:退出容器不停止运行
4、重启容器:docker restart 容器ID/容器名称:TAG
5、停止容器:docker stop 容器ID/容器名称:TAG
6、启动已停止的容器:docker start 容器ID/容器名称:TAG
7、强制停止容器:docker kill 容器ID/容器名
8、删除已停止的容器:docker rm 容器ID/容器名
9、查看容器日志:docker logs 容器ID
10、查看容器内部细节:docker inspect 容器ID
11、重新进入进入容器
-
docker exec -it 容器ID bashShell
-
docker attach 容器ID
attach和exec命令的两个区别:
- attach直接进入容器启动命令的终端,不会启动新的进程,用exit退出,会导致容器的停止。
- exec是在容器中打开新终端,并且可以启动新的进程,用exit退出,不会导致容器的停止。
12、docker容器下的文件复制到主机:docker cp 容器ID:容器路径 主机目录
13、导入导出容器,容器中的所有文件都会导出
导出容器:docker export 容器ID>文件名.tar
默认导出到当前目录下
导入容器:cat 文件名.tar|docker import - 镜像用户名/镜像名:镜像版本号
联合文件系统
UnionFS:union文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改,将修改作为一次次提交进行叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像,可以制作各种具体的应用镜像。它可以一次同时加载多个文件系统,但从表面看来,只能看到一个文件系统,联合加载会把各层文件系统迭加起来,这样最终的文件系统会包含所有底层文件和目录。
Docker镜像加载原理
docker的镜像实际上是由一层层的文件系统组成的,这种层级的文件系统叫做联合文件系统(UnionFS)。
bootfs主要包含bootloader和kernel,bootloader主要是引导加载kernel,Linux刚启动的时候会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs,这一层与我们典型的Linux/Unix系统是一样的,包含加载器和内核。当boot加载完成之后,整个内核都在内存中了,此时内存的使用权已经交给bootfs转交给内核,此时系统也会卸载bootfs。
根文件系统rootfs在bootfs之上,包含的就是典型Linux系统中的/dev,/proc、/bin,/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,如ubuntu,centos等。
镜像分层的目的就是为了共享资源,提高复用性。
Docker镜像层都是只读的,容器层是可写的,当容器启动的时候,一个新的可写层被加载到镜像的顶部。这一层叫做容器层,容器层之下都叫镜像层。
Docker镜像commit
docker commit提交容器副本后将成为一个新的镜像。
docker commit -m="提交的信息" -a="作者" 容器ID tartget_image_name:[版本号]
Docker挂载主机目录访问如果出现cannot open directory Permission denied
,解决办法是在挂载目录后加一个--privileged=true
参数。使用这个参数后容器内的用户才是root权限,否则是普通用户权限。
容器卷
容器数据卷就是存在于容器中的目录或文件。由docker挂载到容器,但是不属于联合文件系统,因此能够绕过联合文件系统提供一些持久存储或共享数据的特性。设计的目的就是数据的持久化,独立于容器的生命周期,因此Docker不会在容器删除时删除挂载的数据卷。
特点:
- 数据卷可以在容器之间共享和重用数据
- 数据卷中的更改可以直接实时生效
- 数据卷中的更改不会影响镜像
- 数据卷的生命周期一直持续到没有容器使用它为止。
数据卷映射命令:docker run -it --privileged=true -v /宿主机绝对路径:/容器内目录 镜像名
当容器被停止之后,如果主机映射的目录下有修改文件操作,当容器再次启动之后,docker也会将这些变化同步给刚刚启动的容器。两者的数据最终保持同步。-v参数后面可以设置多个主机和容器路径的映射。
默认情况下,设置–privileged=true,容器在自己的目录下拥有读写权限。ro:只读权限。设置只读权限:--privileged=true -v /xxx/zzz:/yyy/www:ro
不同容器之间数据卷的继承:docker run -it --privileged=true --volume-from 父容器名 --name 子容器名 镜像名
子容器数据卷继承父容器卷之后,主机,父容器,子容器三者之间的数据卷下面的数据都将保持数据共享和同步。
Dockerfile
Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。当我们需要定制自己额外的需求时,只需在 Dockerfile 上添加或者修改指令,重新生成 image 即可,省去了敲命令的麻烦。
构建自定义镜像的三个步骤
- 编写Dockerfile文件
- docker build命令构建镜像
- docker run 容器实例
Dockerfile文件基础内容
- 每条保留字指令必须为大写字母,且至少跟随一个参数
- 指令按照从上到下,顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层并对镜像进行提交
执行的大致流程
- docker从基础镜像开始运行一个容器
- 执行一条指令并对容器做出修改
- 执行类似docker commit的操作提交一个新的容器
- docker基于提交的镜像运行新的容器
- 依次执行dockerfile中的指令,直到执行完毕
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则设计部署与运维,三者缺一不可,合力充当Docker体系的基石。
Dockerfile常用保留字
- CMD:指定容器启动后要干的事,需要注意的是,CMD以后的命令会覆盖当前指令。CMD是在docker run时运行,RUN是在docker build时运行。
- ENTRYPOINT:用来指定容器启动时要运行的命令,他和CMD的区别是,他定义的指令不会被后面run指令覆盖。并且字儿写命令行参数会传给ENTRYPOINT指令指定的程序。
- EXPOSE:暴露实例的端口,例如
EXPOSE 8080
- VOLUME:容器的数据卷,用于数据持久化工作
- FROM:基础镜像是基于哪个镜像的,例如基于ubuntu:
FROM ubuntu
,必须在Dockerfile第一行 - MAINTAINER:镜像的维护者姓名和邮箱地址
- RUN:可以运行shell格式和exec格式,RUN指令是在docker build时运行
- WORKDIR:创建容器实例后,默认用户进来的工作目录。例如:
WORKDIR /usr/local/tomcat
- USER:指定镜像以哪种用户执行,默认是root用户
- ENV:定义环境变量供后续其他指令使用
- ADD:将宿主机目录下的文件拷贝进镜像且会自动处理URL,解压压缩包。
- COPY:从构建上下文目录中<源路径>文件/目录复制到新的镜像内的<目标路径>。
COPY <src> <dest>
在Dockerfile所在的目录下执行命令,构建新的镜像:docker build -t 镜像名:TAG .
查看虚悬镜像:docker image ls -f dangling=true
删除虚悬镜像:docker image prune
Docker网络
docker启动成功后会产生一个名为docker0的虚拟网桥。
关于docker网络的常用命令。
- 查看所有网络:
docker network ls
- 查看网络源数据:
docker network inspect 网络名字
- 删除网络:
docker network rm 网络名字
- 创建网络:
docker network create 网络名
- 移除所有未使用的网络:
docker network prune
- 断开某个容器的网络连接:
docker network disconnect 容器ID
- 连接某个容器的网络:
docker network connect 容器ID
docker网络可以使容器之间互相关联和通信,容器变动时可以通过服务名提供网络通信,不必关注IP和端口。
网络模式
-
bridge模式(虚拟网桥):为每个容器分配、设置IP等,并将容器连接到一个docker0,默认就是该模式
-
host模式:容器使用宿主机的IP和端口。
-
none:容器有独立的Network namespace,但并没有对其进行网络设置,分配veth pair和网桥连接,IP等。
-
container:新建的容器不会创建自己的网卡和配置自己的IP而是和一个指定的容器共享IP、端口范围等。
docker内部的容器实例之间的网络是会改变的,当一台实例宕机后,他原本所在的IP将会被取代。
Docker服务默认会创建一个叫做docker0的网桥,它在内核层联通了其他的王丽或虚拟网卡,这就将所有容器和本地主机都放在同一个物理网络。Docker默认指定了docker0接口的IP地址和子网掩码,让主机和容器之间可以通过网桥互相通信。
bridge模式,网桥docker0创建一对虚拟设备接口一个叫veth,另一个叫eth0,两者成对匹配。每个容器实例内部也有一块网卡,接口叫做eth0。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zNjRipyR-1643372503289)(https://gitee.com/bailefolen/typora-pictures/raw/master/typora-pictures/img/image-20220127165553281.png)]
host模式示例图
容器不会获得独立的名称空间,而是和宿主机共用一个名称空间,IP,Port。
以host网络模式启动实例:docker run -d -p 8080:8080 --network host --name tomcat 镜像ID/镜像名
none模式下,并不会为Docker容器进行任何网络配置,也就是说,这个Docker容器没有网卡,IP,路由等信息,只有本地地址。
配置命令:docker run -d -p 8080:8080 --network none --name tomcate8080 镜像ID/镜像名
container模式下,容器A依赖容器B的网络配置,当容器A关闭时,容器B的网络模式就会变为none,只有local配置,没有网卡配置。
容器B依赖容器A的配置命令:docker run -d --network container:alpineA --name alpineB 镜像ID/镜像名 /bin/sh
Docker Compose
docker-compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。Compose允许用户通过一个单独的docker-compose.yml模板文件来定义一组相关联的应用容器为一个项目。可以容易的用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose解决了容器与容器之间如何管理编排的问题。
安装Docker Compose
[参考官网](Install Docker Compose | Docker Documentation)
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
#测试安装成功
docker-compose --version
(可选【创建软链接】)sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
使用步骤
- 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
- 使用docker-compose.yml定义一个完整的业务单元,安排好应用中的各个容器服务。
- 执行
docker-compose up
命令,完成整个应用的一键部署
常用命令
docker-compose -h
查看帮助docker-compose up
启动所有docker-compose服务docker-compose up -d
启动所有服务并在后台运行docker-compose down
停止并删除容器、网络、卷、镜像docker-compose exec yml文件中的容器ID
进入容器实例内部``docker-compose exec docker-compose.yml文件中写的服务id /bin/bash`docker-compose ps
查看当前docker-compose编排过运行的所有容器docker-compose top
展示当前docker-compose编排过的容器进程docker-compose config
检查配置docker-compose config -q
检查配置,有问题才输出docker-compose restart
重启服务docker-compose start
启动服务docker-compose stop
停止服务docker-compose logs 服务id
查看服务输出日志
docker-compose.yml案例
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}