容器与应用
(1)容器与应用: 讲述 centos docker的安装,仓库、镜像、容器、服务的概念, dockerfile,compose 文件,容器管理图形界面,以单机操作为主线。
(2)Docker Swarm 集群:讲述集群(cluster)manager,worker,node 的概念与应用在集群部署。重点讲述容器网络、存储管理、集群管理、服务发现等知识。
1、环境与网络
准备三台 Centos 的 物理机或虚拟机,虚拟机可使用 VMware 或 Vbox,本文案例主机采用 Window10,虚拟化软件 Vbox。
虚拟机应采用双网卡配置:
- 第一块网卡配 NAT,
- 第二块网卡按(Host-Only)配内部私有网络。
配置参考: docker 集群网络规划与 VM 网络配置
2、安装 CentOS 与 Docker 引擎
2.1 安装 CentOS 基础环境
1.安装CentOS服务器的模板
双网卡网络配置: NAT,192.168.56.250/24
具体过程:安装基础-centos-7-服务器
2.安装docker-master虚拟机
使用 VBox 复制上述服务器。使用 nmtui
配置:
- 第二网卡,例如:192.168.56.110/24
- 主机名:docker-master
注意:以上只是复制内容,未经本人实践,本人用到的方式是:
在VMware上安装一个CentOS虚拟机,采用桥接网络,进行以下的学习操作,当进行docker swarm集群搭建时,
将该CentOS虚拟机复制2份,进行ip及主机名的改变之后,即可进行操作。以上,经过本人实践。
2.2 安装 Docker 引擎
1. 在阿里云注册账号
进入阿里云,dev.aliyun.com
登陆后,进入【管理中心】
2. 安装 docker 引擎
如果是安装最新版本 docker:
- 【管理中心】 –> Docker镜像仓库 –> 加速器 –> centos
- 按提示操作
如果需要安装 docker 历史版本:
3. 启动 docker 引擎
-
systemctl start docker
-
systemctl enable docker
-
systemctl status docker
-
-
docker version
-
docker run --rm hello-world
4. 配置容器加速服务
- 【管理中心】 –> Docker镜像仓库 –> 加速器 –> centos
5. 建立你的镜像仓库
- 【管理中心】 –> Docker镜像仓库 –> 镜像列表 –> 华南1 –> 【创建镜像创库】
创建公有仓库,(一个仓库一般就存一个镜像的不同版本)。完成后,看到【管理】按钮,进入
3、Docker 入门
docker 官网文档 Get Stated 给出了 6 个基础教程,Part1-6。 Part I 安装,请参考前面。
入门要求 docker 1.13 版本以上,当前版本 17.04.00 ce
3.1 核心概念
Docker引擎 (Docker Engine)
Docker Engine is a client-server application with these major components(一个客户-服务应用,含三个部件)
1)驻守(daemon)进程 docker
2) REST API 接口提供外部系统与 docker 进程交互
3) Cli 命令行接口的应用 docker 命令
图:Docker引擎基础架构
镜像(image)
An image is a read-only template with instructions for creating a Docker container.
镜像是创建docker容器指令的只读模板。包含一个只读的文件系统镜像,应用程序在这个文件系统上运行,并拥有属于自己的网络、内存、CPU 等资源的定义。通常,一个镜像申明了自己主进程的应用。
镜像一般在其他镜像基础上建立,如在 ubuntu 上添加自己的 apache 文件,然后在 apache 上建立 web 应用文件
容器(Container)
A container is a runnable instance of an image.
镜像中的程序(主进程)运行在只读文件镜像上,对现有文件变更将写在一个临时的卷上(新的一层),该主进程、相关进程、文件系统成为一个运行的实例。
- 每个容器创建后,有运行、暂停、中止状态,直到移除。
- 程序运行的产生的数据,都在容器中的文件中,Restart 不会丢失数据。
当主进程结束时,该实例同时结束运行。使用 –rm 表示运行后自动删除容器。
服务(Services)
Services allow you to scale containers across multiple Docker daemons, which all work together as a swarm with multiple nodes.
服务是一组运行于集群不同结点中可复制的容器的集合。通过服务发现机制,使用该服务的客户端可以透明的访问这些容器。这些容器的分布、升级、故障管理有集群统一管理。
一般地,集群内部服务容器地选择由 动态DNS 实现。
栈(stack)
A stack is a group of interrelated services that share dependencies, and can be orchestrated and scaled together.
能被编排和伸缩的一组相互依赖的服务
栈(stack)用 docker-compose.yml 文件描述服务之间的依赖、数据共享、网络等。使用 docker stack 管理
3.2 简单教程
3.2.1 Part 2:镜像与容器(官方)
https://docs.docker.com/get-started/part2/
1)创建镜像
(1) 创建一个目录,如 webservice1, 然后,进入该目录
mkdir webservice1 && cd webservice1
(2) 创建一个简单 web 应用程序
使用 vi app.py
创建 web 应用代码:
-
from flask import Flask
-
from redis import Redis, RedisError
-
import os
-
import socket
-
-
# Connect to Redis
-
redis = Redis(host= "redis", db=0)
-
-
app = Flask(__name__)
-
-
-
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)
写简单 web 应用, python 最方便。 Node.js 也很好! J2EE 就是蹒跚的大象啊。
(3) 创建镜像指令文件 dockerfile
使用 vi dockerfile
创建文件
-
# Use an official Python runtime as a base image
-
FROM python: 2.7-slim
-
-
# Set the working directory to /app
-
WORKDIR /app
-
-
# Copy the current directory contents into the container at /app
-
ADD . /app
-
-
# Install any needed packages specified in requirements.txt
-
RUN pip install -r requirements.txt
-
-
# Make port 80 available to the world outside this container
-
EXPOSE 80
-
-
# Define environment variable
-
ENV NAME World
-
-
# Run app.py when the container launches
-
CMD [ "python", "app.py"]
指令非常直观,
FROM
指示从 python:2.7-slim 镜像基础上开始构建。这个镜像在哪里,docker hub 的仓库。 镜像命名规则 [镜像:版本]WORKDIR
设置主进程的工作目录/app
ADD
将当前目录内容复制到基础镜像文件系统的/app
RUN
在基础镜像文件系统上运行pip install -r requirements.txt
这时 pip 下载依赖包到基础镜像之上EXPOSE
暴露容器对外的 TCP 端口 80ENV
定义进程的环境变量NAME World
CMD
设置主进程启动的命令["python", "app.py"]
。因此,容器一般是单进程应用
最后编辑 python 的依赖包 vi requirements.txt
-
Flask
-
Redis
(4)构建 app 的镜像
检查文件:
-
# ls
-
app.py dockerfile requirements.txt
创建 tag 为 friendlyhello 的镜像:
# docker build -t friendlyhello .
完成之后,检查镜像文件:
-
docker images
-
-
REPOSITORY TAG IMAGE ID
-
friendlyhello latest 326387cea398
2)在容器中运行 app
docker run -d -p 4000:80 friendlyhello
docker run
运行镜像的命令-d
后台运行-p
端口映射,将容器的 80 端口映射到主机(host)的 4000 端口
检查结果:
-
# curl localhost:4000
-
-
<h3>Hello World!</h3><b>Hostname:</b> 82523c7dcf52<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled
检查容器的进程:
-
# docker ps
-
-
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-
82523c7dcf52 friendlyhello "python app.py" 2 minutes ago Up 2 minutes 0.0.0.0:4000->80/tcp sad_wescoff
结束并清理进程:
# docker rm -f 82523c7dcf52
3.2.2 上传镜像到你的仓库
为了说明我们刚才创建的可移植性,可以上传已构建的镜像并在其他地方运行它。但是,在您要将容器部署到生产环境中时,需要了解如何推送到镜像库。
镜像库是镜像仓库的集合,而镜像仓库是镜像的集合 - 除了代码已构建之外,类似于 GitHub 镜像仓库。镜像库中的一个帐户可以创建很多镜像仓库。默认情况下,docker
CLI 使用 Docker 的公用镜像库。
注:我们将在此处使用 Docker 的公用镜像库,仅仅因为它是免费的并且经过预先配置,但有许多公用镜像库可供选择,并且您甚至可以使用 Docker Trusted Registry 设置您自己的专用镜像库。
- 使用 Docker ID 登录
如果您没有 Docker 帐户,请在 cloud.docker.com 中进行注册。记录您的用户名。
登录本地机器上的 Docker 公用镜像库。
docker login
- 标记镜像
用于将本地镜像与镜像库中的镜像仓库相关联的表示法为 username/repository:tag
。tag 是可选项,但建议使用它,因为这是镜像库用于为 Docker 镜像指定版本的机制。针对上下文为镜像库和 tag 指定有意义的名称,例如 get-started:part1
.这会将镜像放入 get-started
镜像仓库并将其标记为 part1
。
现在,将其合并到一起,以标记镜像。使用您的用户名、镜像仓库和标签名称运行 docker tag image
,以便镜像将上传到所需目的地。此命令的语法为:
docker tag image username/repository:tag
再次声明:必须要以您的用户名运行
docker tag image,否则报错,如下,用户名为john
例如:
docker tag friendlyhello john/get-started:part1
运行 docker images 以查看新标记的镜像。(您还可以使用 docker image ls
。)
-
$ docker images
-
REPOSITORY TAG IMAGE ID CREATED SIZE
-
friendlyhello latest d9e555c53008 3 minutes ago 195MB
-
john/ get-started part1 d9e555c53008 3 minutes ago 195MB
-
python 2.7-slim 1c7128a655f6 5 days ago 183MB
-
...
- 发布镜像
将已标记的镜像上传到镜像仓库:
docker push username/repository:tag
例如:
docker push john/get-started:part1
完成后,将公开此上传的结果。如果登录 Docker Hub,可以使用其 pull 命令看到新的镜像。建议您第一次尝试时,进入Docker Hub页面进行查看,以验证您操作的正确性。
-
从远程镜像仓库中拉取并运行镜像
从现在开始,您可以使用 docker run
,并且可以使用以下命令在任何机器上运行您的应用:
docker run -p 4000:80 username/repository:tag
如果镜像在机器本地不可用,Docker 将从镜像仓库中拉取它。如果您还在本机操作,可以尝试删除本机上的该镜像,然后在执行如下操作:docker run -p 4000:80 john/get-started:part1
-
$ docker run -p 4000:80 john/get-started:part1
-
Unable to find image 'john/get-started:part1' locally
-
part1:Pulling from orangesnap/get-started
-
10a267c67f42:Already exists
-
f68a39a6a5e4:Already exists
-
9beaffc0cf19:Already exists
-
3c1fe835fb6b:Already exists
-
4c9f1fa8fcb8:Already exists
-
ee7d8f576a14:Already exists
-
fbccdcced46e:Already exists
-
Digest: sha256: 0601c866aab2adcc6498200efd0f754037e909e5fd42069adeff72d1e2439068
-
Status: Downloaded newer image for john/get-started:part1
-
* Running on http: //0.0.0.0:80/ (Press CTRL+C to quit)
注:如果您未指定这些命令中的
:tag
部分,在进行构建和运行镜像时,将使用标签:latest
。Docker 将使用在未指定标签的情况下运行的镜像的最新版本(可以不是最新镜像)。
无论 docker run
在何处执行,它将从 requirements.txt
拉取您的镜像及 Python 和所有依赖项,然后运行代码。所有内容都在一个小软件包中提供,并且主机只需安装 Docker 来运行它。
3.2.3 使用图形化管理工具
安装及运行请移步这里:https://blog.csdn.net/wangguohe/article/details/81536124
几乎所有容器开发商都有自己的 UI 管理界面。这些 UI 共同的特点就是就是本身以一个容器的方式存在,例如:Portainer 、Shipyard。
以为例,启动 Portainer 非常简单:
docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer
这里最关键的就是 -v /var/run/docker.sock:/var/run/docker.sock
容器与主机共享了文件 /var/run/docker.sock
从而,容器获得了 docker 驻守(daemon)进程 REST API SDK 入口。
现在,在浏览器输入 http://<your machine IP>:9000
就进入了图形管理界面。
3.2.4 Part 3:服务(官方)
A service really just means, “containers in production.” A service only runs one image, but it codifies the way that image runs – what ports it should use, how many replicas of the container should run so the service has the capacity it needs, and so on.
在分布式应用中,应用的不同部分称为“服务”。例如,假设有一个视频共享网站,它可能提供用于在数据库中存储应用程序数据的服务、用于在用户上传一些内容后在后台进行视频转码的服务、用于前端的服务等。
服务实际上是“生产中的容器”。一项服务仅运行一个镜像,但它会编制镜像的运行方式 - 它应使用的端口、容器的多少个从节点应运行才能使服务的容量满足其需求等。扩展服务将更改运行该软件的容器实例数,并将多个计算资源分配给进程中的服务。
幸运的是,很容易使用 Docker 平台定义、运行和扩展服务 – 只需编写一个
docker-compose.yml
文件即可。
运行一个服务,需要使用 docker-compose.yml
文件。顾名思义,这是服务组合的定义。
(1)创建一个目录,例如 service_test:
cd && mkdir service_test && cd service_test
(2)编写服务定义, 例如 vi docker-compose.yml
您可以将 Compose 文件命名为任何所需内容,以使其在逻辑上具有意义;docker-compose.yml
仅为标准名称。我们可以简单地将此文件命名为 docker-stack.yml
或更特定于项目的内容。
-
version: "3"
-
services:
-
web:
-
-
image: username/repository:tag
-
deploy:
-
replicas: 5
-
resources:
-
limits:
-
cpus: "0.1"
-
memory: 50M
-
restart_policy:
-
condition: on-failure
-
ports:
-
- "80:80"
-
networks:
-
- webnet
-
networks:
-
webnet:
注意:缩进为2个空格,每个:后面都要有空格,否则后面操作的时候会报错
yaml: line 6: mapping values are not allowed in this context
此 docker-compose.yml
文件会告诉 Docker 执行以下操作:
-
从镜像库中拉取我们在上传的镜像。
-
将该镜像的五个实例作为服务
web
运行,并将每个实例限制为最多使用 10% 的 CPU(在所有核心中)以及 50MB RAM。 -
如果某个容器发生故障,立即重启容器。
-
将主机上的端口 80 映射到
web
的端口 80。 -
指示
web
容器通过负载均衡的网络webnet
共享端口 80。(在内部,容器自身将在临时端口发布到web
的端口 80。) -
使用默认设置定义
webnet
网络(此为负载均衡的 overlay 网络)。
(3) 启动服务
在启动服务之前,务必初始化集群模式 。注意:多网卡必须说明在那块网卡上组建集群。
docker swarm init --advertise-addr 192.168.56.110
检查是否在集群模式的命令:
-
# docker info
-
-
Containers: 1
-
Running: 1
-
...
-
Swarm: active
-
NodeID: 23iftsrtbxm4kyyh2w5n3fmat
-
...
启动应用程序服务(您必须为应用指定一个名称。在此处该名称设置为 myservice)
docker stack deploy -c docker-compose.yml myservice
检查部署的结果:
-
-
-
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
-
gzg8n8oqpic8 myservice_web .1 registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello docker-master Running Running 4 seconds ago
-
xqyqekt9dubc myservice_web .2 registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello docker-master Running Running 4 seconds ago
-
owvdk5hypg7h myservice_web .3 registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello docker-master Running Running 4 seconds ago
-
0vi2cwingnyw myservice_web.4 registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello docker-master Running Running 3 seconds ago
-
7n2l036fv851 myservice_web.5 registry.cn-shenzhen.aliyuncs.com/pmlpml/repo:friendlyhello docker-master Running Running 4 seconds ago
使用浏览器或curl 访问 http://192.168.56.110:80/
每次返回的主机名都是不一样的,负载均衡实现了。
重启portainer ,使用 portainer 观察主机(host)中的变化:
- Services: 添加了一个服务
myservice_web
- Containers: 添加了 5 个服务
myservice_web.?.<long_id>
- Networks:添加了 2 个 swarm overlay 的网络
- Swarm:有一个管理结点
使用 portainer 的 Containers 杀死 myservice_web 服务的实例,会发现它会自动启动。
(4) 结束服务
docker stack rm myservice
(我们的单节点 swarm 仍处于正常运行状态(如 docker node ls
所示)。使用 docker swarm leave --force
可以清除 swarm)
4、小结
本文给出了在 centos 环境下,完成 docker 官方 part 2,part 3 的教程的要点。由于网络等因素,建议大家使用阿里云或其他 docker 容器服务商提供的安装、容器仓库与加速设施。尽管技术不断发展,无论命令还是定义格式都会发生一些变化,docker 容器的核心内容与操作基本没有大变化。适当使用图形界面,可以更加快速观察系统内部的变化。
本文围绕镜像、容器、服务三个核心知识以及相关的操作,读者应可以从容安装 docker 引擎,并在单机上发布与部署简单的 web 应用。