docker 复习笔记

安装文档:https://docs.docker.com/engine/install/[官网文档]

docker 心得

图片.png
Figure 1. 图片.png

所有的技术诞生都是为了解决某一个问题!

docker 的诞生的意义

将目标应用以及其依赖的环境进行统一打包成一个镜像,使得在任何环境下都操作这个镜像即可,不必考虑环境配置等其他问题。

目前常见开发部署流程为:开发环境→测试环境→生产环境,甚至还有其他的环境。以一个java应用为例,依赖某个版本jdk,当开发人员开发完成后,需要部署到测试环境,那么测试环境也需要安装对应版本的jdk,测试完成后,需要部署到生产,生产环境也要先安装对应版本的jdk,那么每当出现一个新环境,那么都需要安装一遍jdk,并且保证版本一致,如果java的应用依赖不止jdk,还有其他应用,例如tomcat、mysql、redis等等,那么每个环境都需要进行相应的部署,并且应用本身以及其依赖的应用版本发生变化时,那么每个环境也要相应的进行调整,这就会导致每个环境都会做重复的事情。所以能不能一次性交付一个完整的应用,包含其所有的依赖,不同环境只需要运行一个应用即可,这样就减少很多重复工作,做到一次打包,多处运行。因此docker出现了,从它的图标也可知晓,一个docker镜像包含很多个集装箱,每个集装箱都相当于是一个环境依赖,一次性将所有的依赖统一打包成一体。

图片.png
Figure 2. 图片.png

总结下:使用docker之前,各个环境都必须单独的部署或者降级、升级服务,使用docker后,所有的服务都在开发阶段处理并统一打包成docker镜像,不同的环境只需要拉去docker镜像即可。

虚拟化技术

图片.png
Figure 3. 图片.png

VM(VMware)在宿主机器、宿主机器操作系统的基础上创建虚拟层、虚拟化的操作系统、虚拟化的仓库,然后再安装应用;

Container(Docker容器),在宿主机器、宿主机器操作系统上创建Docker引擎,在引擎的基础上再安装应用。

docker 和虚拟化技术的区别
  • 传统虚拟化技术,虚拟化硬件,启动一个完整的系统,然后在这个系统上面安装和运行软件,docker容器则是在宿主机上直接运行,没有自己的内核,也没有虚拟化硬件

  • 每个容器间相互隔离,每个容器内都有自己的文件系统,互不影响。

  • VM 占用内存以及磁盘更大,这是因为它完全是虚拟出一个全新的系统

  • VM 启动速度慢,因为它是一个完整的操作系统

  • docker 的集成性优于VM

docker 的目标

  • 缩短开发到测试部署,再到上线的周期,应用更快的部署和交付

  • 更便捷的升级和扩缩容

  • 易于移植

  • 易于构建,可随时修改容器中的环境

  • 启动快

  • 容器之间相互隔离

  • 同一台宿主机中可以运行多个容器,并且能充分利用服务器资源

docker 的基本组成

图片.png
Figure 4. 图片.png

概览

命令流程示意图
图片.png
Figure 5. 图片.png
  • Images – 镜像相关命令 – rmi 移除镜像 – tag 标签 – history 进行制作历史

  • Host

  • Container

  • Files

  • Dockfile

  • Registry

  • Engine

分层结构
图片.png
Figure 6. 图片.png
查看docker基本信息

docker info

查看docker版本信息

docker version

查看docker对应功能的帮助文档

docker 命令 --help

镜像命令
帮助:

docker image --help

查询所有镜像:

docker images

搜索镜像(具体还是去docker hub上查看吧):

docker search mysql

拉取镜像(如果不加版本tag,则默认拉取:latest,如果目标应用没有latest这个版本会报错):

docker pull mysql

docker pull mysql:5.7

docker pull docker.io/library/mysql:latest

删除镜像:

docker rmi --help

docker rmi 容器id

docker rmi REPOSITORY:tag

====容器

命令帮助

docker run --help

新建容器并启动

docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

