GVKun编程网logo

DOCKER 学习笔记 9 Kubernetes (K8s) 弹性伸缩容器 下(rancher 弹性伸缩)

10

这篇文章主要围绕DOCKER学习笔记9Kubernetes(K8s)弹性伸缩容器下和rancher弹性伸缩展开,旨在为您提供一份详细的参考资料。我们将全面介绍DOCKER学习笔记9Kubernetes

这篇文章主要围绕DOCKER 学习笔记 9 Kubernetes (K8s) 弹性伸缩容器 下rancher 弹性伸缩展开,旨在为您提供一份详细的参考资料。我们将全面介绍DOCKER 学习笔记 9 Kubernetes (K8s) 弹性伸缩容器 下的优缺点,解答rancher 弹性伸缩的相关问题,同时也会为您带来docker kubernetes Swarm 容器编排 k8s CICD 部署 麦兜、Docker Kubernetes 容器扩容与缩容、Docker Kubernetes(K8s)简介、DOCKER 学习笔记9 Kubernetes (K8s) 生产级容器编排 上的实用方法。

本文目录一览:

DOCKER 学习笔记 9 Kubernetes (K8s) 弹性伸缩容器 下(rancher 弹性伸缩)

DOCKER 学习笔记 9 Kubernetes (K8s) 弹性伸缩容器 下(rancher 弹性伸缩)

前言

从上一篇看来,我们已经对于 Kubernetes , 通过 minikube 建立集群,而后使用 kubectl 进行交互,对 Deployment 部署以及服务的暴露等。这节,将学习弹性的将服务部署到多个节点上。

检查

检查部署情况 kubectl get deployments

$ kubectl get deployments
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
mynode   1/1     1            1           10m
  • READY 显示当前 / 所需副本的比率
  • UP-TO-DATE 最新显示已更新以达到所需状态的副本数
  • 显示应用程序有多少副本可供用户使用。
  • AGE 启动时间

kubectl get nodes 检查当前可用节点数

$ kubectl get nodes
NAME       STATUS   ROLES    AGE   VERSION
minikube   Ready    master   39m   v1.17.2

image.png

增加副本数量

kubectl scale deployment <name> --replicas=?

将部署的副本数量调节至指定大小

mrc@mrc-linux:~$ kubectl scale deployment mynode --replicas=4
deployment.apps/mynode scaled

kubectl get pods 可以查看当前 POD 的数量

$ kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
mynode-5479db549c-6n6wt   1/1     Running   0          31m
mynode-5479db549c-hvpnr   1/1     Running   0          4m39s
mynode-5479db549c-mzmht   1/1     Running   0          4m39s
mynode-5479db549c-zwg6k   1/1     Running   0          4m39s

image.png

查看部署创建的复制集合

kubectl get rs

$ kubectl get rs
NAME                DESIRED   CURRENT   READY   AGE
mynode-5479db549c   4         4         4       10h

我们扩容到了四个,所以这里展示的有四个

查看服务状态

$ kubectl get service mynginx
NAME      TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
mynginx   NodePort   10.111.8.25   <none>        80:30857/TCP   5m33s

这里原有的服务就是将 nginx 应用 80 端口暴露到虚拟机 30857 端口下

image.png

更新应用

在 Kubernetes 中,这些是通过滚动更新(Rolling Updates)完成的。 滚动更新 允许通过使用新的实例逐步更新 Pod 实例,零停机进行 Deployment 更新。新的 Pod 将在具有可用资源的节点上进行调度。

image.png

image.png

更新镜像


vi Dockerfile

FROM nginx
RUN echo ''<h1>Update Kubernetes</h1>'' > /usr/share/nginx/html/index.html

重新打包

docker build -t mynginx:v1 .

更换部署镜像

$ kubectl.exe set image deployment <deployment> oldimage=newimage
  • deployment 表示需要修改的应用实例
  • oldimage 原本的镜像名称
  • newimage 新的镜像名称
$ kubectl.exe set image deployment/mynginx mynginx=mynginx:v1                                                                                                                                                                                deployment.apps/mynginx image updated

查看 POD

kubectl.exe get pods

我们会发现多出来两个 POD , 当然这两个 POD 是新的,将要替换掉原来老旧的 POD

$ kubectl.exe get pods                                                                                                                                                                                                                       NAME                       READY   STATUS        RESTARTS   AGE
mynginx-54fdcfb5dd-h7wwl   1/1     Running       0          11s
mynginx-54fdcfb5dd-jk4n4   1/1     Running       0          9s
mynginx-54fdcfb5dd-m9x45   1/1     Running       0          9s
mynginx-54fdcfb5dd-wbrpz   1/1     Running       0          11s
mynginx-6579cc57f7-pkvgv   0/1     Terminating   0          39m
mynginx-6579cc57f7-zlwzj   0/1     Terminating   0          64m

image.png

检查更新结果

$ kubectl get services
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        45h
mynginx      NodePort    10.111.8.25   <none>        80:30857/TCP   125m

获取到暴露出的端口号:30857

image.png

回滚

其实回滚和更新是一个操作,是需要将镜像版本进行修改即可完成回滚

小结

到这里,基本上 docker 学习就先到一段落吧,从最开始的 docker 入门开始,到接触到编排 compose 以及建立虚拟机 docker-machine 再到使用官网的 docker swarm 进行集群的创建,任务的部署。走过很大段的一条路。最后我们尝试着接触一些企业里面流行的生产化容器编排 k8S

革命尚未成功,同志任需努力!

docker kubernetes Swarm 容器编排 k8s CICD 部署 麦兜

docker kubernetes Swarm 容器编排 k8s CICD 部署 麦兜

1docker 版本

docker 17.09

https://docs.docker.com/

appledeAir:~ apple$ docker version

Client: Docker Engine - Community

 Version:           18.09.0

 API version:       1.39

 Go version:        go1.10.4

 Git commit:        4d60db4

 Built:             Wed Nov  7 00:47:43 2018

 OS/Arch:           darwin/amd64

 Experimental:      false

 

Server: Docker Engine - Community

 Engine:

  Version:          18.09.0

  API version:      1.39 (minimum version 1.12)

  Go version:       go1.10.4

  Git commit:       4d60db4

  Built:            Wed Nov  7 00:55:00 2018

  OS/Arch:          linux/amd64

  Experimental:     false

 

 

 

vagrant

创建 linux 虚拟机

创建一个目录 

mkdir centos7

vagrant init centos/7  #会创建一个 vagrant file

vagrant up        # 启动

vagrant ssh        # 进入虚拟机

vagrant status

vagrant halt      # 停机

vagrant destroy    删除机器

 

docker machine 自动在虚拟机安装 docker 的工具

docker-machine create demo    virtualbox 里会自动运行一台虚拟机

docker-machine ls          显示有哪些虚拟机在运行

docker-machine ssh demo      进入机器

docker-machine create demo1    创建第二台有 docker 的虚拟机

docker-machine stop demo1

 

docker playground https://labs.play-with-docker.com/

 

运行 docker

docker run -dit ubuntu /bin/bash

 

执行不退出

docker exec -it 33 /bin/bash

 

 

把普通用户添加到 docker 组,不用 sudo 

sudo gpasswd -a alex docker

/etc/init.d/docker restart

重新登录 shell    exit

验证 docker version

 

 

 

 

创建自己的 image

 

from scratch

ADD app.py /

CMD ["/app.py"]

 

build 自己的 image

docker build  -t alex/helloworld .

 

 

显示当前正在运行的容器

docker container ls

docker container ls -a

 

显示状态为退出的容器

docker container ls -f "status=exited" -q

 

删除容器

docker container rm 89123

docker rm 89123

或者一次性删除全部容器

docker rm $(docker container ls -aq)    

 

 

删除退出状态的容器

docker rm $(docker container ls -f "status=exited" -q)

 

 

删除不用的 image

docker rmi 98766

 

 

把 container,commit 成为一个新的 image

docker commit 12312312 alexhe/changed_a_lot:v1.0

docker image ls

docker history 901923123     (image 的 id)

 

 

 

 

Dockerfile 案例:

 cat Dockerfile 

FROM centos

ENV name Docker

CMD echo "hello $name"

 

用 dockerfile 建立 image

docker build -t alexhe/firstblood:latest .

 

 

从 registry 拉取

docker pull ubuntu:18.04

 

Dockerfile 案例:

cat Dockerfile 

FROM centos

RUN yum install -y vim      

 

 

Dockerfile 案例:

FROM ubuntu

RUN apt-get update && apt-get install -y python

 

 

 

 

 

Dockerfile 语法梳理及最佳实践

From ubuntu:18.04

LABEL maintainer="alex@alexhe.net"

LABEL version="1.0"

