Docker基础知识学习
参考文献:Wolf_Coder
1,Docker介绍
1、容器虚拟化
容器( container-based )虚拟化方案,充分利用了操作系统本身已有的机制和特性,以实现轻量级的虚拟化(每个虚拟机安装的不是完整的虚拟机),甚至有人把他称为新一代的虚拟化技术, Docker 无疑就是其中的佼佼者
在一台服务器上同时运行上百个虚拟机,肯定会被认为是痴人说梦,而在一台机器上同时运行一千个 Docker 容器,这已成为现实
2、Docker 的目标:
Build,Ship and Run Any App,Anywhere— 即通过对应用组件的封装 (Packaging), 发布(Distribution), 运行(runing) 等生命周期的管理 , 达到应用组件级别的”一次封装 , 到处运行”。
3、docker的组成
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
一个完整的Docker有以下几个部分组成:
- Docker Client客户端(通过命令行或者其他工具使用 Docker SDK与 Docker 的守护进程通信)
- Docker Host主机(用于执行 Docker 守护进程和容器)
- Docker Image镜像(用于创建Docker容器模板)
- Docker Container容器(独立运行的一个或一组应用,是镜像运行时的实体)
- Docker Machine(简化安装的命令工具)
容器:
存储、运输工具
实现对容器内部的物品实现包含(实现了一个相对隔离的环境)
容器:模拟(虚拟)出一个相对隔离的空间
镜像:
用来创建容器的模版,放在镜像仓库中,例如nginx,redis,httpd等
2、Docker的特点
1、优点:
(1)启动快,资源占用小 , 资源利用高,快速构建标准化运行环境
(2)创建分布式应用程序时快速交付和部署,更轻松的迁移和扩展,更简单的更新管理
2、局限:
(1)Docker 是基于 Linux 64bit 的,无法在 windows/unix 或 32bit 的 linux环境下使用
(2)LXC 是基于 cgroup 等 linux kernel 功能的,因此 container 的 guest 系统只能是linux
(3)隔离性相比 KVM 之类的虚拟化方案还是有些欠缺,所有 container 公用一部分的运行库
(4)管理相对简单,主要是基于 namespace 隔离
(5)cgroup 的 cpu 和 cpuset 提供的 cpu 功能相比 KVM 的等虚拟化方案相比难以度量 ( 所以 dotcloud 主要是按内存收费 )
(6)docker 对 disk 的管理比较有限(docker磁盘存储在一个目录下)
(7)container 随着用户进程的停止而销毁, container 中的 log 等用户数据不便收集
3、docker与虚拟机的比较:
(1)启动快比虚拟机 , 可以秒级启动
(2)对资源占用小 , 宿主机上可运行千台容器
(3)方便用户获取 , 分布 , 和更新应用镜像 , 指令简单 , 学习费用低
(4)通过 Dockerfile 配置文件来灵活的自动创建和部署镜像 & 容器 , 提高工作效率
(5)Docker 除了运行其中应用外 , 基本不消耗其他系统资源 , 保证应用性能同时 , 尽量减小系统开销
docker与kvm的对比
kvm:
1. 虚拟机
2. 使用复杂
3. 启动过程相对慢(分钟)
4. 模版文件较大
5. 和物理完全隔离
6. 模拟的是一个完整系统,可以登录并实现管理
docker:
1. 直接虚拟出来一个用户空间
2. 使用简单
3. 启动非常块(秒级)
4. 模版文件很小(体积小)(容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包)
5. 在一定程度上和物理机隔离
6. 仅仅是模拟一部分用户空间,不方便管理
4、docker使用理由
(1)快速部署服务
(2)多租户
(3)实现隔离
(4)让一个主机运行多个容器
(5)提高开发效率
(6)简化配置过程
(7)实现软件的跨平台
5、docker的主要用途:
(1)提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。
(2)提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
(3)组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。
6、docker底层依赖的核心技术
(1)命名空间 (Namespaces):实现了容器键资源的隔离
(2)控制组 (Control Groups):主要用来对共享资源进行隔离、限制、审计等
(3)联合文件系统 (Union File System):控制为每一个成员目录设定只读 / 读写 / 写出权限
(4 ) Linux 虚拟网络支持:本地和容器内创建虚拟接口
3,Docker镜像
镜像(docker image) — Docker 运行容器之前需要本地存在镜像,若本能地不存在,那么 Docker 会找默认镜像仓库( Docker Hub 公共注册服务器中的仓科)下载,用户也可以通过配置使用自己的镜像库
docker镜像的分层结构:支持通过扩展现有镜像,创建新的镜像
分层的优势:(1)共享资源;(2)可写的容器层(copy-on-write)
docker镜像常用的命令:
docker search nginx #查看注册表中是否有nginx镜像
docker image pull nginx:latest #下载nginx镜像
docker images #查看本地镜像
docker commit container-name image-name #基于修改后的容器创建镜像
docker load -i nginx.``tar``.gz #导入nginx镜像
docker save -o nginx.tag.gz nginx:latest #导出nginx镜像
docker build -t centos:8 -f dockerfilePATH #基于dockerfile文件创建镜像
dcker inspect nginx #显示nginx镜像的详细信息
docker rmi nginx #删除镜像
docker push ip``/nginx``:v1 #推送镜像nginx到本地仓库
docker tag nginx:latest nginx:v1 #给镜像nginx标记标签v1
docker ``history` `nginx #查看镜像nginx的历史构建信息
Docker镜像分层
docker镜像的分层结构:支持通过扩展现有镜像,创建新的镜像
可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
1、分层结构的优势:
(1)共享资源:
有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
这时可能就有人会问了:如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如说修改 /etc 下的文件,这时其他容器的 /etc 是否也会被修改?
答案是不会!
修改会被限制在单个容器内。
这就是我们接下来要学习的容器 Copy-on-Write 特性。
(2)可写的容器层:
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。
只有容器层是可写的,容器层下面的所有镜像层都是只读的。
2、在容器层的操作及特性
镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。
(1)添加文件
在容器中创建文件时,新文件被添加到容器层中。
(2)读取文件
在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,打开并读入内存。
(3)修改文件
在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。
(4)删除文件
在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。
只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。
这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。
创建镜像的三种方法:
(1)基于修改后的容器创建:docker commit 命令
(2)基于本地模板导入
(3)基于 Dockerfile 文件创建
Dockerfile 中最常用的指令:
FROM:指定 base 镜像。
MAINTAINER:设置镜像的作者,可以是任意字符串。
COPY:将文件从 build context 复制到镜像。
COPY 支持两种形式:
COPY src dest #shell格式
COPY ["src", "dest"] #exec格式
注意:src 只能指定 build context 中的文件或目录。
ADD:与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar, zip, tgz, xz 等),文件会被自动解压到 dest。(自带解压缩功能)
ENV:设置环境变量,环境变量可被后面的指令使用。例如:
...
ENV MY_VERSION 1.3
RUN apt-get install -y mypackage=$MY_VERSION
...
EXPOSE:指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来。我们会在容器网络部分详细讨论。
VOLUME:将文件或目录声明为 volume。
WORKDIR:为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工作目录。
RUN:在容器中运行指定的命令,RUN 指令通常用于安装应用和软件包。
CMD:容器启动时运行指定的命令。
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。CMD 可以被 docker run 之后的参数替换。
ENTRYPOINT:设置容器启动时运行的命令,可让容器以应用程序或者服务的形式运行。
Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效。CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT。
docker的镜像仓库
仓库分为公共仓库和私有仓库
1、公共镜像仓库—Docker Hub
2、搭建本地的registry仓库
Docker Hub 虽然非常方便,但还是有些限制,比如:
(1)需要 internet 连接,而且下载和上传速度慢。
(2)上传到 Docker Hub 的镜像任何人都能够访问,虽然可以用私有 repository,但不是免费的。
(3)安全原因很多组织不允许将镜像放到外网。
解决方案就是搭建本地的 Registry。
(1) 运行registry容器
docker run -d -p 5000:5000 -v /test:/var/lib/registry registry:2
(2) 通过docker tag重命名镜像,使之与registry匹配
docker tag httpd 172.20.10.2:5000/httpd:v1
(3) 修改damon.json文件
在/etc/docker/daemon.json文件中添加:
”insecure-registries”:[“172.20.10.2:5000”]
(4) 重启docker
systemctl restart docker
(5) 上传镜像
docker push 172.20.10.2:5000/httpd:v1
(6) 从其他主机进行下载镜像
docker pull 172.20.10.2:5000/httpd:v1
3、部署harbor私有镜像库
(1)harbor和registry的比较
1)提供分层传输机制,优化网络传输
2)提供web界面,优化用户体验
3)支持水平扩展集群
4)良好的安全机制
5)harbor提供了基于角色的访问控制机制,并通过项目来对镜像进行组织和访问权限的控制。
(2)部署harbor
1)下载harbor包
wget https://storage.googleapis.com/harbor-releases/release-1.4.0/harbor-offline-installer-v1.4.0.tgz
2)解压包并进入目录
tar -zxvf harbor-offline-installer-v1.4.0.tgz -C /usr/local/
cd /usr/local/harbor
3)编辑配置文件
vim harbor.cfg
hostname = 192.168.11.8 #对外访问地址
ui_url_protocol = http #访问方式
max_job_workers = 3 #最大处理进程数
customize_crt = on #是否要启动自定义证书,如果ui_url_protocol = http不生效,如果是https才会生效
harbor_admin_password = Harbor12345 #admin用户的密码
4)执行安装文件
[root@master harbor]# ./install.sh
注意:容器名字不能有registry这个名字,否则脚本执行失败
5)修改访问地址
[root@master harbor]# vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://l10nt4hq.mirror.aliyuncs.com"],
"insecure-registries":["192.168.11.8"]
}
6)重启docker服务
[root@master harbor]# systemctl daemon-reload
[root@master harbor]# service docker restart
Redirecting to /bin/systemctl restart docker.service
7)在Linux下登录harbor
docker login 192.168.11.8
(3)上传镜像到harbor私有镜像仓库
1)本地镜像重新打tag
docker tag SOURCE_IMAGE[:TAG] reg.yunwei.com/learn/IMAGE[:TAG]
2)将重新打好tag的镜像上传到harbor镜像仓库
docker push reg.yunwei.com/learn/IMAGE[:TAG]
(4)harbor的启动和停止
进入到harbor目录下,拥有docker-compose.yml的文件目录下执行如下的命令启动和关闭:
docker-compose start
docker-compose restart
docker-compose stop
docker-compose rm
4、docker容器的操作
docker create -it IMAGE:LABEL #创建容器(并不是启动容器)
docker ps #查看所有处于开机状态的容器
docker ps -a #查看所有状态的容器
docker start CONTAINER_ID #启动容器
docker stop NAME/ID #终止容器
docker kill NAME/ID #终止容器
docker restart NAME/ID #重启容器
docker run -it IMAGE:LABEL /bin/bash #创建并运行一个容器,且直接进入容器里
docker run -<strong>d</strong>ti IMAGE:LABEL #以后台守护进程形态运行(-d参数)
docker -rm -f NAME/ID #删除指定容器
docker rm $(docker ps -aq) #一次性删除全部已经退出的容器
docker exec -it NAME/ID /bin/bash #进入容器(实在容器中打开新的终端,并且可以启动新的进程)
docker attach NAME/ID #直接进入容器(不启动新的进程)
docker export NAME/ID > nginxtest.tar #导出容器(导出一个已经创建的容器到文件,不管容器是否运行)
cat nginxtest.tar | docker import - test #将容器导入系统成为镜像
docker logs -f NAME/ID #查看容器日志
docker pause NAME/ID #暂停容器
docker unpause NAME/ID #取消暂停,继续运行容器
5、docker端口映射的四种方法(外网访问容器服务)
在启动容器的时候,如果不指定参数,在容器外部是没有办法通过网络来访问容器内部的网络应用和服务。当容器需要通信时,我们可以使用 -P (大) &&-p (小)来指定端口映射。
1、将容器中的一个端口映射成宿主机中的一个随机端口
docker run -d -P httpd #P大写
2、将容器中的一个端口映射成宿主机中的一个端口
docker run -d -p 1234:80 httpd
3、将容器中的一个端口映射成宿主机中的一个特定网卡上的随机端口
docker run -d -p 10.220.5.13: :80 httpd
4、将容器中的一个端口映射成宿主机中的一个特定网卡上的一个端口
docker run -d -p 10.220.5.13:80:80 httpd
6、Docker存储
6.1,Docker存储资源类型
用户在使用 Docker 的过程中,势必需要查看容器内应用产生的数据,或者需要将容器内数据进行备份,甚至多个容器之间进行数据共享,这必然会涉及到容器的数据管理
(1)Data Volume (数据卷)
(2)Data Volume Dontainers — 数据卷容器
数据卷 是一个可供一个或多个容器使用的特殊目录,实现让容器中的一个目录和宿主机中的一个文件或者目录进行绑定。数据卷 是被设计用来持久化数据的,对于数据卷你可以理解为NFS中的哪个分享出来的挂载点,指宿主机共享的目录。
主要有如下的功能和特性:
1. 容器中数据的持久存储
2. 容器间的资源共享
3. 容器的迁移(分布式)
4. 对数据卷的修改会立马生效
5. 对数据卷的更新,不会影响镜像
6. 数据卷默认会一直存在,即使容器被删除 (注意docker自主管理的会被删除,容器删除前一定要对数据卷进行备份)
6.2,数据卷Volume
Data Volume 本质上是 Docker Host 文件系统中的目录或文件,使用类似与 Linux 下对目录或者文件进行 mount 操作。数据卷可以在容器之间共享和重用,对数据卷的更改会立马生效,对数据卷的更新不会影响镜像,卷会一直存在,直到没有容器使用
1、功能和特性
容器中数据的持久存储;容器间资源共享;容器的迁移(分布式);对数据卷的修改会立马生效;对数据卷的更新不会影响镜像;数据卷默认会一直存在,即使容器被删除。
2、数据卷Volume共享方式(3种)
(1)Bind mount volume**:用户需要明确指定容器中的目录和宿主机中的哪个目录进行绑定
docker run -it -v /ren:/data/ busybox
(2)Docker Management Volume**:docker daemon自行管理将容器中的目录和宿主机中的哪个目录进行绑定
docker run -it -v /data/ busybox
(3)基于一个现有容器实现多个容器之间文件共享
docker run -it --volume-from ren1(启动的容器) busybox [提前启动一个容器]
3、volume生命周期管理
(1)备份
因为volume 实际上是 host 文件系统中的目录和文件,所以 volume 的备份实际上是对文件系统的备份
(2)恢复
volume 的恢复也很简单,如果数据损坏了,直接用之前备份的数据拷贝到 /ren 就可以了。
(3)迁移
如果我们想使用httpd,那就涉及到数据迁移,方法是:
1) docker stop 当前容器;
2) 启动新版本容器并mount原有volume(docker run -d -v /ken:/var/www/html httpd) 这里要确认新版本的默认数据路径是否发生改变
(4)销毁
对于 docker managed volume,在执行 docker rm 删除容器时可以带上 -v 参数,docker 会将容器使用到的 volume 一并删除,但前提是没有其他容器 mount 该 volume,目的是保护数据,非常合理。
如果删除容器时没有带 -v 呢?这样就会产生孤儿 volume。可用docker volume ls 查看。如果想批量删除孤儿 volume,可以执行:docker volume rm $(docker volume ls -q)
7、docker网络
docker 网络从覆盖范围可分为单个 host 上的容器网络和跨多个 host 的网络
docker 目前提供了映射容器端口到宿主主机和容器互联机制来为容器提供网络服务,在启动容器的时候,如果不指定参数,在容器外部是没有办法通过网络来访问容器内部的网络应用和服务的
docker 安装时会自动在host上创建三个网络,我们查看一下docker网络:
[root@ren8 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
5ada5821d5d1 bridge bridge local
011f63e62210 host host local
12362c774cf8 none null local
1、docker的四种网络模式
(1)bridge模式:docker网络隔离基于网络命名空间,在物理机上创建docker容器时会为每一个docker容器分配网络命名空间,并且把容器IP桥接到物理机的虚拟网桥上。
(2)none模式:此模式下创建容器是不会为容器配置任何网络参数的,如:容器网卡、IP、通信路由等,全部需要自己去配置。
(3)host模式:此模式创建的容器没有自己独立的网络命名空间,是和物理机共享一个Network Namespace,并且共享物理机的所有端口与IP,并且这个模式认为是不安全的。
(4)container模式:此模式和host模式很类似,只是此模式创建容器共享的是其他容器的IP和端口而不是物理机,此模式容器自身是不会配置网络和端口,创建此模式容器进去后,你会发现里边的IP是你所指定的那个容器IP并且端口也是共享的,而且其它还是互相隔离的,如进程等。
2、自定义网络
除了none,host,bridge这三个自动创建的网络,用户也可以根据业务需要创建user-defined 网络。
创建命令:
docker network create --driver bridge ren
创建网段时指定—subset和—gateway参数:
docker network create –driver bridge –subnet 172.21.0.0/16 --gateway 172.21.0.1 ren1
容器使用新定义的网络:
docker run –it –network=ren1 busybox
指定分配IP:
docker run -it –network=ren1 –ip=172.121.0.7 busybox
3、容器间通信
容器之间可通过 IP,Docker DNS Server 或 joined 容器三种方式通信。
(1) 通过IP通信:处于同一网段的容器间可以通信;如果两个容器处于不同网段,可以通过给一个容器添加另一个容器所处网段的网卡,命令为:
docker network connect ren1 container1(现有容器)
(2) Docker DNS server通信:通过 IP 访问容器虽然满足了通信的需求,但还是不够灵活。因为我们在部署应用之前可能无法确定 IP,部署之后再指定要访问的 IP 会比较麻烦。对于这个问题,可以通过 docker 自带的 DNS 服务解决。方法很很简单,在启动容器时给容器命名就可以,访问直接ping容器名即可。但要注意:使用 docker DNS 有个限制:只能在 user-defined网络中使用
(3) joined容器:joined 容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息。实现如下:先启动一个名为web1的容器,然后再创建busybox容器并通过—network=container:web1 指定jointed容器为web1。这时busybox和web1的网卡mac地址与IP完全一样。
joined 容器非常适合以下场景:
1) 不同容器中的程序希望通过 loopback 高效快速地通信,比如 web server 与 app server。
2) 希望监控其他容器的网络流量,比如运行在独立容器中的网络监控程序。
4、容器与外界交互
(1).容器访问外部世界:只要宿主机可以访问外网,默认容器时可以访问外网的;
(2).外部世界访问容器:通过端口映射来。
8、docker容器监控
1、自带的监控命令:ps、top、stats
2、weave scope监控:Weave Scope 的最大特点是会自动生成一张 Docker 容器地图,让我们能够直观地理解、监控和控制容器。还可以监控多主机,只需在主机上安装weave scope。