docker基础篇(二)

  在看了无数篇的博客以后,小编终于决定啃一啃docker的官方文档,这里不是说,其余博主的博客毫无做用,而是,在有必定的docker基础以后,才有能力去挑战一下纯英文的官方文档。
  经过阅读官方文档,确实多docker的了解更加深刻,这里小编主要为你们介绍一下“get-started”,具体说了些什么,能够实现什么,让你们对docker有更深入的了解。
  最后,小编仍是要夸一下官方文档,确实读了官档以后,简直对docker的了解面目一新,虽然知道了这么多docker的命令和基础知识,可是就好像如今的“快船”,没有保罗这个线,果真只是各自绽开光芒的珍珠,总体实力不行啊!小编相信有了官方文档这个线,必定能把docker的知识点都串起来。
  固然上一篇文章是总体的给你们介绍一下docker的使用和基本配置,仅仅处于单机版,如今这个科技爆棚、大数据吹捧的时代,没有分布式,一切都毫无心义,小编经过官档的part1-part6的研读,向你们介绍一下关于docker的分布式的部署和优势,让你们对docker有更更深刻的了解,固然仍是为k8s打基础,好了废话不说了,撸文档。
官方文档地址:https://docs.docker.com/get-started/
 这里详细的告诉咱们,经过阅读这个基础入门,咱们大致上能够学习到:
 -  Part1:如何设置本身的docker环境
 -  Part2:构建一个image并做为容器运行
 -  Part3:扩展应用程序以运行多个容器(这里的扩展表示的是一个容器的多个副本)
 -  Part4:跨集群的分布式应用程序(docker的分布式)
 -  Part5:经过后端数据库来堆栈服务
 -  Part6:将应用程序上线到生产html

1.Part1:Orientation and SetUp

  Part1主要是对docker的概念作了解,并列出了一些docker的基础命令,告诉咱们docker是什么、docker的优点以及docker的下载和安装。
  这里小编就不在介绍docker如何安装,介绍一些docker的常见命令:前端

#查看docker的版本
    docker --version
    #查看docker的详细信息
    docker info
    #使用docker运行一个容器
    docker run hello-world
    #查看docker已下载的images
    docker image ls
    #查看全部的容器(运行的和已退出的)
    docker container ls --all

2.Part2:Containers

  通过part1的介绍和对docker的理解,在part2中咱们也能够构建本身的应用程序,可是这里构建的应用程序只是最底层的使用一个container去构建,以后会介绍service级别的和堆栈级别的(用于生产)。
docker基础篇(二)node

  这里在构建一个应用程序时,体现了docker的一个优点—隔离,也就是说,若是你的应用在以后的升级和更新以后会变得很大,底层依赖的环境会愈来愈多,当这个应用程序大到能够左右你的系统时,那么若是须要对这个应用程序进行迁移或者在这个系统上部署其余的服务,对运维来讲简直就是一个灾难。这时候docker的强大之处就体现出来了,docker能够保证每个container是彻底隔离的,不一样的应用放置在不一样的container中,若是想要迁移这个服务,只须要将这个container构建成一个image,并上传到本身的registry中(企业级的使用harbor),就能够在任意地方,pull这个image,以后运行便可。
  官网给出了这样的一个例子:过去,若是要开始编写Python应用程序,首先要作的就是在机器上安装Python运行时。可是,这就形成了这样一种状况:您的机器上的环境须要根据您的应用程序去部署,以便您的应用程序可以按预期运行,并且还须要与您的生产环境相匹配。使用Docker,您只须要获取一个可移植的Python运行时做为映像,不须要安装。而后,只须要在这个有python环境基础的images上部署你的代码和依赖,他就能够正确的运行你的应用程序。最终这些可移植的image由dockerFile构建。
接下来经过一个实战案例去解释上面这段话的含义python

#Use an official Python runtime as a parent image
FROM python:2.7-slim

#Set the working directory to /app
WORKDIR /app

#Copy the current directory contents into the container at /app
COPY . /app

#Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -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"]

这里这个dockerfile出现了两个文件须要本身编写:app.py and requirements.txtnginx

#app.py
from flask import Flask
from redis import Redis, RedisError
import os
import socket

# Connect to Redis
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)
#requirements.txt
Flask
Redis

注意:dockerfile、app.py 、 requirements.txt在同一个目录下。web

