Docker简介和基本使用(一)

Docker

Docker目前有两个版本:

  1. Docker-ce:社区版
  2. Docker-ee:企业版

基于Ubuntu-18.04-01系统,已经配置阿里云仓库源。

最新镜像下载到官方网站进行下载:
https://ubuntu.com/download/server

Ubuntu环境配置参看:

Ubuntu系统相关配置-针对18.04

安装docker:
https://yq.aliyun.com/articles/110806

Docker起容器,容器内默认根目录在宿主机如下目录中,只是目前不知数据编码如何对应Container ID:

[Thu Jul 04 20:07
 root@docker1 /var/lib/docker/overlay2]#ll ffc43f91e87964bb70d89d5b4296ee0f96d1c8f8aaa3507b4efce7e87b1756ef/merged/
total 80
drwxr-xr-x  1 root root  4096 Jul  4 20:06 ./
drwx------  5 root root  4096 Jul  4 17:15 ../
-rw-r--r--  1 root root 12082 Mar  6 01:36 anaconda-post.log
lrwxrwxrwx  1 root root     7 Mar  6 01:34 bin -> usr/bin/
drwxr-xr-x  1 root root  4096 Jul  4 17:15 dev/
-rwxr-xr-x  1 root root     0 Jul  4 17:15 .dockerenv*
drwxr-xr-x  1 root root  4096 Jul  4 17:15 etc/
drwxr-xr-x  2 root root  4096 Apr 11  2018 home/
-rw-r--r--  1 root root    26 Jul 24  2018 issue
lrwxrwxrwx  1 root root     7 Mar  6 01:34 lib -> usr/lib/
lrwxrwxrwx  1 root root     9 Mar  6 01:34 lib64 -> usr/lib64/
drwxr-xr-x  2 root root  4096 Apr 11  2018 media/
drwxr-xr-x  2 root root  4096 Apr 11  2018 mnt/
drwxr-xr-x  2 root root  4096 Apr 11  2018 opt/
drwxr-xr-x  2 root root  4096 Mar  6 01:34 proc/
dr-xr-x---  1 root root  4096 Jul  4 17:16 root/
drwxr-xr-x 11 root root  4096 Mar  6 01:36 run/
lrwxrwxrwx  1 root root     8 Mar  6 01:34 sbin -> usr/sbin/
drwxr-xr-x  2 root root  4096 Apr 11  2018 srv/
drwxr-xr-x  2 root root  4096 Mar  6 01:34 sys/
drwxrwxrwt  7 root root  4096 Mar  6 01:36 tmp/
drwxr-xr-x 13 root root  4096 Mar  6 01:34 usr/
drwxr-xr-x 18 root root  4096 Mar  6 01:34 var/

容器:

泛指能够盛纳物品的工具,具体如轮船,行李箱,背包等,都可以称为容器,但先在要说的一项容器IT技术——–Docker

容器技术是虚拟化、云计算、大数据之后的又一门炙手可热的新技术。提高了硬件资源利用率,节省IT支出成本,便于业务快速横向扩容,实现宕机功能自愈,现代容器技术是必须掌握的一项IT技术。

容器技术最早出现在freebsd 叫做jail。

Docker 最早采用LXC 技术(LinuX Container 的简写,LXC 是Linux 原生支持的容器技术,可以提供轻量级的虚拟化,可以说 docker 就是基于 LXC 发展起来的,提供 LXC 的高级封装,发展标准的配置方法),而虚拟化技术KVM(Kernel-based Virtual Machine) 基于模块实现,Docker 后改为自己研发并开源的runc 技术运行容器。

Docker 采用客户端/服务端架构,使用远程API 来管理和创建Docker 容器,其可以轻松的创建一个轻量级的、可移植的、自给自足的容器,docker 的三大理念是build(构建)、ship(运输)、 run(运行),Docker 遵从apache 2.0 协议,并通过(namespace 及cgroup 等)来提供容器的资源隔离与安全保障等,所以Docke 容器在运行时不需要类似虚拟机(空运行的虚拟机占用物理机6-8% 性能)的额外资源开销,因此可以大幅提高资源利用率 总而 言之 Docke r 是一种用了新颖方式实现的轻量级虚拟机,类似于 VM 但是在原理和应用上和 VM 的差别还是很大的,并且 docker的专业叫法是应用容器(Application Container),并不能取代VM。

Docker的组成:

  • Docker 主机 Host 一个物理机或虚拟机,用于运行 D ocker 服务 进程和容器。
  • Docker 服务端 Server Docker 守护 进程, 运行 docker 容器。
  • Docker 客户端 Client 客户端 使用 docker 命令 或其他工具 调用 docker API 。
  • Docker 仓库 Registry 保存 镜像的仓库,类似于 git 或 svn 这样的版本控制系
  • Docker 镜像 Images 镜像 可以 理解为创建实例 使用 的模板。
  • Docker 容器 Container )): 容器是 从镜像生成对外提供服务的一个或一组服务 。