LABEL description="This is comment"

RUN yum update && yum instlal -y vim \

  python-dev                    # 每运行一次 run,增加一层 layer,需要合并起来

WORKDIR /root                    # 进入目录,如果没有目录会自动创建目录

WORKDIR demo                              #进入了 /root/demo

ADD hello /

ADD test.tar.gz/                # 添加到根目录并解压

WORKDIR /root

ADD hello test/                # /root/test/hello

WORKDIR /root

COPY hello test/                # 

大部分情况,copy 优于 add,add 除了 copy 还有额外功能(解压),添加远程文件 / 目录请使用 curl 或者 wget

ENV MYSQL_VERSION 5.6            # 设置常亮

RUN apt-get install -y mysql-server="${MYSQL_VERSION}" && rm -rf /var/lib/apt/lists/*          #引用常量

 

RUN vs CMD vs ENTRYPOINT

run: 执行命令并创建新的 image layer

cmd:设置容器启动后默认执行的命令和参数

entrypoint: 设置容器启动时运行的命令

 

shell 格式

RUN apt-get install -y vim

CMD echo "hello docker"

ENTRYPOINT echo "hello docker"

 

Exec 格式

RUN ["apt-get","install","-y","vim"]

CMD ["/bin/echo","hello docker"]

ENTRYPOINT ["/bin/echo","hello docker"]

 

例子:注意

FROM centos

ENV name Docker

ENTRYPOINT ["/bin/bash","-c","echo","hello $name"]    #这样正解    如果 ["echo","hello $name"],这样运行了以后还是显示 hello $name,没有变量替换。用 exec 格式,执行的是 echo 这个命令,而不是 shell,所以没办法把变量替换掉。

 

和上面的区别

FROM centos

ENV name Docker

ENTRYPOINT echo "hello $name"                 # 正常 可以显示 hello Docker 会用 shell 执行命令,识别变量

 

 

CMD:

容器启动时默认执行的命令,如果 docker run 指定了其他命令,CMD 命令被忽略。如果定义了多个 CMD,只有最后一个会执行。

 

ENTRYPOINT:

让容器以应用程序或者服务的形式运行。不会被忽略,一定会执行。最佳实践:下一个 shell 脚本作为 entrypoint

COPY docker-entrypoint.sh /usr/local/bin/

ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 27017

CMD ["mongod"]

 

 

 

镜像发布

docker login

docker push alexhe/hello-world:latest

docker rmi alexhe/hello-world        # 删掉

docker pull alexhe/hello-world:latest    # 再拉回来

 

 

本地 registry private repository

https://docs.docker.com/v17.09/registry/

1. 启动私有 registry

docker run -d -p 5000:5000 -v /opt/registry:/var/lib/registry --restart always --name registry registry:2

 

2. 其他机器测试 telnet x.x.x.x 5000

 

3. 往私有 registry push

3.1 先用 dockerfile build 和打 tag

docker build -t x.x.x.x:5000/hello-world .

3.2 设置允许不安全的私有库

vim /etc/docker/daemon.json

{
  "insecure-registries" : ["x.x.x.x:5000"] }

vim /lib/systemd/service/docker.service

EnvirmentFile=/etc/docker/daemon.json

 

/etc/init.d/docker restart

 

3.3 开始 push

docker push x.x.x.x:5000/hello-world

 

3.4 验证

registry 有 api https://docs.docker.com/v17.09/registry/spec/api/#listing-repositories

GET /v2/_catalog

docker pull x.x.x.x:5000/helloworld

 

 

Dockerfile  github 很多示例 https://github.com/docker-library/docs     https://docs.docker.com/engine/reference/builder/#add

Dockerfile 案例:安装 flask 复制目录中的 app.py 到 /app/ 进入 app 目录 暴露 5000 端口 执行 app.py

cat Dockerfile 

FROM python:2.7

LABEL maintainer="alex he<alex@alexhe.net>"

RUN pip install flask

COPY app.py /app/

WORKDIR /app

EXPOSE 5000

CMD ["python", "app.py"]

 

 cat app.py 

from flask import Flask

app = Flask(__name__)

@app.route(''/'')

def hello():

    return "hello docker"

if __name__ == ''__main__'':

    app.run(host="0.0.0.0", port=5000)

 

 

 

docker build -t alexhe/flask-hello-world .        # 打包

如果打包时出错

docker run -it 报错时的第几步 id  /bin/bash

进入以后看看哪里报错

 

最后 docker run -d alexhe/flask-hello-world   # 让容器在后台运行

 

在运行中的容器,执行命令:

docker exec -it xxxxxx /bin/bash

 

显示 ip 地址:

docker exec -it xxxx ip a

 

docker inspect xxxxxxid

 

显示容器运行产生的输出:

docker logs xxxxx

 

dockerfile 案例:

linux 的 stress 工具

cat Dockerfile

FROM ubuntu

RUN apt-get update && apt-get install -y stress

ENTRYPOINT ["/usr/bin/stress"]                  #使用 entrypoint 加 cmd 配合使用,cmd 为空的,用 docker run 来接收请求参数

CMD []

 

使用:

docker build alexhe/ubuntu-stress .

#dokcer run -it alexhe/ubuntu-stress             # 无任何参数运行,类似于打印

docker run -it alexhe/ubuntu-stress -vm 1  --verbose   # 类似于运行 stress -vm 1 --verbose

 

容器资源限制,cpu,ram

docker run --memory=200M alexhe/ubuntu-stress -vm 1       --vm-bytes=500M  --verbose   # 直接报错,内存不够。因为给了容器 200m,压力测试占用 500m

docker run --cpu-shares=10  --name=test1 alexhe/ubuntu-stress -vm1  # 和下面一起启动,他的 cpu 占用率为 66%

docker run --cpu-shares=5  --name=test2 alexhe/ubuntu-stress -vm1  # 一起启动,他的 cpu 占用率 33%

 

 

容器网络

单机:bridge,host,none

多机:Overlay

 

linux 中的网络命名空间

docker run -dit --name test1 busybox /bin/sh -c "while true;do sleep 3600;done"  

docker exec -it xxxxx /bin/sh

ip a 显示网络接口

exit

进入 host , 执行 ip a ,显示 host 的接口

container 和 host 的网络 namespace 是隔离开的

docker run -dit --name test2 busybox /bin/sh -c "while true;do sleep 3600;done"

docker exec xxxxx ip a    # 看第二台机器的网络

同一台机器,container 之间的网络是相通的。

 

以下是 linux 中的网络命名空间端口互通的原理实现(docker 的和他类似):

host 中执行 ip netns list            查看本机的 network namespace

ip netns delete test1

ip netns add test1                    #创建 network namespace

ip netns add test2      # 创建 network namespace

 

在 test1 的 network namespace 中执行 ip link

ip netns exec test1 ip link                 # 目前状态是 down 的

ip netns exec test1 ip link set dev lo up             # 状态变成了 unknown,要两端都连通,他才会变成 up

创建一对 veth,一个放入 test1 的 namespace,另一个放入 test2 的 namespace。

创建一对 veth:

ip link add veth-test1 type veth peer name veth-test2

把 veth-test1 放入 test1 的 namespace:

ip link set veth-test1 netns test1

看看 test1 的 namespace 里的情况:

ip netns exec test1 ip link                 #test1 的 namespace 多了一个 veth,状态为 down

看看本地的 ip link:

ip link                                            #少了一个,说明这一个已经加到了 test1 的 namespace

把 veth-test2 放入 test2 的 namespace:

ip link set veth-test2 netns test2

看看本地的 ip link:

ip link                # 又少了一个,说明已经加入到了 test2 的 namespace

看看 test2 的 namespace

ip netns exec test2 ip link        #test2 的 namespace 多了一个 veth,状态为 down

给两个 veth 端口添加 ip 地址:

ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1

ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2

查看 test1 和 test2 的 ip link

ip netns exec test1 ip link         # 发现没有 ip 地址,并且端口状态是 down

ip netns exec test2 ip link         # 发现没有 ip 地址,并且端口状态是 down

把两个端口 up 起来

ip netns exec test1 ip link set dev veth-test1 up

ip netns exec test2 ip link set dev veth-test2 up

查看 test1 和 test2 的 ip link

ip netns exec test1 ip link             # 发现有 ip 地址,并且端口状态是 up

ip netns exec test2 ip link            # 发现有 ip 地址,并且端口状态是 up

从 test1 的 namespace 里的 veth-test1 执行 ping test2 的 namespace 中的 veth-test2

ip netns exec test1 ping 192.168.1.2

ip netns exec test2 ping 192.168.1.1

 

docker 的 bridge docker0 网络:

两个容器 test1 和 test2 能互相 ping 通,说明两个 network namespace 是连接在一起的。

目前系统只有一个 test1 的容器,删除 test2 容器

显示 docker 网络:

docker network ls

NETWORK ID          NAME                DRIVER              SCOPE

9d133c1c82ff        bridge              bridge              local

e44acf9eff90        host                host                local

bc660dbbb8b6        none                null                local

显示 bridge 网络的详情:

docker network inspect xxxxxx (上面显示 bridge 网络的 id)

 

host 上的 veth 和容器里的 eth0 是一对儿 veth

ip link                     #veth6aa1698@if18

 docker exec test1 ip link          #18: eth0@if19

这一对儿 veth pair 连接到了 host 上的 docker0 上面。

yum install bridge-utils

brctl show            #主机上的 veth6aa 连接在 docker0 上

新开一个 test2 的容器:

docker run -dit --name test2 busybox /bin/sh -c "while true;do sleep 3600;done"

看看 docker 的网络:

docker network inspect bridge

看到 container 多了一个,地址都有

在 host 运行 ip a,又多了一个 veth。

运行 brctl show,docker0 上有两个接口

 

 

docker 容器之间的互联 link

目前只有一个容器 test1

现在创建第二个容器 test2

docker run -d --name test2 --link test1 busybox /bin/sh -c "while true;do sleep 3600;done"

docker exec -it test2 /bin/sh

进入 test2 后,去 ping test1 的 ip 地址,通,ping test1 的名字 ,也通。

进入 test1 里,去 ping test2 的 ip 地址,通,ping test2 的名字,不通。

 

自己建一个 docker network bridge,并让容器连接他。

docker network create -d bridge my-bridge

创建一个容器,test3

docker run -d --name test3 --network my-bridege busybox /bin/sh -c "while true;do sleep 3600;done"

通过 brctl show 来查看。

把 test2 的网络换成 my-bridge

docker network connect my-bridge test2,当连接进来后,test2 就有了 2 个 ip 地址。

注意:如果用户自己创建自定义的 network,并让一些容器连接进来,这些容器,是能通过名字来互相 ping 连接的。而默认的 bridge 不行,就像上面测试一样。

 

docker 的端口映射

创建一个 nginx 的 container

docker run --name web -d -p 80:80 nginx

 

docker 的 host 和 none 网络

none network:

docker run -d --name test1 --network none busybox /bin/sh -c "while true;do sleep 3600;done"

docker network inspect none               # 可以看到 none 的 network 连接了一个 container

进入容器:

docker exec -it test1 /bin/sh           # 进入看看网络,无任何 ip 网络

 

host network:

docker run -d --name test1 --network host busybox /bin/sh -c "while true;do sleep 3600;done"

docker network inspect host

进入容器:

docker exec -it test1 /bin/sh            #查看 ip a 网络,容器的 ip 和主机的 ip 完全一样,他没有自己独立的 namespace

 

多容器复杂应用的部署:

Flask+redis,   flask 的 container 访问 redis 的 container

cat app.py

from flask import Flask

from redis import Redis

import os

import socket

 

app = Flask(__name__)

redis = Redis(host=os.environ.get(''REDIS_HOST'', ''127.0.0.1''), port=6379)

 

 

@app.route(''/'')

def hello():

    redis.incr(''hits'')

    return ''Hello Container World! I have been seen %s times and my hostname is %s.\n'' % (redis.get(''hits''),socket.gethostname())

 

 

if __name__ == "__main__":

    app.run(host="0.0.0.0", port=5000, debug=True)

 

 cat Dockerfile 

FROM python:2.7

LABEL maintaner="Peng Xiao xiaoquwl@gmail.com"

COPY . /app

WORKDIR /app

RUN pip install flask redis

EXPOSE 5000

CMD [ "python", "app.py" ]

 

1. 创建 redis 的 container:

docker run -d --name redis redis

2. dokcer build -t alexhe/flask-redis .

3. 创建 container

docker run -d -p 5000:5000 --link redis --name flask-redis -e REDIS_HOST=redis alexhe/flask-redis                    #和上面源码的相对应

4. 进入上面的 container, 并执行 env 看一下:

docker exec -it flask-redis /bin/bash 

env                         # 环境变量

ping redis      # 在容器里可以 ping redis

5. 在主机访问 curl 127.0.0.1:5000。可以访问到

 

多主机间,多 container 互相通信

docker 网络的 overlay 和 underlay:

 两台 linux 主机 192.168.205.10    192.168.205.11

vxlan 数据包(google 搜 vxlan 概念)

cat multi-host-network.md 
# Mutil-host networking with etcd

## setup etcd cluster

在docker-node1上

```
vagrant@docker-node1:~$ wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
vagrant@docker-node1:~$ tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
vagrant@docker-node1:~$ cd etcd-v3.0.12-linux-amd64
vagrant@docker-node1:~$ nohup ./etcd --name docker-node1 --initial-advertise-peer-urls http://192.168.205.10:2380 \
--listen-peer-urls http://192.168.205.10:2380 \
--listen-client-urls http://192.168.205.10:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.205.10:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.205.10:2380,docker-node2=http://192.168.205.11:2380 \
--initial-cluster-state new&
```


在docker-node2上

```
vagrant@docker-node2:~$ wget https://github.com/coreos/etcd/releases/download/v3.0.12/etcd-v3.0.12-linux-amd64.tar.gz
vagrant@docker-node2:~$ tar zxvf etcd-v3.0.12-linux-amd64.tar.gz
vagrant@docker-node2:~$ cd etcd-v3.0.12-linux-amd64/
vagrant@docker-node2:~$ nohup ./etcd --name docker-node2 --initial-advertise-peer-urls http://192.168.205.11:2380 \
--listen-peer-urls http://192.168.205.11:2380 \
--listen-client-urls http://192.168.205.11:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.205.11:2379 \
--initial-cluster-token etcd-cluster \
--initial-cluster docker-node1=http://192.168.205.10:2380,docker-node2=http://192.168.205.11:2380 \
--initial-cluster-state new&
```

检查cluster状态

```
vagrant@docker-node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl cluster-health
member 21eca106efe4caee is healthy: got healthy result from http://192.168.205.10:2379
member 8614974c83d1cc6d is healthy: got healthy result from http://192.168.205.11:2379
cluster is healthy
```

## 重启docker服务


在docker-node1上

```
$ sudo service docker stop
$ sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.205.10:2379 --cluster-advertise=192.168.205.10:2375&
```

在docker-node2上

```
$ sudo service docker stop
$ sudo /usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=etcd://192.168.205.11:2379 --cluster-advertise=192.168.205.11:2375&
```

## 创建overlay network

在docker-node1上创建一个demo的overlay network

```
vagrant@docker-node1:~$ sudo docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
0e7bef3f143a        bridge              bridge              local
a5c7daf62325        host                host                local
3198cae88ab4        none                null                local
vagrant@docker-node1:~$ sudo docker network create -d overlay demo
3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9
vagrant@docker-node1:~$ sudo docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
0e7bef3f143a        bridge              bridge              local
3d430f3338a2        demo                overlay             global
a5c7daf62325        host                host                local
3198cae88ab4        none                null                local
vagrant@docker-node1:~$ sudo docker network inspect demo
[
    {
        "Name": "demo",
        "Id": "3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9",
        "Scope": "global",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1/24"
                }
            ]
        },
        "Internal": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]
```

我们会看到在node2上,这个demo的overlay network会被同步创建

```
vagrant@docker-node2:~$ sudo docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
c9947d4c3669        bridge              bridge              local
3d430f3338a2        demo                overlay             global
fa5168034de1        host                host                local
c2ca34abec2a        none                null                local
```

通过查看etcd的key-value, 我们获取到,这个demo的network是通过etcd从node1同步到node2的

```
vagrant@docker-node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl ls /docker
/docker/network
/docker/nodes
vagrant@docker-node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl ls /docker/nodes
/docker/nodes/192.168.205.11:2375
/docker/nodes/192.168.205.10:2375
vagrant@docker-node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl ls /docker/network/v1.0/network
/docker/network/v1.0/network/3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9
vagrant@docker-node2:~/etcd-v3.0.12-linux-amd64$ ./etcdctl get /docker/network/v1.0/network/3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9 | jq .
{
  "addrSpace": "GlobalDefault",
  "enableIPv6": false,
  "generic": {
    "com.docker.network.enable_ipv6": false,
    "com.docker.network.generic": {}
  },
  "id": "3d430f3338a2c3496e9edeccc880f0a7affa06522b4249497ef6c4cd6571eaa9",
  "inDelete": false,
  "ingress": false,
  "internal": false,
  "ipamOptions": {},
  "ipamType": "default",
  "ipamV4Config": "[{\"PreferredPool\":\"\",\"SubPool\":\"\",\"Gateway\":\"\",\"AuxAddresses\":null}]",
  "ipamV4Info": "[{\"IPAMData\":\"{\\\"AddressSpace\\\":\\\"GlobalDefault\\\",\\\"Gateway\\\":\\\"10.0.0.1/24\\\",\\\"Pool\\\":\\\"10.0.0.0/24\\\"}\",\"PoolID\":\"GlobalDefault/10.0.0.0/24\"}]",
  "labels": {},
  "name": "demo",
  "networkType": "overlay",
  "persist": true,
  "postIPv6": false,
  "scope": "global"
}
```


## 创建连接demo网络的容器

在docker-node1上

```
vagrant@docker-node1:~$ sudo docker run -d --name test1 --net demo busybox sh -c "while true; do sleep 3600; done"
Unable to find image ''busybox:latest'' locally
latest: Pulling from library/busybox
56bec22e3559: Pull complete
Digest: sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912
Status: Downloaded newer image for busybox:latest
a95a9466331dd9305f9f3c30e7330b5a41aae64afda78f038fc9e04900fcac54
vagrant@docker-node1:~$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
a95a9466331d        busybox             "sh -c ''while true; d"   4 seconds ago       Up 3 seconds                            test1
vagrant@docker-node1:~$ sudo docker exec test1 ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:02
          inet addr:10.0.0.2  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::42:aff:fe00:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1
          RX packets:15 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1206 (1.1 KiB)  TX bytes:648 (648.0 B)

eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02
          inet addr:172.18.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:648 (648.0 B)  TX bytes:648 (648.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

vagrant@docker-node1:~$
```

在docker-node2上

```
vagrant@docker-node2:~$ sudo docker run -d --name test1 --net demo busybox sh -c "while true; do sleep 3600; done"
Unable to find image ''busybox:latest'' locally
latest: Pulling from library/busybox
56bec22e3559: Pull complete
Digest: sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912
Status: Downloaded newer image for busybox:latest
fad6dc6538a85d3dcc958e8ed7b1ec3810feee3e454c1d3f4e53ba25429b290b
docker: Error response from daemon: service endpoint with name test1 already exists.   #已经用过不能再用
vagrant@docker-node2:~$ sudo docker run -d --name test2 --net demo busybox sh -c "while true; do sleep 3600; done"
9d494a2f66a69e6b861961d0c6af2446265bec9b1d273d7e70d0e46eb2e98d20
```


验证连通性。

```
vagrant@docker-node2:~$ sudo docker exec -it test2 ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:0A:00:00:03
          inet addr:10.0.0.3  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::42:aff:fe00:3/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1450  Metric:1
          RX packets:208 errors:0 dropped:0 overruns:0 frame:0
          TX packets:201 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:20008 (19.5 KiB)  TX bytes:19450 (18.9 KiB)

eth1      Link encap:Ethernet  HWaddr 02:42:AC:12:00:02
          inet addr:172.18.0.2  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:648 (648.0 B)  TX bytes:648 (648.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

  vagrant@docker-node1:~$ sudo docker exec test1 sh -c "ping 10.0.0.3"
  PING 10.0.0.3 (10.0.0.3): 56 data bytes
  64 bytes from 10.0.0.3: seq=0 ttl=64 time=0.579 ms
  64 bytes from 10.0.0.3: seq=1 ttl=64 time=0.411 ms
  64 bytes from 10.0.0.3: seq=2 ttl=64 time=0.483 ms
  ^C
  vagrant@docker-node1:~$
```

 

 

docker 的持久化存储和数据共享:

持久化有两种方式:1,Data Volume  2,Bind Mounting

第一种 Data Volume:

容器产生数据,比如日志,数据库,想保留这些数据

例如 https://hub.docker.com/_/mysql

docker run -d -e MYSQL_ALLOW_EMPTY_PASSWORD=yes --name mysql1 mysql

查看 volume:

docker volume ls

删除 volume

docker volume rm xxxxxxxxxx

查看细节:
docker volume inspect xxxxxxxxx

创建第二个 mysql container


docker run -d -e MYSQL_ALLOW_EMPTY_PASSWORD=yes --name mysql2 mysql

 查看细节:
docker volume inspect xxxxxxxxx

删除 container,volume 是不会删除的:

docker stop mysql1 mysql2

docker rm mysql1 mysql2

docker volume ls               # 数据还在

重新创建 mysql1:

docker run -d -v mysq:/var/lib/mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=yes --name mysql1 mysql     # 这里的 mysq 是 volume 的名字

docker volume ls                     # 会显示 mysq

进入 mysql1 的 container

创建一个新的数据库

create database docker;

退出容器,把 mysql1 container 删除

docker rm -f mysql1             # 强制停止和删除 mysql1 这个 container

查看 volume:
docker volume ls               # 还在

创建一个新的 mysql2 container,但是 volume 使用之前的 mysq

docker run -d -v mysq:/var/lib/mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=yes --name mysql2 mysql 

进入 mysql2 的容器里,看看数据库在不在

show database    #数据库还在

 

第二种持久化方式:bind mounting

和第一种方式区别是什么?如果用 data volume 方式,需要在 dockerfile 里定义创建的 volume,bind mounting 不需要,bind mouting 只需要在运行时指定本地目录和容器目录一一对应的关系。

然后通过这种方式去做一个同步,就是说本地系统中的文件和容器中的文件是同步的。本地文件做了修改,容器目录中的文件也会做修改。

cat Dockerfile

# this same shows how we can extend/change an existing official image from Docker Hub

 

FROM nginx:latest

# highly recommend you always pin versions for anything beyond dev/learn

 

WORKDIR /usr/share/nginx/html

# change working directory to root of nginx webhost

# using WORKDIR is prefered to using ''RUN cd /some/path''

 

COPY index.html index.html

 

# I don''t have to specify EXPOSE or CMD because they''re in my FROM

 

 

index.html 随便整一个

 

 

docker build -t alexhe/my-nginx .

docker run -d -p 80:80 -v $(pwd):/usr/shar/nginx/html --name web alexhe/my-nginx

 

bind mount 其他案例:

cat Dockerfile 

FROM python:2.7

LABEL maintainer="alexhe<alex@alexhe.net>"

 

COPY . /skeleton

WORKDIR /skeleton

RUN pip install -r requirements.txt

EXPOSE 5000

ENTRYPOINT ["scripts/dev.sh"]

 

开始 build image

docker build -t alexhe/flask-skeleton

 

docker run -d -p 80:5000 -v $(pwd):/skeleton --name flask alexhe/flask-skeleton

 

其他源码在

/Users/apple/temp/docker-k8s-devops-master/chapter5/labs/flask-skeleton

 

 

部署一个 WordPress:

docker run -d -v mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=wordpress --name mysql mysql 

docker run -d -e WORDPRESS_DB_HOST=mysql:3306 -e WORDPRESS_DB_PASSWORD=root --link mysql -p 8080:80 wordpress

 

docker compose: 

官网介绍 https://docs.docker.com/compose/overview/

通过一个 yml 文件定义多容器的 docker 应用

通过一条命令就可以根据 yml 文件的定义去创建或者管理这多个容器

docker compose 的三大概念:Services,Networks,Volumes

v2 可以运行在单机,v3 可以运行在多机

services:一个 service 代表一个 container,这个 container 可以从 dokcerhub 的 image 来创建,或者从本地的 dockerfile build 出来的 image 来创建

service 的启动,类似 docker run,我们可以给其制定 network 和 volume,所以可以给 service 指定 network 和 volume 的引用。

例子:

services:

  db:         (container 的名字叫 db)

    image:postgres:9.4(docker hub 拉取的)

    volumes:

      - "db-data:/var/lib/postgresql/data"

    networks:

      - back-tier

就像这样:

docker run -d --network back-tier -v db-data:/var/lib/postgresql/data postgres:9.4

 

例子:

services:

  worker:   (container 的名字)

    build: ./worker     (不是从 dockerhub 取,而是从本地 build)

    links:

      - db

      - redis

    networks:

      - back-tier

 

例子:

cat docker-compose.yml 

version: ''3''

 

services:

 

  wordpress:

    image: wordpress

    ports:

      - 8080:80

    environment:

      WORDPRESS_DB_HOST: mysql

      WORDPRESS_DB_PASSWORD: root

    networks:

      - my-bridge

 

  mysql:

    image: mysql

    environment:

      MYSQL_ROOT_PASSWORD: root

      MYSQL_DATABASE: wordpress

    volumes:

      - mysql-data:/var/lib/mysql

    networks:

      - my-bridge

 

volumes:

  mysql-data:

 

networks:

  my-bridge:

    driver: bridge

 

docker-compose 的安装和基本使用:

安装:https://docs.docker.com/compose/install/

curl -L "https://github.com/docker/compose/releases/download/1.23.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

docker-compose --version

docker-compose version 1.23.2, build 1110ad01

 

使用:

用上面的 docker-compose.yml

docker-compose up                      #在当前文件夹的 docker-compose.yml,启动. 1. 创建 bridge 网络 wordpress_my-bridge. 2. 创建 2 个 service wordpress_wordpress_1 和 wordpress_mysql_1,并且启动 container

docker-compose -f xxxx/docker-compose.yml     # 在调用指定文件夹中的 docker-compose.yml

 

docker-compose ps           # 显示目前的 service

docker-compose stop

docker-compose down         #stop and remove, 但是不会删除 image

docker-compose start

docker-compose up -d       # 后台执行,不显示日志

docker-compose images      #显示 yml 中定义的 container 和使用的 image

docker-compose exec mysql bash         #mysql 是 yml 中定义的 service,进入 mysql 这台 container 的 bash

 

 

案例:docker-compose 调用 Dockerfile 来创建

源码在 /Users/apple/temp/docker-k8s-devops-master/chapter6/labs/flask-redis

cat docker-compose.yml

version: "3"

 

services:

 

  redis:

    image: redis

 

  web:

    build:

      context: .                                #dockerfile 的位置

      dockerfile: Dockerfile                     # 调用目录中的 Dockerfile

    ports:

      - 8080:5000

    environment:

      REDIS_HOST: redis

 

 

cat Dockerfile 

FROM python:2.7

LABEL maintaner="alexhe alex@alexhe.net"

COPY . /app

WORKDIR /app

RUN pip install flask redis

EXPOSE 5000

CMD [ "python", "app.py" ]

 

使用:docker-compose up -d    #如果不使用 - d   会一直停在那里  web 信息输出在前端

 

docker-compose 中的 scale

docker-compose up                   # 用上面的 yml

docker-compose up --scale web=3 -d         # 会报错,报 8080 已经被占用,需要把上面的 ports: - 8000:5000 删除

删除后再执行上面的。会启动 3 个 container,并监听了容器本地的 5000。可用 docker-compose ps 查看

但这样不行,容器本地的 5000 端口我们访问不到。我们需要在 yml 里新增 haproxy

cat docker-compose.yml 

version: "3"

 

services:

 

  redis:

    image: redis

 

  web:

    build:

      context: .

      dockerfile: Dockerfile

    environment:

      REDIS_HOST: redis

 

  lb:

    image: dockercloud/haproxy

    links:

      - web

    ports:

      - 8080:80

    volumes:

      - /var/run/docker.sock:/var/run/docker.sock 

 

cat Dockerfile 

FROM python:2.7

LABEL maintaner="alex alex@alexhe.net"

COPY . /app

WORKDIR /app

RUN pip install flask redis

EXPOSE 80

CMD [ "python", "app.py" ]

 

cat app.py 

from flask import Flask

from redis import Redis

import os

import socket

 

app = Flask(__name__)

redis = Redis(host=os.environ.get(''REDIS_HOST'', ''127.0.0.1''), port=6379)

 

 

@app.route(''/'')

def hello():

    redis.incr(''hits'')

    return ''Hello Container World! I have been seen %s times and my hostname is %s.\n'' % (redis.get(''hits''),socket.gethostname())

 

 

if __name__ == "__main__":

    app.run(host="0.0.0.0", port=80, debug=True)

 

 

docker-compose up -d

curl 127.0.0.1:8080

docker-compose up --scale web=3 -d

 

 

 

案例:部署一个复杂的应用,投票系统,

源码:

/Users/apple/temp/docker-k8s-devops-master/chapter6/labs/example-voting-app

python 前端 + redis+java worker+ pg database + results app

cat docker-compose.yml 

version: "3"

 

services:

  voting-app:

    build: ./voting-app/.

    volumes:

     - ./voting-app:/app

    ports:

      - "5000:80"

    links:

      - redis

    networks:

      - front-tier

      - back-tier

 

  result-app:

    build: ./result-app/.

    volumes:

      - ./result-app:/app

    ports:

      - "5001:80"

    links:

      - db

    networks:

      - front-tier

      - back-tier

 

  worker:

    build: ./worker

    links:

      - db

      - redis

    networks:

      - back-tier

 

  redis:

    image: redis

    ports: ["6379"]

    networks:

      - back-tier

 

  db:

    image: postgres:9.4

    volumes:

      - "db-data:/var/lib/postgresql/data"

    networks:

      - back-tier

 

volumes:

  db-data:

 

networks:

  front-tier:             # 没指明 driver,默认为 bridge

  back-tier:

 

 

docker-compose up 

浏览器通过 5000 端口投票,5001 查看投票结果

 

docker-compose build        #可以事先 build image, 而用 up 会先 build 再做 start。

 

 

 

docker swarm

 

创建一个 3 节点的 swarm cluster

manager 192.168.205.10

worker1 192.168.205.11

worker2 192.168.205.12

 

manager:

docker swarm init --advertise-addr=192.168.205.10

worker1 and 2:

docker swarm join xxxxx

 

manager:

docker node ls                 # 查看所有节点

docker service create --name demo busybox sh -c "while true;do sleep 3600;done"

docker service ls

docker service ps demo         # 看 service 在哪台机器上

docker service scale demo=5        #扩展成 5 台

如果在 work2 上,强制删除了一个 container, docker rm -f xxxxxxxxx.     

这时候如果 docker service ls,会显示 REPLICAS 4/5, 过一会儿会显示 5/5,在 docker service ls 里会显示有状态为 shutdown 的 container

docker service rm demo     # 删除整个 service

docker service ps demo     

 

 

swarm service 部署 WordPress 

docker network create -d overlay demo             # 创建 overlay 的网络,docker network ls

docker service create --name mysql --env MYSQL_ROOT_PASSWORD=root --env MYSQL_DATABASE=wordpress --network demo --mount type=volume,source=mysql-data,destination=/var/lib/mysql mysql                   #service 中 - v 是这样的 mount 格式,名字叫 mysql-data,挂载地址在 /var/lib/mysql

docker service ls

docker service ps mysql

docker service create --name wordpress -p 80:80 --env WORDPRESS_DB_PASSWORD=root --env WORDPRESS_DB_HOST=mysql --network demo wordpress

docker service ps wordpress

访问 manager 或者 worker 的 http 地址,都能访问到 wordpress

 

集群服务间通信之 RoutingMesh

swam 有内置服务发现的功能。通过 service 访问,是连到了 overlay 的网络。 用到了 vip。

首先要有 demo 的 overlay 网络。

docker service create --name whoami -p 8000:8000 --network demo -d jwilder/whoami

docker service ls

docker service ps whoami          #运行在 manager 节点

curl 127.0.0.1:8000

再创建一个 busybox service

docker service create --name client -d --network demo busybox sh -c "while true;do sleep 3600;done"

docker service ls

docker service ps client            #运行在 work1 节点

首先进到 swarm 的 worker1 节点

docker exec -it xxxx sh        进入这个 busybox container

ping whoami           #ping service 的 name, 10.0.0.7, 这个其实是一个 vip,通过 lvs 创建的

docker service scale whoami=2   # 扩展到 2 台

docker service ps whoami      #有一台运行在 work1,一台在 work2

进入 worker1 的节点

docker exec -it xxx sh    #进入 busybox container

ping whoami               # 还是不变

nslookup  whoami       # 10.0.0.7   虚拟 ip

nslookup tasks.whoami   # 有 2 个地址。这才是具体 container 的真实地址

iptables -t mangle -nL    DOCKER-INGRESS 里做了转发

 

Routing Mesh 的两种体现

Internal:在网络中,container 和 container 是通过 overlay 网络来进行通信。

Ingress:如果服务有绑定接口,则此服务可以通过任意 swarm 节点的响应接口访问。服务端口被暴露到每个 swarm 节点

 

 

docker stack 部署 wordpress

compose yml 的 reference:https://docs.docker.com/compose/compose-file/

官方例子:

version: "3.3"

services:
  wordpress:
    image: wordpress
    ports:
      - "8080:80"
    networks:
      - overlay
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: vip                          #vip指service互访的时候,往外暴露的是虚拟的ip,底层通过lvs,负载均衡到后端服务器。默认为vip模式。

  mysql:
    image: mysql
    volumes:
       - db-data:/var/lib/mysql/data
    networks:
       - overlay
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: dnsrr                         #dnsrr,直接使用service的ip地址,当横向扩展了以后,可能有三个或者四个IP地址,循环调用。

volumes:
  db-data:

networks:
  overlay:

还有 labels:打标签

mode:global 和 replicated,global 代表全 cluster 只有一个,不能做横向扩展。replicated,mode 的默认值,可以通过 docker service scale 做横向扩展。

placement:设定 service 的限定条件。比如:

version: ''3.3''
services:
  db:
    image: postgres
    deploy:
      placement:
        constraints:
          - node.role == manager                 #db这个service一定会部署到manager这个节点,并且系统环境一定是ubuntu 14.04
          - engine.labels.operatingsystem == ubuntu 14.04
        preferences:
          - spread: node.labels.zone

replicas:如果设置了模式为 replicted,可以设置这个值

resources:资源占用和保留。

restart_policy: 重启条件,延迟,重启次数

update_config: 配置更新时的参数,比如可以同时更新 2 个,要等 10 秒才更新第二个。

 

cat docker-compose.yml 

version: ''3''

 

services:

 

  web:                                          #这个 service 叫 web

    image: wordpress

    ports:

      - 8080:80

    environment:

      WORDPRESS_DB_HOST: mysql

      WORDPRESS_DB_PASSWORD: root

    networks:

      - my-network

    depends_on:

      - mysql

    deploy:

      mode: replicated

      replicas: 3

      restart_policy:

        condition: on-failure

        delay: 5s

        max_attempts: 3

      update_config:

        parallelism: 1

        delay: 10s

 

  mysql:                                      #这个 service 叫 mysql

    image: mysql

    environment:

      MYSQL_ROOT_PASSWORD: root

      MYSQL_DATABASE: wordpress

    volumes:

      - mysql-data:/var/lib/mysql

    networks:

      - my-network

    deploy:

      mode: global                          #指能创建一台,不允许 replicated

      placement:

        constraints:

          - node.role == manager

 

volumes:

  mysql-data:

 

networks:

  my-network:

    driver: overlay                 # 默认为 bridge,但是我们在多机集群里,要改成 overlay。

 

发布:

docker stack deploy  wordpress  --compose-file=docker-compose.yml         #stack 的名字为 wordpress

查看:

docker stack ls

docker stack ps wordpress

docker stack services wordpress              #显示 services replicas 的情况。

访问:随便挑一台 node 的 ip 8080 端口

注意:docker swarm 不能使用上面投票系统中的 build,所以要自己 build image

 

投票系统,使用 docker swarm 部署:

cat docker-compose.yml 

version: "3"

services:

 

  redis:

    image: redis:alpine

    ports:

      - "6379"

    networks:

      - frontend

    deploy:

      replicas: 2

      update_config:

        parallelism: 2

        delay: 10s

      restart_policy:

        condition: on-failure

 

  db:

    image: postgres:9.4

    volumes:

      - db-data:/var/lib/postgresql/data

    networks:

      - backend

    deploy:

      placement:

        constraints: [node.role == manager]

 

  vote:

    image: dockersamples/examplevotingapp_vote:before

    ports:

      - 5000:80

    networks:

      - frontend

    depends_on:

      - redis

    deploy:

      replicas: 2

      update_config:

        parallelism: 2

      restart_policy:

        condition: on-failure

 

  result:

    image: dockersamples/examplevotingapp_result:before

    ports:

      - 5001:80

    networks:

      - backend

    depends_on:

      - db

    deploy:

      replicas: 1

      update_config:

        parallelism: 2

        delay: 10s

      restart_policy:

        condition: on-failure

 

  worker:

    image: dockersamples/examplevotingapp_worker

    networks:

      - frontend

      - backend

    deploy:

      mode: replicated

      replicas: 1

      labels: [APP=VOTING]

      restart_policy:

        condition: on-failure

        delay: 10s

        max_attempts: 3

        window: 120s

      placement:

        constraints: [node.role == manager]

 

  visualizer:

    image: dockersamples/visualizer:stable

    ports:

      - "8080:8080"

    stop_grace_period: 1m30s

    volumes:

      - "/var/run/docker.sock:/var/run/docker.sock"

    deploy:

      placement:

        constraints: [node.role == manager]

 

networks:

  frontend:                            # 在 swarm 模式下默认是 overlay 的

  backend:

 

volumes:

  db-data:

 

启动:

docker stack deploy  voteapp  --compose-file=docker-compose.yml         

 

 

docker secret 管理

internal distributed store 是存储在所有 swarm manager 节点上的,所以 manager 节点推荐 2 台以上。存在 swarm manger 节点的 raft database 里。

secret 可以 assign 给一个 service,这个 service 就能看到这个 secret

在 container 内部 secret 看起来像文件,但是实际是在内存中。

secret 创建,从文件创建:

vim alexpasswd

admin123

docker secret create my-pw alexpasswd    #给这个 secret 起个名字叫 my-pw

查看:

docker secret ls

从标准输入创建:

echo "adminadmin" | docker secret create my-pw2 -              # 从标准输入创建

删除:

docker secret rm my-pw2

 

把一个 secret 暴露给 service

docker service create --name client --secret my-pw busybox  sh -c while true;do sleep 3600;done"

查看 container 在哪个节点上:

docker service ps client

进入这个 container:

docker exec -it ccee sh

cd /run/secret/my-pw                   # 这里就能看到我们的密码 secret

例如 mysql 的 docker:

docker service create --name db --secret my-pw -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/my-pw mysql

 

secret 在 stack 中使用:

有个密码文件:

cat password 

adminadmin

 

docker-compose.yml 文件:

version: ''3''

 

services:

 

  web:

    image: wordpress

    ports:

      - 8080:80

    secrets:

      - my-pw

    environment:

      WORDPRESS_DB_HOST: mysql

      WORDPRESS_DB_PASSWORD_FILE: /run/secrets/my-pw

    networks:

      - my-network

    depends_on:

      - mysql

    deploy:

      mode: replicated

      replicas: 3

      restart_policy:

        condition: on-failure

        delay: 5s

        max_attempts: 3

      update_config:

        parallelism: 1

        delay: 10s

 

  mysql:

    image: mysql

    secrets:

      - my-pw

    environment:

      MYSQL_ROOT_PASSWORD_FILE: /run/secrets/my-pw

      MYSQL_DATABASE: wordpress

    volumes:

      - mysql-data:/var/lib/mysql

    networks:

      - my-network

    deploy:

      mode: global

      placement:

        constraints:

          - node.role == manager

 

volumes:

  mysql-data:

 

networks:

  my-network:

    driver: overlay

 

# secrets:

#   my-pw:

#    file: ./password

使用:

docker stack deploy wordpress -c=docker-compose.yml

 

service 的更新:

首先建立源 service:

docker service create --name web --publish 8080:5000 --network demo alexhe/python-flask-demo:1.0

开始扩展,至少 2 个:

docker service scale web=2

检查服务 curl 127.0.0.1:8080

while true;do curl 127.0.0.1:8080 && sleep 1;done

更新服务:

可以更新 secret,publish port,image 等等

docker service update --image alexhe/python-flask-demo:2.0 web 

更新端口:

docker service update --publish-rm 8080:5000 --publish-add 8088:5000 web

 

 

k8s 版本

 

 

 

Docker Kubernetes 容器扩容与缩容

Docker Kubernetes 容器扩容与缩容

Docker Kubernetes 容器扩容与缩容

环境:

  • 系统:Centos 7.4 x64
  • Docker 版本:18.09.0
  • Kubernetes 版本:v1.8
  • 管理节点:192.168.1.79
  • 工作节点:192.168.1.78
  • 工作节点:192.168.1.77

创建环境:

  • 1、Deployment 名称:nginx-deployment
  • 2、pods 副本数为:3 
  • 3、image 镜像:nginx1.9

管理节点:扩容或缩容 deploymnet 的 pod 副本数。

kubectl scale deployment nginx-deployment --replicas=10
kubectl scale 资源类型 资源名称 --replicas=扩容副本数
命令注解

管理节点:设置扩容或缩容添加阀值范围。

kubectl autoscale deployment nginx-deployment --min=10 --max=15 --cpu-percent=80
kubectl autoscale 资源类型 资源名称 --max=最大值 --最小值 --cpu-percent=cpu百分比以内
命令注解
NAME                   REFERENCE                     TARGETS           MINPODS   MAXPODS   REPLICAS   AGE
hpa/nginx-deployment   Deployment/nginx-deployment   <unknown> / 80%   10        15        5          41s
查看配置

 

Docker Kubernetes(K8s)简介

Docker Kubernetes(K8s)简介

入职了新公司,使用了Docker和K8s,需要有一个基础的了解,对网络上相关信息进行了简单总结。

一Docker

###1简介: Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。 ###2功能: 虚拟化解决了应用运行环境的复杂,硬件管理的问题,提供可移植性。 ###3架构: Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。 Docker 客户端(clients)会与 Docker 守护进程进行通信。 Docker 守护进程(daemon)和容器运行在一台主机上。用户并不直接和守护进程进行交互,而是通过 Docker 客户端间接和其通信。 Docker 容器和文件夹很类似,一个Docker容器包含了所有的某个应用运行所需要的环境。每一个 Docker 容器都是从 Docker 镜像(image)创建的。 Docker仓库(repsitory)用来保存镜像。

###4应用场景: 1)提供一次性的环境 2)提供弹性的云服务 3)组建微服务架构

二K8s

###1简介: 全新的基于容器技术的分布式架构领先方案。Kubernetes(k8s)是Google开源的容器集群管理系统(谷歌内部:Borg)。在Docker技术的基础上,为容器化的应用提供部署运行、资源调度、服务发现和动态伸缩等一系列完整功能,提高了大规模容器集群管理的便捷性。 ###2功能: Kubernetes内奸的透明负载均衡和故障恢复机制,不管后端有多少服务进程,也不管某个服务进程是否会由于发生故障而重新部署到其他机器,都不会影响我们队服务的正常调用。 ###3架构: Master:集群控制管理节点,所有的命令都经由master处理。 Node:是kubernetes集群的工作负载节点。Master为其分配工作,当某个Node宕机时,Master会将其工作负载自动转移到其他节点。负责Pod对应容器的创建暂停等任务。 kubelet:运行在每个计算节点上,作为agent,接受分配该节点的Pods任务及管理容器,周期性获取容器状态,反馈给kube-apiserver。 Pod:Pod是Kurbernetes进行创建、调度和管理的最小单位,它提供了比容器更高层次的抽象,使得部署和管理更加灵活。一个Pod可以包含一个容器或者多个相关容器。 在Kubenetes中,所有的容器均在Pod中运行,一个Pod可以承载一个或者多个相关的容器,同一个Pod中的容器会部署在同一个物理机器上并且能够共享资源。 ###核心组件: etcd保存了整个集群的状态; apiserver提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制; controller manager负责维护集群的状态,比如故障检测、自动扩展、滚动更新等; scheduler负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上; kubelet负责维护容器的生命周期,同时也负责Volume(CVI)和网络(CNI)的管理; Container runtime负责镜像管理以及Pod和容器的真正运行(CRI); kube-proxy负责为Service提供cluster内部的服务发现和负载均衡;

DOCKER 学习笔记9 Kubernetes (K8s) 生产级容器编排 上

DOCKER 学习笔记9 Kubernetes (K8s) 生产级容器编排 上

前言

在上一节的学习中。我们已经可以通过最基本的 Docker Swarm 创建集群,然后在集群里面加入我们需要运行的任务 以及任务的数量 这样我们就创建了一个服务。 当然,这样的方式在我们本地虚拟机的情况下,完全适用,并且对于

  • 容器
  • 虚拟主机
  • swarm 创建节点组成集群

有一个很好的理解作用。本节将继续学习关于 Kubernetes (K8s) 的内容。

Kubernetes 建立在 Google 15年的生产工作负载管理经验的基础上,结合了来自社区的最佳理念和实践。

Kubernetes (K8s)

Kubernetes是Google开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理。在生产环境中部署一个应用程序时,通常要部署该应用的多个实例以便对应用请求进行负载均衡。 在Kubernetes中,我们可以创建多个容器,每个容器里面运行一个应用实例,然后通过内置的负载均衡策略,实现对这一组应用实例的管理、发现、访问,而这些细节都不需要运维人员去进行复杂的手工配置和处理。

节点与管理节点

在K8s 集群包括两种类型的资源

  • 普通节点 Node 一般用于服务
  • 管理节点 Master 用于管理其他节点

Master 管理节点

Master 负责管理集群。 主服务器协调集群中的所有活动,例如调度应用程序、维护应用程序的期望状态、缩放应用程序和推出新的更新。

Node 服务节点

Node 是作为 Kubernetes 集群中的工作机器的 VM 或物理计算机。 每个节点都有一个 Kubelet,它是管理节点和与 kubernets 主节点通信的代理。 节点还应该具有处理容器操作的工具,如 Docker

这个还是和在上一节当中学习的Swarm 虚拟机中通过 docker swarm init xx 其实还是有类似的地方的。

image.png

服务执行过程

当您在 Kubernetes 上部署应用程序时,您告诉主控程序启动应用程序容器。 主服务器安排容器在集群节点上运行。 节点使用主服务器公开的 Kubernetes API 与主服务器通信。 最终用户还可以直接使用 Kubernetes API 与集群交互。

windows 安装 kubectl 以及 minikube

若没有安装 Docker-toolbox 的同学请参考并安装:

https://blogs.chaobei.xyz/archives/docker6

下载 kubectl

Kubernetes 命令行工具 kubectl 允许您针对 Kubernetes 集群运行命令。 您可以使用 kubectl 部署应用程序、检查和管理集群资源以及查看日志。

https://storage.googleapis.com/kubernetes-release/release/v1.17.0/bin/windows/amd64/kubectl.exe

修改名称为 kubectl.exe

复制到和docker-toolbox 一样的目录下,方便执行

image.png

$ kubectl.exe version  
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.0", GitCommit:"70132b0f130acc0bed193d9ba59dd186f0e634cf", GitTreeState:"clean", BuildDate:"2019-12-07T21:20:10Z", GoVersion:"go1.13.4", Compiler:"gc", Platform:"windows/amd64"}

下载 minikube

https://github.com/kubernetes/minikube/releases/

选择合适的版本后,下载,并且修改名称为 minikube.exe 放到与上面一样的位置下。

$ minikube.exe version                                                                                                 minikube version: v1.7.2
commit: 50d543b5fcb0e1c0d7c27b1398a9a9790df09dfb

使用 minikube 创建集群

minikube start --image-repository=registry.aliyuncs.com/google_containers --registry-mirror=https://fime0zji.mirror.aliyuncs.com --iso-url=https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/iso/minikube-v1.7.0.iso
  • --image-repository 指定使用国内的镜像仓库
  • --registry-mirror 将指定的地址传递给虚拟机docker 作为拉取镜像的地址
  • --iso-url 指定minikubo 镜像的地址。

因为国内防火墙的限制,所以需要将发部分指定为国内地址才可以正常进行。


$ minikube start --image-repository=registry.aliyuncs.com/google_containers --registry-mirror=https://fime0zji.mirror.aliyuncs.com
* Microsoft Windows 10 Pro 10.0.18363 Build 18363 上的 minikube v1.7.2
* Automatically selected the virtualbox driver
* 正在使用镜像存储库 registry.aliyuncs.com/google_containers
* 正在创建 virtualbox 虚拟机(CPUs=2,Memory=2000MB, Disk=20000MB)...
* 找到的网络选项:
  - NO_PROXY=192.168.99.100,192.168.99.102,192.168.99.103
  - no_proxy=192.168.99.100,192.168.99.102,192.168.99.103
* 正在 Docker 19.03.5 中准备 Kubernetes v1.17.2…
  - env NO_PROXY=192.168.99.100,192.168.99.102,192.168.99.103
  - env NO_PROXY=192.168.99.100,192.168.99.102,192.168.99.103
* 正在启动 Kubernetes ...
* Enabling addons: default-storageclass, storage-provisioner
* 等待集群上线...
* 完成!kubectl 已经配置至 "minikube"

官网在线测试环境 https://kubernetes.io/docs/tutorials/kubernetes-basics/create-cluster/cluster-interactive/

可能遇到的问题

* 正在下载 kubectl v1.17.2
* 正在下载 kubeadm v1.17.2
* 正在下载 kubelet v1.17.2

它可能一直在下载,真的是一直在下,我第一次使用的时候,我足足等了一个小时,现在想起来真的是 MMP

解决方案

  • 找到其所下载的版本
  • 通过FQ的方式下载到本地,放到cache 缓存文件夹下。

kubeadm https://storage.googleapis.com/kubernetes-release/release/v1.17.2/bin/linux/amd64/kubeadm kubelet https://storage.googleapis.com/kubernetes-release/release/v1.17.2/bin/linux/amd64/kubelet kubectl.http://mirror.azure.cn/kubernetes/kubectl/v1.17.2/bin/linux/amd64/kubectl

从上面的下载地址里面修改版本号即可下载你想要的版本。

需要FQ上网才能下载,你懂得

image.png

Kubernetes仪表板

minikube dashboard

$ minikube dashboard
* 正在开启 dashboard ...
* Verifying dashboard health ...
* Launching proxy ...
* Verifying proxy health ...
* Opening http://127.0.0.1:63230/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser...

image.png

集群状态

kubectl cluster-info

因为我们已经安装了与之交互的 kubectl


$ kubectl.exe cluster-info
Kubernetes master is running at https://192.168.99.113:8443
KubeDNS is running at https://192.168.99.113:8443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use ''kubectl cluster-info dump''.

可以了解到 Kubernets 主节点运行地址以及 Kube 的DNS

获取所有的节点信息

$ kubectl.exe get nodes                                      

NAME       STATUS   ROLES    AGE   VERSION
minikube   Ready    master   31m   v1.17.2

创建APP 镜像

image.png

构建一个node 应用

这个应用需要创建在你的minikube 虚拟机内。而不是本地docker

## 创建一个文件夹
mkdir -p nodetest

## 创建自定义镜像文件并加入以下内容
vi Dockerfile

FROM nginx
RUN echo ''<h1>Hello, Docker!</h1>'' > /usr/share/nginx/html/index.html

构建测试镜像

docker build -t mynginx:test .

尝试运行测试镜像

$ docker run --name mynginx-d -p 8080:80 mynginx:test

测试访问

因为我们的的镜像是跑在虚拟机当中的,获取其网卡地址后,用8080访问

使用kubectl创建部署

Kubernetes Pod 是一组由一个或多个容器组成的组,为了管理和联网的目的而连接在一起。

当我们在 Kubernetes 上创建一个 Deployment 时,Deployment 会创建包含容器的 Pods (而不是直接创建容器)。 每个 Pod 都绑定到节点的预定位置,直到终止(根据重新启动策略)或删除为止。 如果节点出现故障,则在集群中的其他可用节点上调度相同的 Pods。

image.png

一个 Pod 总是在一个 Node 上运行。 Node 是 Kubernetes 的工作机器,根据集群的不同,它可以是虚拟机,也可以是物理机器。 每个节点由主节点管理。 一个 Node 可以有多个POD,Kubernetes 主机自动处理跨集群中的 Node 的POD调度。 主机的自动调度考虑到了每个节点上的可用资源。

创建一个POD

Pod 是一组或多个应用程序容器(如 Docker 或 rkt) ,包括共享存储(卷)、 IP 地址和有关如何运行它们的信息。

kubectl create deployment mynode --image=mynginx:test

使用 kubectl create 命令创建一个管理 Pod 的 Deployment。 Pod 基于所提供的 Docker 图像运行一个容器。

查看部署

$ kubectl.exe get deployment
NAME     READY   UP-TO-DATE   AVAILABLE   AGE
mynode   1/1     1            1           10s

查看POD

kubectl.exe get pods

$ kubectl.exe get pods                                                                                                  NAME                      READY   STATUS    RESTARTS   AGE
mynode-5479db549c-fm4qk   1/1     Running   0          9m33s

集群事件

kubectl get events

kubectl 配置

kubectl config view

$ kubectl.exe config view                                                                                               apiVersion: v1
clusters:
- cluster:
    certificate-authority: C:\Users\17639\.minikube\ca.crt
    server: https://192.168.99.100:8443
  name: minikube
contexts:
- context:
    cluster: minikube
    user: minikube
  name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
  user:
    client-certificate: C:\Users\17639\.minikube\client.crt
    client-key: C:\Users\17639\.minikube\client.key

创建一个服务暴露你的应用

默认情况下,Pod 只能通过它在 Kubernetes 集群中的内部 IP 地址访问。 要使 hello-node Container 可以从 Kubernetes 虚拟网络外部访问,必须将 Pod 公开为 Kubernetes 服务。

Kubernetes 的服务是一个抽象概念,它定义了一组逻辑 Pods 和一个访问它们的策略。 服务允许独立的Pods 之间的松散耦合。 服务是使用 YAML (首选)或 JSON 定义的,就像所有的 Kubernetes 对象一样。

尽管每个 Pod 都有一个唯一的 IP 地址,但是如果没有 Service,这些 IP 不会在集群之外公开。 服务允许应用程序接收流量。 通过在 ServiceSpec 中指定类型,可以以不同的方式公开服务:

  • ClusterIP (default) 公开集群中内部 IP 上的服务。 此类型使服务只能从集群内部访问
  • NodePort 使用 NAT 公开集群中每个选定节点的同一端口上的服务
  • LoadBalancer 负载均衡器,创建一个负载均衡器,并且为服务分配固定IP
  • ExternalName

服务以及标签

image.png

一组PODS 组成一个服务。服务是一种抽象,它允许POD 在节点关闭时候死亡,以及复制。而不会影响到服务的运行。服务内部依赖的PODS 之间的发现和关联都是由Kubernets Service 来处理的。

服务使用标签和选择器来匹配一组PODS

标签是附加在对象上的键值对,可以以任何方式使用。

image.png

这个图里面我们可以发现,在管理节点里面部署了两个应用。每个应用分别将标签app=B app=A 的所有POD 整理起来组成服务。

创建服务

  • kubectl get pods 查看当前所有的POD
  • kubectl get service 查看当前所有服务

$ kubectl get pods
NAME                      READY   STATUS    RESTARTS   AGE
mynode-5479db549c-lgtfv   1/1     Running   0          56m

$ kubectl get service
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   16h

kubectl expose deployment mynode --type=NodePort --port=80 将一个deployment 通过服务的方式暴露出去,暴露端口80,也就是我们容器内部的80端口,mynode 是我们已经部署过的一个应用(资源)。

$ kubectl.exe get service mynginx
NAME      TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
mynode    NodePort   10.111.8.25   <none>        80:30857/TCP   5s

这里发现其将我们的服务暴露到了30857下。

此服务的类型:ClusterIP、NodePort、LoadBalancer或ExternalName。默认值为“ClusterIP”。

$ kubectl get deployment                                                                                                                                                                                                                     NAME     READY   UP-TO-DATE   AVAILABLE   AGE
mynode   1/1     1            1           64m

image.png

nodePort

 外部机器可访问的端口。 比如一个Web应用需要被其他用户访问,那么需要配置type=NodePort,而且配置nodePort=30001,那么其他机器就可以通过浏览器访问scheme://node:30001访问到该服务,例如http://node:30001。  例如MySQL数据库可能不需要被外界访问,只需被内部服务访问,那么不必设置NodePort

targetPort

 容器的端口(最根本的端口入口),与制作容器时暴露的端口一致(DockerFile中EXPOSE),例如docker.io官方的nginx暴露的是80端口。  docker.io官方的nginx容器的DockerFile参考https://github.com/nginxinc/docker-nginx

port

 kubernetes中的服务之间访问的端口,尽管mysql容器暴露了3306端口(参考https://github.com/docker-library/mysql/的DockerFile),但是集群内其他容器需要通过33306端口访问该服务,外部机器不能访问mysql服务,因为他没有配置NodePort类型

参考:https://www.cnblogs.com/devilwind/p/8881201.html

通过标签的方式查询

kubectl describe <type> <name> 可以查询到我们想看的信息,若不填写名称,则默认管理节点。

$ kubectl describe deployment
Name:                   mynode
Namespace:              default
CreationTimestamp:      Sun, 16 Feb 2020 12:52:50 +0800
Labels:                 app=mynode
.....

可以看到我们部署的资源的标签 app=mynode

kubectl get pods -l app=mynode 加入-l 进行标签查询。

删除服务

kubectl delete service <name> 通过名称删除一个服务

删除 POD deployment

先删除POD 而后删除 Deployment

## 查看所有POD
kubectl get pods
## 查看所有部署
kubectl get deployment

kubectl delete pod <name>

kubectl delete deployment  <name>

参考

  • 官网:https://kubernetes.io/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/
  • 例子:https://minikube.sigs.k8s.io/docs/examples/

遇到的坑

未使用国内镜像仓库


E0215 13:06:36.509035   15568 cache.go:62] save image to file "gcr.io/k8s-minikube/storage-provisioner:v1.8.1" -> "C:\\Users\\17639\\.minikube\\cache\\images\\gcr.io\\k8s-minikube\\storage-provisioner_v1.8.1" failed: nil image for gcr.io/k8s-minikube/storage-provisioner:v1.8.1: Get https://gcr.io/v2/: dial tcp [2404:6800:4008:c03::52]:443: connectex: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

原文出处:https://www.cnblogs.com/ChromeT/p/12316817.html

今天关于DOCKER 学习笔记 9 Kubernetes (K8s) 弹性伸缩容器 下rancher 弹性伸缩的分享就到这里,希望大家有所收获,若想了解更多关于docker kubernetes Swarm 容器编排 k8s CICD 部署 麦兜、Docker Kubernetes 容器扩容与缩容、Docker Kubernetes(K8s)简介、DOCKER 学习笔记9 Kubernetes (K8s) 生产级容器编排 上等相关知识,可以在本站进行查询。

本文标签: