Docker实现原理

namespaces

System V IPC概述

==System V引入了三种高级进程间的通信机制:消息队列、共享内寸和信号量==

IPC对象(消息队列、共享内存和信号量)存在于内核中而不是文件系统中,由用户控制释放,不像管道的释放由内核控制

IPC对象通过其标识符来引用和访问,所有IPC对象在内核空间有唯一性标志ID,在用户空间的唯一性标识符称为key

LINUX IPC 继承自System IPC

IPC对象时全局对象,可用ipcs,ipcrm等命令查看或删除

ipcs -q: 只显示消息队列。 ipcs -s: 只显示信号量。 ipcs -m: 只显示共享内存。 ipcs –help: 其他的参数

Linux中有三个命令是和System V的三个IPC相关的:

  • ipcmk
  • ipcrm
  • ipcs

POSIX消息队列

==消息队列是Linux IPC中很常用的一种通信方式,它通常用来在不同进程间发送特定格式的消息数据。==

消息队列和之前讨论过的管道和FIFO有很大的区别,主要有以下两点:

==一个进程向消息队列写入消息之前,并不需要某个进程在该队列上等待该消息的到达,而管道和FIFO是相反的,进程向其中写消息时,管道和FIFO必需已经打开来读==,那么内核会产生SIGPIPE信号(感谢shanshan_fangfang的指正)。 IPC的持续性不同。管道和FIFO是随进程的持续性,当管道和FIFO最后一次关闭发生时,仍在管道和FIFO中的数据会被丢弃。消息队列是随内核的持续性,即一个进程向消息队列写入消息后,然后终止,另外一个进程可以在以后某个时刻打开该队列读取消息。只要内核没有重新自举,消息队列没有被删除。

系统多了一个 SCSI硬盘/dev/sdd和一个磁盘分区/dev/sdd1,/dev/sdd1就是我们要挂接的 U盘。

建立一个目录用来作 挂接点(mount point)

mkdir -p /mnt/usb

mount ==-t vfat==(格式) /dev/sdd1(设备) /mnt/usb(目录)

为什么要mount?

【答】

简单说下,比如你插入了一个U盘,LINUX系统需要执行挂载命令,==指定这个设备的类型,以确定用什么方式去访问和控制==。不然就像WINDOWS98不能自动识别U盘一样,需要自己安装USB驱动。 ==不挂载LINUX系统就无法访问这个磁盘设备==。==挂载相当于是把这个设备注册到系统的文件树中==,然后有了这个设备文件,系统才可以对它进行相应的通用fopen, fclose等操作。

Cgroups

UnionFS的实现原理:

镜像保存/载入:docker load/docker save;将一个镜像导出为文件,再使用docker load命令将文件导入为一个镜像,会保存该镜像的的所有历史记录。比docker export命令导出的文件大,很好理解,因为会保存镜像的所有历史记录。

容器导入/导出:docker import/docker export;将一个容器导出为文件,再使用docker import命令将容器导入成为一个新的镜像,但是相比docker save命令,容器文件会丢失所有元数据和历史记录,仅保存容器当时的状态,相当于虚拟机快照。

【TODO】容器文件会丢失所有元数据和历史记录 ---这个到底指的是啥?

Docker学习笔记之docker-save vs docker-export vs docker-commit

1.docker save

docker save -h

Usage: docker save [OPTIONS] IMAGE [IMAGE...]

Save one or more images to a tar archive (streamed to STDOUT by default)

--help Print usage

-o, --output Write to a file, instead of STDOUT

从接的参数就可以猜到,直接接image,不太可能导出单纯的文件系统(因为镜像本身就是分层存储的)

简单测试一下

docker save -o busybox.tar busybox && mkdir busybox && tar xf busybox.tar -C busybox

tree busybox

busybox

├── 2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749.json

├── 374004614a75c2c4afd41a3050b5217e282155eb1eb7b4ce8f22aa9f4b17ee57

│ ├── VERSION

│ ├── json

│ └── layer.tar

├── manifest.json

└── repositories

docker load 与之匹配,将其(带历史地)导入到docker images中

docker load -i busybox.tar

2.docker export

docker export -h

Usage: docker export [OPTIONS] CONTAINER

Export a container's filesystem as a tar archive

--help Print usage

-o, --output Write to a file, instead of STDOUT

从接的参数猜测,==直接接cnotallow==,多半就是dump rootfs了

栗子测试一下:

docker run --name container -d busybox

docker export -o busybox.tar container && mkdir busybox && tar xf busybox.tar -C busybox

tree busybox -L 1

busybox

├── bin

├── dev

├── etc

├── home

├── proc

├── root

├── sys

├── tmp

├── usr

└── var

docker import 与之匹配

docker import busybox.tar my-busybox:1.0

docker images

# REPOSITORY TAG IMAGE ID CREATED SIZE

# my-busybox 1.0 5bfea374dd5c 3 seconds ago 1.093 MB

注意:docker import后面接的是docker export导出的文件,也就是一个文件系统,所以导入的镜像是不带历史的 ==使用docker history $image_name 查看镜像,只有一层==

3.docker commit

docker commit -h /tmp/pkg_debian (debian) choldrim-pc

Usage: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

Create a new image from a container's changes

-a, --author Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")

-c, --change=[] Apply Dockerfile instruction to the created image

--help Print usage

-m, --message Commit message

-p, --pause=true Pause container during commit

commit是合并了save、load、export、import这几个特性的一个综合性的命令,它主要做了:

  • 将container当前的读写层保存下来,保存成一个新层
  • 和镜像的历史层一起合并成一个新的镜像

==如果原本的镜像有3层,commit之后就会有4层,最新的一层为从镜像运行到commit之间对文件系统的修改==

docker commit ==cnotallow== my-commit-image

docker history my-commit-image

IMAGE CREATED CREATED BY SIZE COMMENT

e86539128c67 5 seconds ago sh 0 B

2b8fd9751c4c 9 weeks ago /bin/sh -c #(nop) CMD ["sh"] 0 B

<missing> 9 weeks ago /bin/sh -c #(nop) ADD file:9ca60502d646bdd815 1.093 MB

1、rootfs、文件系统和镜像层的关系? ----小邹

【答】

多个镜像层+一个容器层组成一个rootfs(文件系统)

2、docker save/load重命名功能的实现,而不是替代。 ---小邹

【答】

容器里面进程调用是怎么样的?

【答】

containerd架构图

自己动手写Docker

namespace、Cgroups、UnionFS

容器和宿主机进程调用关系

【答】

/bin/bash 跟/bin/sh的区别

【答】

*sh跟bash的区别,实际上就是bash有没有开启posix模式的区别*

/bin/sh -c的作用

【答】

第一种是利用 "sh -c" 命令,它可以让 bash 将一个字串作为完整的命令来执行,这样就可以将 sudo 的影响范围扩展到整条命令

查看已经停止的容器

docker ps -a |grep Exited |awk '{print $1}'

删除所有已经停止的容器

docker rm docker ps -a |grep Exited |awk '{print $1}'(esc下面的符号)

Docker run 命令

  • -P: 随机端口映射,容器内部端口随机映射到主机的端口
  • -p: 指定端口映射,格式为:主机(宿主)端口:容器端口

使用镜像nginx:latest以后台模式启动一个容器,并将容器的80端口映射到主机随机端口。

docker run -P -d nginx:latest

docker镜像的commit与push

语法为:docker commit 容器名称 新镜像名称:标签(如果标签不存在则表示为最新的latest)

登陆到Docker Hub ---==这个可以指定IP地址吗?==

docker login -u 用户名 -p 密码

Docker push 命令

上传本地镜像myapache:v1到镜像仓库中。

docker push myapache:v1

**docker commit :**从容器创建一个新的镜像。

将容器a404c6c174a2 保存为新的镜像,并添加提交人信息和说明信息。

docker commit -a "runoob.com" -m "my apache" a404c6c174a2 mymysql:v1

Docker tag 命令

将镜像ubuntu:15.10标记为 runoob/ubuntu:v3 镜像。 软连接

docker tag ==SOURCE_IMAGE==[:TAG] ==TARGET_IMAGE==[:TAG]

docker tag ubuntu:15.10 runoob/ubuntu:v3

docker tag httpd fedora/httpd:version1.0

通过容器提交镜像(docker commit)以及推送镜像(docker push)笔记

DockerFile用来创建image

image用来创建container

docker查看私有仓库里所有镜像命令

curl -XGET http://10.202.80.238:5000/v2/_catalog

curl -XGET http://10.8.56.131:5000/v2/_catalog

或者直接网页打开:

​http://10.8.56.131:5000/v2/_catalog​

配置私有仓库可以被http访问,而非一定要https访问

【答】新版:

root@zhoufeng-ProLiant-DL380p-Gen8:~# cat /etc/docker/daemon.json { "insecure-registries":["10.8.56.131:5000", "10.8.56.171:5000"] }

老版:

cat /etc/sysconfig/docker

==老版本Docker下载私有仓库镜像出现docker tls: oversized record received with length 20527 修改/etc/sysconfig/docker文件,取消INSECURE_REGISTRY字段注释,修改为:INSECURE_REGISTRY='--insecure-registry 10.8.57.100:5000'==

sh文件执行的3种方式

1. 用绝对路径或相对路径执行

/xxx/xx/test.sh 或 ./test.sh, 要求sh文件必须有可执行权限,可以用命令 chmod a+x test.sh来添加

2. 用bash或sh来执行

bash test.sh 或 sh test.sh

3. 用source 或 . 来执行

source test.sh 或 . test.sh 这样的一大特点是,在本shell执行,==前面的方式都是在本shell的子shell中执行,不能获取sh文件中的变量==

TAP设备

TAP 设备与 TUN 设备工作方式完全相同,区别在于:

  1. ==TUN 设备是一个三层设备==,它只模拟到了 IP 层,即网络层 我们可以通过 /dev/tunX 文件收发 IP 层数据包,它无法与物理网卡做 bridge,但是可以通过三层交换(如 ip_forward)与物理网卡连通。可以使用ifconfig之类的命令给该设备设定 IP 地址。
  2. ==TAP 设备是一个二层设备==,它比 TUN 更加深入,通过 /dev/tapX 文件可以收发 MAC 层数据包,即数据链路层,拥有 MAC 层功能,可以与物理网卡做 bridge,支持 MAC 层广播。同样的,我们也可以通过ifconfig之类的命令给该设备设定 IP 地址,你如果愿意,我们可以给它设定 MAC 地址。

LINUX ip-netns 解析与使用(网络命名空间的原理)

按照约定,一个网络命名空间是一个可以打开的(open)对象(object)放置于/var/run/netns/NAME(可以理解成一个对象文件) 从这个路径打开(open)这个文件(也就是网络命名空间的文件)将产生一个有关于这个网络命名空间的文件描述符 保持这个文件描述符处于open状态将保持这个命名空间处于生存状态。

这个怎么看?

使用docker进行开发和部署的流程

  1. 在开发主机上构建容器A,可以是手工或者Dockerfile自动构建
  2. 将容器A保存为镜像A
  3. push到Docker库中进行共享
  4. 产品部署,通过Docker库中搜索来获得镜像A
  5. 在产品集群中运行容器A

两种类型的容器:后台型容器和交互性容器

交互性容器

交互型容器:运行在前台,通常会指定有交互的控制台。终端被关闭、exit命令或者docker stop、kill都会使容器处于停止状态

-i 打开容器的标准输入STDIN

-t 新建一个命令行终端

这两个-it提供了交互shell

每个shell进程里面 /dev/stdout or /dev/stdin 都会链接到不同的/dev/pts/1-n设备上去

终端设备跟shell的关系

终端设备/dev/pts/1-n ==软链接== /dev/stdin ==输入输出== shell

/dev/pts/1-n 同样软链接到 /dev/stdout

shell跟内核的关系

用户 -> 终端 ->==shell== ->内核

后台型容器

后台型容器:即使终端关闭了,不影响容器状态。只有stop、kill才能影响

服务型容器不会因为终端的退出而退出。

Docker run 命令

  • -d: 后台运行容器,并返回容器ID;
  • -i: 以交互模式运行容器,通常与 -t 同时使用;
  • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
  • -P: 随机端口映射,容器内部端口随机映射到主机的端口
  • -p: 指定端口映射,格式为:主机(宿主)端口:容器端口
  • -a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
  • --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: 绑定一个卷

Ctrl+P+Q

【答】

退出容器:

exit

或者

ctrl + D

或者

Ctrl+P+Q

--rm参数 ----遗留问题

【答】

在 Docker 容器退出时,默认容器内部的文件系统仍然被保留,以方便调试并保留用户数据。

但是,对于 foreground 容器,由于其只是在开发调试过程中短期运行,其用户数据并无保留的必要,因而可以在容器启动时设置 --rm 选项,这样在容器退出时就能够自动清理容器内部的文件系统。

示例如下:

docker run --rm ba-208

等价于:

docker run --rm=true ba-208

显然,--rm 选项不能与 -d 同时使用(或者说同时使用没有意义),即只能自动清理 foreground 容器,不能自动清理detached容器。

注意,--rm 选项也会清理容器的匿名data volumes。

所以,执行 docker run 命令带 --rm命令选项,等价于在容器退出后,执行 docker rm -v

它们是哪两个文件? 它们是/dev/stdin这个文件和/dev/stdout这个文件。 也就是说所谓的标准输入和标准输出其实就是两个linux下的文件

查看容器

最后创建的容器:docker ps -l

最后创建的n个容器: docker ps -n=2

当容器运行完自己的任务,容器会退出,进入到停止状态

默认情况下容器是不重启的,只有配置了--restart参数才会重启:

--restart=always:不管返回码是什么。都会重启

--restart=on-failure:只有返回码非0时,才会重启

依附容器 ---遗留问题

attach:将终端依附到容器上,只有交互性容器才能依附

后台型容器无法依附终端的,因为它本身就不接受用户交互输入。

查看容器的日志 -- 遗留问题

docker logs命令将输出到标准输出的数据作为日志输出到运行docker logs命令的终端上

默认情况下,logs输出是从容器启动到调用logs命令时的所有输出。

-f:可以不断更新

--tail=5:查看最后5行

-t:查看日志产生的时刻

容器内执行命令

docker exec可以用在容器运行新的任务:

-d:后台型任务

-it:会创建一个交互终端,并捕捉进程的标准输入和输出。通过该交互终端,我们可以在容器内运行命令和查看信息。

容器的导入和导出

export:docker export cranky_babbage > cranky_babbage.tar

import:cat cranky_babbage.tar | docker import - imported:container

镜像文件系统的依赖关系

镜像1中的fileA是镜像2中修改版本,newfile是新创建的文件,其他文件则全部引自镜像2

DockerFile

RUN:创建一个新的镜像层。

EXPOSE:指明容器内进程对外开放的端口及端口列表。

当我们声明了EXPOSE端口之后,我们使用-P命令进行随机映射的时候,是会对这个端口进行映射的。比如说我们现在对一个tomcat容器进行EXPOSE 9999声明,那么我们进行-P随机映射的时候是会对9999端口进行映射的。

ADD:添加文件,如果源文件是tar/zip,则会解压

CMD:设置启动容器时的默认运行命令。 ---遗留问题:会创建一个新的镜像层吗?【答】不会。

ENRYTPOINT:ENRYTPOINT和CMD的区别在于运行容器时添加在镜像名之后的参数,ENRYTPOINT是拼接。CMD是覆盖。 ---遗留问题。

ONBUILD:触发器指令。将ONBUILD指令保存到镜像的元数据中。单钱镜像的构建过程并不会执行,只有新的镜像才会触发执行 ---[TODO]

把DockerFile放在gitlab上:

自动化构建镜像:

数据卷的作用 --遗留问题

  1. 绕过 拷贝写 系统,以达到本地磁盘I/O性能
  2. 绕过 拷贝写 系统,有些文件不需要再docker commit的时候打包进镜像中
  3. 再多个容器之间共享目录
  4. 再宿主和容器之间共享目录
  5. 再宿主和容器之间共享单个文件(可以是socket)

为了保证DockerFile的移植性,不支持VOLUME挂载本地目录到数据卷

数据卷容器:两个容器的源目录和目的目录是一样的

docker rm -v db3 :删除db3容器的时候,也删除了volume

数据的备份与恢复:

源地址:/dbdata 目的地址:/backup/backup.tar

阿里云ECS DOCKER实践指示:

容器网络原理

基础工具
  1. iptables netfilter/iptables。一共分为4个表:filter、nat、mangle和raw。
  • filter定位了过滤规则
  • nat定义了地址转换规则

mangle根据规则修改报文数据

ram默认为空。

iptables内置了5条标准规则链,也叫钩子函数。

PREROUTING: 路由前钩子

INPUT:数据包流入口钩子

FORWARD:转发钩子

OUTPUT:数据包出口钩子

POSTROUTING:路由后钩子

  1. ip命令比ifconf、route还要强大,可以取代。

ip addr add 10.8.8.8 dev waln0

ip addr show wlan0

ip route show

  1. brctl-util 用来配置网桥
  • brctl addbr bridege0
  • brctl delbr
  • brclt addif bridege0 veth0
网络空间虚拟化

基于linux的网络命名空间 net namespace实现的

ip netns add net0

ip netns list

ip netns exec net0 ip add add 10.8.8.8/16 dev eth0

虚拟以太网设备 veth virtual Ethernet

创建一对veht设备:ip link add A type veth peer name B 连接不通命名空间用的。

从none网络生成bridge网络

上图中创建的docker0哪里来的?

12.2 配置及原理 ---[TODO]

Fig:多容器管理工具。通过一个YAML配置文件来管理多个和docker容器。比如使用Fig来配置Rails+PostgreSQL应用。

K8S章节 ---遗留问题

shipyard:通过Web UI方式管理Docker的工具。提供Web UI、命令行 CLI以及API三种方式管理集群。

Docker三剑客:

Machine:解决在各个平台上安装Docker的问题,通过一条指令就可以安装好docker

Swarm:将Docker本地集群集中管理,像单个主机一个简单。

Compose:用于安排应用部署到哪个容器组中。 采用YAML作为配置文件。让多个容器跑起来。

Docker项目已加入Linux基金会,并遵循Apache2.0协议(全部开源代码放在https://github.com/docker)

LXC:Linux Container (Linux容器)

配置Docker

  1. 操作系统对Docker服务进行了封装
  • service docker restart
  • 默认配置文件为/etc/default/docker, 如让Docker服务开启2375端口:

  1. Docker服务启动时本质是调用dockerd命令,监听本地2376端口
  • $ dockerd -D -H tcp://127.0.0.1:2376
  1. dockerd服务启动的时候也会读取/etc/docker/daemon.json文件

日志查询

journalctl -u docker.service

实时查看日志:journalctl -u docker.service -f

创建镜像

  1. docker commit:基于已有容器创建一个新的镜像
  2. docker import:模版压缩包 .tar包导入镜像
  3. docker build:Dockerfile

存出和载入镜像

docker save: -o ubuntu.tar ubuntu. docker save docker save 也可以打包container,保存的是容器背后的image. 也可以打包container,保存的是容器背后的image.

docker load: -i ubuntu.tar docker load用于将打包的tar中包含的镜像load到本地镜像库,但不能重命名其中的镜像名。

==【TODO】各方面的实验==

总结一下

docker save保存的是镜像(image),docker export保存的是容器(container); docker load用来载入镜像包,必须是一个分层文件系统,必须是是save的包; docker import用来载入容器包,但两者都会恢复为镜像; docker load不能对载入的镜像重命名,而docker import可以为镜像指定新名称。 docker export的包会比save的包要小,原因是save的是一个分层的文件系统,export导出的只是一个linux系统的文件目录

区别

docker load导入镜像存储文件到本地镜像库

docker import导入一个容器快照到本地镜像库

进入容器

docker diff

Symbol

Description

A

A file or directory was added

D

A file or directory was deleted

C

A file or directory was changed

Docker update

仓库

一个注册服务器(Registry)上有多个仓库,每个仓库下有多个镜像(image)

自动构建 ---遗留问题

docker国内镜像源---遗留问题

Docker中国区官方镜像: https://registry.docker-cn.com 网易: http://hub-mirror.c.163.com ustc: https://docker.mirrors.ustc.edu.cn 中国科技大学: https://docker.mirrors.ustc.edu.cn 阿里云: https://cr.console.aliyun.com/

配置docker

hub.docker.com

~/.docker/config.json保存用户名和密码

-v 和 -mount 选项

最开始 -v 或者 --volume 选项是给单独容器使用, --mount 选项是给集群服务使用。但是从 Docker 17.06 开始,也可以在单独容器上使用 --mount。通常来讲 --mount 选项也更加具体(explicit)和”啰嗦”(verbose),最大的区别是

  • -v 选项将所有选项集中到一个值
  • --mount 选项将可选项分开

如果需要指定 volume driver 选项,那么必须使用 --mount

  • -v 或 --volume: 包含三个 field,使用 : 来分割,所有值需要按照正确的顺序。第一个 field 是 volume 的名字,并且在宿主机上唯一,对于匿名 volume,第一个field通常被省略;第二个field是宿主机上将要被挂载到容器的path或者文件;第三个field可选,比如说 ro
  • --mount: 包含多个 key-value 对,使用逗号分割。--mount 选项更加复杂,但是各个值之间无需考虑顺序。
  • type,可以为 bind, volume, tmpfs, 通常为 volume
  • source 也可以写成 src,对于 named volumes,可以设置 volume 的名字,对于匿名 volume,可以省略
  • destination 可以写成 dst或者 target 该值会挂载到容器
  • readonly 可选,如果使用,表示​​只读​
  • volume-opt 可选,可以使用多次

两个例子

docker run -d \

--name=nginxtest \

--mount source=nginx-vol,destinatinotallow=/usr/share/nginx/html \

nginx:latest

docker run -d \

--name=nginxtest \

-v nginx-vol:/usr/share/nginx/html \

nginx:latest

本地目录的路径必须是绝对理由,容器内的路径可以是相对路径。

数据卷容器的目的:多个容器共享数据。

tmpfs类型的数据卷:数据只存在内存中,容器退出后自动删除。用于不希望将数据报错在主机或者容器中的应用场景。

-P:随机映射到49000~49900的端口

-P是将所有image指定的端口自动转发一个比较大的端口,但是你image里没有EXPOSE指定端口,当然不能用-P。

-P参数为什么看不到端口映射?

【答】

可能是因为image里面没有EXPOSE参数

为啥--rm和-d不能同时使用?

【答】

能不能从本质上理解--rm和-d的应用场景

docker --link参数中DB_PORT等参数从哪里来的?

【答】

指令说明

DockerFile里面碰到ADD、COPY、和RUN指令会生产一层新的镜像

目前常用的linux发行版主要包括Debian/Ubuntu系列和CentOS/Fedora系列。

Nginx的热部署:采用master管理进程和worker工作进程的分离设计,故支持热部署

  1. 在不断服务的前提下,可以直接升级后版本
  2. 在不停止服务的情况下修改配置文件,更换日志文件等。

关系型数据库:Mysql、Oracle、PostGreSQL、MariaDB、SQLServer

非关系型数据库:MongoDB、Redis

项目架构师和开发人员的作用贯彻整个开发、测试、生产三个环节。

容器访问外部的实现

外部访问容器的实现

Mesos最初设计为资源调度器。

安装Docker的先决条件

  1. 运行64位CPU架构的计算机(X86_64或AMD64)
  2. 运行Linux3.8或更高版本内核
  3. 内核必须支持一种存储驱动:AUFS、VFS、Device Mapper或者overlay2
  4. 内核必须支持cgroup和namespace功能
unix套接字和tcp套接字的区别

UNIX Socket是同一台服务器上不同进程间的通信机制。TCP/IP Socket是网络上不同服务器之间进程的通信机制,也可以让同一服务器的不同进程通信。

Postgres的一位核心开发者曾经做过实验,证明UNIX Socket的方式比TCP/IP Socket方式要快31%,所以,在同一个服务器上应该优先选择UNIX Socket方式。

dockerd和/usr/bin/docker的关系

【答】

-it的本质

跟踪容器刚刚生成的日志,不必读取整个日志文件

docker logs --tail 0 -f

实时读取容器全部日志

docker logs -f

读取最后10行日志

docker logs --tail 10

加上时间戳

docker logs -ft

​linux shell 中的sleep命令​

在有的shell(比如linux中的bash)中sleep还支持睡眠(分,小时) sleep 1 睡眠1秒 sleep 1s 睡眠1秒 sleep 1m 睡眠1分 sleep 1h 睡眠1小时

为啥这里sleep是进程,echo不是?

#docker run --name zhoufeng2 -d ubuntu /bin/sh -c "while true;do echo hello world;sleep 1;done"

root@zhoufeng-ProLiant-DL380p-Gen8:~# docker top zhoufeng2 UID PID PPID C STIME TTY TIME CMD root 57131 57103 0 10:04 ? 00:00:00 /bin/sh -c while true;do echo hello world;sleep 1;done root 59083 57131 0 10:10 ? 00:00:00 sleep 1

apt-get update 和 upgrade 的区别

update update 是同步 /etc/apt/sources.list 和 /etc/apt/sources.list.d 中列出的源的索引,这样才能获取到最新的软件包。

upgrade upgrade 是升级已安装的所有软件包,升级之后的版本就是本地索引里的,因此,在执行 upgrade 之前一定要执行 update, 这样才能是最新的。

用户在使用Docker时,需要使用Docker命令行工具docker与Docker daemon建立通信。Docker daemon是Docker守护进程,负责接收并分发执行Docker命令。

Docker命令行工具docker与Docker daemon是同一个二进制文件?

【答】【TODO】

不是,一个是docker一个是dockerd

【TODO】docker start 命令使用-i选项来开启交互模式,始终保持输入流开放。使用-a选项来附加标准输入、输出或错误输出。

docker attach命令:可以连接到正在运行的容器。观察该容器的运行情况,或与容器的主进程镜像交互。

配置文件

由于容器的轻量化设计,其中缺乏相应的文本编辑命令工具,这时可以利用volume来实现文件的创建。省去了在容器中安装各种编辑工具的麻烦。

只配置了一个link参数,两个容器能相互访问吗?

【答】

Link是单向通信,当前容器可以访问link参数后面设置的目标容器,但是不能从目标容器访问当前容器

APP向db请求数据后,如何应答?

【答】

Docker通过namespace实现了资源隔离

通过cgroups实现了资源限制

通过COW写时复制机制实现了高效的文件操作

Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版),我们用社区版就可以了。

Docker的应用场景

  • Web 应用的自动化打包和发布。
  • 自动化测试和持续集成、发布。
  • 在服务型环境中部署和调整数据库或其他的后台应用。
  • 从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。
快速,一致地交付您的应用程序

Docker 允许开发人员使用您提供的应用程序或服务的本地容器在标准化环境中工作,从而简化了开发的生命周期。

容器非常适合持续集成和持续交付(CI / CD)工作流程,请考虑以下示例方案:

  • 您的开发人员在本地编写代码,并使用 Docker 容器与同事共享他们的工作。
  • 他们使用 Docker 将其应用程序推送到测试环境中,并执行自动或手动测试。
  • 当开发人员发现错误时,他们可以在开发环境中对其进行修复,然后将其重新部署到测试环境中,以进行测试和验证。
  • 测试完成后,将修补程序推送给生产环境,就像将更新的镜像推送到生产环境一样简单。

Docker 架构

Docker 包括三个基本概念:

  • 镜像(Image):==Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统==。
  • 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
  • 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。

一个 Docker Registry(注册中心)中可以包含多个仓库(Repository)

通常,一个仓库会包含同一个软件不同版本的镜像

概念

说明

Docker 镜像(Images)

Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。

Docker 容器(Container)

容器是独立运行的一个或一组应用,是镜像运行时的实体。

Docker 客户端(Client)

Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。

Docker 主机(Host)

一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。

Docker Registry

Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(​​https://hub.docker.com​​) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。

Docker Machine

Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。

Ubuntu Docker 安装

​https://www.runoob.com/docker/ubuntu-docker-install.html​

【TODO】

Windows Docker 安装

​https://www.runoob.com/docker/windows-docker-install.html​

镜像加速器

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://2pb8maay.mirror.aliyuncs.com"]

}

EOF

sudo systemctl daemon-reload

sudo systemctl restart docker

云服务器

**云服务器(Elastic Compute Service, ECS)**是一种简单高效、安全可靠、处理能力可弹性伸缩的计算服务。

云服务器管理方式比物理服务器更简单高效,我们无需提前购买昂贵的硬件,即可迅速创建或删除云服务器,云服务器费用一般在几十到几百不等,可以根据我们的需求配置。