官方仓库:
https://hub.docker.com/

Docker对比虚拟机:

  1. 资源利用率更高 一台物理机可以运行数百个容器,但是一般只能运行数十个虚拟机 。
  2. 开销更小 不需要启动单独的 虚拟机 占用硬件资源。
  3. 启动速度 更快 可以在数秒内 完成 启动。

通常情况下,使用虚拟机可以更好的隔离程序运行环境,让每个虚拟机拥有不同的操作系统和内核。大部分时候,一个虚拟机仅运行一个服务,如nginix,PHP,Tomcat等web应用程序,资源不能充分利用,且较为浪费,容器技术的出现打破了这种浪费,每个容器里起服务。即加快启动速度,资源较虚拟机也不会出现过度浪费资源情况。

当一个宿主机 运行了N个容器, 多个容器带来的以下问题怎么解决?

  1. 怎么样保证每个容器都有不同的文件系统并且能互不影响?
  2. 一个 docker 主 进程内的各个容器都是其子进程,那么 实现 同一个主进程下不同类型的子进程? 各个进程间通信能相互访问内存数据吗?
  3. 每个容器怎么解决 IP 及 端口分配的问题?
  4. 多个 容器 的 主机名能一样吗?
  5. 每个容器都 要不要有 root 用户?怎么解决账户重名问题?
    以上问题怎么解决?

Linux Namespace技术:

namespace是在Linux系统的内核层实现,即有一些不同类型的命名空间,被部署在核内各个docker容器,运行在同一个docker主进程,并且共用同一个宿主机系统内核,各docker容器运行在宿主机的用户空间,每个容器都要有类似于虚拟机一样的相互隔离的运行空间,但是容器技术是在一个进程内实现运行指定服务的运行环境,并且还可以保护宿主机内核不受其他进程的干扰和影响,如文件系统空间、网络空间、进程空间等,目前主要通过以下技术实现容器运行空间的相互隔离:


MNT Namespace

容器有独立的根文件系统和用户空间,为的是在容器里面启动服务并且使用容器的运行环境,即容器和宿主机操作系统可不同。一个宿主机是ubuntu的服务器,可以在里面启动一个centos运行环境的容器,可在容器里面启动一个Nginx服务,但容器里面是不能访问宿主机的资源,宿主机是使用了chroot技术把容器锁定到一个指定的运行目录里面。

[Thu Jul 04 17:18
 root@docker1 ~]#find / -name 81b9c9c93ca1*
/sys/fs/cgroup/hugetlb/docker/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/sys/fs/cgroup/cpuset/docker/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/sys/fs/cgroup/memory/docker/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/sys/fs/cgroup/cpu,cpuacct/docker/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/sys/fs/cgroup/blkio/docker/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/sys/fs/cgroup/perf_event/docker/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/sys/fs/cgroup/net_cls,net_prio/docker/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/sys/fs/cgroup/freezer/docker/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/sys/fs/cgroup/pids/docker/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/sys/fs/cgroup/devices/docker/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/sys/fs/cgroup/systemd/docker/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/run/docker/runtime-runc/moby/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/run/docker/containerd/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/run/containerd/io.containerd.runtime.v1.linux/moby/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/var/lib/docker/image/overlay2/layerdb/mounts/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/var/lib/docker/containers/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
/var/lib/docker/containers/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95-json.log
/var/lib/containerd/io.containerd.runtime.v1.linux/moby/81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95

例如:/var/lib/containerd/io.containerd.runtime.v1.linux/moby/容器ID

docker在github上是moby的一个项目。

[Thu Jul 04 20:17
 root@docker1 /var/lib/docker/overlay2]#tree -L 3 /run/containerd/io.containerd.runtime.v1.linux/moby/
/run/containerd/io.containerd.runtime.v1.linux/moby/
├── 315d9c2c0e1e992d9873d0bbd627bb51fae74dec63daae0706185d66d743f131
│   ├── config.json
│   ├── init.pid
│   ├── log.json
│   └── rootfs
├── 62c436c41a0897d65b3a43900948a9849c706d7a622b0bd6b162ae58e275d5be
│   ├── config.json
│   ├── init.pid
│   ├── log.json
│   └── rootfs
├── 81b9c9c93ca1d04eac768f9c0883afff9ec594e96ef20baa008d30293923bb95
│   ├── config.json
│   ├── d364233e1fbb1fd6509b5958261f61084f108b9da9639c7a14b05cf97573c864.pid
│   ├── init.pid
│   ├── log.json
│   └── rootfs
└── ec968c5f073f6686989bb8b195b199eea00006d200341876216b741685d9ed08
    ├── config.json
    ├── init.pid
    ├── log.json
    └── rootfs
