Docker
1. Docker简介
docker是一门虚拟化容器技术,其将应用程序与该程序的依赖,打包在一个镜像文件中。将镜像文件导入docker引擎运行,就会生成一个虚拟容器,程序在这个虚拟容器里运行,与在真实的物理机上运行一样,docker为程序的运行提供了独立的环境。
2. Docker架构
docker采用的是C/S架构。客户端向服务器发送请求,服务器负责构建、运行和分发容器。客户端和服务器可以运行在同一个Host上,客户端也可以通过socket或者REST API与远程的服务器通信。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oVoysWk9-1606457733450)(/images/16e11d4da211ac76.jpg)]
2.1 Docker核心组件
- docker 客户端 - Client
- Docker 引擎 - Docker daemon
- Docker 镜像 - Image
- Registry 仓库
- Docker 容器 - Container
2.2 Docker客户端
通过客户端使用docker命令进行操作,通过docker可以很快的在host上构建镜像和运行容器,常见的命令为docker pull ,docker run ,docker build.
2.3 Docker引擎
Docker daemon 是服务器组件,以 Linux 后台服务的方式运行。 Docker daemon 运行在 Docker host 上,负责创建、运行、监控容器,构建、存储镜像。
引擎架构大致如上图所示,与docker首次发布时不同的是在后面的版本中docker一直在进行拆解与重构工作,容器执行和运行时代码已从引擎中拆解出来。
- Docker daemon:提供API及其他特性
- containerd:所有容器执行逻辑均被重构到此工具中,主要任务为容器的生命周期管理,同时新版本中也负责一些镜像管理工作
- shim:实现无守护进程容器的工具。主要工作为:(1)保持所有的STDIN和STDOUT流为开启状态,当daemon重启时运行的容器不会因为管道的关闭而终止 (2)将容器的退出状态反馈给daemon
- runc:容器运行时工具(内核原语接口),唯一作用为创建容器,是一个轻量级的针对Libcontainer(取代了早期的LXC组件为提供命名空间等服务)进行了包装的命令行交互工具
模型优势
- 容器运行时与Docker deamon解耦(无守护进程的容器),对Docker deamon的升级维护不会影响容器的运行
启动新容器的过程
为了总结引擎工具的作用,下面简述一个启动新容器的过程
2.4 Docker镜像
docker镜像是构建docker容器的基础,与常用的VM虚拟机做对比,如果使用VM启动一个操作系统,Dcoker镜像可以理解为此操作系统的ISO文件,即虚拟机运行的模板。
1.简介
- 描述:镜像=VM模板=类
- 组成:镜像=镜像层+镜像层(OS+文件+依赖包)
- 使用:Docker hub拉取—>本地Docker主机—>启动容器
2.镜像拉取
- 本地仓库:/var/lib/docker/<>
- 远程查找:docker search NAME
- 拉取镜像:docker image pull :(lastest不保证可以拉取最新镜像)
- 拉取全部:docker image pull -a
- 列出镜像:docker image ls
- 注意:将用户加入DOCKER UNIX组中
3.镜像命名和标签
- 两个不同标签可以指向相同镜像
- 悬虚镜像(dangling):在仓库中:存在,原因为构建新镜像,使用了已存在的表情
- 输出悬虚:docker image ls --filter dangling=true
- 删除悬虚:docker image prune
4.镜像过滤
-
–filter
command usage dangling 返回悬虚或非悬虚镜像 before 需要镜像名称/ID,返回之前被创建的全部镜像 since 返回指定镜像之后创建的全部镜像 label 根据标注的名称/值对镜像进行过滤 reference 过滤公式 -
–format
Go模板:”{{.size .rep .tag}}“
5.镜像分层
-
镜像由松耦合的只读镜像层构成
- 查看方法:(1)pull的时候的层次输出 (2)docker image inspect :
-
原理简述:
- 所有镜像都基于一个基础镜像层(比如一个系统)
- 进行修改或增加内容时,在当前镜像层之上建立新的镜像层
- 镜像始终保持是当前所有镜像层的组合
-
实现方式:通过快照方式
-
共享镜像层:镜像拉取时自动识别本地已经存在的镜像层进行共享,因此某一镜像层与镜像不是严格从属关系
-
创建镜像时镜像层的变化问题
所有的Docker都基于基础镜像层,当进行修改或添加新内容时,就会在当前的镜像层之上创建新的镜像层。在添加额外镜像层的同时,镜像始终保持当前所有镜像层的集合。如下图所示,第三层更新文件5时,会对第二层的文件5进行覆盖,整体看了此镜像仍是具有5个文件。
6.镜像散列值
- 为什么用散列值(SHA):当更新某个已存在的镜像,为新镜像重新打标签,旧镜像成为悬虚镜像被覆盖,表现为<none:none>如果生产环境中已经部署了大量镜像,那么仅凭标签已经无法区分,需要使用散列值来区分新老镜像
- 查看方式:docker image ls -digests —> SHA签名值
- 精确拉取:docker image pull @sha256
- 镜像散列值(摘要)
- 背景:镜像(唯一标识为加密ID)=一个或多个镜像层(每个镜像层拥有自身加密ID)+实际存储数据+元数据(加密ID是SHA256串)
- 实质:镜像本身和镜像层都有内容hash值校验,保证了不可被篡改
- 其他作用:镜像上传至仓库需要压缩,对于压缩后散列值改变无法校验的情况,系统中也有一个压缩后的散列值变量,解决了这个问题
7.多架构
- 实现一个镜像支持多种架构
- 策略:Manifest列表和Manifest文件
- 根据架构选择镜像是Docker自己完成
8. 镜像删除
- 删除某个:docker image rm
- 删除全部:docker image rm ${docker image ls -q} -f
9.镜像的创建
镜像创建的三种方法 |
---|
1. 从无到有,写Dockfile结合程序内容上下文进行创建 |
2. 用docker commit 通过运行/停止的容器创建,好处是可以在容器中运行时的改变代码,保存更改生成镜像 |
3.使用已存在的镜像进行创建,一种做法是在Dockerfile中FROM 已存在的镜像做基础层 |
10.相关命令
command | usage |
---|---|
docker image pull name:tag | 拉取镜像 |
docker image ls | 列出镜像 |
docker image inspect | 查看详细信息 |
docker image rm | 删除镜像,有容器依赖不可删除 |
docker image prune | 删除悬虚镜像 |
2.5 Docker仓库
Docker 镜像的仓库用来存放镜像,分私有和公有两种。
-
DockerHub(https://hub.docker.com/)是默认的 Registry,由 Docker 公司维护,上面有数以万计的镜像,用户可以自由下载和使用。
-
用户也可以创建自己的私有 Registry,速度或安全更优
-
相关命令:
docker pull 命令可以从 Registry 下载镜像。
docker run 命令则是先下载镜像(如果本地没有),然后再启动容器。
2.6 Docker容器
1.简介
- docker容器是docker镜像的运行时实例
- 用户可以在单个镜像上启动一个或多个容器
2.容器VS虚拟机
Docker | 虚拟机 | |
---|---|---|
资源占用 | 系统资源 | 物理资源 |
虚拟化 | 操作系统虚拟化 | 硬件虚拟化 |
额外开销 | 无 | 底层硬件资源划分,每个虚拟机都要有操作系统来声明 |
启动时间 | 共享内核,速度快 | 需要初始化内核,速度慢 |
3.运行容器
-
检查docker daemon:docker version
-
无权限解决方案
-
usermod -aG docker 并重新退出登录
-
service docker status/systemctl is-active docker
-
-
运行:docker container run :
4.容器进程
-
容器运行=容器内必须有进程在运行,否则容器自动退出
-
Ctrl-PQ:退出容器但不停止容器运行
5.相关命令:
command | usage |
---|---|
docker container ls | 列出容器列表 |
docker container run(-it /bin/bash) | 启动容器(并启动容器内系统命令行工具) |
docker container exec (-it bash)) | 启动容器内新进程(启动了一个命令行工具) |
docker container stop | 优雅的停止容器执行 |
docker container start | 启动容器 |
docker container rm | 删除容器 |
docker container inspect | 显示容器的配置信息 |
3. Docker应用容器化
1. 完整步骤
- 编写应用代码
- 创建Dockerfile,包括当前应用的描述,依赖,以及如何创建及使用什么命令运行这个应用
- 对Dockerfile进行docker image build操作
- 等待Docker将应用程序构建到Docker中
- 由镜像启动容器,运行应用
- 镜像导出保持:docker save > imagename.tar
2. Dockerfile 解析
- FROM:指定基础镜像
- MAINTAINER:描述
- RUN:创建时执行的命令,导致创建新的镜像层
- COPY:将文件作为新的镜像层添加进镜像中,将本地文件拷贝进镜像哪个目录(这里将Dockfile中同目录下的项目代码拷贝进镜像ubuntu系统中与home同级的新建的pro文件夹)
- WORKDIR:设置工作路径
- CMD:可以设置一些启动容器时默认执行的命令,比如运行应用等,不过暂未深入研究,本次部署是进去之后一步一步在命令行设置的。shell exec格式的命令,只能有一条
- ENTRYPOINT:指定容器启动后默认要运行的程序,与CMD类似,shell exec格式的命令,与CMD有覆盖冲突,只能有一条,多条需要写sh,如[ENTRYPOINT[”./start.sh“]
- EXPOSE:指定用于记录应用所使用的端口
这也是镜像层逐渐增多的过程,FROM RUN COPY等每执行一条新建一个镜像层。
3. 创建过程
-
在应用代码目录同级创建并写好了Dockerfile
-
使用docker image build -t name:tag . 命令创建镜像
-
使用docker image ls 查看已经创建的镜像
-
一般这一步启动并开启命令行交互:docker container run -it name :tag /bin/bash
-
推送至仓库
docker login
docker image tag image_name:tag registry_name/image_name:tag
-
一般由此镜像启动容器后我们还需要进入容器进行配置,这导致内容的改变,一般配置完成后需要在新的容器基础上生成新的镜像,这里使用docker commit命令,由容器创建新镜像
4.第一层为基础ubuntu镜像开始创建常遇到的问题
问题1:docker加速器
-
创建或修改
/etc/docker/daemon.json
sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://1nj0zren.mirror.aliyuncs.com", "https://docker.mirrors.ustc.edu.cn", "http://f1361db2.m.daocloud.io", "https://registry.docker-cn.com" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker
-
验证:docker info
Registry Mirrors: [...]
问题2:docker部署系统apt不能使用
-
描述:docker中使用ubuntu镜像,需要更新apt,但是国外源巨慢,换源需要使用vim,but镜像中不带vim,陷入死循环,只能使用echo来写
echo "deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse" >>/etc/apt/sources.list echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse" >>/etc/apt/sources.list echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse" >>/etc/apt/sources.list echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse" >>/etc/apt/sources.list echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse" >>/etc/apt/sources.list echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse" >>/etc/apt/sources.list echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse" >>/etc/apt/sources.list echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse" >>/etc/apt/sources.list echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse" >>/etc/apt/sources.list echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse" >>/etc/apt/sources.list
问题3:与宿主机传递文件
sudo docker cp /local/dirname <containername>:/dirname