目前市场上的云服务器很多,这里主要介绍三家:

  • ​阿里云​​:活动折扣力度很大(1核2G,87.12/年),[ 直达链接 ](https://www.aliyun.com/minisite/goods?taskCode=yds2021-07zy&recordId=811046&userCode=i5mn5r7m)。
  • ​腾讯云​​:腾讯云目前活动多一些,性价比也高,[ 直达链接 ](https://curl.qcloud.com/JsztA7Wh)。
  • ​华为云​​:领券购买也很划算,[ 直达链接 ](https://activity.huaweicloud.com/cps/recommendstore.html?fromacct=f3797f3d-4da5-4a2f-9149-130ad807c940&utm_source=dGlhbnFpeGlu=&utm_medium=cps&utm_campaign=201905)。
docker 命令行
  • docker: Docker 的二进制执行文件。

root@controller:~# docker login registry.cn-hangzhou.aliyuncs.com

root@controller:~# docker search tomcat

安装完docker后,执行docker相关命令,出现:

”Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.26/images/json: dial unix /var/run/docker.sock: connect: permission denied“

原因

摘自docker mannual上的一段话:

Manage Docker as a non-root user

The docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root and other users can only access it using sudo. The docker daemon always runs as the root user.

If you don’t want to use sudo when you use the docker command, create a Unix group called docker and add users to it. When the docker daemon starts, it makes the ownership of the Unix socket read/writable by the docker group

大概的意思就是:docker进程使用Unix Socket而不是TCP端口。而默认情况下,Unix socket属于root用户,需要root权限才能访问。

解决方法1

使用sudo获取管理员权限,运行docker命令

解决方法2

docker守护进程启动的时候,会默认赋予名字为docker的用户组读写Unix socket的权限,因此只要创建docker用户组,并将当前用户加入到docker用户组中,那么当前用户就有权限访问Unix socket了,进而也就可以执行docker相关命令

sudo groupadd docker #添加docker用户组

sudo gpasswd -a $USER docker #将登陆用户加入到docker用户组中

newgrp docker #更新用户组

docker ps #测试docker命令是否可以使用sudo正常使用

FROM:只有一条:从docker images里面获取987XXX的镜像层

MAINTAINER、RUN、EXPOSE等:都是分为四步:1、指令 2、创建新容器 3、删除新容器 4、输出新的镜像

最后提交最后的镜像层和tag名称。

我们也可以使用 -p 标识来指定容器端口绑定到主机端口。

两种方式的区别是:

  • -P :是容器内部端口随机映射到主机的高端口。
  • -p : 是容器内部端口绑定到指定的主机端口。

上面的例子中,默认都是绑定 tcp 端口,如果要绑定 UDP 端口,可以在端口后面加上 /udp

runoob@runoob:~$ docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py

6779686f06f6204579c1d655dd8b2b31e8e809b245a97b2d3a8e35abe9dcd22a

自定义网络不是本来就提供DNS功能,支持容器名作为域名直接访问

的原理是什么?

【答】

docker自定义网络里的dns实现原理

简单说一下流程吧,不写了。

docker会修改容器里的/etc/resolv.conf文件,把dns服务器设置成127.0.0.11,因为127.0.0.0/8地址都是本机回环地址,所以dns查询的时候实际上是把请求发给了自己。虽然是发给自己,但是还是要走netfilter表的。nat表的output链里把发往127.0.0.11:53的UDP包转到了41741端口

iptables -A DOCKER_OUTPUT -d 127.0.0.11``/32` `-p udp -m udp --dport 53 -j DNAT --to-destination 127.0.0.11:41741

netstat -anp查看发现是dockerd在监听41741端口,等dns请求又回环到filter表的input链的时候dockerd就接到了这个请求。所以,辗转了半天dns请求最终发给了dockerd进程。dockerd自身处理这些请求,处理不了的应该是要发给宿主机的dns服务器。

【答】只有user-define的网络且指定了--name的容器才能被dockerd的DNS处理。

dockerd自身如何处理的?【TODO】

【答】

dockerd本身就是个嵌入式dns服务器,而只有自定义网络的容器才会使用这个功能,至于它的实现肯定有一个自定义网络的容器名与IP的对应关系表,dns服务器读取该表决定是不是返回该名称对应的ip

--dns=IP_ADDRESS: 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。

其中:默认bridge模式下,会添加

DNS服务

默认情况下,容器继承主机的 DNS 设置,如/etc/resolv.conf配置文件中所定义 。使用默认bridge 网络的容器获得该文件的副本,而使用​​自定义网络的​​容器 使用 Docker 的嵌入式 DNS 服务器,它将外部 DNS 查找转发到主机上配置的 DNS 服务器。

上面的链接和图片为什么不深入思考下呢?dockerd内嵌的dns服务器跟--dns的关系是什么?是否不会覆盖掉还是只是添加?还有这两者跟/etc/resolv.conf的逻辑关系是什么。优先处理哪个?都需要做实验才知道啊

【答】

解决:Nginx访问静态页面出现中文乱码

修改/etc/nginx/conf.d中default.conf文件。此文件被/etc/nginx/nginx.conf文件include进来

修改后,重启Nginx服务。

Windows版nginx重启命令:nginx.exe -s reload

指令详解

COPY

复制指令,从上下文目录中复制文件或者目录到容器里指定路径。

格式:

COPY [--chown=<user>:<group>] <源路径1>... <目标路径>

COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]

[--chown=:]:可选参数,用户改变复制到容器内文件的拥有者和属组。

<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

COPY hom* /mydir/

COPY hom?.txt /mydir/

<目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

ADD

ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:

  • ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
  • ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

-v:主机的目录/data映射到容器的/data

健康检查中 cat /text.txt || exit 1

【答】

|则与&&相反。如果||左边的命令(command1)未执行成功,那么就执行||右边的命令(command2)

举例:203上/zhoufeng/docker/Dockerfile

【总结】

ENTRYPOINT跟CMD同时存在时,CMD只会作为参数使用了。

ENTRYPOINT必须跟长时间运行的进程,否则马上退出。

HEALTHCHECK

只会提示unhealthy,不会stop或者restart container。

远程复制到本地:

scp root@10.8.52.54:/usr/local/bin/docker-compose /usr/local/bin/docker-compose

docker镜像文件传输

如果有的网络已经被隔离,无法访问外网,这个时候你还要使用外网的镜像怎么办?

1、在能连接外网的机器上将镜像pull下来,即docker pull xxx:tag

2、将该镜像保存为一个tar文件,即

docker save -o xxx.tar xxx:tag

3、导出tar文件,拷贝到内网的机器上

4、将tar文件加载为docker镜像,即

docker load --input xxx.tar

5、查看镜像,即

docker images

这个时候可以直接使用这个本地镜像了。

Compose 架构关系

docker-compose up 依赖 docker-compose.yml文件 -->> 一个service是web(从.即当前的dockerfile中运行flack);一个service是redis(使用images)创建 -->>app.py运行flask程序及读取redis数据库。

实验环境:52.54:/zhoufeng/docker/docker-compose

实验结果:

LXC为Linux Container的简写。

docker本质就是宿主机的一个进程,docker是通过namespace实现资源隔离,通过cgroup实现资源限制,通过写时复制技术(copy-on-write)实现了高效的文件操作(类似虚拟机的磁盘比如分配500g并不是实际占用物理磁盘500g)

二、docker架构

1、总体架构

  • distribution 负责与docker registry交互,上传洗澡镜像以及v2 registry 有关的源数据
  • registry负责docker registry有关的身份认证、镜像查找、镜像验证以及管理registry mirror等交互操作
  • image 负责与镜像源数据有关的存储、查找,镜像层的索引、查找以及镜像tar包有关的导入、导出操作
  • reference负责存储本地所有镜像的repository和tag名,并维护与镜像id之间的映射关系
  • layer模块负责与镜像层和容器层源数据有关的增删改查,并负责将镜像层的增删改查映射到实际存储镜像层文件的graphdriver模块
  • graghdriver是所有与容器镜像相关操作的执行者
2、docker架构2

如果觉得上面架构图比较乱可以看这个架构:

从上图不难看出,用户是使用Docker Client与Docker Daemon建立通信,并发送请求给后者。

而Docker Daemon作为Docker架构中的主体部分,首先提供Server的功能使其可以接受Docker Client的请求;而后Engine执行Docker内部的一系列工作,每一项工作都是以一个Job的形式的存在。

Job的运行过程中,当需要容器镜像时,则从Docker Registry中下载镜像,并通过镜像管理驱动graphdriver将下载镜像以Graph的形式存储;当需要为Docker创建网络环境时,通过网络管理驱动networkdriver创建并配置Docker容器网络环境;当需要限制Docker容器运行资源或执行用户指令等操作时,则通过execdriver来完成。

而libcontainer是一项独立的容器管理包,networkdriver以及execdriver都是通过libcontainer来实现具体对容器进行的操作。当执行完运行容器的命令后,一个实际的Docker容器就处于运行状态,该容器拥有独立的文件系统,独立并且安全的运行环境等。

这个架构图更加清晰了架构

docker daemon就是docker的守护进程即server端,可以是远程的,也可以是本地的,这个不是C/S架构吗,客户端Docker client 是通过rest api进行通信。

docker cli 用来管理容器和镜像,客户端提供一个只读镜像,然后通过镜像可以创建多个容器,这些容器可以只是一个RFS(Root file system根文件系统),也可以ishi一个包含了用户应用的RFS,容器再docker client中只是要给进程,两个进程之间互不可见。

用户不能与server直接交互,但可以通过与容器这个桥梁来交互,由于是操作系统级别的虚拟技术,中间的损耗几乎可以不计。

主要的模块有:Docker Client、Docker Daemon、Docker Registry、Graph、Driver、libcontainer以及Docker container。   

1、docker client

docker client 是docker架构中用户用来和docker daemon建立通信的客户端,用户使用的可执行文件为docker,通过docker命令行工具可以发起众多管理container的请求。

==docker client可以通过一下三宗方式和docker daemon建立通信:====tcp://host:port;unix:path_to_socket;fd://socketfd。==

==docker client可以通过设置命令行flag参数的形式设置安全传输层协议(TLS)的有关参数,保证传输的安全性。==

docker client发送容器管理请求后,由docker daemon接受并处理请求,当docker client 接收到返回的请求相应并简单处理后,==docker client 一次完整的生命周期就结束了==,当需要继续发送容器管理请求时,用户必须再次通过docker可以执行文件创建docker client。

2、docker daemon

docker daemon 是docker架构中一个常驻在后台的系统进程,功能是:接收处理docker client发送的请求。该守护进程在后台启动一个server,server负载接受docker client发送的请求;接受请求后,server通过路由与分发调度,找到相应的handler来执行请求。

docker daemon启动所使用的可执行文件也为docker,与docker client启动所使用的可执行文件docker相同,在docker命令执行时,通过传入的参数来判别docker daemon与docker client。

容器重启(stop/start)的话

如上图

PID(物理机上的进程号)会发生改变

NAME、IP地址不会发生改变。

docker --privileged=true 参数作用

container内的root拥有真正的root权限

COPY命令的源文件必须放在build context目录下吗?

【答】是的

遗留问题:

1、服务发现到底指的是啥?

【答】

==服务发现会保存容器集群中所有微服务最新的信息。比如IP和端口,并对外提供API,提供服务查询功能。==

2、基于容器的PAAS指的是啥?

Dokku 是一个微型的 Heroku,由 Docker 使用不多于 100 行的 Bash 编写。一旦安装完成,你就可以通过 Git 推送兼容 Heroku 的应用到平台上运行

没看懂

3、etcd是关系型数据库还是kv的数据?关系型数据库和非关系型数据库的区别?

【答】

一、关系型数据库

关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织 优点: 1、易于维护:都是使用表结构,格式一致; 2、使用方便:SQL语言通用,可用于复杂查询; 3、复杂操作:支持SQL,可用于一个表以及多个表之间非常复杂的查询。 缺点: 1、读写性能比较差,尤其是海量数据的高效率读写; 2、固定的表结构,灵活度稍欠; 3、高并发读写需求,传统关系型数据库来说,硬盘I/O是一个很大的瓶颈。

二、非关系型数据库

非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者键值对等。 优点: 1、格式灵活:存储数据的格式可以是key,value形式、文档形式、图片形式等等,文档形式、图片形式等等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。 2、速度快:nosql可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘; 3、高扩展性; 4、成本低:nosql数据库部署简单,基本都是开源软件。

缺点: 1、不提供sql支持,学习和使用成本较高; 2、无事务处理; 3、数据结构相对复杂,复杂查询方面稍欠。

非关系型数据库的分类和比较: 1、文档型 2、key-value型 3、列式数据库 4、图形数据库

4、consul比zookeeper和etcd好?进行对比分析

【答】

服务发现对比:Zookeeper vs etcd vs Consul

相关推荐

  1. Docker in Docker原理实战

    2024-04-01 13:54:01       43 阅读
  2. Docker in Docker原理实战

    2024-04-01 13:54:01       41 阅读
  3. Docker in Docker原理实战

    2024-04-01 13:54:01       39 阅读
  4. Docker in Docker原理实战

    2024-04-01 13:54:01       32 阅读
  5. Docker in Docker原理实战

    2024-04-01 13:54:01       44 阅读
  6. Docker in Docker原理实战

    2024-04-01 13:54:01       37 阅读
  7. Docker in Docker原理实战

    2024-04-01 13:54:01       33 阅读
  8. Docker in Docker原理实战

    2024-04-01 13:54:01       34 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-01 13:54:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-01 13:54:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-01 13:54:01       87 阅读
  4. Python语言-面向对象

    2024-04-01 13:54:01       96 阅读

热门阅读

  1. c++ 设计模式 桥模式

    2024-04-01 13:54:01       38 阅读
  2. pytorch中nn.GroupNorm()作用及参数说明

    2024-04-01 13:54:01       48 阅读
  3. Let`s move - sui move开发实战-dao(5)反馈

    2024-04-01 13:54:01       44 阅读
  4. el-dialog宽度自适应

    2024-04-01 13:54:01       44 阅读
  5. 04_Linux磁盘和文件系统

    2024-04-01 13:54:01       40 阅读
  6. 使用Jackson进行序列化和反序列化

    2024-04-01 13:54:01       37 阅读
  7. Android笔记--MediaCodec(一)

    2024-04-01 13:54:01       36 阅读
  8. 英国生物数据库的申请流程

    2024-04-01 13:54:01       40 阅读
  9. flask+uwsgi+云服务器 部署服务端

    2024-04-01 13:54:01       41 阅读