Server: Docker Engine - Community
 Engine:
  Version:          18.09.7
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       2d0083d
  Built:            Thu Jun 27 17:23:02 2019
  OS/Arch:          linux/amd64
  Experimental:     false

# docker run -d --name=nginx-1 -p 80:80 nginx
# docker run -d --name=nginx-2 -p 81:80 nginx
# docker run -d --name=nginx-3 -p 82:80 nginx

Debian系统 安装基础命令:

# apt update
# apt install procps (top 命令)
# apt install iputils ping (ping 命令)
# apt install net-tools ( 网络工具)
#docker ps #查看宿主机上的容器列表。
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
62c436c41a08        nginx               "nginx -g 'daemon of…"   3 minutes ago       Up 3 minutes        0.0.0.0:82->80/tcp   nginx-3
315d9c2c0e1e        nginx               "nginx -g 'daemon of…"   3 minutes ago       Up 3 minutes        0.0.0.0:81->80/tcp   nginx-2
ec968c5f073f        nginx               "nginx -g 'daemon of…"   3 minutes ago       Up 3 minutes        0.0.0.0:80->80/tcp   nginx-1
81b9c9c93ca1        centos              "/bin/bash"              28 minutes ago      Up 28 minutes                            centos

#验证容器的根文件系统:

[Thu Jul 04 17:13
 root@docker1 ~]#cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.1 LTS (Bionic Beaver)"

# docker exec -it 62c436c41a08 /bin/bash
root@62c436c41a08:/# cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
NAME="Debian GNU/Linux"

IPC Namespace

一个容器内的进程间通信允许一个容器内的不同进程的内存、缓存等数据访问,但是不能夸容器访问其他容器的数据。

UTS Namespace

UTS namespace(UNIX Time sharing System包含了运行内核的名称、版本、底层体系结构类型等信息)用于系统标识,其中包含了hostname和域名domainname它使得一个容器拥有属于自己hostname标识,这个主机名标识独立于宿主机系统和其上的其他容器。

# 内核版本是基于宿主机内核。
root@62c436c41a08:/# uname -a
Linux 62c436c41a08 4.15.0-29-generic #31-Ubuntu SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 GNU/Linux

PID Namespace

Linux系统中,有一个PID为1的进程init/systemd是其他所有进程的父进程,那么在每个容器内也要有一个父进程来管理其下属的子进程,那么多个容器的进程通PIDnamespace进程隔离比如PID编号重复、器内的主进程生成与回收子进程等。
例如:下图是在一个容器内使用top命令看到的PID为1的进程是nginx

容器内的Nginx主进程与工作进程:

查看 宿主机上的 PID 信息

最后所有进程PID为1

Net Namespace

每一个容器都类似于虚拟机一样有自己的网卡、监听端口、TCP/IP协议栈等,Docker使用network namespace启动一个vethX接口,这样你的容器将拥有它自己的桥接ip地址,通常是docker0,而docker0实质就是Linux的虚拟网桥,网桥是在OSI七层模型的数据链路层的网络设备,通过mac地址对网络进行划分,并且在不同网络直接传递数据。

查看宿主机的网卡信息:


查看宿主机桥接设备:

通过brctl show命令查看桥接设备:

宿主机 iptables 规则:

所有来自容器内172.17.0.0/16的数据,出口为非docker0接口,做地址伪装(MASQUERADE),即从宿主机上的任意网卡通向外部。

User Namespace

每个容器内拥有相同ID的root(0)用户,即容器内通过user namespace机制进行用户隔离,作用范围仅限容器内部。

root@62c436c41a08:/# id root
uid=0(root) gid=0(root) groups=0(root)

Linux control groups

在一个容器,如果不对其做任何资源限制,则宿主机会允许其占用无限大的内存空间,有时候会因为代码bug程序会一直申请内存,直到把宿主机内存占完,为了避免此类的问题出现,宿主机有必要对容器进行资源分配限制,比如CPU、内存等,LinuxCgroups的全称是Linux Control Groups它最主要的作用,就是限制一个进程组能够使用的资源上限,包括CPU、内存、磁盘、网络带宽等等。此外,还能够对进程进行优先级设置,以及将进程挂起和恢复等操作。

验证系统cgroups

Cgroups在内核层,默认已经开启,内核较新的ubuntu支持的功能更多。CentOS内核版本相对旧些,支持功能少。

ubuntu cgroups

cgroups 具体实现:

