Openshift是一个开源的容器云平台,底层基于当前容器的事实标准编排系统Kubernetes和docker引擎,企业可以基于此平台搭建内部Paas平台,贯穿CI/CD流程,提高企业IT效率,拥抱DevOps和敏捷开发。
docker总结
docker 总结
基本概念
docker是一个帮助开发者使用容器进行开发、部署项目的平台。
容器概念
容器是一种轻量级虚拟化,也称为操作系统级虚拟化。它是一个中间件和回显系统,允许在多个称为容器的实例之间共享操作系统。每个容器与其他容器分开,并且可以具有与其他容器和基本操作系统不同的Linux风格。
容器和虚拟机的区别
docker可以将应用程序封装在不同的容器中执行并为每个容器提供单独的运行环境,每个容器内部都可以视为一个完整的主机环境,其功能类似于虚拟机,但和虚拟机相比容器更加轻量。虚拟机和主机操作系统的关系是相互独立的,它们共享主机硬件但虚拟机之间以及和主机操作系统之间内核是相互隔离的,虚拟机拥有完整的系统内核。容器是运行在主机操作系统之上的,容器以及主机其他程序共享系统内核,但每个容器拥有自己独立的运行库以及其他运行环境
组成结构
docker采用客户端-服务器模式,其主要由以下部分构成:
- daemon:是运行在主机上的守护进程,docker的所有操作指令通过该守护进程进行
- API:docker提供的daemon的接口,通过API来控制daemon
- CLI:是docker的客户端,通过命令行或者界面输入docker指令,输入的指令实际会传输给daemon执行
- network:docker提供的网络服务,docker允许容器之间通过多种网络驱动方式进行通信
- image:docker所管理的镜像,其组成结构类型于栈,由多个只读层叠加而成,是生成容器的模板
- container:docker所管理的容器,应用程序运行在容器内部,容器通过镜像构建而成。
- volumes:docker提供的数据存储功能,docker提供与容器独立的数据存储功能以减小容器大小,同时持久化数据,docker提供两种数据存储方式。
Dockerfile
dockerfile是一个包含构建镜像所需命令的文本文件,docker可以根据dockerfile文件构建镜像
dockerfile以from
开始,表示使用另一个镜像作为生成当前镜像的基础,新创建的镜像会包含基础镜像的内容。dockerfile中包含了构建镜像所需的全部命令。
1 | # 使用python的运行环境作为parent image |
镜像image
docker中的容器都是基于镜像构成的,镜像是由多个只读层构成,每个只读层记录了dockerfile的一条命令,docker每执行dockerfile的一条命令都会新建一个只读层记录该指令操作结果。
1 | $ docker history yezh01/getstart:v1.0 |
docker可以在一个镜像的基础上生成新的镜像,新的镜像不会复制原有镜像的内容而是和原有镜像共享文件数据,这样可以减小镜像大小,提高存储和传输效率。
容器
容器内包含了应用程序和其所需的与运行环境,docker可以为每个容器设置不同的运行环境,而且彼此互不干扰。
容器是根据镜像生成的,容器与镜像很重要的一个区别在于,镜像都是由只读层构成的,而容器在镜像只读层之上构建了一个读写层用于记录对容器的修改操作,因此,容器是可修改的,而镜像是只读的。
一个镜像可以同时生成多个容器副本,容器副本之间共享同一个镜像,不同容器副本只保留自己容器的修改结果。
容器读写策略
docker采用写时复制(cop-on-write)策略,当容器需要读取底层层次的数据时,如果不需要对数据进行修改,则直接从底层读取数据;如果需要对数据进行修改,则将数据复制到当前层次进行修改并将修改后的数据保留在当前层次。这样可以减小容器体积同时提高读写效率。
应用程序的分级结构
docker对应用程序的执行方式可以分成三级层次结构:
- 堆栈stack
- 服务services
- 容器container
容器
容器是应用的最底层,容器内部包含了一个应用程序或者应用程序的一个组件。应用程序都是在容器内部执行的。
服务
服务是指应用程序的其中一部分功能,服务可以理解为一群“运行中的容器”,服务中的容器都是根据同一个镜像生成的,服务定义了容器的行为方式,包括:容器对外开放的借口、生成的容器数量等。 服务是通过yml文件进行配置的。
集群
docker支持在集群上运行服务,即一个服务可以执行在多台主机或者虚拟机中。
docker可以将主机设置为集群模式或者加入一个集群,每个集群含有一个管理者manager和若干工作者worker,manager可以控制集群工作,而worker只提供自身的计算能力。集群模式下的控制命令与独立容器的控制命令一致,将命令发送给manager,manager会自动控制集群执行命令。
集群会自动进行负载均衡,即当manager收到一个提供服务的命令后,集群会自动将服务的容器实例均匀分布到各个集群主机中。
外界对任何一台集群主机的访问的结果都是一致的,外界可以通过一台主机访问集群内所有主机的服务。
堆栈
堆栈是一组相互关联的服务,它们共享依赖关系,并且可以协调和缩放在一起。单个堆栈能够定义和协调整个应用程序的功能
数据管理
docker使用union file system来管理数据,docker构建image和container也是采用了同样的技术。
docker支持多种数据存储驱动,官方推荐的最新驱动是overlay2
数据存储
由于容器读写层数据在容器结束后会丢失,同时,在容器中记录过多数据会导致容器体积过大,因此,docker提供了而外的数据存储方式:挂载主机文件、挂载docker volume、挂载tmpfs。
- 挂载主机文件是直接将主机中的目录挂载在docker中,这中方式依赖于主机特定的文件系统。
- 挂载docker volume。volume是docker提供的首选数据存储方式,volume独立于容器存在,容器结束后volum不会消失。
- tmpfs是linux上的文件系统,其将数据保留在主机内存中,主机关机后,内存数据丢失,tmpfs上保留的数据也会丢失。
网络
docker提供多种网络驱动:
- bridge: docker默认网络驱动,docker提供默认网桥也允许自定义网桥,官方推荐自定义网桥
- overlay:支持不同daemon下的容器之间一个集群服务之间的通信,适用于集群环境
- host: 容器与主机没有网络隔绝,与主机贡献网络,适用于需要隔绝除网络以外的其他部分的场景
- macvlan:为容器分配MAC地址,daemon可以通过容器MAC地址将流量直接路由给容器而无需通过主机网络栈
- none:禁用容器一切网络
docker容器内访问docker daemon(window10)
windows10下实现在docker容器中访问docker daemon。
在docker desktop setting中选择 expose daemon on tcp://localhost:2375 without tls
.
在容器应用中使用docker.for.win.localhost
指向主机localhost
1 | import docker |
docker深入学习三:network
docker学习三:network
docker支持容器之间的网络通信,docker的网络通信方式有以下五种:
driver | 说明 | 使用场景 |
---|---|---|
bridge | docker 默认的网络驱动,如果不指定网络驱动,docker就会创建一个bridge | bridge适用于同一docker主机上的容器通信 |
overlay | overlay支持不同daemon下的容器之间和集群服务之间的相互通信 | overlay适用于不同主机的容器之间的通信,或者集群服务中的多个应用程序协调工作 |
host | host消除了独立容器与主机之间的网络隔离,container直接使用主机的网络 | host适用于需要隔离容器除网络以外的其他部分的情况 |
macvlan | macvlan允许用户为容器分配MAC地址,daemon可以将流量通过容器MAC地址之间路由到容器而不需要经过docker host的网络栈 | macvlan适用于从虚拟机配置移植或者需要让容器表现为一台包含mac地址的物理机的情况 |
none | none禁止容器的所有网络,其一般和用户自定义网络驱动一起使用,集群服务不支持none |
bridge
docker bridge与一般的网桥功能类似,能够让同一网桥下的容器相互通信。
docker提供默认bridge,若不指定容器的驱动,则自动将容器关联到默认bridge中。 官方推荐用户自定义bridge而不是使用默认bridge
自定义bridge和默认bridge的区别
自定义bridge | 默认bridge | |
---|---|---|
隔离性和连接性 | 位于同一bridge的容器之间暴露自身所有的端口,容器端口默认对外界关闭,需要使用-p 或--publish 开启 |
需要手动打开端口,同时需要通过docker外的方式控制外界对端口的访问 |
容器之前的DNS服务 | 支持自动DNS解析,可以通过容器别名访问容器 | 容器之间只能通过ip地址访问或者为通信两端的容器分别使用--link 选项 |
热插拔 | 支持在运行过程中断开或连接自定义bridge | 容器与默认网桥断开时,需要关闭容器并使用新配置重建容器 |
全局配置 | 每个自定义bridge可以使用docker命令单独配置 | 对默认bridge的配置会影响到所有使用默认bridge的容器,且配置默认bridge需要使用docker外的命令 |
共享环境变量 | 自定义bridge无法直接共享环境变量,但可以通过 挂载卷或者目录 使用compos声明共享变量 使用集群服务代替独立容器,通过配置共享变量 |
使用--link flag共享环境变量 |
配置自定义bridge
创建和删除bridge的命令如下:
1 | docker network create my-net |
创建bridge时可以配置bridge的子网范围、网关和其他选项,具体的配置参数可以使用docker network --help
或者查看官方文档
连接bridge
可以在创建容器的同时连接bridge,如:
1 | $ docker create --name my-nginx \ |
上面创建了一个容器my-nginx,同时将容器连接到my-net 网桥并将8080端口暴露出来供外界访问。
连接已存在的容器和bridge时可以使用以下命令
1 | $ docker network connect my-net my-nginx |
取消连接可以使用以下命令
1 | $ docker network disconnect my-net my-nginx |
overlay
overlay在多个docker主机上面创建一个分布式网络,该网络位于各个主机的具体网络之上,允许容器连接该网络进行通信。
当创建一个集群或者将docker主机加入到集群时,docker主机会创建两个网络:
ingress
:是一个overlay网络,用于处理和集群控制有关的命令和数据流量,如果创建集群时没有指定自定义overlay网络,集群默认连接到ingress
docker_gwbridge
:一个 bridge网络,用于连接集群中各个daemon守护进程
创建overlay
创建overlay的命令与bridge基本一致,但创建overlay的命令必须在位于集群中的主机执行,使用命令docker swarm init
或 docker swarm join
将主机加入到集群中
1 | $ docker network create -d overlay my-overlay |
host
使用host网络相当于容器和主机共享一个网络,docker不会为容器分配ip地址,访问容器端口的方式改为直接访问主机对应的端口,-p
、-P
等端口相关的指令会被忽略。
host网络只在linux下工作,不提供对mac和Windows的支持
macvlan
某些应用程序,尤其是后台应用程序或监视网络流量的应用程序,希望直接连接到物理网络。在这种情况下,您可以使用macvlan网络驱动程序为每个容器的虚拟网络接口分配MAC地址,使其看起来像是直接连接到物理网络的物理网络接口。在这种情况下,您需要在Docker主机上指定一个物理接口,用于macvlan,以及macvlan的子网和网关。您甚至可以使用不同的物理网络接口隔离您的macvlan网络。但需要记住以下事项:
- 由于IP地址耗尽或“VLAN传播”,很容易无意中损坏您的网络,在这种情况下,网络中存在大量不合适的MAC地址。
- 您的网络设备需要能够处理“混杂模式”,其中一个物理接口可以分配多个MAC地址。
- 如果您的应用程序可以使用bridge(在单个Docker主机上)或overlay(跨多个Docker主机进行通信),那么从长远来看,这些解决方案可能会更好。
none:关闭容器的网络
使用--network none
可以关闭容器内的网络栈,在容器内只剩下回环地址。
1 | $ docker run --rm -dit \ |
查看容器内部网络,里面只含有回环地址
1 | $ docker exec no-net-alpine ip link show |
docker深入学习二:存储
dicker:数据管理
数据管理机制
docker使用union file system来管理数据,docker构建image和container也是采用了同样的技术。
image层次
iamge由多个层次构成,每个层次包含dockerfile的一条指令,除了最后一层外,其他层次都是只读的。
1 | FROM ubuntu:18.04 |
其一共生成四个层次:
- FROM 将ubuntu:18.04作为base image
- copy将运行docker命令的目录下的文件复制到容器中的app文件中
- run 使用make命令生成应用程序
- cmd 在容器中运行指定命令
docker层次的管理方式类似于git版本管理,层次的结构类似于一个栈,每个层次只记录与之前的层次的差异。当创建一个container时,会在image层次的基础上再创建一个读写层,对容器的修改操作都记录在读写层上而不会修改底层记录的数据。
container层次
container和image最大的区别在于container比image多了一层读写层用于记录对容器的修改,读写层在容器结束运行后销毁,其所记录的一切结果都不会保留,也不会改变image的数据。
由于container不会修改底层image的数据,所以多个container副本底层可以共享一个image。
copy-on-write策略
copy-on-write用于提高共享和复制文件的效率。
当需要对低层次数据进行读取时,如果不涉及数据修改,那么直接从低层读取现有数据;如果需要修改数据,则将数据拷贝到当前层次进行修改,下次读取相同数据时,从修改后的最新数据读取。
当我们将某个image作为base image构建新的image时,新的image不会复制base image的层次,而是共享相同的只读层。
存储驱动
docker支持多种存储驱动,官方推荐的驱动程序是overlay2。
使用docker info
可以查看docker使用的是那种驱动
1 | $ docker info |
数据存储方式
docker中存储用户数据有三种方式:记录在读写层、挂在主机文件系统、设置volume。
其中使用读写层记录数据会存在以下问题:
- 数据无法持久化,当容器关闭后,读写层记录的数据就会消失
- 数据不利于共享,其他容器或进程很难获取到容器读写层的数据
- 读写效率低,读写层存储数据需要使用存储驱动,该驱动需要使用linux内核,运行效率低
如上图所示,
volume是将数据主机文件系统中docker所管理的区域,bind mount是将主机文件系统中的任何一部分挂载到container中,tmpfs mount是linux上的一个文件管理系统,他所有的数据都存储在内存中而不会保留在硬盘上,所以掉电后,其里面所有数据都会丢失。
相关链接
https://docs.docker.com/storage/storagedriver/
https://docs.docker.com/storage/storagedriver/select-storage-driver/
https://docs.docker.com/storage/storagedriver/overlayfs-driver$
docker深入学习一:组成
docker 理解
docker是一个客户服务器结构的应用程序,其结构如下所示
其组成部分包括
- container容器:是image的运行实例,一般container之间以及container与主机之间是相互隔离的,相当于一台轻量级的虚拟机
- iamge镜像:是一个只读模板,是静态的,image通常是基于另一个image创建的
- docker CLI 客户端:通过调用RESTAPI控制docker daemon
- RESTAPI:是与docker daemon交互的API
- docker daemon :docker daemon是一个始终运行的守护进程,docker的指令通过客户端传递给daemon执行
- network: docker提供的网络功能,用于容器间的通信
- datavolumes:docker提供的数据存储功能,用于将数据存储与容器分离
dockerfile
dockerfile是一个包含生成image所需命令的文本文件,使用docker build
可以自动生成image。
Dockerfile文件是以FROM
开头的,也就是说必须引用一个base image如下所示
1 | # 使用python的运行环境作为parent image |
docker build
后面可以接本地地址PATH
也可以使用远程地址URL
,如
1 | $ docker build . |
实际 执行build
指令的是daemon而不是CLI(CLI相当输入命令的shell),也就是说输入docker build
后,cli会将命令连同上下文环境一起发送给daemon, docker build
后面接的PATH
或者URL
就是上下文环境。
注意:不要将\
目录作为上下文环境,因为docker会将上下文环境下的所有文件和文件夹递归发送给daemon。 推荐的做法是新建一个空目录作为上下文环境
类似于github的.gitignore
文件,docker也可以使用.dockerignore
来忽略指定文件和目录
docker build
后面的PATH
并不代表的dockerfile所在的路径,但默认情况下docker会在PATH
中寻找Dockerfile,如果要指定dockerfile ,可以使用参数-f
,如
1 | docker build -f /path/dockerfile . |
使用参数-t
可以可以指定生成image的仓库名称和标签,如
1 | docker build -t yezh01/getstart . |
image
image是根据Dockerfile生成的由多个只读层组成的。对于下面的dockerfile,每条命令生成一个只读层
1 | FROM ubuntu:18.04 |
其一共生成四个层次:
- FROM 将ubuntu:18.04作为基础image
- copy将运行docker命令的目录下的文件复制到容器中的app文件中
- run 使用make命令生成应用程序
- cmd 在容器中运行指定命令
container
container是根据image生成的,与image相比,container在image层次的基础上增加了一层读写层。所有对container的操作,例如增加、删除、修改文件等操作都会写入读写层。
container不会复制image,而是直接在image的上面叠加一层读写层,同时,同一image生成的不同container会共享image,由于container修改的所有内容都保存在读写层中而无法修改image的内容,因此不同container之间不会因为其他container产生干扰。
docker(四):swarm
docker使用入门(四):集群swarm
swarm是一组位于同一集群且运行docker的机器,用户可以通过swarm manager向swarm输入命令,swarm中的机器可以是虚拟机也可以是物理机。
swarm中分为swarm manager和workers。用户通过swarm manager管理swarm,worker只提供处理能力,对worker的管理操作都是通过swarm manager进行的
创建swarm
创建虚拟机
linux下的docker-machine需要手动安装,安装方案见官方教程
此外还需要在linux上安装virtualbox,运行以下命令进行安装
1 | sudo apt-get install virtualbox |
运行以下命令创建两台虚拟机
1 | docker-machine create --driver virtualbox myvm1 |
第一次运行时,需要从github上下载文件,如果下载较慢,可以提前将boot2docker.iso下载到~/.docker/machine/cache/
使用docker-machine ls
可以列出虚拟机的信息
1 | $ docker-machine ls |
配置swarm
使用docker-machine ssh
可以向虚拟机传达指令,现在使用以下指令将vm1设置为swarm manager,令其能够执行swarm管理命令并且验证worker加入swarm。
1 | docker-machine ssh myvm1 "docker swarm init --advertise-addr <myvm1 ip>" |
其中,myvm1 ip
为myvm1的ip地址
执行结果如下
1 | $ docker-machine ssh myvm1 "docker swarm init --advertise-addr 192.168.99.102" |
注意:docker swarm init
和docker swarm join
命令通常使用端口2377执行,docker-machine ls
使用端口2376执行,要确保这些端口不被占用
使用以下命令将vm2添加到swarm中
1 | docker-machine ssh myvm2 "docker swarm join \ |
执行结果如下
1 | $ docker-machine ssh myvm2 " docker swarm join --token SWMTKN-1-33l8tomuwv9cyt9ig54cztdpl4h9kyfc5vimlv58mb6zdn4fiw-dn3ic01jklavcvvsb8ltr86bu 192.168.99.102:2377" |
myvm2中执行的命令可以直接复制添加myvm1时返回的命令提示信息
在manager中运行docker node ls
可以查看节点信息
1 | $ docker-machine ssh myvm1 "docker node ls" |
将应用程序部署到swarm上
关联manager和shell
运行以下指令将当前shell与vm1关联到一起
1 | $ docker-machine env myvm1 |
执行以下命令使配置生效
1 | eval $(docker-machine env myvm1) |
执行成功后,在当前shell中输入的docker命令都会在myvm1中执行,执行docker-machine ls
可以看到myvm1的状态已经改变
1 | $ docker-machine ls |
以上配置仅在当前shell有效,在其他shell中需要重新配置,也可在当前shell重新执行以上指令覆盖原有的设置。
部署应用程序
将应用程序部署到swarm的命令与之前一样,不过现在该命令执行在与manager关联的shell上,通过manager在swarm上执行
1 | docker stack deploy -c docker-compose.yml hello |
执行docker stack ps getstartedlab
可以发现实例分布在不同的虚拟机上,实现负载均衡
1 | $ docker stack ps hello |
测试应用程序
可以通过任意一个虚拟机的ip地址访问应用程序,而且访问效果相同,都可以访问到swarm中的所有运行实例,在swarm中的示意图如下所示
相关命令
1 | docker-machine create --driver virtualbox myvm1 # Create a VM (Mac, Win7, Linux) |
相关链接
docker(三):服务services
docker(三):服务services
docker中services位于container上面,services可以控制container的运行方式(包括container运行时所分配的资源以及container实例数量)
创建yml文件
yml文件定义了容器运行时的行为。我们先创建一个docker-compose.yml
文件,其包含以下内容
1 | version: "3" |
其中,各个字段含义如下
image
是容器仓库的名字replicas
表示生成的实例个数,上述表示5个实例cpus
表示占用cpu的时间,上述表示每个实例占用单核cpu10%的运行时间memory
表示占用内存大小condition: on-failure
表示当一个实例故障时,重启容器ports
将web的80端口映射到主机的4000端口network
使用默认设置配置webnet
运行服务
执行以下指令运行服务
1 | docker swarm init |
其中hello是自行设置的应用程序名
使用以下命令可以获取服务id
1 | $ docker service ls |
使用以下命令可以获得各个实例的信息
1 | $ docker stack ps hello |
拓展应用程序
docker支持即时更新部署,可以在运行时更新应用程序而无需停止服务,更新语句与运行语句一致
1 | docker stack deploy -c docker-compose.yml hello |
关闭应用程序
1 | docker stack rm hello |
相关命令
1 | docker stack ls # List stacks or apps |
docker (二):容器container
docker (二):容器container
docker层次结构可以分为三层,从下往上是:容器(container)、服务(services)、堆栈(stack),其中services定义了容器的行为,stack 定义了services的交互
接下来是尝试如何使用docker在容器中启动一个应用程序
创建容器
- 创建一个空的文件夹,其中包含Dockerfile、app.py、requirements.txt三个文件,文件内容分别如下
Dockerfile
1 | # 使用python的运行环境作为parent image |
requirements.txt
1 | Flask |
app.py
1 | from flask import Flask |
构建应用程序
使用以下命令build应用程序
1 | docker build --tag=friendlyhello . |
其中TAG默认为latest
,可以使用--tag=friendlyhello:v0.0.1.
来指定tag.
表示上下文环境。
使用docker image ls
可以查看构建的image
1 | $ docker image ls |
运行应用程序
使用以下语句运行程序
1 | docker run -p 4000:80 friendlyhello |
其中-p 4000:80
表示将image的80端口映射到主机的4000端口。
打开http://localhost:4000
可以查看程序运行结果
加入参数-d
可以让程序后台运行
1 | $ docker run -d -p 4000:80 friendlyhello |
相关命令
1 | docker build -t friendlyhello . # Create image using this directory's Dockerfile |
docker(一): 安装
docker(一): 安装
开始
docker是一个可以帮助开发者使用容器(containers)开发、部署和运行应用程序的平台。llinux下使用容器部署系统称为containerization。
container 是映像(image)的运行实例,image包括应用的源文件、运行库、配置文件等运行应用程序时所需要的一切资源。
container与其他进程一样共享主机的内核。而虚拟机则是一个完整的操作系统,相当于拥有自己独立的系统内核,container比虚拟机更加轻量。
对比container与虚拟机的结构可以发现,其在应用程序和系统之间增加docker层,而container与其一般进程行为相似。虚拟机是在硬件与操作系统之间增加了hypervisor层,hypervisor层往上是主机的操作系统和虚拟机的操作系统,主机操作系统无法之间调用虚拟机的应用程序。
安装docker
下载网页
如果之前安装过旧版本的docker,需要先卸载docker
1 | sudo apt-get remove docker docker-engine docker.io containerd runc |
执行以下命令以允许通过https安装
1 | $ sudo apt-get install \ |
添加docker官方密钥(国内连接官方网站较慢,可以跳过这步使用下面的国内镜向网站下载)
1 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - |
验证密钥获取是否成功
1 | $ sudo apt-key fingerprint 0EBFCD88 |
根据电脑系统选择合适仓库,具体信息可以查看官网
1 | sudo add-apt-repository \ |
国外的网站连接速度慢,可以改用国内的镜像网站,下面是中科大的源
1 | curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add - |
安装docker
1 | sudo apt-get update |
验证是否安装成功
1 | sudo docker run hello-world |
docker配置
使用一般用户允许docker
安装玩docker后,想要运行docker必须要有管理员权限,通过为docker创建分组,可以让一般权限使用docker
1 | sudo groupadd docker # 添加docker分组 |
通过newgrp docker
命令更新分组
验证一般权限允许docker
1 | docker run hello-world |
相关命令
1 | ## List Docker CLI commands |