#构建并运行容器:
#构建images
docker build -t --tag=friendlyhello .
#查看构建的image
$ docker image ls
#运行image的容器
docker run -p 4000:80 friendlyhello
若是顺利的话,就能够在http://localhost:4000中看见以下界面:
docker基础篇(二)
到这里,一个基于dockerfile的容器就这样构建好,并运行起来了,是否是很是的简单。redis

3.Part3:Services

  在part2中咱们只是使用dockerfile构建一个image,而且经过image运行了container,在part3中咱们将实现分布式应用服务的一个特性--load-balancing,这就不得不将刚刚的container上升一个高度到:service。
docker基础篇(二)
  在分布式应用程序中,应用程序的不一样部分称为“服务”。例如,若是您设想一个视频共享站点,它可能包括一个用于在数据库中存储应用程序数据的服务、一个用于用户上传内容后在后台进行视频代码转换的服务、一个用于前端的服务,等等。
  服务实际上只是“生产中的容器”。“一个服务只运行一个映像,可是它将映像运行的方式进行了编码——应该使用什么端口,应该运行多少个容器副本,以便服务具备所需的容量,等等。扩展服务能够改变运行该软件的容器实例的数量,从而为流程中的服务分配更多的计算资源。
这里咱们就着手去构建一个本身的services:
#编写一个docker-compose.yml文件:
#Yml是一个yaml文件,它定义了Docker容器在生产环境中的行为。docker

version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: nginx
    deploy:
      replicas: 5
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
      restart_policy:
        condition: on-failure
    ports:
      - "4000:80"
    networks:
      - webnet
networks:
  webnet:

这个文件告诉了docker须要作的事情:shell

  • 从registry中pull一个nginx镜像
  • 运行5个名字叫作web的镜像实例。(其中也定义了这五个实例的资源配额)
  • 设置了失败重启策略
  • 设置了端口映射
  • 经过一个称为webnet的负载均衡网络,指示web的容器共享端口80(有点像nginx的负载均衡)
  • 使用默认设置定义webnet网络(这是一个负载平衡的覆盖网络)数据库

    #设置节点为集群管理器
    docker swarm init
    #运行本身的负载均衡app
    docker stack deploy -c docker-compose.yml getstartedlab
    注意:这里“getstartedlab”是给本身的service起一个名字
    #查看全部的service
    docker service ls
    #查看具体的service
    docker stack services getstartedlab
    docker基础篇(二)
    能够看到这个service中运行了5个副本,而其名称为“getstartedlab_web”

    #咱们在查看getstartedlab_web下的task
    docker service ps getstartedlab_web
    docker stack ps getstartedlab #这种方式也能够获取service的容器的运行状态
    docker基础篇(二)
    注意:这里的一个单一的container在service中称为task,每个container在service有一个惟一的ID,以数字的形式顺序递增。

    #同理咱们查看docker的容器,一样能够看见这个五个task
    [root@zy dockerfile]# docker ps
    docker基础篇(二)
    此时在浏览器中输入http://localhost:4000,就能看见以下界面:
    docker基础篇(二)
    补充:

    #删除服务
    docker stack rm getstartedlab
    #取消这个节点为集群的管理节点
    docker swarm leave --force

4.Part4:Swarms

  这一部分介绍的是,将应用程序部署到集群中去,并在多台机器上运行。多容器、多机器的应用程序能够经过将多台机器链接到一个叫“Dockerized”集群中来实现。
  Swarms 是一组运行docker并加入到集群的机器。在Swarms中运行的docker命令,都将由集群管理器执行,集群中的机器能够是物理机也能够是虚拟机。一旦加入到了Swarms中它们就被称为一个节点。
  集群的管理器可使用不一样的策略去运行容器。如“emptiest node” 表示:用容器填充利用率最低的容器;或者“global”表示:确保每台机器只得到指定容器的一个实例。指示集群管理器在编排文件中使用这些策略,就像已经使用的策略同样。
  Swarms的集群管理器是惟一可以执行命令的机器。他能够受权其余的机器做为worker加入集群,worker只提供生产能力,没有权利指示其余的机器该作什么和不应作什么。

(1)创建本身的Swarms

  集群是由多个节点组成的,能够是物理机也能够是虚拟节点。其基本概念比较简单:运行docker swarm init 以启用集群模式,并使当前正在使用的机器成为一个集群管理器,而后在其余机器上运行docker swarm join让他们做为worker加入到集群中。这里咱们使用的是vm快速建立一个双机集群。