blkio :块设备 IO 限制。
cpu :使用调度程序为 cgroup 任务提供 cpu 的访问。
cpuacct :产生 cgroup 任务的 cpu 资源报告。
cpuset :如果是多核心的 cpu ,这个子系统会为 cgroup 任务分配单独的 cpu 和内存。
devices :允许或拒绝 cgroup 任务对设备的访问。
freezer :暂停和恢复 cgroup 任务。
memory :设置每个 cgroup 的内存限制以及产生内存资源报告。
net_cls :标记每个网络包以供 cgroup 方便使用。
ns :命名空间子系统。
perf_event :增加了对每 group 的监测跟踪的能力,可以监测属于某个特定的 group 的所有线程以及运行在特定 CPU 上的线程。
查看系统cgroups
[Thu Jul 04 19:30
 root@docker1 ~]#ll /sys/fs/cgroup/
total 0
drwxr-xr-x 15 root root 380 Jul  4 16:43 ./
drwxr-xr-x 10 root root   0 Jul  4 16:43 ../
dr-xr-xr-x  5 root root   0 Jul  4 16:43 blkio/
lrwxrwxrwx  1 root root  11 Jul  4 16:43 cpu -> cpu,cpuacct/
lrwxrwxrwx  1 root root  11 Jul  4 16:43 cpuacct -> cpu,cpuacct/
dr-xr-xr-x  5 root root   0 Jul  4 16:43 cpu,cpuacct/
dr-xr-xr-x  3 root root   0 Jul  4 16:43 cpuset/
dr-xr-xr-x  5 root root   0 Jul  4 16:43 devices/
dr-xr-xr-x  3 root root   0 Jul  4 16:43 freezer/
dr-xr-xr-x  3 root root   0 Jul  4 16:43 hugetlb/
dr-xr-xr-x  5 root root   0 Jul  4 16:43 memory/
lrwxrwxrwx  1 root root  16 Jul  4 16:43 net_cls -> net_cls,net_prio/
dr-xr-xr-x  3 root root   0 Jul  4 16:43 net_cls,net_prio/
lrwxrwxrwx  1 root root  16 Jul  4 16:43 net_prio -> net_cls,net_prio/
dr-xr-xr-x  3 root root   0 Jul  4 16:43 perf_event/
dr-xr-xr-x  5 root root   0 Jul  4 16:43 pids/
dr-xr-xr-x  2 root root   0 Jul  4 16:43 rdma/
dr-xr-xr-x  6 root root   0 Jul  4 16:43 systemd/
dr-xr-xr-x  5 root root   0 Jul  4 16:43 unified/

有了以上的chroot、namespace、cgroups就具备了基础的容器运行环境,但是还需要有相应的容器创建与删除的管理工具、以及怎么样把容器运行起来、容器数据怎么处理、怎么进行启动与关闭等问题需要解决,于是容器管理技术出现了。

容器管理工具

目前主要是使用docker,早期有使用 lxc

docker

宿主机起容器,需要借助外部模板镜像,此镜像可在公共仓库共享,也可在私有仓库。最主要是可以在现有镜像上做自定义配置,然后再提交为一个镜像,一个镜像可起多个容器。

Docker镜像采用分层结构,镜像最底部为库文件且只读,从镜像加载启动一个容器后会生成一个可读写层,写入的数据会存入容器内,即写入容器在宿主机上的存储目录里。删除容器时,加-fv参数,佛则只是删除容器,容器的本地存储目录不会自动清除,随着删除的容器数量增多,会导致磁盘空间越来越小。

Docker的优势:

  1. 快速部署:短时间内可以部署成百上千个应用 ,更 快速交付到线上 。
  2. 高效虚拟化:不需要额外的 hypervisor 支持,直接基于 linux 实现 应用虚拟化,相比虚拟机大幅提高性能和效率。
  3. 节省开支:提高服务器利用率,降低 IT 支出 。
  4. 简化配置:将运行环境打包保存至容器,使用时直接启动即可。
  5. 快速迁移和扩展:可夸平台运行在物理机、虚拟机、公有云等环境, 良好的兼容性可以方便将应用从 A 宿主机迁移到 B 宿主机 甚至是 A 平台迁移到 B 平台 。

Docker的缺点:

隔离性:各应用之间的隔离不如虚拟机彻底。

