1. 简述什么是 Docker 容器?
Docker 容器 在应用程序层创建抽象并将应用程序及其所有依赖项打包在一起。这使我们能够快速可靠地部署应用程序。容器不需要我们安装不同的操作系统。相反,它们使用底层系统的 CPU 和内存来执行任务。这意味着任何容器化应用程序都可以在任何平台上运行,而不管底层操作系统如何。我们也可以将容器视为 Docker 镜像的运行时实例
2. 简述Docker的应用场景 ?
(1)Web 应用的自动化打包和发布。
(2)自动化测试和持续集成、发布。
(3)在服务型环境中部署和调整数据库或其他的后台应用。
(4)从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。
3. 整体简述Docker 架构 ?
Docker 包括三个基本概念:
镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。
容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。
Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。
Docker 容器通过 Docker 镜像来创建。
概念 说明
(1)Docker 镜像(Images) Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。
(2)Docker 容器(Container) 容器是独立运行的一个或一组应用,是镜像运行时的实体。
(3)Docker 客户端(Client) Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 (1)Docker 的守护进程通信。
(4)Docker 主机(Host) 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。
(5)Docker Registry Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
4. 请列举Docker的常用基础命令 ?
1.systemctl is-enabled docker 检查服务是否开机启动
2.systemctl enable docker 将服务配置成开机启动
3.systemctl start docker 启动服务
4.systemctl disable docker 禁止开机启动
5.systemctl stop docker 停止
6.systemctl restart docker 重启
7.docker version :查看当前docker版本号
8.docker info:查看docker信息
9.docker --help:docker帮助命令
10.docker images:列出本地主机的镜像
11.docker search xx:查找xx镜像
12.docker search --limit 5 tomcat:查询点赞收藏前五条的镜像
13.docker search --limit 5 --no-trunc tomcat:查询并显示镜像详细信息
14.docker pull xx:拉取xx镜像
15.docker image pull xx:拉取xx镜像
16.docker image rm xx:删除xx镜像
17.docker rmi xx:删除xx镜像
docker rmi -f xx:强制删除xx镜像
docker rmi -f xx:yy:zz:强制删除xx,yy,zz镜像
18.随机指定端口方式启动创建的mytomcat镜像
docker run -it -P dsfz/mytomcat:1.0
19.docker run -it --name “新名字”:指定容器名称
20.docker container ls [OPTIONS]
docker ps [OPTIONS]两个命令的选项一致
加粗样式[OPTIONS]说明(常用)
-a:列出当前所有的正在运行的容器+历史上运行郭的
-l:显示最近创建的容器
-n;显示最近n个创建的容器
-q;静默模式,只显示容器编号
21.exit:退出容器
22.docker run -d xx:启动守护式容器
23.docker logs -f -t --tail ;查看容器日志
24.docker cp 容器ID:从容器内拷贝文件到主机上
5. 简述Linux安装Docker流程和步骤 ?
【Docker的自动化安装】
Docker官方和国内daocloud都提供了一键安装的脚本,使得Docker的安装更加便捷。
官方的一键安装方式:
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
国内 daocloud一键安装命令:
curl -sSL https://get.daocloud.io/docker | sh
执行上述任一条命令,耐心等待即可完成Docker的安装
【Docker手动安装】
手动安装Docker分三步:卸载、设置仓库、安装。
卸载Docker(可选)
第一步,卸载历史版本。这一步是可选的,如果之前安装过旧版本的Docker,可以使用如下命令进行卸载:
yum remove docker
docker-client
docker-client-latest
docker-common
docker-latest
docker-latest-logrotate
docker-logrotate
docker-selinux
docker-engine-selinux
docker-engine
docker-ce
设置源仓库
第二步,设置仓库。新主机上首次安装Docker Engine-Community之前,需要设置Docker仓库。此后可从仓库安装和更新Docker。
在设置仓库之前,需先按照所需的软件包。yum-utils提供了yum-config-manager,并且device mapper存储驱动程序需要device-mapper-persistent-data和lvm2。
$ sudo yum install -y yum-utils
device-mapper-persistent-data
lvm2
执行上述命令,安装完毕即可进行仓库的设置。使用官方源地址设置命令如下:
$ sudo yum-config-manager
–add-repo
https://download.docker.com/linux/centos/docker-ce.repo
通常,官方的源地址比较慢,可将上述的源地址替换为国内比较快的地址:
阿里云:http:**//mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
清华大学源:https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/**docker-ce.repo
仓库设置完毕,即可进行Docker的安装。
Docker安装
执行一下命令,安装最新版本的 Docker Engine-Community 和 containerd。
sudo yum install -y docker-ce docker-ce-cli containerd.io
docker-ce为社区免费版本。稍等片刻,docker即可安装成功。但安装完成之后的默认是未启动的,需要进行启动操作。
如果不需要docker-ce-cli或containerd.io可直接执行如下命令:
yum install -y docker-ce
至此,完成Docker安装。
【Docker启动】
启动Docker的命令:
sudo systemctl start docker
通过运行hello-world镜像来验证是否正确安装了Docker Engine-Community。
// 拉取镜像
sudo docker pull hello-world
// 执行hello-world
sudo docker run hello-world
如果执行之后,控制台显示如下信息,则说明Docker安装和启动成功:
[root@iZ8vb8pfb2awsz4qy7vm7qZ ~]#docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
……
除了启动Docker,一些其他启动相关的命令:
守护进程重启:systemctl daemon-reload
重启Docker服务:systemctl restart docker / service docker restart
关闭Docker服务:docker service docker stop / docker systemctl stop docker
6. 简述Linux(离线)安装Docker流程和步骤 ?
下载地址:https://download.docker.com/linux/static/stable/x86_64/
参考文档:https://docs.docker.com/engine/install/binaries/
机房设备无法访问互联网原因,需要进行离线安装
K8S 生态周报| Docker和containerd 全版本漏洞公布,近期在 Docker 中发现了一个 影响所有版本的安全漏洞 CVE-2022-24769,该漏洞已经在 Docker 最新的版本 v20.10.14 中修复。建议安装docker-20.10.14 最新版本
一、安装docker
1.下载 Docker 二进制文件(离线安装包)
wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.14.tgz
2.通过mobaXterm等工具上传到服务器
3.解压安装包
tar -zxvf docker-20.10.14.tgz
4.将docker 相关命令拷贝到 /usr/bin
cp docker
/* /usr/bin/
5.docker注册成系统服务
vim /etc/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target
6.添加执行权限
chmod +x /etc/systemd/system/docker.service
7.重新加载配置文件(每次有修改docker.service文件时都要重新加载下)
systemctl daemon-reload
8.启动服务
systemctl start docker
9.设置开机自启
systemctl enable docker.service
10.查看状态
systemctl status docker
11.查看Docker版本
docker -v
7. 简述如何启动、停止和终止容器?
一.Docker 容器的启动
上一篇我们说到过两种创建容器的方法
2.1.直接创建 docker create …
1.docker create命令创建容器
2.执行docker start命令来启动容器
使用docker start命令结合容器id或者容器name可以启动一个容器
2.2 创建+启动 docker run …
使用了docker run命令创建了容器,则创建完成后容器就已经启动了
二.停止容器
docker stop
可以通过name或者id终止一个容器
三.删除容器
4.1删除单个容器
docker rm
注意:删除容器时,只能删除已经停止运行的容器,不能删除正在运行的容器
4.1批量删除
docker rm $(docker ps -a -q)
docker ps -a -q会列出所有容器的id,供rm命令删除。
删除已退出的孤立的容器
docker container prune
四.依附容器(交互形容器)
依附容器这个主要是针对交互型容器而言的,
docker attach
局限性:
1.docker attach只能进入交互容器进行操作
2.docker attach不能进入一个关闭的容器,或者是一个后台容器
正确试验方法
1.创建一个容器,然后启动,但是不进入
docker run --name ubuntu -dit ubuntu
2.执行docker attach ubuntu进入我们的交互形容器
五.容器内执行命令(还是交互形)
如果,容器在后台启动了,那我们可以使用docker exec在容器内执行命令
注意
1.使用docker exec``即使用户从终端退出,容器也不会停止运行 2.使用docker attach```时,如果用户从终端退出,则容器会停止运行
延续四中,继续使用其中的容器
可以发现docker exec只能进入一个挂起在后台,且是启动状态的交互形容器
8. Docker 运行在哪些平台上?
Docker 在以下 Linux 发行版上运行:
CentOS 6+
Gentoo
ArchLinux
CRUX 3.0+
openSUSE 12.3+
RHEL 6.5+
Fedora 19/20+
Ubuntu 12.04、13.04
9. 简述解释 Docker 核心组件 ?
三个架构组件包括 Docker 客户端、主机和注册表。
Docker 客户端:该组件执行构建和运行操作以与 Docker 主机通信。
Docker 主机:该组件包含 Docker 守护程序、Docker 镜像和 Docker 容器。守护进程建立到 Docker Registry 的连接。
Docker Registry:该组件存储 Docker 镜像。它可以是公共注册表,例如 Docker Hub 或 Docker Cloud,也可以是私有注册表。
10. 如何调整Docker镜像仓库 ?
修改docker的registry
修改/etc/docker目录下的daemon.json文件
在文件中加入 {
“registry-mirrors”: [“https://registry.docker-cn.com”]
}
保存退出
重新启动docker
chmod +x /etc/systemd/system/docker.service #添加文件权限并启动docker
systemctl daemon-reload #重载unit配置文件
systemctl start docker #启动Docker
systemctl restart docker #重新启动Docker
systemctl enable docker.service #设置开机自启
11. 简述如何查看Docker相关的进程 ?
[root@localhost ~]#ps -ef | grep docker
root 1460 1 0 Jun23 ? 04:45:43 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root 2249 1460 0 Jun23 ? 00:00:09 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 5433 -container-ip 172.26.0.2 -container-port 5432
root 2280 1460 0 Jun23 ? 00:00:09 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 5432 -container-ip 172.26.0.3 -container-port 5432
root 2310 1455 0 Jun23 ? 00:09:35 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/78dc6aacc7d9490fa7c7252dd6b4df01af3b68c2adb69767fb0d51974ea0728c -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
root 2311 1455 0 Jun23 ? 00:16:19 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/d6ec26035ca0428d5c3bd1cc154a76b356cf3a7d0746b0455d81223c7b9ab7fd -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
root 2483 1460 0 Jun23 ? 00:00:32 /usr/bin/docker-proxy -proto tcp -host-ip 127.0.0.1 -host-port 1514 -container-ip 172.21.0.4 -container-port 10514
root 2538 1455 0 Jun23 ? 02:25:41 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/98500167fb283c56fd43f42d3357c52b393481fdcca2bc7a87128ac35e19fa5a -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
root 2571 1455 0 Jun23 ? 02:17:17 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/412652067b159ca617625c315940ce6865534e80fa94b93ef3174f653d21b826 -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
root 7077 1460 0 Jun23 ? 00:00:09 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 3306 -container-ip 172.19.0.2 -container-port 3306
root 7085 1455 0 Jun23 ? 00:09:39 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/976bb8cd43729535a74d1583a758be937b6cf8f7a3329a1737fcb722576d1fea -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
root 7354 1460 0 Jun23 ? 00:00:09 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 3308 -container-ip 172.19.0.3 -container-port 3306
root 7386 1455 0 Jun23 ? 00:09:45 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/14112371b62521a9b52968a6b0d275700343afeceaac478cfb7a90241dfcdf61 -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
root 7402 1460 0 Jun23 ? 00:00:09 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 3307 -container-ip 172.19.0.4 -container-port 3306
root 7431 1455 0 Jun23 ? 00:10:30 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/a0c6a5d5f891d293ae19e0bc3413729ac41cf38cc7e58d5a547b0f0df87fd6c4 -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
root 28336 21582 0 15:32 pts/0 00:00:00 grep --color=auto docker
12. 简述虚拟化和容器化有什么区别?
虚拟化
虚拟化帮助我们在单个物理服务器上运行和托管多个操作系统。在虚拟化中,管理程序为客户操作系统提供了一个虚拟机。VM 形成了硬件层的抽象,因此主机上的每个 VM 都可以充当物理机。
容器化
容器化为我们提供了一个独立的环境来运行我们的应用程序。我们可以在单个服务器或 VM 上使用相同的操作系统部署多个应用程序。容器构成了应用层的抽象,所以每个容器代表一个不同的应用
13. 简述什么是 DockerFile?
Dockerfile 是一个文本文件,其中包含我们需要运行以构建 Docker 映像的所有命令。Docker 使用 Dockerfile 中的指令自动构建镜像。我们可以docker build用来创建按顺序执行多个命令行指令的自动构建
14. 简述如何从 Docker 镜像创建 Docker 容器?
1.获取镜像
docker images #查看本机所有的镜像内容,若没有镜像存在可使用镜像拉取命令从镜像加速地址拉取所需要的镜像。
docker pull [options] name [:tag] #表示从仓库拉取镜像, options是参数, tag是版本
如:docker pull harbor.test.cn:centos7.6-python
2.创建容器
docker run -it centos7.6-python /bin/bash
注:命令含义–创建一个伪终端时刻保持连接,并使用/bin/bash作为交互命令
建立容器成功后可使用 docker ps -a 查看容器的信息
3.进入容器
docker exec -it imageID bash
注:注意一定在命令行尾部添加bash或者/bin/bash,imageID可使用docker image查看
15. 简述什么是Docker Swarm?
Swarm是Docker公司推出的用来管理docker集群的平台,几乎全部用GO语言来完成的开发的,代码开源在https://github.com/docker/swarm, 它是将一群Docker宿主机变成一个单一的虚拟主机,Swarm使用标准的Docker API接口作为其前端的访问入口,换言之,各种形式的DockerClient(compose,docker-py等)均可以直接与Swarm通信,甚至Docker本身都可以很容易的与Swarm集成,这大大方便了用户将原本基于单节点的系统移植到Swarm上,同时Swarm内置了对Docker网络插件的支持,用户也很容易的部署跨主机的容器集群服务。
16. 简述Docker镜像加载原理 ?
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS.
**bootfs(boot file system)**主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system),在bootfs之上。包含的就是典型Linux系统中的/dev, /proc,/bin, letc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu , Centos等等
17. 简述流程如何构建Dockerfile?
编码Dockerfile 文件
docker build命令构建镜像
docker run依镜像运行容器实例
为了使用我们概述的规范创建映像,我们需要构建一个 Dockerfile。要构建 Dockerfile,我们可以使用以下docker build命令:
$ docker build
18. 简述Docker执行Dockerfile的大致流程 ?
(1)docker从基础镜像运行一个容器
(2)执行一条指令并对容器作出修改
(3)执行类似docker commit的操作提交一个新的镜像层
(4)docker再基于刚提交的镜像运行一个新容器
(5)执行dockerfile中的下一条指令直到所有指令都执行完成
19. 使用什么命令将新镜像推送到 Docker Registry?
要将新镜像推送到 Docker Registry,我们可以使用以下docker push命令:
$ docker push myorg/img
20. 简述Docker镜像是什么?
镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时的库、环境变量和配置文件。
镜像是一个只读模板,带有创建Docker容器的说明。通常,一个镜像基于另一个镜像,并带有一些额外的定制。例如,您可以构建一个基于ubuntu镜像的镜像,但是要安装Apache web服务器和您的应用程序,以及运行应用程序所需的配置细节。
Docker 镜像(Image),就相当于是一个 模板,其中包含创建 Docker 容器的说明,可以通过模板来创建容器服务,通过这个镜像我们可以创建多个容器,最终服务运行或项目运行都是在容器中的。
21. 讲述常规操作如何获取镜像?
可以创建自己的镜像,也可以只使用其他人创建并在Docker Hub中发布的镜像。要构建自己的镜像,需要创建一个Dockerfile,使用简单的语法定义创建和运行镜像所需的步骤。Dockerfile中的每一条指令都会在图像中创建一个层。当你更改Dockerfile并重新构建镜像时,只有那些已经更改的层才会重新构建。与其他虚拟化技术相比,这是镜像如此轻量级、小巧和快速的原因之一。
从Docker Hub上拉取镜像(常用)
自己制作镜像 Dockerfile 创建
从别人那边拷贝一份
22. 简述什么是base镜像 ?
base 镜像简单来说就是不依赖其他任何镜像,完全从0开始建起,其他镜像都是建立在他的之上,可以比喻为大楼的地基,docker镜像的鼻祖。
base 镜像有两层含义:(1)不依赖其他镜像,从 scratch 构建;(2)其他镜像可以之为基础进行扩展。
所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。
我们以 CentOS 为例查看 base 镜像包含哪些内容。
下载及查看镜像:
root@ubuntu:~#docker pull centos
Using default tag: latest
latest: Pulling from library/centos
d9aaf4d82f24: Pull complete
Digest: sha256:4565fe2dd7f4770e825d4bd9c761a81b26e49cc9e3c9631c58cfc3188be9505a
Status: Downloaded newer image for centos:latest
root@ubuntu:~#docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest d123f4e55e12 3 weeks ago 197MB
ubuntu 12.04 5b117edd0b76 7 months ago 104MB
我们看到CentOS的镜像大小不到200MB,平时我们安装一个CentOS至少是几个GB,怎么可能才 200MB !
下面我们来解释这个问题,Linux 操作系统由内核空间和用户空间组成。
23. 简述什么是Docker镜像分层 ?
Docker 支持通过扩展现有镜像,创建新的镜像。
实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。比如我们现在构建一个新的镜像,Dockerfile 如下:
#Version: 0.0.1
FROM debian 1.新镜像不再是从 scratch 开始,而是直接在 Debian base 镜像上构建。
MAINTAINER wzlinux
RUN apt-get update && apt-get install -y emacs 2.安装 emacs 编辑器。
RUN apt-get install -y apache2 3.安装 apache2。
CMD [“/bin/bash”] 4.容器启动时运行 bash。.
构建过程如下图所示:
可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层
24. 为什么 Docker 镜像要采用这种分层结构呢?
1:分层最大的优点是共享资源。
2:多个镜像都可以基于相同的 Base 镜像构建而来,那么宿主机只需在磁盘上保存一份base 镜像即可。:3:同时内存中也只需要加载一份 Base 镜3:就可以为所有容器服务,而且镜像的每一层都可以被共享。
如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是否也会被修改?
答案是不会!
修改会被限制在单个容器内。
这就是我们接下来要说的容器 Copy-on-Write(COW) 特性。
新数据会直接存放在最上面的容器层。
修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接保存在容器层中,镜像层保持不变。
如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件。
25. 解释什么是Copy-on-Write(COW) ?
Copy-on-write 是一种共享和复制文件以实现最大效率的策略。当我们试图读取一个文件时,Docker 会从上到下一层层去找这个文件,找到的第一个就是我们的文件,所以下面层相同的文件就被“覆盖”了。
而修改就是当我们找到这个文件时,将它“复制”到读写层并修改,这样读写层的文件就是我们修改后的文件,并且“覆盖”了镜像中的文件了。这最大限度地减少了 I/O 和每个后续层的大小。而删除就是创建了一个特殊的 whiteout 文件,这个 whiteout 文件覆盖的文件即表示删除了。
26. 请简述Docker中可写的容器层的概念 ?
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
典型的Linux在启动后,首先将 rootfs 置为 readonly, 进行一系列检查, 然后将其切换为 “readwrite” 供用户使用。在docker中,起初也是将 rootfs 以readonly方式加载并检查,然而接下来利用 union mount 的将一个 readwrite 文件系统挂载在 readonly 的rootfs之上,并且允许再次将下层的 file system设定为readonly 并且向上叠加, 这样一组readonly和一个writeable的结构构成一个container的运行目录, 每一个被称作一个Layer。
所有对容器的改动,无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
下面我们深入讨论容器层的细节。
镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。
**添加文件:**在容器中创建文件时,新文件被添加到容器层中。
**读取文件:**在容器中读取某个文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后打开并读入内存。
**修改文件:**在容器中修改已存在的文件时,Docker 会从上往下依次在各镜像层中查找此文件。一旦找到,立即将其复制到容器层,然后修改之。
**删除文件:**在容器中删除文件时,Docker 也是从上往下依次在镜像层中查找此文件。找到后,会在容器层中记录下此删除操作。
只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。
这样就解释了我们前面提出的问题:容器层记录对镜像的修改,所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享
27. 简述如何进行Commit镜像 ?
Commit镜像
1、作用
将容器提交后,创建为一个新的镜像,命令与git原理类似。
2、格式:
docker commit [OPTIONS] 容器id [目标镜像名[:TAG]]
3、可选项:
名称,简写 默认 描述
–author,-a 作者
–change,-c 将 Dockerfile 指令应用于创建的镜像
–message,-m 提交的描述消息
–pause,-p true 提交期间暂停容器
4、说明:
将容器的文件更改或设置后创建为新镜像。这允许您通过运行交互式shell调试容器,或者将工作数据集导出到另一个服务器。一般来说,最好使用Dockerfiles以文档化和可维护的方式来管理映像。
提交操作将不包括容器内挂载的卷中包含的任何数据。
默认情况下,正在提交的容器及其进程将在映像提交时暂停。这减少了在创建提交过程中遇到数据损坏的可能性。如果不希望出现这种行为,请将 --pause 选项设置为false。
–change选项将对所创建的映像应用Dockerfile指令。
支持的Dockerfile指令:CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | ONBUILD | USER | VOLUME | WORKDIR
5、测试
1)提交一个容器
docker ps 找到一个新的容器,用commit命令提交一个容器,新增了一个命名为commit/test的镜像 tag为test1.0,用docker images查看本地镜像是否成功提交了。
2)提交一个新配置的容器
用docker inspect命令查看容器的环境变量
提交一个新配置的容器,新增了一个命名为commit/test的镜像 tag为test2.0,跟上一个例子区分
3)实战测试
拉取并启动一个tomcat:9.0的镜像。
我们用docker exec命令进入tomcat 容器中,官方默认的tomcat镜像时没有 webapps 应用,需要将webapps.dist目录下的基本文件拷贝到webapps目录下。
验证tomcat,访问http://localhost:8088/
将操作过后的tomcat容器提交为一个镜像,下次用的时候直接运行这个修改后的tomcat镜像即可。
28. 简述使用“docker commit”命令基于已有容器手动构建镜像?
基于已有容器构建镜像主要是通过docker commit命令来构建新的镜像。
dockercommit构建进行主要有三步:
运行容器
修改容器
将容器保存为新的镜像
比如在centos镜像中安装vim编辑器并存为新的镜像
(1)运行容器
(2)安装vim编辑器
vim编辑器确认没有安装
进行安装
(3)保存为新得镜像
首先查看当前运行的镜像
使用commit存为新的镜像
69f501e858a6是运行容器的ID使用name下面的名称也行
centos-vim是新镜像的名字
查看一下是否有了centos-vim镜像
重新启动新的镜像,验证是否可以使用vim编辑器
可以发现新的镜像可以使用vim编辑器了
上面演示了如何使用commit创建新的镜像,但是docker并不建议使用这种方式创建镜像,原因如下:
这是一种手工创建镜像的方式,容器出错,而且效率低且可重复性弱
更重要的是。使用者并不知道镜像是如何创建出来的。里面是否有恶意程序
29. 简述什么是Docker引擎?
Docker Engine 是一种开源容器化技术,我们可以使用它来构建和容器化我们的应用程序。Docker Engine 由以下组件支持:
Docker 引擎 REST API
Docker 命令行界面 (CLI)
Docker 守护进程
30. 如何访问正在运行的Docker容器?
要访问正在运行的容器,我们可以使用以下命令:
$ docker exec -it bash
31. 如何列出所有正在运行的容器?
要列出所有正在运行的容器,我们可以使用以下命令:
$ docker ps
32. 请描述描述 Docker 容器的生命周期 ?
Docker 容器经历以下阶段:
创建容器
运行容器
暂停容器(可选)
取消暂停容器(可选)
启动容器
停止容器
重启容器
杀死容器
销毁容器
33. 简述什么是Docker对象标签?
Docker 对象标签是存储为字符串的键值对。它们使我们能够将元数据添加到 Docker 对象,例如容器、网络、本地守护进程、图像、Swarm 节点和服务
34. 解释Docker create命令有什么作用?
该docker create命令在指定映像上创建可写容器层,并准备该映像以运行指定命令
35. 简述如何查看某个容器的文件目录 ?
docker exec 容器name ls
[root@VM-4-17-centos containers]#docker exec centos6-2 ls /proc
103
acpi
buddyinfo
bus
cgroups
cmdline
consoles
cpuinfo
crypto
devices
diskstats
dma
driver
execdomains
fb
filesystems
fs
interrupts
iomem
ioports
irq
kallsyms
kcore
key-users
keys
kmsg
kpagecount
kpageflags
loadavg
locks
mdstat
meminfo
misc
modules
mounts
mtrr
net
pagetypeinfo
partitions
sched_debug
schedstat
scsi
self
…
36. 简述容器与主机之间的数据拷贝命令?
主机到容器:
docker cp /localfilename 96f7f14e99ab:/www/
容器到主机:
docker cp 96f7f14e99ab:/www/ /localfilename
37. 编写启动nginx容器(随机端口映射),并挂载本地文件目录到容器html的命令?
docker run -d -p --name nginx2 -v /home/nginx:/usr/share/nginx/html nginx
38. DockerFile中有那些常见的指令?
基础镜像信息 FROM
维护者信息 MAINTAINER
镜像操作指令 RUN、COPY、ADD、EXPOSE、WORKDIR、ONBUILD、USER、VOLUME等
容器启动时执行指令 CMD、ENTRYPOINT
39. 详细阐述Dockerfile每个指令的作用 ?
1.1、FROM :指定基础镜像
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个nginx镜像的容器,再进行修改一样,基础镜像是必须指定的。而FROM就是指定基础镜 像,因此一个Dockerfile中FROM是必备的指令,并且必须是第一条指令。
如:指定ubuntu的14版本作为基础镜像
FROM ubuntu:14
1.2、 RUN:执行命令
RUN指令在新镜像内部执行的命令,如:执行某些动作、安装系统软件、配置系统信息之类,
格式如下两种:
1)shell格式:RUN< command > ,就像直接在命令行中输入的命令一样。
如在nginx里的默认主页中写”hello“:
RUN echo 'hello ’ >/etc/nginx/html/index.html
2)exec格式:RUN [“可执行文件”, “参数1”, “参数2”]
如在新镜像中用yum方式安装nginx:
RUN [“yum”,“install”,“nginx”]
注:多行命令不要写多个RUN,原因是Dockerfile中每一个指令都会建立一层.多少个RUN就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错,RUN书写时的换行符是\
1.3、COPY:复制文件
COPY命令用于将宿主机器上的的文件复制到镜像内,如果目的位置不存在,Docker会自动创建。但宿主机器用要复制的目录必须是和Dockerfile文件统计目录下。
格式:
COPY [–chown=:] <源路径>… <目标路径>
COPY [–chown=:] [“<源路径1>”,… “<目标路径>”]
如把宿主机中的package.json文件复制到容器中/usr/src/app/目录下:
COPY package.json /usr/src/app/
1.4、CMD:容器启动命令
CMD命令用于容器启动时需要执行的命令,CMD在Dockerfile中只能出现一次,如果出现多个,那么只有最后一个会有效。
其作用是在启动容器的时候提供一个默认的命令项。如果用户执行docker run的时候提供了命令项,就会覆盖掉这个命令,没提供就会使用构建时的命令。
格式:
shell 格式:CMD <命令>
exec 格式:CMD [“可执行文件”, “参数1”, “参数2”…]
如容器启动时进入bash:
CMD /bin/bash
也可以用exec写法:
CMD [“/bin/bash”]
1.5 MAINTAINER:指定作者
用来指定dockerfile的作者名称和邮箱,主要作用是为了标识软件的所有者是谁。
语法:
MAINTAINER
如:
MAINTAINER autor_jiabuli [email protected]
1.6、EXPOSE:暴露端口
EXPOSE命名适用于设置容器对外映射的容器端口号,如tomcat容器内使用的端口8081,则用EXPOSE命令可以告诉外界该容器的8081端口对外,在构建镜像时
用docker run -p可以设置暴露的端口对宿主机器端口的映射。
语法:
EXPOSE <端口1> [<端口2>…]
如:
EXPOSE 8081
EXPOSE 8081 其实等价于 docker run -p 8081 当需要把8081端口映射到宿主机中的某个端口(如8888)以便外界访问时,则可以用docker run -p 8888:8081
1.7、WORKDIR:配置工作目录
WORKDIR命令是为RUN、CMD、ENTRYPOINT指令配置工作目录。其效果类似于Linux命名中的cd命令,用于目录的切换,但是和cd不一样的是:如果切换到的目录不存在,WORKDIR会为此创建目录。
语法:
WORKDIR path
如需要在nginx目录下创建一个hello.txt的文件:
##进入/usr/local/nginx目录下
WORKDIR /usr/local/nginx
##进入/usr/local/nginx中的html目录下
WORKDIR html
##在html目录下创建了一个hello.txt文件
RUN echo ‘hello’ > hello.txt
1.8、ENTRYPOINT:容器启动执行命名
ENTRYPOINT的作用和用法和CMD一模一样,但是ENTRYPOINT有和CMD有2处不一样:
CMD的命令会被docker run的命令覆盖而ENTRYPOINT不会
CMD和ENTRYPOINT都存在时,CMD的指令变成了ENTRYPOINT的参数,并且此CMD提供的参数会被 docker run 后面的命令覆盖
1.9、VOLUME
VOLUME用来创建一个可以从本地主机或其他容器挂载的挂载点。例如我们知道tomcat的webapps目录是放web应用程序代码的地方,此时我们要把webapps目录挂载为匿名卷,这样任何写入webapps中的心都不会被记录到容器的存储层,让容器存储层无状态化。
格式:
VOLUME [“path”]
如创建tomcat的webapps目录的一个挂载点
VOLUME /usr/local/tomcat/webapps
这样,在运行容器时,也可以用过docker run -v来把匿名挂载点挂载都宿主机器上的某个目录,如
docker run -d -v /home/tomcat_webapps:/usr/local/tomcat/webapps
1.10、 USER
USER命令用于指定当前望下执行的用户,需要注意的是这个用户必须是已经存在,否则无法指定。它的用法和WORKDIR有点像,切换用户。
格式:
- View Code
1.11、ADD
作用和使用方法和COPY一模一样,在此不重复讲述。
.12、ONBUILD
ONBUILD用于配置当前所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。
意思就是:这个镜像创建后,如果其它镜像以这个镜像为基础,会先执行这个镜像的ONBUILD命令
格式:
- View Code
1.13、ENV:设置环境变量
ENV命名用于设置容器的环境变量,这些变量以”key=value”的形式存在,在容器内被脚本或者程序调用,容器运行的时候这个变量也会保留。
格式:
1) 设置一个: ENV
2) 设置多个:ENV = =…
如设置一个环境变量JAVA_HOME,接下来的命名就可以使用这个变量:
ENV JAVA_HOME /opt/jdk
ENV PATH
P
A
T
H
:
PATH:
PATH:JAVA_HOME/bin
在使用ENV设置环境变量时,有几点需要注意:
1)具有传递性,也就是当前镜像被用作其它镜像的基础镜像时,新镜像会拥有当前这个基础镜像所有的环境变量
2)ENV定义的环境变量,可以在dockerfile被后面的所有指令(CMD除外)中使用,但不能被docker run 的命令参数引用
如:
ENV tomcat_home_name tomcat_7
RUN mkdir $tomcat_home_name
3)除了ENV之外,docker run -e 也可以设置环境变量传入容器内。
如:
docker run -d tomcat -e “tomcat_home_name=tomcat_7”
这样我们进入容器内部用ENV可以看到tomcat_home_name这个环境变量
40. 简述Docker构建Dockerfile的大致流程 ?
1 用Dockerfile的核心在于编写Dockerfile,但是编写完之后我们需要知道怎么使用Dockerfile来构建镜像,下面以构建nginx镜像为例来简要说明构建流程
1.1 上传安装包
首先我们需要把要构建的软件安装包上传到服务器中,我们可以在服务器目录上创建一个专门的文件夹,如:/var/nginx_build,然后把从nginx官网下载的nginx-1.15.8.tar.gz安装包上传到这个目录里。
1.2 编写Dockerfile
如何编写nginx的Dockerfile上面已经详细介绍,现在我们只需把编写好的Dockerfile上传到/var/nginx_build目录下,当然你也可以在服务器上直接编写Dockerfile,但是要记得一定保证Dockerfile文件和安装包在一个目录下。
1.3 运行构建命令构建
docker build 命令用于使用 Dockerfile 创建镜像。
格式:
docker build [OPTIONS] PATH | URL | -
OPTIONS有很多指令,下面列举几个常用的:
–build-arg=[] :设置镜像创建时的变量;
-f :指定要使用的Dockerfile路径;
–force-rm :设置镜像过程中删除中间容器;
–rm :设置镜像成功后删除中间容器;
–tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;
因此我们构建nginx可以用以下命令:
当Dockerfile和当前执行命令的目录不在同一个时,我们也可以指定Dockerfile,如
docker build -f /var/nginx_build/Dockerfile .
执行命名之后,会看到控制台逐层输出构建内容,直到输出两个Successfully即为构建成功
41. DockerFile中的命令COPY和ADD命令有什么区别?
COPY和ADD的区别是COPY的SRC只能是本地文件,其他用法一致
42. 简述Docker Daemon 原理 ?
Docker Daemon是一个守护进程,Docker Client通过命令行与Docker Daemon通信,完成Docker相关操作。Docker Daemon有近50个启动选项,配置这些选项,可以提高Docker的运行效率,增加Docker的安全性。定制适合自己应用场景的 Docker运行环境,Docker Daemon的选项包括仓库、安全、日志、存储、网络等。
43. 简述Docker与传统虚拟机的区别 ?
1、传统虚拟机是需要安装整个操作系统的,然后再在上面安装业务应用,启动应用,通常需要几分钟去启动应用,而docker是直接使用镜像来运行业务容器的,其容器启动属于秒级别;
2、Docker需要的资源更少,Docker在操作系统级别进行虚拟化,Docker容器和内核交互,几乎没有性能损耗,而虚拟机运行着整个操作系统,占用物理机的资源就比较多;
3、Docker更轻量,Docker的架构可以共用一个内核与共享应用程序库,所占内存极小;同样的硬件环境,Docker运行的镜像数远多于虚拟机数量,对系统的利用率非常高;
4、与虚拟机相比,Docker隔离性更弱,Docker属于进程之间的隔离,虚拟机可实现系统级别隔离;
5、Docker的安全性也更弱,Docker的租户root和宿主机root相同,一旦容器内的用户从普通用户权限提升为root权限,它就直接具备了宿主机的root权限,进而可进行无限制的操作。虚拟机租户root权限和宿主机的root虚拟机权限是分离的,并且虚拟机利用如Intel的VT-d和VT-x的ring-1硬件隔离技术,这种技术可以防止虚拟机突破和彼此交互,而容器至今还没有任何形式的硬件隔离;
6、Docker的集中化管理工具还不算成熟,各种虚拟化技术都有成熟的管理工具,比如:VMware vCenter提供完备的虚拟机管理能力;
7、Docker对业务的高可用支持是通过快速重新部署实现的,虚拟化具备负载均衡,高可用、容错、迁移和数据保护等经过生产实践检验的成熟保障机制,Vmware可承诺虚拟机99.999%高可用,保证业务连续性;
8、虚拟化创建是分钟级别的,Docker容器创建是秒级别的,Docker的快速迭代性,决定了无论是开发、测试、部署都可以节省大量时间;
9、虚拟机可以通过镜像实现环境交付的一致性,但镜像分发无法体系化,Docker在Dockerfile中记录了容器构建过程,可在集群中实现快速分发和快速部署。
44. 简述Docker与LXC ( Linux Container)的区别 ?
LXC利用Linux上相关技术实现了容器支持; Docker早期版本中使用了LXC技术,后期演化为新的 libcontainer, 在如下的几个方面进行了改进:
移植性: 通过抽象容器配置, 容器可以实现从一个平台移植到另一个平台;
镜像系统: 基于AUFS的镜像系统为容器的分发带来了很多的便利, 同时共同的镜像层只需要存储一份,实现高效率的存储;
版本管理: 类似于Git的版本管理理念, 用户可以更方便地创建、 管理镜像文件;
仓库系统: 仓库系统大大降低了镜像的分发和管理的成本;
周边工具: 各种现有工具(配置管理、 云平台)对Docker的支持, 以及基于Docker 的PaaS、CI等系统, 让Docker的应用更加方便和多样化
45. Docker本地的镜像文件都存放在哪里?
与 Docker 相关的本地资源都存放在/var/lib/docker/目录下,其中 container 目录存放容器信息,graph 目录存放镜像信息,aufs 目录下存放具体的内容文件
46. 当启动容器的时候提示:exec format error?如何解决问题
exec format error的原因是Docker镜像中不存在可用于运行的可执行文件,或者Docker镜像中存在的可执行文件格式不正确
检查启动命令是否有可执行权限,进入容器手工运行脚本进行排查。
47. 解释如何退出一个镜像的 bash,而不终止它?
按 Ctrl-p Ctrl-q
48. 如何批量清理临时镜像文件?
可以使用 sudo docker rmi $(sudo docker images -q -f danging=true)命令
49. 如何查看镜像支持的环境变量?
使用 sudo docker run IMAGE env
50. Docker容器退出后,通过 docker ps 命令查看不到,数据会丢失么?
容器退出后会处于终止(exited)状态,此时可以通过 docker ps -a 查看,其中数据不会丢失,还可以通过 docker start 来启动,只有删除容器才会清除数据
51. 如何快速停止所有正在运行的容器?
使用 docker kill $(sudo docker ps -q)
52. 如何清理批量后台停止的容器?
使用 docker rm $(sudo docker ps -a -q)
53. 简述什么是Docker Hub?
Docker hub是一个基于云的注册表服务,允许您链接到代码存储库,构建镜像并测试它们,存储手动推送的镜像以及指向Docker云的链接,以便您可以将镜像部署到主机。它为整个开发流程中的容器镜像发现,分发和变更管理,用户和团队协作以及工作流自动化提供了集中资源。
54. 阐述Docker容器之间怎么隔离?
Linux中的PID、IPC、网络等资源是全局的,而NameSpace机制是一种资源隔离方案,在该机制下这些资源就不再是全局的了,而是属于某个特定的NameSpace,各个NameSpace下的资源互不干扰。
虽然有了NameSpace技术可以实现资源隔离,但进程还是可以不受控的访问系统资源,比如CPU、内存、磁盘、网络等,为了控制容器中进程对资源的访问,Docker采用control groups技术(也就是cgroup),有了cgroup就可以控制容器中进程对系统资源的消耗了,比如你可以限制某个容器使用内存的上限、可以在哪些CPU上运行等等。
有了这两项技术,容器看起来就真的像是独立的操作系统了。
55. 简述什么是Docker镜像仓库( Repository) ?
docker镜像仓库(repository)是集中存放镜像的地方。方便与后续的镜像拉取与上传,便于对镜像的集中管理。镜像仓库一般可分为Docker Hub公共中央仓库和个人或者公司使用的私有仓库,私有仓库如果是个人使用则可以直接使用docker自带的registry私有仓库,如果是企业级使用则可以搭建Harbor镜像私有仓库。
56. 简述什么是Docker注册服务器( Registry) ?
很多的Registry服务器都支持第三方用户注册,而后基于用户名去做自己的仓库,但是使用互联网上的Registry有一个缺陷,那就是我们去推送和下载镜像时都不会很快,而在生产环境中很可能并行启动的容器将达到几十、上百个,而且很有可能每个服务器本地是没有镜像的,此时如果通过互联网去下载镜像会有很多问题,比如下载速度会很慢、带宽会用很多等等,如果带宽不够的话,下载至启动这个过程可能要持续个几十分钟,这已然违背了使用容器会更加轻量、快速的初衷和目的。因此,很多时候我们很有可能需要去做自己的私有Registry。
Registry用于保存docker镜像,包括镜像的层次结构和元数据。用户可以自建Registry,也可以使用官方的Docker Hub。
Docker Registry分类:
Sponsor Registry:第三方的Registry,供客户和Docker社区使用
Mirror Registry:第三方的Registry,只让客户使用
Vendor Registry:由发布docker镜像的供应商提供的registry
Private Registry:通过设有防火墙和额外的安全层的私有实体提供的registry
事实上,如果运维的系统环境托管在云计算服务上,比如阿里云,那么用阿里云的Registry则是最好的选择。很多时候我们的生产环境不会在本地,而是托管在数据中心机房里,如果我们在数据中心机房里的某台主机上部署Registry,因为都在同一机房,所以属于同一局域网,此时数据传输走内网,效率会极大的提升。
所有的Registry默认情况下都是基于https工作的,这是Docker的基本要求,而我自建Registry时很可能是基于http工作的,但是Docker默认是拒绝使用http提供Registry服务的,除非明确的告诉它,我们就是要用http协议的Registry。
57. 简述什么是Harbor ?
• Harbor是VMware公司开源的企业级Docker Registry项目,其目标是帮助用户迅速搭建一个企业级的Docker Registry服务
• Harbor以 Docker 公司开源的Registry 为基础,提供了图形管理UI、基于角色的访问控制(Role Based AccessControl)、AD/LDAP集成、以及审计日志(Auditlogging)等企业用户需求的功能,同时还原生支持中文
• Harbor的每个组件都是以Docker 容器的形式构建的,使用docker-compose 来对它进行部署。用于部署Harbor 的docker- compose模板位于harbor/ docker- compose.yml
58. 描述Harbor的特性 ?
1.基于角色控制: 用户和仓库都是基于项目进行组织的,而用户在项目中可以拥有不同的权限
2.基于镜像的复制策略: 镜像可以在多个Harbor实例之间进行复制(同步)
3.支持LDAP/AD: Harbor 可以集成企业内部有的AD/LDAP (类似数据库的一-张表),用于对已经存在的用户认证和管理
4.镜像删除和垃圾回收: 镜像可以被删除,也可以回收镜像占用的空间
5.图形化用户界面: 用户可以通过浏览器来浏览,搜索镜像仓库以及对项目进行管理
6.审计管理: 所有针对镜像仓库的操作都可以被记录追溯,用于审计管理
7.支持RESTful API: RESTful API提供给管理员对于Harbor 更多的操控,使得与其它管理软件集成变得更容易
8.Harbor 和docker registry的 关系: Harbor实质 上是对docker registry做 了封装,扩展了自己的业务模板
59. 简述Harbor的构成 ?
Harbor在架构上主要有Proxy、 Registry、 Core services、 Database (Harbor-db) 、Log collector ( Harbor-log)、Job services六个组件
1 Proxy: Harbor 的Registry、 UI、Token 服务等组件,都处在nginx 反向代理后边。该代理将来自浏览器、docker clients的请求转发到后端不同的服务上
2 Registry:负责储存Docker 镜像,并处理Docker push/pull命令。由于要对用户进行访问控制,即不同用户对Docker 镜像有不同的读写权限,Registry 会指向一个Token 服务,强制用户的每次Docker pull/push 请求都要携带一个合法的Token,Registry会通过公钥对Token进行解密验证
3 Core services: Harbor的核心功能,主要提供以下3个服务:
1.UI (harbor-ui) :提供图形化界面,帮助用户管理Registry. 上的镜像( image),并对用户进行授权
2.WebHook: 为了及时获取Registry.上image 状态变化的情况,在Registry. 上配置 Webhook,把状态变化传递给UI模块
3.Token 服务:负责根据用户权限给每个Docker push/pull 命令签发Token。 Docker 客户端向Registry服务发起的请求,
如果不包含Token,会被重定向到Token服务,获得Token后再重新向Registry 进行请求
#Database (harbor-db) :为core services提供数据库服务,负责储存用户权限、审计日志、Docker 镜像分组信息等数据
#Job services: 主要用于镜像复制,本地镜像可以被同步到远程Harbor 实例上
#Log collector (harbor-log) :负责收集其他组件的日志到一个地方
#Harbor的每个组件都是以Docker 容器的形式构建的,因此,使用Docker Compose 来对它进行部署。
#总共分为7个容器运行,通过在docker-compose.yml所在目录中执行docker-compose ps命令来查看,
名称分别为: nginx、 harbor-jobservice、 harbor-ui、 harbor-db、harbor-adminserver、registry、 harbor-log.
其中harbor-adminserver主要是作为一个后端的配置数据管理,并没有太多的其他功能。harbor-ui所要操作的所有数据都通过harbor-adminserver这样一个数据配置管理中心来完成。
60. 如何给Docker镜像打标签 ?
docker tag 用于给镜像打标签,语法如下:
docker tag SOURCE_IMAGE[:TAG] 原镜像 TARGET_IMAGE[:TAG] 新镜像
1、docker images 查看镜像
docker images
2、对docker.io/centos 这个镜像打标签。在没有打标签之前docker.io/centos 的标签默认是latest的,如果是其他版本要注明。
例如对docker.io/centos这个镜像打标签:
docker tag docker.io/centos docker.io/centos:v1
执行完成后,通过docker images查看出现新的镜像 TAG:v1
说明成功!
3、以此类推,当需要开发第二个版本时,继续打标签:v2
docker tag docker.io/centos docker.io/centos:v2
4、如果因为某些原因,当想要需要回滚版本时,可以通过指定标签的镜像来创建容器:
栗子:
启动centos:v1 版本:
docker run -itd docker.io/centos:v1
执行完毕,通过docker ps 查看
发现容器已启动!
61. 如何实现Docker镜像导入导出 ?
一、使用 export 和 import
1,查看本机的容器
这两个命令是通过容器来导入、导出镜像。首先我们使用 docker ps -a 命令查看本机所有的容器。
2,导出镜像
(1)使用 docker export 命令根据容器 ID 将镜像导出成一个文件。
docker export f299f501774c > hangger_server.tar
(2)上面命令执行后,可以看到文件已经保存到当前的 docker 终端目录下。
3,导入镜像
(1)使用 docker import 命令则可将这个镜像文件导入进来。
docker import - new_hangger_server < hangger_server.tar
(2)执行 docker images 命令可以看到镜像确实已经导入进来了。
二、使用 save 和 load
1,查看本机的容器
这两个命令是通过镜像来保存、加载镜像文件的。首先我们使用 docker images 命令查看本机所有的镜像。
2,保存镜像
(1)下面使用 docker save 命令根据 ID 将镜像保存成一个文件。
docker save 0fdf2b4c26d3 > hangge_server.tar
(2)我们还可以同时将多个 image 打包成一个文件,比如下面将镜像库中的 postgres 和 mongo 打包:
docker save -o images.tar postgres:9.6 mongo:3.4
3,载入镜像
使用 docker load 命令则可将这个镜像文件载入进来。
docker load < hangge_server.tar
62. Docker的导出导出操作(export 和 import)和(save 和 load)的区别 ?
特别注意:两种方法不可混用。
如果使用 import 导入 save 产生的文件,虽然导入不提示错误,但是启动容器时会提示失败,会出现类似"docker: Error response from daemon: Container command not found or does not exist"的错误。
1,文件大小不同
export 导出的镜像文件体积小于 save 保存的镜像
2,是否可以对镜像重命名
docker import 可以为镜像指定新名称
docker load 不能对载入的镜像重命名
3,是否可以同时将多个镜像打包到一个文件中
docker export 不支持
docker save 支持
4,是否包含镜像历史
export 导出(import 导入)是根据容器拿到的镜像,再导入时会丢失镜像所有的历史记录和元数据信息(即仅保存容器当时的快照状态),所以无法进行回滚操作。
而 save 保存(load 加载)的镜像,没有丢失镜像的历史,可以回滚到之前的层(layer)。
5,应用场景不同
docker export 的应用场景:主要用来制作基础镜像,比如我们从一个 ubuntu 镜像启动一个容器,然后安装一些软件和进行一些设置后,使用 docker export 保存为一个基础镜像。然后,把这个镜像分发给其他人使用,比如作为基础的开发环境。
docker save 的应用场景:如果我们的应用是使用 docker-compose.yml 编排的多个镜像组合,但我们要部署的客户服务器并不能连外网。这时就可以使用 docker save 将用到的镜像打个包,然后拷贝到客户服务器上使用 docker load 载入。
63. Docker如何在非Linux系统中运行容器?
Docker for Mac和Windows都使用Linux VM来运行容器。Docker Toolbox用于在Virtual Box VM中运行容器
64. 使用docker port命令映射容器的端口时系统报错Error∶NO public port '80’publis hed for …?
创建镜像时DockerFile要指定正确的EXPOSE的端口,容器启动时指定PublishAllport=true
65. 解释可以在一个容器中同时运行多个应用进程吗?
可以,但没必要。一般不推荐在一个容器内运行多个应用进程,如果有类似需求,可以用过额外的进程管理机制,比如supervisord来管理所运行的进程
66. 如何控制Docker容器占用系统资源CPU的份额?
【CPU控制】
cgroups,是一个非常强大的linux内核工具,他不仅可以限制被namespace隔离起来的资源,
还可以为资源设置权重、计算使用量、操控进程启停等等。所以cgroups (Control groups) 实现了对资源的配额和度量。
cgroups有四大功能:
资源限制:可以对任务使用的资源总额进行限制;
优先级分配:通过分配的cpu时间片数量以及磁盘I0带宽大小,实际上相当于控制了任务运行优先级;
资源统计:可以统计系统的资源使用量,如cpu时长, 内存用量等;
任务控制: cgroup可以对任务执行挂起、恢复等操作。
1、设置CPU使用率上限
Linux通过CFS ( Completely Fair Scheduler, 完全公平调度器)来调度各个进程对CPU的使用。CFS默认的调度周期是100ms。
可以设置每个容器进程的调度周期,以及在这个周期内各个容器最多能使用多少CPU时间。
使用–cpu-period即可设置调度周期,使用–cpu-quota即可设置在每个周期内容器能使用的CPU时间。两者可以配合使用。
CFS周期的有效范围是1ms~1s, 对应的–cpu-period的数值范围是1000~1000000。
容器的CPU 配额必须不小于1ms,即–cpu-quota 的值必须>= 1000。
【查看CPU使用率】
docker run -itd --name test centos:7 /bin/bash
cd /sys/fs/cgroup/cpu/docker/98804287283ce0f6abe8a19c9884c6b5149acc5a050a767e 9f5f4bac5472ef56/
cat cpu.cfs_period_us cpu.cfs_quota_us
100000
-1
#cpu.cfs_period_us:cpu分配的周期(微秒,所以文件名中用 us 表示),默认为100000。
#cpu.cfs_quota_us:表示该control group限制占用的时间(微秒),默认为-1,表示不限制。 如果设为50000,表示占用50000/100000=50%的CPU。
进行CPU压力测试
docker exec -it 98804287283c /bin/bash
vim /cpu.sh
#!/bin/bash
i=0
while true
do
let i++
done
chmod +x /cpu.sh
./cpu.sh
exit
top
【设置CPU使用率】
#设置50%的比例分配CPU使用时间上限
docker run -itd --name test2 --cpu-quota 50000 centos:7 /bin/bash #可以重新创建一个容器并设置限额
或者
cd /sys/fs/cgroup/cpu/docker/98804287283ce0f6abe8a19c9884c6b5149acc5a050a767e9f5f4bac5472ef56
echo 50000 > cpu.cfs_quota_us
docker exec -it 98804287283c /bin/bash
./cpu.sh
exit
top #可以看到cpu占用率接近50%,cgroups对cpu的控制起了效果
2、设置CPU资源占用比(设置多个容器时才有效)
Docker 通过–cpu-shares 指定 CPU 份额,默认值为1024,值为1024的倍数。
#创建两个容器为 c1 和 c2,若只有这两个容器,设置容器的权重,使得c1和c2的CPU资源占比为1/3和2/3。
docker run -itd --name test1 --cpu-shares 1024 centos:7
docker run -itd --name test2 --cpu-shares 512 centos:7
#分别进入容器,进行压力测试
docker exec -it 2e71bd7f3c4c bash
yum install -y epel-release
yum install stress -y
stress -c 4 #产生四个进程,每个进程都反复不停的计算随机数的平方根
#查看容器的运行状态(动态更新)
docker stats
3、设置容器绑定指定的CPU
#先分配虚拟机4个CPU核数
docker run -itd --name test2 --cpuset-cpus 1,3 centos:7 /bin/bash
#进入容器,进行压力测试
yum install -y epel-release
yum install stress -y
stress -c 4
exit
67. 如何控制Docker容器占用系统资源内存的份额?
、创建指定物理内存的容器
-m(–memory=)选项用于限制容器可以使用的最大内存
docker run -itd --name test4 -m 512m centos:7 /bin/bash
docker stats
2、创建指定物理内存和swap的容器
docker run -itd --name gxd7 -m 512m --memory-swap 1g centos:7 /bin/bash
强调一下,–memory-swap是必须要与–memory一起使用的
正常情况下,–memory-swap的值包含容器可用内存和可用swap
所以-m 300m --memory-swap=1g 的含义为:容器可以使用300M 的物理内存,并且可以使用700M (1G - 300M)的swap
如果–memory-swap设置为0或者不设置,则容器可以使用的swap大小为-m值的两倍
如果–memory-swap的值和-m值相同,则容器不能使用swap
如果–memory-Swap值为-1,它表示容器程序使用的内存受限,而可以使用的swap空间使用不受限制(宿主机有多少,swap容器就可以使用多少)
68. 如何控制Docker容器占用系统资源(磁盘配额)的份额?
对磁盘IO配额控制(blkio)的限制
1.1 设置限制项
–device-read-bps:限制某个设备上的读速度bps(数据量),单位可以是kb、mb(M)或者gb。
例:docker run -itd --name test1 --device-read-bps /dev/sda:1M centos:7 /bin/bash
–device-write-bps : 限制某个设备上的写速度bps(数据量),单位可以是kb、mb(M)或者gb。
例:docker run -itd --name test1 --device-write-bps /dev/sda:1mb centos:7 /bin/bash
–device-read-iops :限制读某个设备的iops(次数)
–device-write-iops :限制写入某个设备的iops(次数)
1.2 创建容器,并限制写速度
1.3 通过dd来验证写速度
docker exec -it test1 bash #进入容器
dd if=/dev/zero of=test.out bs=1M count=50 oflag=direct #添加oflag参数以规避掉文件系统cache
1、清理docker占用的磁盘空间
docker system prune -a #可以用于清理磁盘,删除关闭的容器、无用的数据卷和网络
69. 解释从非官方仓库下载镜像的时候,有时候会提示"Error∶lnvail d registry endpoint ?
需要手动添加对非官方仓库的信任。
DOCKER_ORTS=”-insecure-registry dl.dockerpool.com:5000”重启docker服务
70. Docker的配置文件放在哪里如何修改配置?
Ubuntu系统下Docker的配置文件是/etc/default/docker
CentOS系统Docker配置文件存放在/etc/sysconfig/docker
71. 如何更改Docker的默认存储设置?
Docker的默认存放位置是/var/lib/docker,如果希望将docker的本地文件存储到其他分区,可以使用Linux软连接的方式来做
72. 简述什么是Docker镜像联合文件系统 UnionFS ?
镜像联合文件系统是Docker的基础之一。联合文件系统(UnionFS )是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
73. 简述什么类型的应用程序无状态或有状态更适合Docker容器?
状态(公共交互)信息是由,请求方保存就是无状态,状态(公共交互)信息是由响应方保存就是有状态。
Docker容器适合创建无状态应用程序。无状态应用程序比有状态应用程序更容易使用Docker容器进行扩展,有助于在不同场景中重用相同的镜像。
74. 如何实现退出容器时候自动删除?
docker run命令里加–rm参数
75. 解释Docker容器退出时是否丢失数据?
当Docker容器退出时,不会丢失数据。应用程序写入磁盘的所有数据都会保留在其容器中直到删除该容器为止。即使在容器停止后,该容器的文件系统仍然存在
76. 简述Docker部署Java服务的超完整步骤 ?
查找系统中是否存在jdk
yum list java-1.8*
安装java1.8
yum install java-1.8.0-openjdk* -y
验证是否安装成功
java -version
使用上边的docker exec命令进入到容器中,只想java -verson查看jdk是否安装成功,安装成功显示如下。
java-version
此外通过yum install jdk的方式有一个好处,PATH路径会自动给配置好。如果没有配置的话,需要手动将JAVA_HOME、JAR_HOME等信息在profile中配置。配置项如下:
JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.342.b07-1.el7_9.x86_64
JRE_HOME=
J
A
V
A
H
O
M
E
/
j
r
e
C
L
A
S
S
P
A
T
H
=
.
:
JAVA_HOME/jre CLASS_PATH=.:
JAVAHOME/jreCLASSPATH=.:JAVA_HOME/lib/dt.jar:
J
A
V
A
H
O
M
E
/
l
i
b
/
t
o
o
l
s
.
j
a
r
:
JAVA_HOME/lib/tools.jar:
JAVAHOME/lib/tools.jar:JRE_HOME/lib
PATH=
P
A
T
H
:
PATH:
PATH:JAVA_HOME/bin:$JRE_HOME/bin
export JAVA_HOME JRE_HOME CLASS_PATH PATH
启动JAVA_HOME中jdk的路径换成自己安装的路径即可。
77. 简述Docker的CMD指令 ?
CMD在容器运行的时候提供一些命令及参数,用法如下:
CMD [“executable”,“param1”,“param2”] (exec form, this is the preferred form)
CMD [“param1”,“param2”] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)
第一种用法:运行一个可执行的文件并提供参数。
第二种用法:为ENTRYPOINT指定参数。
第三种用法(shell form):是以”/bin/sh -c”的方法执行的命令。
如你指定:
CMD [“/bin/echo”, “this is a echo test”]
build后运行(假设镜像名为ec):
docker run ec
就会输出: this is a echo test
docker run命令如果指定了参数会把CMD里的参数覆盖:
这里说明一下,如:docker run -it ubuntu /bin/bash 命令的参数是指/bin/bash 而非 -it ,-it只是docker 的参数,而不是容器的参数。
同样是上面的ec镜像启动:
docker run ec /bin/echo hello
docker run ec /bin/echo hello
就不会输出:this is a echo test,因为CMD命令被”/bin/bash”覆盖了
78. 简述什么是Docker compose ?
docker compose是用于定义和运行多容器docker应用程序的工具,compose 通过一个配置文件来管理多个docker容器。
可以使用docker-compose.yml脚本来启动、停止、重启应用,进行docker容器的编排和管理。
但是docker compose并没有实现容器的负载均衡,还需要借助其他工具实现
79. 简述Docker-compose安装的全过程 ?
1).升级内核
(1).查看内核
uname -r
(2).更新yum
sudo yum update
(3).通过yum升级内核
yum install -y kernel
(4).重启系统
shutdown -r now
2).安装docker
(1).下载docker
systemctl start docker
(2).启动docker
yum install -y docker-io
(3).加入开启重启项
systemctl enable docker
(4).查看docker状态
systemctl status docker
3).利用安装包下载安装docker-compose
(1)下载compose
(2).上传到centos系统
(3).把docker-compose移动到 /usr/local/bin/
mv docker-compose-linux-x86_64 /usr/local/bin/
修改包名
mv docker-compose-linux-x86_64 docker-compose
(4).修改文件权限并配置环境变量
chmod 777 docker-compose-linux-x86_64
(5).在当前目录下查看版本
./docker-compose -v
(6).配置环境变量
vim ~/.bash_profile
添加环境变量
PATH=$PATH:/usr/local/bin/
使环境变量生效
source ~/.bash_profile
4).或者利用pip下载安装docker-compose
(1).安装pip
yum -y install epel-release
yum -y install python-pip
查看版本
pip --version
(2).安装compose
pip install docker-compose
查看版本
docker-compose version
2.删除docker-compose
sudo rm /usr/local/bin/docker-compose
80. 简述Docker如何修改容器ip范围 ?
改路由比较办法,可以一开始就将docker配置的bip改成169.254.0.1/24,可以避免冲突。
在daemon配置文件里加个"bip":“169.254.0.1/24”,重启docker就可以了
[root@st-dev6 ~]#vim /etc/docker/daemon.json
{
“bip”:“169.254.0.1/24”
}
81. 简述Docker如何自定义网络配置 ?
通过ip addr命令可以看到,这里有三个网卡,
lo: 本机回环地址
etho : 默认网卡
docker0 :docker的网卡
[root@VM_0_5_centos dockerFile]#ip addr
1: lo: mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 52:54:00:6f:cb:a8 brd ff:ff:ff:ff:ff:ff
inet 172.27.0.5/20 brd 172.27.15.255 scope global eth0
valid_lft forever preferred_lft forever
3: docker0: mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:27:d8:f7:98 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
82. 简述Docker私有仓库打开2375端口的实现 ?
登录docker所在服务器,修改docker.service文件
vi /usr/lib/systemd/system/docker.service
修改如下内容:
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
改为:
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
重启服务
最后重新加载服务的配置文件和重启docker服务:
systemctl daemon-reloadsystemctl restart docker
83. 简述Docker之实现挂载的三种方式汇总 ?
Docker实现挂载的方式
在介绍VOLUME指令之前,我们来看下如下场景需求:
1.容器是基于镜像创建的,最后的容器文件系统包括镜像的只读层+可写层,容器中的进程操作的数据持久化都是保存在容器的可写层上。一旦容器删除后,这些数据就没了,除非我们人工备份下来(或者基于容器创建新的镜像)。能否可以让容器进程持久化的数据保存在主机上呢?这样即使容器删除了,数据还在。
2. 当我们在开发一个web应用时,开发环境是在主机本地,但运行测试环境是放在docker容器上。这样的话,我在主机上修改文件(如html,js等)后,需要再同步到容器中。这显然比较麻烦。
3. 多个容器运行一组相关联的服务,如果他们要共享一些数据怎么办?
对于这些问题,我们当然能想到各种解决方案。而docker本身提供了一种机制,可以将主机上的某个目录与容器的某个目录(称为挂载点、或者叫卷)关联起来,容器上的挂载点下的内容就是主机的这个目录下的内容,这类似linux系统下mount的机制。 这样的话,我们修改主机上该目录的内容时,不需要同步容器,对容器来说是立即生效的。 挂载点可以让多个容器共享。
下面我们来介绍具体的实现机制。
一、通过docker run命令
1.运行命令:docker run --name test -it -v /home/xqh/myimage:/data ubuntu /bin/bash
其中的 -v 标记 在容器中设置了一个挂载点 /data(就是容器中的一个目录),并将主机上的 /home/xqh/myimage 目录中的内容关联到 /data下。
这样在容器中对/data目录下的操作,还是在主机上对/home/xqh/myimage的操作,都是完全实时同步的,因为这两个目录实际都是指向主机目录。
2.运行命令:docker run --name test1 -it -v /data ubuntu /bin/bash
上面-v的标记只设置了容器的挂载点,并没有指定关联的主机目录。这时docker会自动绑定主机上的一个目录。通过docker inspect 命令可以查看到。
xqh@ubuntu:~/myimage$ docker inspect test1
[ {
“Id”: “1fd6c2c4bc545163d8c5c5b02d60052ea41900a781a82c20a8f02059cb82c30c”,
…
“Mounts”: [ {
“Name”: “0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01”,
“Source”: “/var/lib/docker/volumes/0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01/_data”,
“Destination”: “/data”,
“Driver”: “local”,
“Mode”: “”,
“RW”: true
}
],
上面 Mounts下的每条信息记录了容器上一个挂载点的信息,“Destination” 值是容器的挂载点,"Source"值是对应的主机目录。可以看出这种方式对应的主机目录是自动创建的,其目的不是让在主机上修改,而是让多个容器共享。
二、通过dockerfile创建挂载点
上面介绍的通过docker run命令的-v标识创建的挂载点只能对创建的容器有效。通过dockerfile的 VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点。
还有一个区别是,通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。
#test
FROM ubuntu
MAINTAINER hello1
VOLUME [“/data1”,“/data2”]
上面的dockfile文件通过VOLUME指令指定了两个挂载点 /data1 和 /data2.
我们通过docker inspect 查看通过该dockerfile创建的镜像生成的容器,可以看到如下信息
“Mounts”: [ {
“Name”: “d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21”,
“Source”: “/var/lib/docker/volumes/d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21/_data”,
“Destination”: “/data1”,
“Driver”: “local”,
“Mode”: “”,
“RW”: true
}
, {
“Name”: “6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36”,
“Source”: “/var/lib/docker/volumes/6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36/_data”,
“Destination”: “/data2”,
“Driver”: “local”,
“Mode”: “”,
“RW”: true
}
],
可以看到两个挂载点的信息。
三、容器共享卷(挂载点)
下面我们创建另一个容器可以和test1(已经创建好的容器)共享 /data1 和 /data2卷,这是在 docker run中使用 --volumes-from标记,如:
可以是来源不同镜像,如:
docker run --name test2 -it --volumes-from test1 ubuntu /bin/bash
也可以是同一镜像,如:
docker run --name test3 -it --volumes-from test1 myimage /bin/bash
上面的三个容器 test1 , test2 , test3 均有 /data1 和 /data2 两个目录,且目录中内容是共享的,任何一个容器修改了内容,别的容器都能获取到。
四、最佳实践:数据容器
如果多个容器需要共享数据(如持久化数据库、配置文件或者数据文件等),可以考虑创建一个特定的数据容器,该容器有1个或多个卷。
其它容器通过–volumes-from 来共享这个数据容器的卷。
因为容器的卷本质上对应主机上的目录,所以这个数据容器也不需要启动。
如: docker run --name dbdata myimage echo “data container”
说明:有个卷,容器之间的数据共享比较方便,但也有很多问题需要解决,如权限控制、数据的备份、卷的删除等。以后在介绍。
关于Docker中挂载的解释
现在有这么一个命令:
docker run -p 33061:3306 --name mysql --restart=always -e MYSQL_ROOT_PASSWORD=pisen -v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro -d mysql:5.7
因为着重要说挂载的问题,就单独揪出来参数来说
-v /etc/localtime:/etc/localtime:ro
就是将 宿主机的/etc/localtime文件挂载到容器的/etc/localtime 文件,并且容器内的/etc/localtime文件设置为只读(:ro)
实际的效果就是mysql容器启动后,时间时区的设置,使用的就是宿主机的 /etc/localtime 文件内设置的内容起作用。
如果没有设置只读的情况下,该挂载实现的效果是:
情况1:使用echo命令去修改
echo ‘lq’ > timezone
无论更改宿主机上的/etc/localtime文件内容还是修改容器内的/etc/localtime文件内容,都会影响到对方。
情况2:使用vi命令去修改
vi timezone
则无论修改哪边都不会影响到另外一方的文件内容。
84. 简述Docker Pull很慢如何解决?
经常拉取镜像的时候很慢或者拉不下来,这里可以使用阿里云镜像加速器,然后试试看有没有效果
##使用阿里云镜像加速器
[root@localhost ~]#mkdir -p /etc/docker
[root@localhost ~]#tee /etc/docker/daemon.json <<-‘EOF’ {
“registry-mirrors”: [“https://9cpn8tt6.mirror.aliyuncs.com”]
}
EOF
[root@localhost ~]#systemctl daemon-reload
[root@localhost ~]#systemctl restart docker
docker pull时候太慢卡死
有时候我们在pull镜像的时候总是很慢, 这个时候网上的答案是把镜像的地址改成registry.docker-cn.com以提高镜像拉取速度
{
“registry-mirrors”: [“http://registry.docker-cn.com”] }
镜像加速
鉴于国内网络问题,后续拉取 Docker 镜像十分缓慢,我们可以需要配置加速器来解决,我使用的是网易的镜像地址:http://hub-mirror.c.163.com。
新版的 Docker 使用 /etc/docker/daemon.json(Linux) 或者 %programdata%\docker\config\daemon.json(Windows) 来配置 Daemon。
请在该配置文件中加入(没有该文件的话,请先建一个):
{
“registry-mirrors”: [“http://hub-mirror.c.163.com”]
}
85. 简述Docker中配置Hosts的方法实现 ?
配置的方法
方法一:启动容器的时候加上“–add-host”
示例:
1
docker run --add-host=‘www.lyb-geek.com:127.0.0.1’ --add-host=‘www.lyb-geek.cn:192.168.3.1’ --name hello-docker -it 192.168.0.1:5002/lybgeek/hello-docker:1.0
方法二:如果是通过docker-compose启动容器,可以配置extra_hosts属性
示例
version: ‘3.7’
services:
hello-docker:
restart: always
image: 192.168.0.1:5002/lybgeek/hello-docker:1.0
extra_hosts:
- “www.lyb-geek.com:127.0.0.1”
- “www.lyb-geek.cn:192.168.3.1”
container_name: hello-docker
network_mode: bridge
ports: - “80:80”
environment: - ENV=dev
方法三:如果是通过k8s来管理容器,则在可以在创建pod的yaml文件通过hostAliases添加域名IP映射
示例:
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: dev
name: hello-docker-deployment
labels:
app: hello-docker
spec:
replicas: 3
selector:
matchLabels:
app: hello-docker
template:
metadata:
labels:
app: hello-docker
spec:
hostAliases:
- hostnames:
- www.lyb-geek.com
ip: 127.0.0.1 - hostnames:
- www.lyb-geek.cn
ip: 192.168.3.1
imagePullSecrets: - name: default-secret
containers: - name: hello-docker
image: 192.168.0.1:5002/lybgeek/hello-docker:1.0
imagePullPolicy: Always
ports: - containerPort: 80
env: - name: ENV
value: “dev”
核心配置
spec:
hostAliases: - hostnames:
- www.lyb-geek.com
ip: 127.0.0.1 - hostnames:
- www.lyb-geek.cn
ip: 192.168.3.1
总结
不知道大家有没有好奇为什么没介绍通过dockerfile的方式,因为dockerfile的方式,我试过在dockerfile文件中配置
RUN echo ‘www.lyb-geek.com:127.0.0.1’ >> /etc/hosts
不过没生效。也试过将hosts的文件放在项目目录下
通过配置如下内容
COPY hosts /etc/hosts
RUN echo ‘www.lyb-geek.com:127.0.0.1’ >> /etc/hosts
86. Dockerfile构建镜像出现异常,如何排查?
首先,Dockerfile是一层一层的构建镜像,期间会产生一个或多个临时容器,构建过程中其实就是在临时容器里面安装应用,如果因为临时容器安装应用出现异常导致镜像构建失败,这时容器虽然被清理掉了,但是期间构建的中间镜像还在,那么我们可以根据异常时上一层已经构建好的临时镜像,将临时镜像运行为容器,然后在容器里面运行安装命令来定位具体的异常。
87. 简述Docker容器中文乱码的解决方法 ?
1.查看系统支持和默认的字符集,更新yum
locale -a #查看系统支持字符集
echo $LANG #查看默认字符集
yum update
image-20230129142301139
2.下载中文包和对应的依赖包
yum install -y kde-l10n-Chinese
yum reinstall -y glibc-common
rpm -qa | grep glibc-common-2.17-222.el7.x86_64
yum groupinstall “fonts” -y
yum install -y system-config-language
3.添加UTF-8和GBK和GB2312字符集
localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
localedef -c -f GBK -i zh_CN zh_CN.GBK
localedef -c -f GB2312 -i zh_CN zh_CN.GB2312
locale -a #查看
image-20230129142523431
4.修改系统字符集
echo ‘LANG=“zh_CN.UTF-8”’ > /etc/locale.conf #修改系统字符集
source /etc/locale.conf
echo ‘export LC_ALL=“zh_CN.utf8”’ >> /etc/profile
source /etc/profile
5.退出容器重启服务器
exit
reboot
6.检查容器字符集
echo $LANG
echo $LC_ALL
touch 中文.txt
image-20230129143045267
后续一:重启容器使用nohup命令看日志发现还是乱码,再重启项目jar包反而不乱码了,emo了
思路:修改自启动系统文件(一般是/etc/rc.d/rc.local)中的java -jar命令(添加-Dfile.encoding=utf-8)
java -Dfile.encoding=utf-8 -jar xxx.jar --spring.profiles.active=pro >nohup.out &
前提条件是java项目Maven打包的时候添加依赖(原因:Java源代码->Java字节码->JVM->操作系统)
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
后续二:这样上述改后又出现问题了,发现数据库插入中文数据的时候数据库乱码了,emo++
经历:经尝试,发现docker run使用 /bin/bash命令初始化的时候会乱码和/usr/sbin/init命令不会,但是容器内很多服务不启动 思路:创建容器run的时候,给容器定义编码格式(添加’-e LANG=en_US.UTF-8’)
docker run -dit -p 映射端口:端口 --name=容器名 -e LANG=en_US.UTF-8 镜像名 /bin/bash
88. 简述Docker中的有几种网络模式 ?
Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
ocker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接Container-IP访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即docker run创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。
四类网络模式
host模式 –net=host:容器和宿主机共享Network namespace。
container模式 –net=container:NAME_or_ID 容器和另外一个容器共享Network namespace。 kubernetes中的pod就是多个容器共享一个Network namespace。
none模式 –net=none:容器有独立的Network namespace,但并没有对其进行任何网络设置,如分配veth pair 和网桥连接,配置IP等。
bridge模式–net=bridge:(默认为该模式)
89. 简述Docker中CMD和ENTRYPOINT区别 ?
一、CMD的两种格式完全等效,但是ENTRYPOINT两种格式是有区别的
二、docker run 命令替代了dockerfile的CMD命令
三、docker run 命令在ENTRYPOINT的键值对格式下,是作为ENTRYPOINT命令的参数,docker run wx-centos ls -l会出错。
四、docker run 命令在ENTRYPOINT的命令行格式下,无法替换ENTRYPOINT命令(命令行格式的ENTRYPOINT命令,霸道!!!)
五、当CMD和ENTRYPOINT命令行格式的命令在一起时,ENTRYPOINT命令无条件替换CMD命令(霸道!!!1)
六、当CMD和ENTRYPOINT键值对格式的命令在一起时,CMD命令是ENTRYPOINT命令的参数
CMD 和 ENTRYPOINT的其他细节结论
1.CMD的两种格式,一个是命令行格式(shell格式),另一个是键值对格式(exec格式,JSON格式)。
2.键值对后面引号的内容,是前面命令的参数.
3.如果在键值对格式下,看见“/bin/sh”和“-c”的固定搭配,他的本质就是命令行格式。
4.多条CMD命令,只执行最后一条
5.多条ENTRYPOINT 命令,只执行最后一条命令
6.entrypoint小写也可以实现功能,但是不允许,不符合规范,dockerfile命令不准小
90. Docker如何查询镜像版本信息 ?
1).查询镜像
docker search 镜像名称
2).拉取镜像
docker pull 镜像名称
3).启动容器(以tomcat作为实例)
docker run -d --name fist_tomcat --privileged=true -e TZ=“Asia/Shanghai” -v /etc/localtime:/etc/localtime -p 8081:8080 docker.io/tomcat
-d 表示以“守护模式”执行/root/run.sh脚本,此时 Tomcat 控制台不会出现在输出终端上。
-p 表示宿主机(8081)与容器的端口映射(8080,Tomcat容器固定的端口为8080,必须映射到8080)
–name 表示容器名称,用一个有意义的名称命名即可。
-v 表示需要将本地哪个目录挂载到容器中,格式:-v <宿主机目录>:<容器目录>
-e 运行上海时区格式
–privileged=true 开启特权,可以设置容器里的内核参数
-e TZ=“Asia/Shanghai” -v /etc/localtime:/etc/localtime都是用来解决容器时区的问题
91. 请列举Docker-Compose 所有语法 ?
一份标准配置文件应该包含 version、services、networks 三大部分,其中最关键的就是 services 和 networks 两个部分,下面先来看 services 的书写规则。
- image
services:
web:
image: hello-world
在 services 标签下的第二级标签是 web,这个名字是用户自己自定义,它就是服务名称。
image 则是指定服务的镜像名称或镜像 ID。如果镜像在本地不存在,Compose 将会尝试拉取这个镜像。
例如下面这些格式都是可以的:
image: redis
image: ubuntu:14.04
image: tutum/influxdb
image: example-registry.com:4000/postgresql
image: a4bc65fd - build
服务除了可以基于指定的镜像,还可以基于一份 Dockerfile,在使用 up 启动之时执行构建任务,这个构建标签就是 build,它可以指定 Dockerfile 所在文件夹的路径。Compose 将会利用它自动构建这个镜像,然后使用这个镜像启动服务容器。
build: /path/to/build/dir
也可以是相对路径,只要上下文确定就可以读取到 Dockerfile。
build: ./dir
设定上下文根目录,然后以该目录为准指定 Dockerfile。
build:
context: …/
dockerfile: path/of/Dockerfile
注意 build 都是一个目录,如果你要指定 Dockerfile 文件需要在 build 标签的子级标签中使用 dockerfile 标签指定,如上面的例子。
如果你同时指定了 image 和 build 两个标签,那么 Compose 会构建镜像并且把镜像命名为 image 后面的那个名字。
build: ./dir
image: webapp:tag
既然可以在 docker-compose.yml 中定义构建任务,那么一定少不了 arg 这个标签,就像 Dockerfile 中的 ARG 指令,它可以在构建过程中指定环境变量,但是在构建成功后取消,在 docker-compose.yml 文件中也支持这样的写法:
build:
context: .
args:
buildno: 1
password: secret
下面这种写法也是支持的,一般来说下面的写法更适合阅读。
build:
context: .
args:
- buildno=1
- password=secret
与 ENV 不同的是,ARG 是允许空值的。例如:
args: - buildno
- password
这样构建过程可以向它们赋值。
注意:YAML 的布尔值(true, false, yes, no, on, off)必须要使用引号引起来(单引号、双引号均可),否则会当成字符串解析。
- command
使用 command 可以覆盖容器启动后默认执行的命令。
command: bundle exec thin -p 3000
也可以写成类似 Dockerfile 中的格式:
command: [bundle, exec, thin, -p, 3000]
4.container_name
前面说过 Compose 的容器名称格式是:<项目名称><服务名称><序号>
虽然可以自定义项目名称、服务名称,但是如果你想完全控制容器的命名,可以使用这个标签指定:
container_name: app
这样容器的名字就指定为 app 了。
5.depends_on
在使用 Compose 时,最大的好处就是少打启动命令,但是一般项目容器启动的顺序是有要求的,如果直接从上到下启动容器,必然会因为容器依赖问题而启动失败。
例如在没启动数据库容器的时候启动了应用容器,这时候应用容器会因为找不到数据库而退出,为了避免这种情况我们需要加入一个标签,就是 depends_on,这个标签解决了容器的依赖、启动先后的问题。
例如下面容器会先启动 redis 和 db 两个服务,最后才启动 web 服务:
version: ‘2’
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
注意的是,默认情况下使用 docker-compose up web 这样的方式启动 web 服务时,也会启动 redis 和 db 两个服务,因为在配置文件中定义了依赖关系。
6.dns
和 --dns 参数一样用途,格式如下:
dns: 8.8.8.8
也可以是一个列表:
dns: - 8.8.8.8
- 9.9.9.9
此外 dns_search 的配置也类似:
dns_search: example.com
dns_search: - dc1.example.com
- dc2.example.com
- tmpfs
挂载临时目录到容器内部,与 run 的参数一样效果:
tmpfs: /run
tmpfs:
- /run
- /tmp
- entrypoint
在 Dockerfile 中有一个指令叫做 ENTRYPOINT 指令,用于指定接入点,第四章有对比过与 CMD 的区别。
在 docker-compose.yml 中可以定义接入点,覆盖 Dockerfile 中的定义:
entrypoint: /code/entrypoint.sh
格式和 Docker 类似,不过还可以写成这样:
entrypoint:
- php
- -d
- zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so
- -d
- memory_limit=-1
- vendor/bin/phpunit
9.env_file
还记得前面提到的 .env 文件吧,这个文件可以设置 Compose 的变量。而在 docker-compose.yml 中可以定义一个专门存放变量的文件。
如果通过 docker-compose -f FILE 指定了配置文件,则 env_file 中路径会使用配置文件路径。
如果有变量名称与 environment 指令冲突,则以后者为准。格式如下:
env_file: .env
或者根据 docker-compose.yml 设置多个:
env_file: - ./common.env
- ./apps/web.env
- /opt/secrets.env
注意的是这里所说的环境变量是对宿主机的 Compose 而言的,如果在配置文件中有 build 操作,这些变量并不会进入构建过程中,如果要在构建中使用变量还是首选前面刚讲的 arg 标签。
- environment
与上面的 env_file 标签完全不同,反而和 arg 有几分类似,这个标签的作用是设置镜像变量,它可以保存变量到镜像里面,也就是说启动的容器也会包含这些变量设置,这是与 arg 最大的不同。
一般 arg 标签的变量仅用在构建过程中。而 environment 和 Dockerfile 中的 ENV 指令一样会把变量一直保存在镜像、容器中,类似 docker run -e 的效果。
environment:
RACK_ENV: development
SHOW: ‘true’
SESSION_SECRET:
environment:
- RACK_ENV=development
- SHOW=true
- SESSION_SECRET
- expose
这个标签与Dockerfile中的EXPOSE指令一样,用于指定暴露的端口,但是只是作为一种参考,实际上docker-compose.yml的端口映射还得ports这样的标签。
expose:
- “3000”
- “8000”
- external_links
在使用Docker过程中,我们会有许多单独使用docker run启动的容器,为了使Compose能够连接这些不在docker-compose.yml中定义的容器,我们需要一个特殊的标签,就是external_links,它可以让Compose项目里面的容器连接到那些项目配置外部的容器(前提是外部容器中必须至少有一个容器是连接到与项目内的服务的同一个网络里面)。
格式如下:
external_links:
- redis_1
- project_db_1:mysql
- project_db_1:postgresql
- extra_hosts
添加主机名的标签,就是往/etc/hosts文件中添加一些记录,与Docker client的–add-host类似:
extra_hosts:
- “somehost:162.242.195.82”
- “otherhost:50.31.209.229”
启动之后查看容器内部hosts:
162.242.195.82 somehost
50.31.209.229 otherhost
- labels
向容器添加元数据,和Dockerfile的LABEL指令一个意思,格式如下:
labels:
com.example.description: “Accounting webapp”
com.example.department: “Finance”
com.example.label-with-empty-value: “”
labels:
- “com.example.description=Accounting webapp”
- “com.example.department=Finance”
- “com.example.label-with-empty-value”
- links
还记得上面的depends_on吧,那个标签解决的是启动顺序问题,这个标签解决的是容器连接问题,与Docker client的–link一样效果,会连接到其它服务中的容器。
格式如下:
links:
- db
- db:database
- redis
使用的别名将会自动在服务容器中的/etc/hosts里创建。例如:
172.12.2.186 db
172.12.2.186 database
172.12.2.187 redis
相应的环境变量也将被创建。
- logging
这个标签用于配置日志服务。格式如下:
logging:
driver: syslog
options:
syslog-address: “tcp://192.168.0.42:123” - pid
pid: “host”
将PID模式设置为主机PID模式,跟主机系统共享进程命名空间。容器使用这个标签将能够访问和操纵其他容器和宿主机的名称空间。 - ports
映射端口的标签。
使用HOST:CONTAINER格式或者只是指定容器的端口,宿主机会随机映射端口。
ports:
- “3000”
- “8000:8000”
- “49100:22”
- “127.0.0.1:8001:8001”
注意:当使用HOST:CONTAINER格式来映射端口时,如果你使用的容器端口小于60你可能会得到错误得结果,因为YAML将会解析xx:yy这种数字格式为60进制。所以建议采用字符串格式。
- security_opt
为每个容器覆盖默认的标签。简单说来就是管理全部服务的标签。比如设置全部服务的user标签值为USER。
security_opt:
- label:user:USER
- label:role:ROLE
- stop_signal
设置另一个信号来停止容器。在默认情况下使用的是SIGTERM停止容器。设置另一个信号可以使用stop_signal标签。
stop_signal: SIGUSR1 - volumes
挂载一个目录或者一个已存在的数据卷容器,可以直接使用 [HOST:CONTAINER] 这样的格式,或者使用 [HOST:CONTAINER:ro] 这样的格式,后者对于容器来说,数据卷是只读的,这样可以有效保护宿主机的文件系统。
Compose的数据卷指定路径可以是相对路径,使用 . 或者 … 来指定相对目录。
数据卷的格式可以是下面多种形式:
volumes:
// 只是指定一个路径,Docker 会自动在创建一个数据卷(这个路径是容器内部的)。
- /var/lib/mysql
// 使用绝对路径挂载数据卷 - /opt/data:/var/lib/mysql
// 以 Compose 配置文件为中心的相对路径作为数据卷挂载到容器。 - ./cache:/tmp/cache
// 使用用户的相对路径(~/ 表示的目录是 /home/<用户目录>/ 或者 /root/)。 - ~/configs:/etc/configs/:ro
// 已经存在的命名的数据卷。 - datavolume:/var/lib/mysql
如果你不使用宿主机的路径,你可以指定一个volume_driver。
volume_driver: mydriver
- volumes_from
从其它容器或者服务挂载数据卷,可选的参数是 :ro或者 :rw,前者表示容器只读,后者表示容器对数据卷是可读可写的。默认情况下是可读可写的。
volumes_from:
- service_name
- service_name:ro
- container:container_name
- container:container_name:rw
- cap_add, cap_drop
添加或删除容器的内核功能。详细信息在前面容器章节有讲解,此处不再赘述。
cap_add:
- ALL
cap_drop: - NET_ADMIN
- SYS_ADMIN
- cgroup_parent
指定一个容器的父级cgroup。
cgroup_parent: m-executor-abcd - devices
设备映射列表。与Docker client的–device参数类似。
devices:
- “/dev/ttyUSB0:/dev/ttyUSB0”
- extends
这个标签可以扩展另一个服务,扩展内容可以是来自在当前文件,也可以是来自其他文件,相同服务的情况下,后来者会有选择地覆盖原有配置。
extends:
file: common.yml
service: webapp
用户可以在任何地方使用这个标签,只要标签内容包含file和service两个值就可以了。file的值可以是相对或者绝对路径,如果不指定file的值,那么Compose会读取当前YML文件的信息。
更多的操作细节在后面的12.3.4小节有介绍。 - network_mode
网络模式,与Docker client的–net参数类似,只是相对多了一个service:[service name] 的格式。
例如
network_mode: “bridge”
network_mode: “host”
network_mode: “none”
network_mode: “service:[service name]”
network_mode: “container:[container name/id]”
可以指定使用服务或者容器的网络。 - networks
加入指定网络,格式如下:
services:
some-service:
networks:
- some-network
- other-network
关于这个标签还有一个特别的子标签aliases,这是一个用来设置服务别名的标签,例如:
services:
some-service:
networks:
some-network:
aliases: - alias1
- alias3
other-network:
aliases: - alias2
相同的服务可以在不同的网络有不同的别名。
- 其它
还有这些标签:cpu_shares, cpu_quota, cpuset, domainname, hostname, ipc, mac_address, mem_limit, memswap_limit, privileged, read_only, restart, shm_size, stdin_open, tty, user, working_dir
上面这些都是一个单值的标签,类似于使用docker run的效果。
cpu_shares: 73
cpu_quota: 50000
cpuset: 0,1
user: postgresql
working_dir: /code
domainname: foo.com
hostname: foo
ipc: host
mac_address: 02:42:ac:11:65:43
mem_limit: 1000000000
memswap_limit: 2000000000
privileged: true
restart: always
read_only: true
shm_size: 64M
stdin_open: true
tty: true
92. 简述Docker中的容器文件拷贝及目录挂载方式 ?
Docker:容器文件拷贝
目标:掌握文件拷贝命令
将linux宿主机中的文件拷贝到容器内可以使用命令:
#docker cp 需要拷贝的文件或目录 容器名称:容器目录
#创建一个文件abc.txt
touch abc.txt
#复制 abc.txt 到 mycentos2 的容器的 / 目录下
docker cp abc.txt mycentos2:/
#进入mycentos2容器
docker exec -it mycentos2 /bin/bash
#查看容器 / 目录下文件
ll
将文件从容器内拷贝出来到linux宿主机使用命令:
#docker cp 容器名称:容器目录 需要拷贝的文件或目录
#进入容器后创建文件aaa.txt
touch aaa.txt
#退出容器
exit
#在Linux宿主机器执行复制;将容器mycentos2的/aaa.txt文件复制到 宿主机器的/root目录下
docker cp mycentos2:/aaa.txt /root
注意:停止状态的容器也是可以进行文件拷贝的,可以拷进去,也可以拷出来。
Docker:容器目录挂载
目标:掌握目录挂载命令(其实就是目录映射)
可以在创建容器的时候,将宿主机的目录与容器内的目录进行映射,这样我们就可以通过修改宿主机某个目录的文件从而去影响容器。
创建容器时添加-v参数,后边为宿主机目录:容器目录
例如: docker run -di -v /usr/local/test:/usr/local/test --name=mycentos3 centos:7(两个目录可以路径不同)
#创建linux宿主机器要挂载的目录
mkdir /usr/local/test
#创建并启动容器mycentos3
#并挂载 linux中的/usr/local/test目录到容器的/usr/local/test
#也就是在 linux中的/usr/local/test中操作相当于对容器相应目录操作
docker run -di -v /usr/local/test:/usr/local/test --name=mycentos3 centos:7
#在linux宿主机下创建文件
touch /usr/local/test/bbb.txt
#进入容器
docker exec -it mycentos3 /bin/bash
#在容器中查看目录中是否有对应文件bbb.txt
cd /usr/local/test
ll
注意:如果你共享的是多级的目录,可能会出现权限不足的提示。
这是因为CentOS7中的安全模块selinux把权限禁掉了,需要添加参数 --privileged=true 来解决挂载的目录没有权限的问题。
93. 请简述Docker容器内缺少命令的简单解决办法 ?
背景
而使用 docker exec 进入其中后,但该容器没有安装 sudo 或 netstat 或者 ping 等命令。
解决方案
在宿主机使用 nsenter 进入容器对应的命名空间下执行对应的命令即可
安装方式如下
系统 命令
Ubuntu/Debian: apt-get install -y util-linux
Centos/Fedora yum install -y util-linux
Apline apk add util-linux --no-cache
使用方式如下
nsenter 的 c 使用语法为,nsenter -t pid -n ,-t 接 进程 ID 号,-n 表示进入名称空间内, 为执行的命令。
举例:有一个容器的 PID 为 30749,进入该容器名称空间内执行 ifconfig ,如下列所示
nsenter -t 30749-n ifconfig
容器的PID获取方式, 例如查找容器 paas-web
先获取容器的ID
[root@portal1 ~]#docker ps | grep paas-web
d3c24a612b88 4e0043f40393 “/docker-entrypoint.…” 2 weeks ago Up 2 weeks k8s_paas-web_paas-web-c54d74d44-hr697_kube-system_74070b4e-3405-45aa-8bb1-469e37b6b313_0
097146cbeb00 ********:40443/kubernetes/pause-amd64:3.1 “/pause” 2 weeks ago Up 2 weeks k8s_POD_paas-web-c54d74d44-hr697_kube-system_74070b4e-3405-45aa-8bb1-469e37b6b313_0
d3c24a612b88 是我的目标容器,然后执行
[root@portal1 ~]#docker inspect --format “{{ .State.Pid }}” d3c24a612b88
44463
[root@portal1 ~]#
其中 44463 就是我要的容器PID
94. 简述Docker查看运行容器日志的步骤 ?
- 查看运行着的容器
docker ps -a - 查看容器日志命令
docker logs [OPTIONS] CONTAINER
[OPTIONS]
-f : 跟踪日志输出
-t : 显示时间戳
–tail :仅列出最新N条容器日志
–since:显示某个日期至今的所有日志
CONTAINER
代表容器ID或容器名称 - 查看最近10条日志, 并持续打印
docker logs -f --tail 10 efb78392fcc6 - 查看某个日期至今的所有日志, 并持续打印
docker logs -f --since “2022-05-16” efb78392fcc6
95. 解释Docker容器网络更改的实现方式 ?
1.添加自定义网络(默认是桥接模式)
docker network create 网络名称
2.解除容器绑定的网络
docker network disconnect 网络名称 容器名称
3.为容器重新指定网络
docker network connect 网络名称 容器名称
4.重启容器
docker restart 容器名称
5.查看效果
docker inspect 容器名称
96. 简述Docker私有仓库打开XXX端口的实现 ?
在我们开发测试过程中,需要频繁的更新docker镜像,然而默认情况下,docker的xxx端口是关闭的,下面介绍如何打开端口。
1、打开步骤
1.1、修改配置
登录docker所在服务器,修改docker.service文件
vi /usr/lib/systemd/system/docker.service
修改如下内容:
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
改为:
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0: 端口号 -H unix://var/run/docker.sock
1.2 重启服务
最后重新加载服务的配置文件和重启docker服务:
systemctl daemon-reloadsystemctl restart docker
97. 简述解释一下 Dockerfile 的 ONBUILD 指令 ?
当镜像用作另一个镜像构建的基础时, ONBUILD 指令向镜像添加将在稍后执行的触发指令。如果要构建将用作构 建其他镜像的基础的镜像(例如,可以使用特定于用户的配置自定义的应用程序构建环境或守护程序),这将非常 有用
98. 简述如何在生产中监控 Docker ?
Docker 提供 docker stats 和 docker 事件等工具来监控生产中的 Docker。我们可以使用这些命令获取重要统计数 据的报告。
Docker 统计数据:当我们使用容器 ID 调用 docker stats 时,我们获得容器的CPU,内存使用情况等。它类似于 Linux 中的 top 命令。
Docker 事件: Docker 事件是一个命令,用于查看 Docker 守护程序中正在进
行的活动流。
一些常见的 Docker 事件: attach, commit, die, detach, rename,
destroy 等。我们还可以使用各种选项来限制或过滤我们感兴趣的事件。
99. 简述Docker Image 和 Docker Layer (层)有什么不同 ?
Image:一个 Docker Image 是由一系列 Docker 只读层(read-only Layer)创建出来的。
Layer:在 Dockerfile 配置文件中完成的一条配置指令,即表示一个 Docker 层(Layer)。
如下 Dockerfile 文件包含4 条指令,每条指令创建一个层(Layer)。
FROM ubuntu:15.04
COPY ./app
RUN make /app
CMD python /app/app.py
重点,每层只对其前一层进行一(某)些进化
100. 简述什么是孤儿卷及如何删除它 ?
孤儿卷是未与任何容器关联的卷。在 Docker v 。1.9 之前的版本中,删除这些孤儿卷存在很大问题
101. 简述在非 Linux 操作系统平台上如何运行 Docker ?
容器化虚拟技术概念可能来源于,在 Linux 内核版本2.6.24 上加入的对命名空间(namespace)的技术支持特 性。容器化进程加入其进程 ID 到其创建的每个进程上并且对每个进程中的系统级调用进行访问控制及审查。其本 身是由系统级调用 clone ()克隆出来的进程,允许其创建属于自己命名空间的进程实例,而区别于之前的,归属与 整个本机系统的进程实例。
如果上述在 Linux 系统内核上的技术实现成为可能,那么明显的问题是如何在非 Linux 系统上运行容器化的
Docker 。过去, Mac 和 Windows 系统上运行 Docker 容器都使用 Linux 虚拟机(VMs)技术, Docker 工具箱 使用的容器运行在 Virtual Box 虚拟机上。现在,最新的情况是, Windows 平台上使用的是 Hyper-V 产品技术, Mac 平台上使用的是 Hypervisor.framework (框架)产品技术
102. 简述为什么 Docker compose 采取的是并不等待前面依赖服务项的容器启动 就绪后再启动的组合容器启动策略 ?
Docker 的 Compose 配置总是以依赖启动序列来启动或停止 Compose 中的服务容器,依赖启动序列是由
Compose 配置文件中的 depends_on , links , volumes_from 和 network_mode: "service : …"等这些配置指令 所确定的。
然而, Compose 启动中,各容器的启动并不等待其依赖容器(这必定是你整个应用中的某个依赖的服务或应用) 启动就绪后才启动。使用这种策略较好的理由如下:
等待一个数据库服务(举例)就绪这样的问题,在大型分布式系统中仅是相比其它大问题的某些小问题。在实际发 布产品运维中,您的数据库服务会由于各种原因,或者迁移宿主机导致其不可访问。您发布的产品需要有应对这样 状况的弹性。
掌控这些,开发设计您的应用,使其在访问数据库失效的情况下,能够试图重连数据库,直至其连接到数据库为
止。最佳的解决方案是在您的应用代码中检查是否有应对意外的发生,无论是任何原因导致的启动或连接失效都应 考虑在内。