OPTIONS:

  • -a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;

  • -d: 后台运行容器,并返回容器ID;

  • -i: 以交互模式运行容器,通常与 -t 同时使用;

  • -P: 随机端口映射,容器内部端口随机映射到主机的端口

  • -p: 指定端口映射,格式为:主机(宿主)端口:容器端口

  • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;

  • –name=“nginx-lb”: 为容器指定一个名称;

  • –dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;

  • –dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;

  • -h “mars”: 指定容器的hostname;

  • -e username=“ritchie”: 设置环境变量;

  • –env-file=[]: 从指定文件读入环境变量;

  • –cpuset=“0-2” or –cpuset=“0,1,2”: 绑定容器到指定CPU运行;

  • -m :设置容器使用内存最大值;

  • –net=“bridge”: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;

  • –link=[]: 添加链接到另一个容器;

  • -expose=[]: 开放一个端口或一组端口;

  • –volume , -v: 绑定一个卷

查看正在运行的容器

docker ps

查看所有运行过的容器

docker ps -a

操作容器状态

docker start/stop/restart/kill [容器id][容器名称]

删除已停止的容器

docker rm [容器id][容器名称]

删除运行中的容器

docker rm -f [容器id][容器名称]

删除所有容器

docker rm -f $(docker ps -aq) docker ps -a -q | xargs docker rm

查看容器日志

docker logs -f -t --tail 1000 [容器id]

  • 1000 表示数量

查看容器中的进程:

docker top [容器id]

查看容器的信息:

docker inspect [容器id]

进入容器:

docker exec -it [容器id] /bin/bash

拷贝容器中的文件

docker cp 容器id:/path/file/ /home/file

  • /path/file:容器中的文件

  • /home/file: 主机中的文件地址

查看容器资源占用情况:

docker stats

常见问题:
  1. 要使 docker 容器后台运行,一定要在启动时加上 -d 参数。

commit 镜像

将一个使用中的容器打包成新的镜像

docker commit -m="描述" -a="作者" 容器id 目标镜像名:[tag]

可视化web界面

Potainer
docker run -d -p 9000:9000 --name portainer \
    --restart=always \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v portainer_data:/data \
    portainer/portainer-ce:2.9.3

注:这里开放端口9000,http访问,官方文档还开放了 -p 8000:8000 -p 9443:9443, 8000是一个tcp端口,9443,是https访问,根据实际调整。

通过 Portainer 可以在web界面直接操作镜像、容器、数据卷、网络等,实质就是将命令以可视化的形式提供操作。

Rancher CI/CD

镜像原理

UnionFS 联合文件系统

联合文件系统是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一虚拟文件系统下。UnionFS 是docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像可以制作出各种具体的应用镜像。

Docker 镜像加载原理

docker 镜像实际上是由一层层文件系统组成,这种层级文件系统就是UnionFS。

bootfs: 主要包含bootloader以及kernel,linux启动时会加载bootfs文件系统,这里牵涉到些linux系统启动过程。主要作用就是将内核加载到内存中,加载完成后,会卸载bootfs。

rootfs: 各种不同操作系统发行版的一些标准目录和文件,例如Ubuntu/Centos发行版中的 /dev、/porc、/bin等等文件。

详见分层结构

图片.png
Figure 7. 图片.png

注:bootfs 是所有共有的,而rootfs则是具体需要的,所有镜像共有部分都不要,而只关注各种不同的rootfs,一个精简的系统,rootfs是可以很小的,所以当我们查看image的大小时,会发现centos/ubuntu等size都很小,这是因为其中的bootfs都是相似的,并不包含在这个镜像中,底层直接使用了宿主机的bootfs。

这里就可以知道为什么虚拟机启动是分钟级,而容器是秒级的? bootfs由宿主机完成,容器是不需要执行的,所以很快。

理解 Docker 分层

所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。相同的层级可以共用,这样也能理解在pull镜像时,如果底层的镜像层已经存在,那么就不会再去拉取了。

图片.png
Figure 8. 图片.png

数据卷

为什么要有数据卷?

容器中的数据,一旦容器销毁,则数据随之销毁,因此,如果需要持久化容器中的数据,那么得将数据存储在宿主机本地,因此则需要数据卷。

例如 mysql中的数据需要持久化,肯定不能随着容器的删除而删除,那么就得将容器中mysql的数据同步到宿主机中,这样即使删除容器,那么其数据也不会丢失。