docker( 容器 的核心技术:

容器规范:

open container (OCI):2015年6月成立,成员有Linux基金会、Docker、微软、红帽、谷歌和、IBM等公司,发布了两个规范,分别是runtime specimage format spec。所有公司二次开发的容器技术,需遵守这两个规范,以便保证后期的可移植性和相互可操作性。

容器runtime

runtime是 真正运行容器的地方,因此为了运行不同的容器 runtime 需要和操作系统内核紧密合作相互在支持,以便为容器提供相应的运行环境。

目前主流的三种 runtime
  1. Lxc:linux 上早期的runtime Docker,早期就是采用lxc作为runtime 。
  2. runc:目前 Docker 默认的 runtime runc 遵守OCI规范,因此可以兼容lxc。
  3. rkt:CoreOS 开发的容器 runtime ,也符合 OCI 规范 ,所以使用rkt runtime也可以运行 Docker 容器。

容器管理工具:

管理工具连接runtime与用户,对用户提供图形或命令方式操作,然后管理工具将用户操作传递给runtime执行。
  1. lxc是lxd的管理工具。
  2. Runc的管理工具是docker engine,docker engine包含后台deamon和cli两部分,大家经常提到的Docker就是指的docker engine。
  3. Rkt的管理工具是rkt cli。

容器定义工具:创建镜像必考题

容器定义工具允许用户定义容器的 属性 和内容,以方便容器能够被保存、共享和重建 。
  1. Docker image:是docker容器的模板,runtime依据docker image创建容器。
  2. Docker file:包含N个命令的文本文件,通过docker file创建出docker image。
  3. ACI(App container image):与docker image类似,是CoreOS开发的rkt容器的镜像格式。

Registry

统一保存镜像而且是多个不同镜像版本的地方,叫做镜像仓库。
  1. Image registry:docker官方提供的私有仓库部署工具。
  2. Docker hub:docker官方的公共仓库,已经保存了大量的常用镜像,可以方便大家直接使用。
  3. Harbor:vmware提供的自带web界面,自带认证功能的镜像仓库,目前有很多公司使用。

编排工具:

当多个容器在多个主机运行的时候,单独管理容器是相当复杂而且很容易出错,而且也无法实现某一台主机宕机后容器自动迁移到其他主机从而实现高可用的目的,也无法实现动态伸缩的功能,因此需要有一种工具可以实现统一管理、动态伸缩、故障自愈、批量执行等功能这就是容器编排引擎。容器编排通常包括容器管理、调度、集群定义和服务发现等功能。
  1. Docker swarm:docker开发的容器编排引擎。
  2. Kubernetes:google领导开发的容器编排引擎,内部项目为Borg,且其同时支持docker和CoreOS。
  3. Mesos+Marathon:通用的集群组员调度平台mesos(资源分配)与marathon(容器编排平台)一起提供容器编排引擎功能。

docker(容器)依赖的技术:

容器网络:

docker自带的网络docker network仅支持管理单机上的容器网络,当多主机运行的时候需要使用第三方开源网络,例如calico、flannel等。

服务发现:

容器的动态扩容特性,决定了容器IP也会随之变化,因此需要有一种机制,开源自动识别,并将用户请求动态转发到新创建的容器上,kubernetes自带服务发现功能,需要结合kubedns服务解析内部域名。

容器监控:

可以通过原生命令docker ps/top/stats查看容器运行状态,另外也可以使heapster/Prometheus等第三方监控工具监控容器的运行状态。

数据管理:

容器的动态迁移会导致其在不同的Host之间迁移,因此如何保证与容器相关的数据也能随之迁移或随时访问,可以使用逻辑卷存储挂载等方式解决。

日志收集:

docker原生的日志查看工具docker logs,但是容器内部的日志需要通过ELK等,专门的日志收集分析和展示工具进行处理。

Docker安装及基础命令介绍

官方网址: https://www.docker.com/

系统版本选择:

Docker支持多种操作系统,在linux中,要使用内核3.0版本以上的系统。Docker版本号一直是0.X或1.X,但在2017年3月后,每季度发布一次稳定版,版本号更改为YY.MM,例如1803,本次演示基于Centos7.6。

Docker版本选择:

目前Docker新项目名为Moby,github地址为:https://github.com/moby/moby
Moby项目为Docker项目的全新上游,Docker将是属于Moby项目的一个子产品,之后版本分为CE(社区版)和EE(企业收费版),两个版本都是每季度推出一款稳定版,EE后期维护期为1年,CE为4个月,本次使用CE18.03,官方地址为:https://blog.docker.com/2017/03/docker-enterprise-edition/

方法1:rpm包安装

官方下载地址:https://download.docker.com/linux/centos/7/x86_64/stable/Packages/

阿里镜像下载地址:https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/

方法2:通过修改yum源安装:

[Sat Jul 06 10:47
 root@Centos7 ~]$# cd /etc/yum.repos.d/

[Sat Jul 06 10:47
 root@Centos7 /etc/yum.repos.d]# mkdir backup

[Sat Jul 06 10:47
 root@Centos7 /etc/yum.repos.d]# mv CentOS* backup/

[Sat Jul 06 10:48
 root@Centos7 /etc/yum.repos.d]# wget -O CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo

[Sat Jul 06 10:50
 root@Centos7 /etc/yum.repos.d]# wget -O epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

[Sat Jul 06 10:51
 root@Centos7 /etc/yum.repos.d]# wget -O docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

 root@Centos7 /etc/yum.repos.d]# yum install docker-ce

