docker
6.1 docker概述
6.1.1 什么是docker
docker是一个开源的应用容器引擎,它基于go语言开发,并遵从Apache2.0开源协议。使用docker可以让开发者封装它们的应用以及依赖包到一个可移植的容器中,然后发布到任意的Linux机器上,也可以实现虚拟化。docker容器完全使用沙箱机制,相互之间不会有任何接口,这保证了容器之间的安全性。
6.1.2 docker的特点
1.更快速的交付和部署
2.更高效的虚拟化
3.更轻松的迁移和扩展
4.更简单的管理
docker还具有实现逻辑分离、适合与面向服务的架构配合使用的特点。
6.1.3 docker与虚拟机的区别
虚拟机是运行在每个应用层级的客户端操作系统上的,这是资源密集型的。由于产生的磁盘镜像和应用程序的操作系统设置相互交叉,所以导致虚拟机对系统的依赖性很强,一旦系统出现问题,虚拟机依赖的文件以及安全补丁都可能出现文件丢失的情况。
docker中的容器是基于进程的隔离,多个容器可以共享单个内核,并且创建docker容器的镜像所需要的配置并不依赖于宿主机系统。正是因为容器之间配置的隔离性,容器之间就没有配置交叉,所以docker的应用可以运行在任何地方。
6.2 docker安装要求
1.Ubuntu版本支持
Ubuntu trusty 14.04(LTS)
ubuntu xenial 16.04(LTS)
ubuntu zesty 17.04
其他更高版本
2.Ubuntu内核支持
docker需要在64位版本的Ubuntu上安装,还要保证Ubuntu内核版本不低于3.10,可以通过uname -r命令查看,其中3.10版本和更新维护版也是可以使用的,在低于3.10版本的内核上运行docker会丢失一部分功能。
6.3 docker安装方式
在线安装方式比较容易,且后期升级维护相对方便,先设置一个docker仓库,然后通过该仓库进行安装和后续更新。
1.设置docker仓库
(1)更新apt索引包
$ sudo apt-get update
(2)安装软件包允许apt通过HTTPS方式使用docker仓库
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
(3)添加docker官网的GPG key
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
(4)添加docker稳定的仓库源,AMD64
$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
2.安装docker ce
(1)更新apt索引包
$ sudo apt-get update
(2)安装最新版本docker
$ sudo apt-get install docker-ce
(3)安装完成后,运行测试
$ sudo docker run hello-world
6.4 docker运行机制
6.4.1 docker的引擎
docker引擎是docker核心部分,使用的是客户端-服务端C/S架构模式,包含了三个核心组件。
- docker cli :表示docker命令行接口,开发者可以在命令行中使用docker相关指令与docker守护进程进行交互,从而管理诸如image镜像、container容器、network网络和data volumes数据卷等实体。
- rest api :表示应用程序API接口,开发者通过该API接口可以与docker守护进程进行交互,从而指示后台进行相关操作。
- docker daemon:表示docker的服务端组件,它是docker架构中运行在后台的一个守护进程,可以接受并处理来自命令行接口及API接口的指令,然后进行相应后台操作。
6.4.2 docker的架构
1.client客户端
docker cli开发者通过这个客户端使用docker相关指令与docker守护进程交互,从而进行docker镜像的创建、拉取和运行操作。
2.docker_host主机
docker_host即docker内部引擎运行的主机,主要指docker daemon。可以通过docker守护进程与客户端还有docker镜像仓库registry进行交互,从而管理images镜像和containers容器。
3.registry注册中心
实质就是docker镜像仓库,默认官方docker hub,也可以使用开发者搭建的本地仓库,包含大量镜像,可以是官网镜像,也可以是其他开发者上传的镜像。
docker镜像就是一个只读模板,包含了一些创建docker容器的操作指令。通常一个docker镜像是基于另一个基础镜像创建的,并且新创建的镜像会额外包含一些功能配置。
docker容器属于镜像的一个可运行实例,开发者可以通过API接口或cli命令行接口创建、运行、停止、移动、删除一个容器,也可以将一个容器连接到一个或多个网络中,将数据存储与容器进行关联。
6.5 docker底层技术
1.名称空间
docker使用名称空间来为容器提供隔离的工作空间。当一个容器运行时,docker就会为该容器创建一系列名称空间,并为名称空间提供一层隔离。每一个容器都运行在相对隔离的环境下,对其他名称空间是相对受限的。
2.控制组
基于Linux系统的docker引擎也依赖于另一项控制组技术。控制组可以对程序进行资源限定,并允许docker引擎在容器空间进行硬件资源共享以及随时进行限制和约束,例如开发者可以限制某特定容器的可用内存。
3.联合文件系统
联合文件系统是一种分层、轻量级且高性能的文件系统,它支持将文件系统的修改作为一次提交来一层层地叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。不同docker容器可以共享一些基础的文件系统层,与自己独有的改动层一起使用,可以大大提高存储效率。
4.容器格式
docker引擎将名称空间、控制组和联合文件系统组合成一个叫做容器格式的整体。当前默认容器格式是libcontainer,未来docker可能通过与其他技术集成使用来开发其他容器格式。
7.1 docker入门程序
(1)编写dockerfile文件。创建一个空的docker工作目录dockerspace,进入该目录,并使用sudo vim dockerfile指令新建并打开一个dockerfile文件,然后向该文件编辑内容。
#使用docker官方的Python作为一个基础镜像
FROM python:2.7-slim
#设置工作目录/app
WORKDIR /app
#复制当前目录下的所有内容到容器内的/app目录下
ADD . /app
#安装在requirements.txt文件中声明的文件包
RUN pip install -r requirements.txt
#设置容器暴露的端口为80
EXPOSE 80
#定义环境变量
ENV NAME World
#当容器启动后立即运行app.py
CMD ["python","app.py"]
文件的主要作用就是在一个基础镜像上安装其他程序来构建一个新的镜像,这个过程中,主要涉及两个外部文件requiremnets.txt和app.py。其中requirements.txt是一个普通TXT文本,声明了需要安装的两个工具,而app.py是一个简单的Python小程序。
首先docker会从docker远程仓库拉取Python作为一个基础镜像;然后在docker容器内创建一个目录为app的工作空间,并通过add指令将当前目录中的所有文件复制到app目录下;接下来使用pip指令安装requirements.txt文件内指定的工具,指定容器创建后暴露的端口为80,以及定义内部环境变量name并赋值为world;最后在容器启动后运行app .py文件。
(2)编写外部文件。
from flask import Flask
from redis import Redis,RedisError
import os
import socket
redis=Redis(host="redis",\
db=0,socket_connect_timeout=2,socket_timeout=2)
app=Flask(__name__)
@app.route("/")
def hello():
try:
visits=redis.incr("counter")
except RedisError:
visits="<i>cannot connect to Redis,counter disabled</i>"
html="<h3>Hello {name}!</h3>" \
"<b>Hostname:</b> {hostname}<br/>"
"<b>Visits:</b> {visits}"
return html.format(name=os.getenv("NAME","world"), \
hostname=socket.gethostname(),
visits=visits
)
if __name__ == "__main__":
app.run(host='0.0.0.0',port=80)
(3)创建镜像
$ docker build -t hellodocker .
(4)查看镜像
$ docker images
(5)创建并启动容器
$ docker run -d -p 5000:80 hellodocker
(6)查看运行容器
$ docker ps
(7)访问程序,localhost:5000
(8)停止容器
$ docker stop 653347ecc6df
7.2 dockerfile介绍
7.2.1 dockerfile基本结构
基础镜像信息、维护者信息、镜像操作指令、容器启动执行的指令
7.2.2 dockerfile常用指令
1.from
from指令用于初始化一个新的镜像构建阶段,同时为之后的指令设置一个基础镜像。设定的基础镜像可以从dockerhub镜像注册中心或本地镜像列表选取,当本地镜像列表中存在设定的镜像就会直接使用本地镜像,否则会先从远程镜像注册中心拉取到本地再使用。
FROM <image>:<tag>
2.MAINTAINER
用于指定当前构建的镜像维护者信息
MAINTANER "shitou"<shitou@163.com>
3.RUN
用于执行指定的脚本命令
RUN <command>
RUN ["executable","param1","param2"]
4.CMD
用于指定启动容器时执行的命令
CMD ["executable","param1","param2"]
5.EXPOSE
用于声明容器内部暴露的端口号,供容器访问连接使用。
EXPOSE <port>
6.ENV
用于为下文设定一个环境变量,该变量值在后续指令或内联文件中都可以使用
ENV <key> <value>
7.ADD
用于复制指定的src资源文件到容器中的dest目录下,复制的资源可以是文件、目录以及URLs资源。
ADD <src>
8.COPY
都是复制src资源文件到容器中的dest目录下,copy不能复制URL路径文件,也不能解压文件。
COPY <src>
9.ENTRYPOINT
配置容器启动后执行的命令,每个dockerfile只能有一个ENTRYPOINT
ENTRYPOINT ["executable","param1","param2"]
10.WORKDIR
用于为后续指令指定工作目录
WORKDIR /path/to/workdir
7.3 docker客户端常用指令
7.3.1 docker常用操作指令
1.列出镜像
$ docker images
2.搜索镜像
$ docker search ubuntu
3.拉取镜像
$ docker pull ubuntu
4.构建镜像
$ cd workspace/dockerspace/
$ docker build -t hellodocker2 .
5.删除镜像
$ docker rmi -f hellodocker2 hellodocker3
6.创建并启动容器
$ docker run -d -p 5000:80 --name test hellodocker
7.列出容器
$ docker ps
8.执行命令
$ docker exec f0c9a8b6e8cc5 ls -l
9.停止容器
$ docker stop f0c9a8b6e8c5
$ docker kill f0c9a8b6e8c5
10.启动容器
$ docker start f0c9a8b6e8c5
$ docker restart f0c9a8b6e8c5
11.删除容器
$ docker rm -f f0c9a8b6e8c5
8.1 docker网络管理
8.1.3 自定义bridge网络
$ docker network create --driver bridge isolated_nw
$ docker run --network=isolated_nw -itd --name=nwtest busybox
$ docker network connect bridge nwtest
$ docker network disconnect isolated_nw nwtest
$ docker network rm isolated_nw
8.1.4 容器之间网络通信
$ docker run -itd --name=container1 busybox
$ docker run -itd --name=container2 busybox
$ docker run --network=isolated_nw -itd --name=container3 busybox
$ docker network connect isolated_nw container2
$ docker attach container2
在容器内使用ifconfig查看IP地址
8.3 docker数据管理
8.3.1 docker数据存储机制
docker容器与镜像之间的主要区别是顶部的容器层,而所有对容器中数据的添加、修改都会被存储在容器层。当容器被删除时,容器层也会被删除,其中存储的数据会被一同删除,而下面的镜像层保持不变。
由于所有的容器都是通过镜像构建的,所以每个容器都有各自的容器层,对于容器数据的更改就会保存在各自的容器层中。也就是说,由同一个镜像构建多个容器,它们会拥有相同的底部镜像层,而拥有不同的容器层,多个容器可以访问相同的镜像层,并有自己独立的数据状态。
基于同一个镜像构建的多个容器可以共享该镜像层,但是多个容器想要共享相同的数据,就需要将这些数据存储到容器之外的地方,这就是数据外部挂载机制。
8.3.2 docker数据存储方式
默认情况下,docker中的数据都是存放在容器层的,但是这样存储数据有较多缺陷
-
当容器不再运行时,容器中的数据无法持久化保存,如果另一个进程需要这些数据,将很难从容器中获取数据。
-
容器层与正在运行的主机紧密耦合,不能轻易地移动数据。
-
容器层需要一个存储驱动程序来管理文件系统,存储驱动程序提供了一个使用Linux内核的联合文件系统,这种额外的抽象化降低了性能。
8.4.2 volumes数据卷使用
(1)创建数据卷
$ docker volume create my-vol
(2)查看数据卷
$ docker volume ls
(3)核查数据卷
$ docker volume inspect my-vol
(4)删除数据卷
$ docker volume rm my-vol
(5)启动容器并挂载数据卷
$ docker run -d \
-it \
--name devtest \
--mount source=myvol,target=/app \
busybox:latest
$ docker run -d \
-it \
--name devtest2 \
-v myvol:/app \
busybox:latest