容器的持久化和同步操作,容器间的数据可以共享。数据卷的挂载方式有如下四种。

方式一:挂载宿主机的目录以及对应容器中的目录

docker run -it -v 主机目录:容器中的目录

方式二:匿名挂载:-v 容器路径

匿名挂载,只需要指定容器中的文件路径,在宿主机中,会由docker默认创建一个目录进行挂载。 其存放位置为 /var/lib/docker/volume/2f50c3744cc2b0ec800669c89bc727efdaf83c59cc56c45b42abff236bfe9a0f

root@wangxiao-docker:/home/mysql/data/test# docker volume ls
DRIVER    VOLUME NAME
local     2f50c3744cc2b0ec800669c89bc727efdaf83c59cc56c45b42abff236bfe9a0f
方式三:具名挂载:-v 名字:容器路径

其存放位置为 /var/lib/docker/volume/nginx-data

DRIVER    VOLUME NAME
local     nginx-data
方式四:创建镜像的时候可以进行挂载
FROM centos

# 只能创建匿名挂载
VOLUME ["volume1", "volume2", "volume3"]

CMD echo "-----end"
CMD /bin/bash

DockerFile 创建自己的镜像

指令列表
图片.png
Figure 9. 图片.png
基础知识
  • 指令必须大写

  • 执行从上到下顺序执行

  • # 表示注释

  • 每一个指令都会创建提交一个新的镜像层,并提交

  • 创建一个镜像需要一个dockerfile文件描述镜像,以及使用 docker build 命令

通过 DockerFile 文件创建镜像

案例,构建自己的centos

root@wangxiao-docker:/home/file# cat mydockerfile
FROM ubuntu
MAINTAINER wanghengzhi<zerothreeoneone@foxmail.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN apt-get update
RUN apt-get -y install vim
RUN apt-get -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "-----end------"
CMD /bin/bash

root@wangxiao-docker:/home/file# docker build -f ./mydockerfile -t wanghengzhi/ubuntu:1.0 .
CMD 命令与 ENTRYPOINT 命令

CMD: 指定这个容器启动时要运行的命令,只有最后一个会生效,可被替代 ENTRYPOINT: 指定这个容器启动时要运行的命令,可以追加命令。

# ls -a 会替换掉容器最开始默认的命令 /bin/bash
docker run -it wanghengzhi/ubuntu:1.0 ls -a

如果构建的镜像中使用ENTRYPOINT,则会执行原来的命令,并且也执行启动时指定的命令

案例

图片.png # docker import和docker load的区别是什么?

发布镜像

将自行构建的镜像发布到仓库中,可以是公有仓库,也可以自己搭建私服。

步骤
  • docker login -u username

  • docker push 镜像名:tag

提交的时候也是按照层级提交的。

docker 全流程
图片.png
Figure 10. 图片.png

docker 网络

docker0 理解

ip addr

图片.png
Figure 11. 图片.png
  • 启动docker服务后,就会创建一个docker0桥接网络

  • 每启动一个docker容器,docker会给容器分配一个ip,通过宿主机是能够ping通的。

  • veth-pair 技术,一对虚拟设备接口,成对出现,充当桥梁,链接各种虚拟网络

  • 容器和容器之间也能ping通

容器之间并不是直接连接的,而是通过docker0进行链接的。 图片.png

通过–link在启动容器时指定连接的服务,后面可以直接通过link的服务名,进行ping通,其原理,是内部保存了一个link服务的地址信息,可以通过 docker inspect 查看。但是link的服务不能反向ping通当前服务。

自定义网络

docker network COMMAND

网络模式
  • brigde: 桥接模式,默认模式

  • none: 不配置网络

  • host: 和宿主机共享网络

  • container: 容器网络连通

创建网络

docker network create --driver bridge --subnet 192.168.0.0/24 --gatway 192.168.0.1 mynet

查看网络

docker network inspect mynet

容器指定网络

docker run .... --net mynet ....

在自定义网络中,不需要使用 link 指定,可以直接使用容器名进行ping通。

网络连通

将一个容器连接到另一个网络中,其实质就是将容器加入到网络配置中。

docker network connect mynet tomcat1

后记

docker.service: Failed with result ’exit-code‘

dockerd --debug 查询原因