启动并验证docker版本信息:

# systemctl start docker
# systemctl enable docker
# systemctl status docker
# docker version    #查看Docker客户端和服务端版本信息

验证docker0网卡:

默认情况下安装完毕,会自动生成一个网卡,名称为docker0。

# ifconfig docker0

查看docker相关信息:

# docker info

docker存储引擎:

目前新版docker,默认存储引擎overlay2,需要磁盘分区支持d-type文件分层功能,因此需要额外的系统磁盘支持。

官方存储引擎选择文档:
https://docs.docker.com/storage/storagedriver/select-storage-driver/

Docker官方推荐首选存储引擎为overlay2,其次为devicemapper,但是devicemapper存在使用空间方面的一些限制(上限存储最大100G,磁盘空间再大也无用), 虽然可以通过后期配置解决,但是官方依然推荐使用overlay2 ,以下 是网上查到的部分资料:
https://www.cnblogs.com/youruncloud/p/5736718.html

如果docker数据目录是一块单独的磁盘分区,而且是xfs格式的,那么需要在格式化的时候加上参数-n ftype=1,否则后期在启动容器的时候会报错不支持d-type。但默认centos 7.6(1810)格式化xfs格式磁盘时,默认带ftype=1;centos 7.2(1511)默认ftype=0。

查看containerd进程关系:

共四个进程:
  1. dockerd:被client直接访问,其父进程为宿主机的systemd(pid 1)守护进程。
  2. docker-proxy:实现容器间通信,其父进程为dockerd。
  3. containerd:被dockerd进程调用以实现与runc交互。
  4. containerd-shim:真正运行容器的载体其父进程为containerd。


# ps -ef | grep containerd

# ps -ef | grep docker-proxy

containerd shim命令使用:

[Sat Jul 06 11:30
 root@Centos7 ~]# containerd-shim -h
Usage of containerd-shim:
  -address string
        grpc address back to main containerd
  -containerd-binary containerd publish
        path to containerd binary (used for containerd publish) (default "containerd")
  -criu string
        path to criu binary
  -debug
        enable debug output in logs
  -namespace string
        namespace that owns the shim
  -runtime-root string
        root directory for the runtime (default "/run/containerd/runc")
  -socket string
        abstract socket path to serve
  -systemd-cgroup
        set runtime to use systemd-cgroup
  -workdir string
        path used to storge large temporary data

容器的创建与管理过程:

通信流程:
1. dockerd 通过 grpc 和 containerd 模块通信, dockerd 由 libcontainerd 负责和 containerd 进行交换, dockerd 和 containerd 通信基于 socket 文件:/run/containerd/containerd.sock 。
2. containerd 在 dockerd 启动时被启动, 然后 containerd 启动 grpc 请求监听, containerd 处理 grpc 请求,根据请求做相应动作。
3. 若是 start 或是 exec 容器, containerd 拉起一个 container-shim , 并进行相应的操作。
4. container-shim 被拉起后, start/exec/create 拉起 runC 进程,通过 exit 、 control 文件和containerd 通信,通过父子进程关系和 SIGCHLD 监控容器中进程状态。
5. 在整个容器生命周期中, containerd 通过 epoll 监控容器文件,监控容器事件。

grpc简介:

由google开发的一款高性能,开源和通用的RPC框架,支持众多语言客户端。

docker镜像加速配置

获取加速地址:

浏览器打开 https://cr.console.aliyun.com 注册或登录阿里云账号,点击左侧的镜像加速器,将会得到一个专属的加速地址 而且下面有使用配置说明:

生成配置文件:

xxxxx为阿里云提供,每个账号不相同

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://XXXXXXXX.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

Docker镜像管理

Docker镜像含有启动容器所需要的文件系统及所需要的内容,因此镜像主要用于创建并启动 docker容器。

Docker 正是利用AUFS来实现对container的快速更新。

AUFS (AnotherUnionFS)是一种 Union FS, 简单来说就是支持将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)的文件系统, 更进一步地, AUFS支持为每一个成员目录(AKA branch)设定’readonly’, ‘readwrite’ 和 ‘whiteout-able’ 权限, 同时AUFS里有一个类似分层的概念, 对 readonly 权限的branch可以逻辑上进行修改(增量地, 不影响readonly部分的)。