#建立两个虚拟节点
#这里使用docker-machine,以VirtualBox 驱动建立两个虚拟节点:
$docker-machine create --driver virtualbox myvm1
$docker-machine create --driver virtualbox myvm2

注意:Docker-machine是 Docker 官方提供的一个工具,它能够帮助咱们在远程的机器上安装 Docker,或者在虚拟机 host 上直接安装虚拟机并在虚拟机中安装 Docker。
https://docs.docker.com/machine/install-machine/ 官网的安装docker-machine。

#查看这两个虚拟机的IP
docker-machine ls

注意:这里的默认端口是2376,若是系统中有进程占用了2376,会报错。

#初始化集群并添加节点
#以myvm1为管理节点,执行管理命令并验证myvm2是否加入集群,myvm2是一个从节点。
$ docker-machine ssh myvm1 "docker swarm init --advertise-addr <myvm1 ip>"

注意:若是这里出现了问题,使用--native-ssh 使用系统的ssh

docker-machine --native-ssh ssh myvm1 ...
#添加myvm2做为工做节点
$ docker-machine ssh myvm2 "docker swarm join \
--token <token> \
<ip>:2377"

到这里,就建立好了属于本身swarm的集群。

#查看集群的节点
$ docker-machine ssh myvm1 "docker node ls"

(2)部署本身的app在swarm集群上

#运行docker-machine env myvm1得到命令,将shell配置为与myvm1对话:
$ docker-machine env myvm1
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/Users/sam/.docker/machine/machines/myvm1"
export DOCKER_MACHINE_NAME="myvm1"
# Run this command to configure your shell:
# eval $(docker-machine env myvm1)

注意:这句话表示当前的shell链接myvm1。(也就是在这个shell的操做实际上实在myvm1中的)

#运行给定的命令,将shell配置为与myvm1对话
eval $(docker-machine env myvm1)
#查看myvm1是否active,*号表示成功
$ docker-machine ls
在swarm管理节点上部署app
docker stack deploy -c docker-compose.yml getstartedlab

注意:虽说这个shell是在myvm1中的,可是只要咱们的所在位置是docker-compose.yml的文件所在位置,那么仍然可使用docker-compose.yml文件。

#若是镜像不是在docker Hub,而是在本身的私服上,可使用docker login 登陆
$docker login registry.example.com
$docker stack deploy --with-registry-auth -c docker-compose.yml getstartedlab
#查看stack中运行的container
$ docker stack ps getstartedlab

注意:注意这里在集群的各个节点上都有运行,而且在访问时时随机的指定哪个container提供服务,实现了负载均衡。
固然使用虚拟机的IP,去查看:
docker基础篇(二)

(3)实现负载均衡的原理

docker基础篇(二)
  这两个IP地址都能工做的缘由是群中的节点参与了一个入口路由网格。这能够确保部署在集群中某个端口的服务始终保留该端口,无论实际运行容器的是哪一个节点。上面是一个图,展现了一个名为my-web的服务的路由网格是如何在一个三节点群上的8080端口发布的。

(4)应用程序的迭代和扩展

状况一:经过改变docker-compose.yml 文件去扩展应用程序。
状况二:改变应用程序的行为和代码以后,构建出一个新的image,而且push的仓库中。
以上的两种状况只须要docker-compose.yml file 从新构建service便可。
固然若是,swarm集群中加入了新的节点,此时,只须要在这个新的节点上执行docker swarm join 将这个节点加入到swarm集群中,以后的 docker stack deploy 操做会自动的利用新的资源(新加入的节点)。

(5)清除和重启

#拆除stack
docker stack rm getstartedlab
#移除整个swarm集群
链接每个worker节点执行:
docker-machine ssh 节点名 "docker swarm leave"

#在每一个节点上取消以前的环境变量:
  eval $(docker-machine env -u)

#重启docker machines
docker-machine start <machine-name>

5.Part5:stack

docker基础篇(二)
  在part4部分中,学习了如何设置一个运行docker容器的集群,并将一个应用程序部署到其中,容器在多台机器上同时运行。
  在part5将介绍分布式应用程序层次中的顶层:堆栈。堆栈是一组互相关联的服务,他们共享依赖关系,而且能够在一块儿编排和伸缩,单个堆栈可以定义和协调整个应用程序的功能(很是复杂的应用程序须要使用多个堆栈)。
  其实在part3中就使用了堆栈,当在撰写一个Compose 文件时就是使用的堆栈deploy,可是在单个主机上运行的单个服务堆栈,这个通常在生产环境中不会出现,在part5中可使多个服务彼此关联,并在多台机器上运行。

(1) 添加新服务并从新部署

  添加新服务很简单,使用Compose.yml文件便可。这里咱们添加一个免费的visualizer服务,他容许咱们查看集群如何调度容器、服务额部署。

#docker- composition.yml:
version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: nginx
    deploy:
      replicas: 5
      restart_policy:
        condition: on-failure
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
    ports:
      - "80:80"
    networks:
      - webnet
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
networks:
  webnet:

这里咱们建立了两个服务,nginx和visualizer。而且使用了volumes,提供了本机映射docker的目录文件。而且添加了一个放置键,保证了服务只能在docker的管理节点上运行,而不是在worker上运行。

#确保shell配置为与myvm1对话
$eval $(docker-machine env myvm1)
#在管理节点上从新运行docker stack deploy命令,任何须要更新的服务都会更新:
$ docker stack deploy -c docker-compose.yml getstartedlab

经过docker-machine ls得到其中一个节点的IP地址。去任何一个IP地址的8080端口均可以看见:
docker基础篇(二)
此时能够看见visualizer单一副本的服务在管理节点上运行,而且web的5个实例分散在集群中。能够经过docker stack ps <stack>,来验证:

$docker stack ps getstartedlab

(2)Persist the data

  visualizer是一个独立的服务,能够在任何包含在堆栈中的应用程序中运行。它不依赖于其余任何东西。如今让咱们建立一个具备依赖性的服务:提供访问者计数器的Redis服务。

#docker-compose.yml:
version: "3"
services:
  web:
    # replace username/repo:tag with your name and image details
    image: nginx
    deploy:
      replicas: 5
      restart_policy:
        condition: on-failure
      resources:
        limits:
          cpus: "0.1"
          memory: 50M
    ports:
      - "80:80"
    networks:
      - webnet
  visualizer:
    image: dockersamples/visualizer:stable
    ports:
      - "8080:8080"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - webnet
  redis:
    image: redis
    ports:
      - "6379:6379"
    volumes:
      - "/home/docker/data:/data"
    deploy:
      placement:
        constraints: [node.role == manager]
    command: redis-server --appendonly yes
    networks:
      - webnet
networks:
  webnet:

redis在镜像库中有一个官方的镜像,命名就是Redis,最重要的是,在Redis规范中有两件事可让数据在这个堆栈的部署之间持久:

  • Redis老是在管理节点上运行,全部它使用的相同的文件系统
  • Redis容器映射出来一个/data目录,在主机的/home/docker/data,存储容器数据。
    总之:这是在主机的物理文件系统中为Redis数据建立一个“真实源”。若是没有这个,Redis将把它的数据存储在容器的文件系统中,若是容器被从新部署,文件系统将被删除。
    部署:
    #在管理机器上建立一个/data目录
    $docker-machine ssh myvm1 "mkdir ./data"
    #保证当前shell在myvm1:
    $eval $(docker-machine env myvm1)
    #更新堆栈:
    $ docker stack deploy -c docker-compose.yml getstartedlab
    #查看服务
    $ docker service ls
    #查看IP
    $docker-machine ls

    #验证:
    验证nginx在任意节点上访问nginx:
    docker基础篇(二)
    #查看visualizer 服务:
    docker基础篇(二)
    检查一个节点的web页面,例如http://192.168.130.101,并查看访问者计数器的结果,该计数器如今是活动的,并在Redis上存储信息。
    总结:栈是相互关联的服务,而且全部的服务是同步运行的。使用位置约束和数据卷,能够将容器中的数据持久化到本地主机中,所以当容器被从新部署的时候,应用程序的数据不会丢失。

6.Part6

最终part6总结了dockerized应用程序的一些选项:

#建立本身的swarm在node上
docker swarm init
#部署本身的app
docker stack deploy -c docker-compose.yml getstartedlab

#查看本身swarm的node
$ docker node ls
#查看服务列表
$ docker service ls
#查看具体服务下的容器
$ docker service ps vy7n2piyqrtr
#删除一个堆栈
docker stack rm getstartedlab
相关文章
相关标签/搜索