通常 Union FS有两个用途, 一方面可以实现不借助 LVM, RAID 将多个disk和挂在到一个目录下, 另一个更常用的就是将一个readonly的branch和一个writeable的branch联合在一起,Live CD正是基于此可以允许在 OS image 不变的基础上允许用户在其上进行一些写操作。Docker在AUFS上构建的container image也正是如此,接下来我们从启动container中的linux为例介绍docker在AUFS特性的运用。

当我们使用镜像时,只会看到一个整体,结构如下:

典型的Linux启动到运行需要两个FS – bootfs + rootfs (从功能角度而非文件系统角度)

对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs 如下

典型的Linux在启动后,首先将 rootfs 置为 readonly, 进行一系列检查, 然后将其切换为 “readwrite” 供用户使用。在docker中,起初也是将 rootfs 以readonly方式加载并检查,然而接下来利用 union mount 的将一个 readwrite 文件系统挂载在 readonly 的rootfs之上,并且允许再次将下层的 file system设定为readonly 并且向上叠加, 这样一组readonly和一个writeable的结构构成一个container的运行目录, 每一个被称作一个Layer

docker命令是最常使用的 docker 客户端命令,其后面可以加不同的参数以实现响应的功能,常用的命令如下:

搜索镜像

# docker search centos:7.2.1511
# docker search centos

下载镜像

从docker仓库将镜像下载到本地 命令格式如下:

# docker pull 仓库服务器:端口/项目名称/镜像名称:tag(版本)号

查看本地镜像

# docker images
# docker image list
REPOSITORY #镜像所属的仓库名称
TAG #镜像版本号(标识符) 默认为 latest
IMAGE ID #镜像唯一 ID 标示
CREATED #镜像创建时间
VIRTUAL SIZE #镜像的大小

镜像导出:

可以将镜像从本地导出问为 一个压缩文件,然后复制到其他服务器进行导入使用。

# 导出方法1
# docker save centos -o /opt/centos.tar.gz

#导出方法2
# docker save centos > /opt/centos 1.tar.gz

#查看镜像内容
# cat manifest.json
[{"Config":"9f38484d220fa527b1fb19747638497179500a1bed8bf0498eb788229229e6e1.json","RepoTags":["centos:latest"],"Layers":["3dd8a7a03c185daa33b52d9d0bb475d902915732e5fdc92a4dd2c93c58fe9d14/layer.tar"]}]

#分层为了方便文件的共用,即相同的文件可以共用
[{" 配置文件 .json","RepoTags":["docker.io/nginx:latest"]," 分层
1/layer.tar"," 分层 2 /layer.tar"," 分层 3 /layer.tar"]}]

镜像导入:

将镜像导入到docker

# docker load < /opt/centos.tar.gz

删除镜像:

# docker rmi centos

批量删除无用镜像:

# docker rmi `docker images | grep "none" | awk '{print $3}'`

命令总结:

# docker save -o > /opt/centos.tar.gz   #导出镜像
# docker load -i < /opt/centos.tar.gz   #导入镜像
# docker rmi 镜像名称/镜像ID  #删除镜像,容器启动时,无法删除镜像,除非将镜像停止
# docker rmi `docker images | grep "none" | awk '{print $3}'`   #批量删除无用镜像
# docker rm 容器名称/容器ID   #删除容器,但不删除本地数据,不推荐这么操作
# docker rm -fv 容器名称/容器ID   #删除容器,如果此容器正在运行,强行删除容器,一并删除其本地存储目录。
# docker tag centos:latest centos:7.6.1810  #重打标签

容器操作基础命令

Usage:  docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
# docker run [参数选项 ] 镜像名称,必须在所有选项的后面 ] [/bin/echo 'hello
wold'] # 单次执行,没有自定义容器名称
# docker run centos /bin/echo 'hello wold' #启动的容器在执行完 shel 命令就退出了

从镜像启动一个容器:

创建容器并随机生成容器 ID 和 名称
# docker run -it -d centos

退出容器不注销
#ctrl+p+q或者exit

显示正在运行的容器

# docker ps
或者
# docker container ls|list

显示所有的容器

包括正在运行和关闭的容器

# docker ps -a
或者
# docker container ls|list -a

随机映射端口

# docker pull nginx     #下载nginx镜像
# docker run -P nginx       #前台启动,并随机映射宿主机端口到容器内80端口。
                            #前台启动的容器,退出即销毁容器。
                            #随机端口映射,从32768开始。
[Sat Jul 06 13:56
 root@Centos7 ~]# lsof -i:32768
COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
docker-pr 26943 root    4u  IPv6 267522      0t0  TCP *:filenet-tms (LISTEN)
访问验证:

指定端口映射:

方法1
# docker run -p 80:80 --name=nginx-test1 nginx
#创建容器名为nginx-test1的容器,并映射宿主机所有IP的端口80到容器内端口80

方法2
# docker run -p 172.16.36.102:81:80 --name=nginx-test2 nginx
#绑定IP的端口映射

方法3
# docker run -p 172.16.36.102::80 --name=nginx-test3 nginx
#绑定IP的随机端口映射

方法4
# docker run -p 172.16.36.102:82:80/udp --name=nginx-test4 nginx
#绑定IP的端口映射,协议改为udp,默认为tcp

方法5
# docker run -p 443:443/tcp -p 53:53/udp --name=nginx-test5 nginx   
#多端口映射,多协议

查看Nginx容器的访问日志:

[Sat Jul 06 14:07
 root@Centos7 ~]# docker logs nginx-test1
172.16.36.1 - - [06/Jul/2019:05:57:36 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0" "-"
2019/07/06 05:57:36 [error] 6#6: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 172.16.36.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "172.16.36.102:32768"
172.16.36.1 - - [06/Jul/2019:05:57:36 +0000] "GET /favicon.ico HTTP/1.1" 404 153 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0" "-"

查看容器已经映射的端口:

[Sat Jul 06 14:08
 root@Centos7 ~]# docker port musing_blackwell
80/tcp -> 0.0.0.0:32768

创建并进入容器(选项-d)

[Sat Jul 06 14:08
 root@Centos7 ~]# docker run -P --name=nginx-martin nginx bash

创建后台运行容器(选项-d)

[Sat Jul 06 14:08
 root@Centos7 ~]# docker run -d -P --name=nginx-martin nginx

进入容器:

[Sat Jul 06 14:08
 root@Centos7 ~]# docker exec -it nginx-martin /bin/bash

单次运行容器:

退出即销毁容器:测试环境,用于进入容器查看Dockerfile文件内命令是否执行正确

[Sat Jul 06 14:21
 root@docker1 ~]#docker run -it --rm nginx /bin/bash

传递运行命令

容器的运行需要有一个持续在前台运行的进程,才能保证容器的持续运行,通过传递运行参数是一种方式,另外也可以在自定义构建镜像时,指定容器启动时运行的前台命令。
# docker run -d centos /usr/bin/tail -f '/etc/hosts'

容器的启动和关闭:

# docker start nginx-test1/容器ID
# docker stop nginx-test2/容器ID

进入正在运行的容器

方法1:
# docker attach 容器ID
# docker attach 65728abckd
此方法进入容器后,多个终端进入到此容器,任何一个终端输入命令,其余终端都可看见操作记录,使用exit退出容器时,容器被销毁。所以此方法可以忽略。

方法2:
# docker exec -it 容器ID/容器名称 命令
# docker exec -it 65728abckd/nginx-test2 /bin/bash
此方法进入容器后,可exit退出,容器不销毁,但不是很推荐此方法。

方法3
使用nsenter命令
# yum install util-linux    安装nsenter命令
# docker inspect -f "{{.NetworkSettings.IPAddress}}" 容器ID/容器名称
# docker inspect -f "{{.NetworkSettings.IPAddress}}" nginx-test1
172.17.0.2
获取容器PID
# docker inspect -f "{{.State.Pid}}" serene_morse
7243
通过容器PID进入容器内部
# nsenter -t 7243 -m -u -i -n -p

方式4:使用脚本方式进入容器:推荐此方法进入容器

将nsenter命令写入到脚本进行调用,如下:
[Sat Jul 06 17:21
 root@docker1 ~]#vim docker-in.sh
#!/bin/bash
docker_in(){
        NAME_ID=$1
        PID=$(docker inspect -f "{{.State.Pid}}" ${NAME_ID})
        nsenter -t ${PID} -m -u -i -n -p
}
docker_in $1

# chmod +x docker-in.sh
#./docker-in.sh serene_morse
[root@6a6df0943075 /]#

查看容器内部的hosts文件:

#./docker-in.sh serene_morse
[root@6a6df0943075 /]#cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2      6a6df0943075    #此为容器自动生成,可修改

# ping 6a6df0943075     #可以ping通

批量关闭正在运行的容器:

# docker stop $(docker ps -q)   #关闭正在运行的主机

批量强制关闭正在运行的容器:

# docker kill $(docker ps -q)

批量删除已经退出的不需要的容器:

# docker rm -fv $(docker ps -qa -f status=exited)   #连同本地容器存储目录一并删除
# docker rm -fv $(docker ps -qa -f id=6a6df0943075)

批量删除所有容器:

# docker rm -fv $(docker ps -qa)

指定容器DNS

#docker run -it --rm --dns=8.8.8.8 centos /bin/bash
[root@ecd91c4870eb /]# cat /etc/resolv.conf 
search localdomain
nameserver 8.8.8.8