docker 全集

docker命令

下载镜像
docker pull images-name
上传镜像
docker push images-name
查找镜像
docker search images-id
查看当前运行的容器
docker ps 或docker container ls -a 显示所有状态的容器

查看所有容器名称和ip地址
docker inspect --format='{{.Name}} - {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aq) 或容器内cat /etc/hosts 或 docker inspect container-id | grep IPAdd
创建容器
docker run -d -P images-id nginx -g "daemon off;"
删除容器
docker rm container-id
docker rm -v $(docker ps -aq)(已经运行的删除不了)
docker rm -v $(docker ps -aqf status=exited)删除退出状态的容器
删除镜像
docker rmi images:tag
docker rmi $(docker images| awk '{print $1}')
docker tag 给镜像打tag改变镜像repository的名字
docker tag myimages myimages2:1.9.1

从容器到宿主机复制
docker cp 容器名:容器路径 宿主机路径

查看容器端口
docker port container-id
ps aux | grep docker-proxy(控制流量进程)

进入容器
docker exec -it container-id /bin/bash
exec 则是在容器中打开新的终端,并且可以启动新的进程。
docker attach container-id
attach 直接进入容器 启动命令 的终端,不会启动新的进程
查看启动容器的历史操作
docker history images-id
查看容器或者镜像的详细信息
docker inspect container-id or images-id
保存镜像
docker save -o php-fpm7.0.tar docker.io/lyberteam/php-fpm7.0
导入镜像
docker load -i php-fpm7.0.tar

允许远程客户端请求,需要在配置文件中打开 TCP 监听
vim /etc/systemd/system/multi-user.target.wants/docker.service,在环境变量 ExecStart 后面添加 -H tcp://0.0.0.0,允许来自任意 IP 的客户端连接。
docker客户端执行docker -H server-ip info

docker commit构建镜像
docker commit 命令是创建新镜像最直观的方法,其过程包含三个步骤:
1.运行容器
2.修改容器
3.将容器保存为新的镜像
docker commit container-id(name) newimages-id(name)

docker file构建镜像
docker build -t ubuntu-with-vi . (或者-f指定dockerfile文件)
-t 将新镜像命名为 ubuntu-with-vi
末尾的 . 指明 build context 为当前目录
Docker 默认会从 build context 中查找 Dockerfile 文件
docker history 会显示镜像的构建历史,也就是 Dockerfile 的执行过程

1.从 base 镜像运行一个容器。2.执行一条指令,对容器做修改。3.执行类似 docker commit 的操作,生成一个新的镜像层。4.Docker 再基于刚刚提交的镜像运行一个新容器。5.重复 2-4 步,直到 Dockerfile 中的所有指令执行完毕

FROM
指定 base 镜像。
MAINTAINER
设置镜像的作者,可以是任意字符串。
COPY
将文件从 build context 复制到镜像。
1. 1.COPY src dest
2. 2.COPY ["src", "dest"]
ADD
与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar, zip, tgz, xz 等),文件会被自动解压到 dest。ENV
设置环境变量,环境变量可被后面的指令使用.
如:ENV MY_VERSION 1.3
RUN apt-get install -y mypackage=$MY_VERSION
EXPOSE指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来。我们会在容器网络部分详细讨论。
VOLUME
将文件或目录声明为 volume。我们会在容器存储部分详细讨论。
WORKDIR
为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工作目录。如果 WORKDIR 不存在,Docker 会自动为我们创建。
RUN
在容器中执行命令并创建新的镜像层,RUN 经常用于安装软件包。
CMD容器启动时运行指定的命令。Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。CMD 可以被 docker run 之后的参数替换。
ENTRYPOINT
设置容器启动时运行的命令。
Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效。CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT。

容器自动重启。启动容器时设置 --restart 就可以达到这个效果。
docker run -d --restart=always httpd 自动重启

暂停容器/解暂停
docker pause/unpause container-id
内存限额 物理memory和swap内存
1. -m 或 --memory:设置内存的使用限额,例如 100M, 2G。
2. --memory-swap:设置 内存+swap 的使用限额
docker run -m 200M --memory-swap=300M ubuntu (参数值为-1既没有限制)
其含义是允许该容器最多使用 200M 的内存和 100M 的 swap

对容器执行压力测试 progrium/stress 镜像
docker run -it -m 200M --memory-swap=300M progrium/stress --vm 1 --vm-bytes 280M
--vm 1:启动 1 个内存工作线程。
--vm-bytes 280M:每个线程分配 280M 内存。

Docker可以通过 -c 或 --cpu-shares 设置容器使用CPU的权重。如果不指定,默认值为 1024 --cpu 用来设置工作线程的数量(服务器几颗CPU)
默认设置下,所有容器可以平等地使用 host CPU 资源并且没有限制
docker run --name "container_A" -c 1024 ubuntu
docker run --name "container_B" -c 512 ubuntu

默认情况下,所有容器能平等地读写磁盘
--blkio-weight 参数来改变容器 block IO 磁盘的读写优先级,设置的是相对权重值,默认为 500
docker run -it --name container_A --blkio-weight 600 ubuntu
docker run -it --name container_B --blkio-weight 300 ubuntu
--device-read-bps,限制读某个设备的 bps。
--device-write-bps,限制写某个设备的 bps。
--device-read-iops,限制读某个设备的 iops。
--device-write-iops,限制写某个设备的 iops。
docker run -it --device-write-bps /dev/sda:30MB ubuntu

cgroup
cgroup 全称 Control Group。Linux 操作系统通过 cgroup 可以设置进程使用 CPU、内存 和 IO 资源的限额
--cpu-shares、-m、--device-write-bps 实际上就是在配置 cgroup。
/sys/fs/cgroup/cpu/docker 目录中,Linux 会为每个容器创建一个 cgroup 目录,以容器长ID 命名,内存以及 Block IO 的 cgroup 配置

namespace
实现了容器间资源的隔离。
Linux 使用了六种 namespace,分别对应六种资源:Mount、UTS、IPC、PID、Network 和 User
Mount namespace 让容器看上去拥有整个文件系统,可以执行 mount 和 umount 命令,不会影响到 host 和其他容器
UTS namespace 让容器有自己的 hostname,容器的 hostname 是它的短ID,可以通过 -h 或 --hostname 参数设置
IPC namespace 让容器拥有自己的共享内存和信号量(semaphore)来实现进程间通信
PID namespace 容器在 host 中以进程的形式运行,通过ps axf查看,容器进程的 PID 不同于 host 中对应进程的 PID,容器拥有自己独立的一套 PID
Network namespace 让容器拥有自己独立的网卡、IP、路由等资源
User namespace 让容器能够管理自己的用户,host 不能看到容器中创建的用户

Docker-host-network
安装时会自动在 host 上创建三个网络,我们可用 docker network ls 命令查看
bridge docker创建的容器会自动挂载在bridge网络上brctl show可以看容器的挂载情况,docker network ls可以显示host主机网络
host 容器共享 Docker host 的网络栈,容器的网络配置与host 完全一样。可以通过 --network=host 指定使用 host 网络。容器对网络传输效率有较高要求,则可以选择 host 网络
none 网络就是什么都没有的网络。挂在这个网络下的容器除了 lo,没有其他任何网卡。容器创建时,可以通过 --network=none 指定使用 none 网络。

docker 自定义网络
user-defined 网络驱动 bridge, overlay 和 macvlan,overlay 和 macvlan 用于创建跨主机的网络
docker自动分配ip网段
docker network create --driver bridge my_net (创建容器时不可指定静态ip)
自定义ip网段
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 my_net2 查看命令docker network inspect my_net2(创建容器时可以指定静态ip地址)

docker容器之间不同网段的通信
docker network connect my_net2 container-id(将容器连接到这个网段)
docker DNS server
docker daemon 实现了一个内嵌的 DNS server,使容器可以直接通过“容器名”通信 --name ,只能在 user-defined 网络中使用
docker joined 容器
joined 容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined 容器之间可以通过 127.0.0.1 直接通信
docker run -d --network=container:web1 httpd(此容器和web1容器的ip、mac地址是一样的)

Docker 存储
1.由 storage driver 管理的镜像层和容器层。多层数据的堆叠并为用户提供一个单一的合并之后的统一视图。
Docker 支持多种storage driver,有 AUFS、Device Mapper、Btrfs、OverlayFS、VFS 和 ZFS。它们都能实现分层的架构,同时又有各自的特性(docker info查看)
(1)新数据会直接存放在最上面的容器层。(2)修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接保存在容器层中,镜像层保持不变。(3)如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件。
2、Data Volume。本质上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中,data volume 数据可以被永久的保存,即使使用它的容器已经销毁。
Data Volume 分为bind volume 和 docker managed volume两种方式
(1)bind mount 是将 host 上已存在的目录或文件 mount 到容器 -v 选项挂载可选择读写方式
(2)docker manager volume 不需要指定 mount 源,指明 mount point 就行了 -v选项只能指目录 通过docker inspect container-id查看挂载源 (docker volume ls也可以查看)
删除容器时没有带-v选项 会产生孤儿volume 删除孤儿volume :docker volume rm volume-name或docker volume rm $(docker volume ls -q)
Docker容器之间数据共享
(1)bind volume 一对多共享,一个docker host文件或目录对多个container
(2)volume container 是专门为其他容器提供 volume 的容器。它提供的卷可以是 bind mount,也可以是 docker managed volume,其他容器可以通过 --volumes-from使用:如
docker create --name vc_data -v ~/index.html:/root/index.html -v /usr/local/nginx/ busybox
docker run -d --name web1 --volume-from vc_data httpd
(3)data-packed volume container。其原理是将数据打包到镜像中,然后通过 docker managed volume 共享。

管理docker容器(多个docker host)----- Docker Machine
----用 Docker Machine 可以批量安装和配置 docker host,这个 host 可以是本地的虚拟机、物理机,也可以是公有云中的云主机。docker Machine统一命名为provider

安装:(安装版本去网址看最新的)
curl -L https://github.com/docker/machine/releases/download/v0.16.0/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine &&
chmod +x /tmp/docker-machine &&
sudo cp /tmp/docker-machine /usr/local/bin/docker-machine

为了得到更好的体验,我们可以安装 bash completion script,这样在 bash 能够通过 tab 键补全 docker-mahine 的子命令和参数。安装方法是从https://github.com/docker/machine/tree/master/contrib/completion/bash下载
completion script:
docker-machine-prompt.bash
docker-machine-wrapper.bash
docker-machine.bash
将其放置到 /etc/bash_completion.d 目录下。然后将如下代码添加到$HOME/.bashrc:PS1='[\u@\h \W$(__docker_machine_ps1)]\$ '
远程创建容器
$docker-machine create --driver generic --generic-ip-address=192.168.218.130 --generic-ssh-user=ubuntu host1
远程登陆容器
$eval $(docker-machine env host1)
注:需要无密码登陆,需要root权限,ubuntu 通过sudo -i切换root登陆
远程主机sudoers文件添加:Defaults visiblepw \root ALL=(ALL:ALL) NOPASSWD: ALL

管理docker容器(多个docker host)----- Docker Compose
sudo curl -L https://github.com/docker/compose/releases/download/1.17.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version

跨主机网络概述
docker原生态的跨主机网络overlay、macvlan
第三方主机网络,flannel、calico、weave 与docker集成在一起是因为docker的libnetwork和CNM(Container Network Model)
libnetwork是容器的网络库。
CNM由以下三类组件组成:
sandbox:是容器的网络栈,包含容器的interface,路由表和DNS设置
endpoint:是将sandbox接入网络,endpoint的典型实现是veth-pair(虚拟网卡,成对出现)
network: 包含一组endpoint,同一网络的endpoint可以直接通信,网络的实现可以是vlan和linux bridge

跨主机Docker_Overlay网络:
docker overlay网络需要一个key-value数据库保存网络的状态信息,包括network、endpoint、ip等,etcd、consul、Zookeeper等都是docker支持key value的软件
如consul:收集节点的网络后在同步
最简单的方式是以容器方式运行 Consul:
docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap
可通过ip:8500 访问consul查看节点
修改其他主机docker daemon 的配置文件/etc/systemd/system/docker.service.d/*.conf 添加:--cluster-store=consul://192.168.218.132:8500 --cluster-advertise=ens33:2376
注:没有配置文件的话可以自己添加mkdir /etc/systemd/system/docker.service.d/
在这个目录下创建*.conf文件
cat docker-overlay.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2376 -H unix:///var/run/docker.sock --storage-driver overlay2 --label provider=generic --cluster-store=consul://127.0.0.1:8500 --cluster-advertise=ens33:2376
Environment=
--cluster-store 指定 consul 的地址。
--cluster-advertise 告知 consul 自己的连接地址。
重启 docker daemon
systemctl daemon-reload
systemctl restart docker.service
在节点1上运行容器创建overlay网络:docker network create -d overlay vnet1 ---会自动同步到其他节点
在节点上实现跨主机访问:host1 上 docker run -itd --network vnet1 --name bbox1 busybox
host2上 docker run -itd --network vnet1 --name bbox2 busybox
docke exec bbox1 ping bbox2 ;实现了跨主机访问
overlay 网络的具体实现:
docker 会为每个 overlay 网络创建一个独立的 network namespace,其中会有一个 linux bridge br0,endpoint 还是由 veth pair 实现,一端连接到容器中(即 eth0),另一端连接到 namespace 的 br0 上。
br0 除了连接所有的 endpoint,还会连接一个 vxlan 设备,用于与其他 host 建立 vxlan tunnel。容器之间的数据就是通过这个 tunnel 通信的.
VXLAN提供了一个在可靠的共享网络设施上扩展2层网段的解决方案.
查看network namespace:在此之前先执行ln -s /var/run/docker/netns /var/run/netns;apt install bridge-utils
查看network namespace: ip netns
查看network namespace 中的 br0 上的设备:ip netns exec 1-0d44a66acb brctl show
查看 vxlan1 设备的具体配置信息可知此 overlay 使用的 VNI(VxLAN ID)为 256:ip netns exec 1-0d44a66acb ip -d l show veth0

overlay网络隔离:overlay网络默认不同网段之间是不能互相访问的
overlay不同网络互访:docker network connect vnet1 bbox3(容器名字或id)
overlay IPAM(IP Adddress Manage)
overlay网络默认分配24位的子网掩码,所有主机共享这个 subnet,容器启动时会顺序从此空间分配 IP。当然我们也可以通过 --subnet 指定 IP 空间。
docker network create -d overlay --subnet 10.22.1.0/24 ov_net3

跨主机Docker_Macvlan网络:
macvlan 是 linux kernel 比较新的特性,macvlan 允许你在主机的一个网络接口上配置多个虚拟的网络接口,这些网络 interface 有自己独立的 mac 地址,也可以配置上 ip 地址进行通信。
$ modprobe macvlan
$ lsmod | grep macvlan
macvlan 190460
如果第一个命令报错,或者第二个命令没有返回,则说明当前系统不支持 macvlan,需要升级系统或者升级内核。
创建macvlan网络:
1、打开网卡的混杂模式:ip link set enp0s9 promisc on
2、开启网卡:ifconfig ens33 up
3、创建macvlan网络:docker network create -d macvlan --subnet=192.168.218.0/24 --gateway=192.168.218.2 -o parent=ens38 vnet3
4、运行docker验证:host1上docker run -itd --name aaa --network=vnet3 --ip=192.168.218.44 busybox
host2上docker run -itd --name bbb --network=vnet3 --ip=192.168.218.55 busybox
以上是单网卡网络。

用sub-interface(子网卡)实现多macvlan 网络:(要求有多个网关)
# 为物理网卡ens38创建Macvlan子接口
ubuntu18命令行:
$ ip link add link ens38 name ens38.100 type vlan id 100
$ ip link add link ens38 name ens38.200 type vlan id 200
$ ip link set ens38.100 up
$ ip link set ens38.200 up
$ ip link set ens38.100 promisc on
$ ip link set ens38.200 promisc on

ubuntu18配置文件:
vi /etc/network/interfaces
auto ens38
iface ens38 inet manual
auto ens38.100
iface ens38.100 inet manual
vlan-raw-device ens38
auto ens38.200
iface ens38.200 inet manual
vlan-raw-device ens38
service networking restart(若没有这个命令要安装apt install ifupdown)
ip addr flush dev ens38
ifdown ens38
ifup ens38

docker network create -d macvlan --subnet=192.168.75.0/24 --gateway=192.168.75.1 -o parent=ens38.100 mnet1
docker network create -d macvlan --subnet=192.168.56.0/24 --gateway=192.168.56.1 -o parent=ens38.200 mnet2
注:
Macvlan有四种工作模式:Private、VEPA、Bridge和Passthru。最常用和默认的模式是Bridge模式
macvlan会自动分配ip,为避免ip冲突,要手动指定。
macvlan 不依赖 Linux bridge,brctl show 可以确认没有创建新的 bridge。
macvlan网关是真实存在的,不然无法通信。
Docker 没有为 macvlan 提供 DNS 服务,这点与 overlay 网络是不同的。
macvlan不同的网络不能 在二层上 通信。在三层上可以通过网关将 macvlan 连通。





跨主机flannel-vxlan网络:
flannel 是 CoreOS 开发的容器网络解决方案。flannel 为每个 host 分配一个 subnet,容器从此 subnet 中分配 IP,这些 IP 可以在 host 间路由,容器间无需 NAT 和 port mapping 就可以跨主机通信。
flannel 用 etcd(与 consul 类似的 key-value 分布式数据库)存放网络配置、已分配的 subnet、host 的 IP 等信息。
etcd的安装配置:
最新版本参见:https://github.com/etcd-io/etcd/releases
编辑执行脚本

#!/bin/bash
ETCD_VER=v3.3.10
# choose either URL
GOOGLE_URL=https://storage.googleapis.com/etcd
GITHUB_URL=https://github.com/etcd-io/etcd/releases/download
DOWNLOAD_URL=${GOOGLE_URL}
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
rm -rf /tmp/etcd-download-test && mkdir -p /tmp/etcd-download-test
curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1
cp /tmp/etcd-download-test/etcd* /usr/local/bin/
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
/tmp/etcd-download-test/etcd --version
ETCDCTL_API=3 /tmp/etcd-download-test/etcdctl version

export ETCDCTL_API=3 切换api版本到3
etcdctl --version 查看版本(或etcdctl version)

运行: 1、nohup etcd --listen-client-urls http://0.0.0.0:2379 -advertise-client-urls http://0.0.0.0:2379 &
2、 etcd --listen-client-urls=http://[::1]:2379,http://127.0.0.1:2379 --advertise-client-urls=http://[::1]:2379
3、 etcd --initial-advertise-peer-urls http://127.0.0.1:2380 \
--listen-peer-urls http://127.0.0.1:2380 \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://0.0.0.0:2379
测试 etcd 是否可用:
etcdctl --endpoints=192.168.56.101:2379 set foo "bar"
etcdctl --endpoints=192.168.56.101:2379 get foo

flannel网络的安装配置:
最新版本参见:https://github.com/coreos/flannel/releases/

wget https://github.com/coreos/flannel/releases/download/v0.10.0/flannel-v0.10.0-linux-amd64.tar.gz
mkdir /tmp/flannel/
tar -zxvf flannel-v0.10.0-linux-amd64.tar.gz -C /tmp/flannel/
cp /tmp/flannel/{flanneld,mk-docker-opts.sh} /usr/local/bin/

可以将其制作成启动服务,配置systemd unit后就可以启动服务。
vi /lib/systemd/system/flanneld.service
[Unit]
Description=Flanneld overlay address etcd agent
After=network.target
After=network-online.target
Wants=network-online.target
After=etcd.service
Before=docker.service

[Service]
Type=notify
ExecStart=/usr/local/bin/flanneld \
-etcd-endpoints=http://10.20.109.197:2379 \
-etcd-prefix=/docker-test/network \
-iface=eth1
ExecStartPost=/usr/local/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
Restart=on-failure

[Install]
WantedBy=multi-user.target
RequiredBy=docker.service

将 flannel 网络的配置信息保存到 etcd:
vim flannel-config.json
{
"Network": "10.2.0.0/16",
"SubnetLen": 24,
"Backend": {
"Type": "vxlan"
}
}
Network 定义该网络的 IP 池为 10.2.0.0/16。
SubnetLen 指定每个主机分配到的 subnet 大小为 24 位,即10.2.X.0/24。
Backend 为 vxlan,即主机间通过 vxlan 通信。

将配置存入 etcd:
etcdctl --endpoints=http://127.0.0.1:2379 set /docker-test/network/config < flannel-config.json

启动flannel:
flanneld -etcd-endpoints=http://127.0.0.1:2379 -iface=ens33 -etcd-prefix=/docker-test/network
1: ens33 被选作与外部主机通信的 interface。
2:识别 flannel 网络池 10.2.0.0/16。
3:分配的 subnet 为 10.2.X.0/24,flannel 会为每个主机分配了独立的 subnet。
4:一个新的 interface flannel.1 被创建
5:添加路由条目,目的网段的路由由flannel.1转发
6:将subnet路由保存到etcd中,当etcd检测到有其他主机的时候,同步路由信息到其他主机。

编辑docker的配置文件 /etc/systemd/system/docker.service,设置 --bip 和 --mtu
添加配置:--bip=10.2.X.1/24 --mtu=1450
注:这两个参数的值必须与 /run/flannel/subnet.env 中 FLANNEL_SUBNET 和FLANNEL_MTU 一致

重启 Docker daemon。
systemctl daemon-reload
systemctl restart docker.service
Docker 会将 10.2.X.1 配置到 Linux bridge docker0 上,并添加路由条目 10.2.X.0/24 dev docker0 proto kernel scope link src 10.2.X.1,flannel 没有创建新的 docker 网络,而是直接使用默认的 bridge 网络。同一主机的容器通过 docker0 连接,跨主机流量通过 flannel.1 转发。
创建容器验证flannel网络:
docker run -itd --name bbox1 busybox

跨主机flannel-host-gw网络:
host-gw 把每个主机都配置成网关,主机知道其他主机的 subnet 和转发地址。vxlan 则在主机间建立隧道,不同主机的容器都在一个大的网段内(比如 10.2.0.0/16)。
由于 vxlan 需要对数据进行额外打包和拆包,性能会稍逊于 host-gw。

将 flannel 网络的配置信息保存到 etcd:
vim flannel-config.json
{
"Network": "10.2.0.0/16",
"SubnetLen": 24,
"Backend": {
"Type": "host-gw"
}
}
etcdctl --endpoints=http://127.0.0.1:2379 set /docker-test/network/config < flannel-config.json
重启flanneld服务
flanneld -etcd-endpoints=http://127.0.0.1:2379 -iface=ens33 -etcd-prefix=/docker-test/network
查看flannel的环境变量文件 /run/flannel/subnet.env
修改docker的配置文件:vi /etc/systemd/system/docker.service.d/docker-overlay.conf 添加配置 --bip=10.2.X.1/24 --mtu=1500(VxLAN是1450)

跨主机weave网络:
weave 是 Weaveworks 开发的容器网络解决方案。weave 创建的虚拟网络可以将部署在多个主机上的容器连接起来。对容器来说,weave
就像一个巨大的以太网交换机,所有容器都被接入这个交换机,容器可以直接通信,无需 NAT 和端口映射。除此之外,weave 的 DNS 模块使容器可以通过 hostname 访问。
weave 不依赖分布式数据库(例如 etcd 和 consul)交换网络信息,每个主机上只需运行 weave 组件就能建立起跨主机容器网络。

weave安装:
curl -L git.io/weave -o /usr/local/bin/weave
chmod a+x /usr/local/bin/weave
weave launch
启动 weave 相关服务。weave 的所有组件都是以容器方式运行的,weave 会从 docker hub 下载最新的 image 并启动容器。
weave 运行了三个容器:
IMAGE COMMAND CREATED STATUS PORTS NAMES
weaveworks/weave:2.5.0 "/home/weave/weaver …" 40 minutes ago Up 40 minutes weave
weaveworks/weaveexec:2.5.0 "data-only" 40 minutes ago Created weavevolumes-2.5.0
weaveworks/weavedb:latest "data-only" 40 minutes ago Created weavedb

weave 是主程序,负责建立 weave 网络,收发数据 ,提供 DNS 服务等。
weave 主机间是通过 bridge和 VxLAN 通信的。
运行容器:
eval $(weave env) 这一步很重要, docker 命令发给 weave proxy 处理。如果要恢复之前的环境,可执行 eval $(weave env --restore)
docker run --name bbox1 -itd busybox

从机运行weave:
weave launch 192.168.218.32(指定其他weave主机地址,把本地的weave加入到weave网络)
eval $(weave env)
docker run --name bbox3 -itd busybox

-e WEAVE_CIDR=net:10.32.2.0.0/24 给容器分配指定网段
-e WEAVE_CIDR=ip:10.32.2.2/24 给容器分配指定IP
此作用是划分网段,隔离网络,即不在同一subnet的不能通信。

weave本身是与外界不通信的,真正与外界通信的docker内部的bridge网络。
主机访问weave容器运行:
# weave expose 给weave虚拟网卡分配网关,就可以访问了
其他非 weave 主机访问本地weave容器:
添加路由静态路由:ip route add 10.32.0.0/12 via 192.168.218.132

IPAM
10.32.0.0/12 是 weave 网络使用的默认 subnet,如果此地址空间与现有 IP 冲突,可以通过 --ipalloc-range 分配特定的 subnet。
weave launch --ipalloc-range 10.2.0.0/16

跨主机Calico网络:
Calico 是一个纯三层的虚拟网络方案,Calico 为每个容器分配一个 IP,每个 host 都是 router,把不同 host 的容器连接起来。与 VxLAN 不同的是,Calico 不对数据包做额外封装,不需要 NAT 和端口映射,扩展性和性能都很好。
与其他容器网络方案相比,Calico 还有一大优势:network policy。用户可以动态定义 ACL 规则,控制进出容器的数据包,实现业务需求。
Calico 依赖 etcd 在不同主机间共享和交换信息,存储 Calico 网络状态。
Calico 网络中的每个主机都需要运行 Calico 组件,提供容器 interface 管理、动态路由、动态 ACL、报告状态等功能。

安装etcd:
方法同上,参见flannel
启动etcd:
etcd --initial-advertise-peer-urls http://127.0.0.1:2380 \
--listen-peer-urls http://127.0.0.1:2380 \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://0.0.0.0:2379
修改docker的配置文件添加配置:--cluster-store=etcd://192.168.218.132:2379
重启docker:
systemctl deamon-reload
service docker restart

安装Calico工具:
wget -O /usr/local/bin/calicoctl https://github.com/projectcalico/calicoctl/releases/download/v3.4.0/calicoctl
chmod a+x /usr/local/bin/calicoctl

编辑calico配置文件:
默认在/etc/calico/calicoctl.cfg 没有就创建
apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
datastoreType: "etcdv3"
etcdEndpoints: "http://etcd1:2379,http://etcd2:2379"

运行calico-node节点:
calicoctl node run --node-image=quay.io/calico/node:v2.6.12 --name=ubuntu1 --config=/etc/calico/calicoctl.cfg
这里会创建docker container:
docker run --net=host --privileged --name=calico-node -d --restart=always -e NODENAME=ubuntu -e CALICO_NETWORKING_BACKEND=bird -e CALICO_LIBNETWORK_ENABLED=true -e ETCD_ENDPOINTS=http://192.168.218.135:2379 -v /var/log/calico:/var/log/calico -v /var/run/calico:/var/run/calico -v /var/lib/calico:/var/lib/calico -v /lib/modules:/lib/modules -v /run:/run -v /run/docker/plugins:/run/docker/plugins -v /var/run/docker.sock:/var/run/docker.sock quay.io/calico/node:v2.6.2
注:v2.6版本以上的calico没有运行libnetwork-pulgin,这里用v2.6版本的,每台主机都要运行

创建calico网络:
docker network create --driver calico --ipam-driver calico-ipam cal_net1
注:任意一台执行,etcd会同步到其他主机上,没有同步的话重启docker服务,docker配置文件会去重新加载etcd信息。
命令:calicoctl get nodes 查看节点
calicoctl node status 查看节点状态
calicoctl get node <node_name> --export -o yaml > node.yml 导出节点信息
calicoctl delete -f node.yml 删除节点


跨主机Docker主机存储 data volume:
容器可以分为两类:无状态(stateless)容器和有状态(stateful)容器
无状态就是数据一次性,用完就恢复不了。
有状态是指容器需要保存数据,而且数据会发生变化。

任何一个 data volume 都是由 driver 管理的,创建 volume 时如果不特别指定,将使用 local 类型的 driver,即从 Docker Host 的本地目录中分配存储空间。如果要支持跨主机的 volume,则需要使用第三方 driver。完整的列表可参考 https://docs.docker.com/engine/extend/legacy_plugins/#volume-plugins
创建volume:
docker volume create --name myvolume -d azurefile -o share=myshare
docker run -i -t -v my_volume:/data busybox


Docker监控工具:

docker container ps/top/stats
ps/ls :查看当前运行的容器
top :查看当前容器运行了哪些进程,还可以跟上 Linux 操作系统 ps 命令的参数显示特定的信息,比如 -au
stats :查看当前容器资源使用情况,显示容器网络和磁盘的 IO 数据。


还有sysdig;weaveScope;cAdvisor/Heapster;Prometheus,
sysdig:
安装:
docker container run -itd --rm --name=sysdig --privileged=true \
--volume=/var/run/docker.sock:/host/var/run/docker.sock \
--volume=/dev:/host/dev \
--volume=/proc:/host/proc:ro \
--volume=/boot:/host/boot:ro \
--volume=/lib/modules:/host/lib/modules:rw \
--volume=/usr:/host/usr:ro \
sysdig/sysdig
进到容器执行csysdig,按提示操作

weavescope:
安装:
curl -L git.io/scope -o /usr/local/bin/scope
chmod a+x /usr/local/bin/scope
scope launch
scope launch 将以容器方式启动 Weave Scope。
访问地址为 http://[Host_IP]:4040/
web界面操作
多台主机要在两个 host 上都执行如下命令:
scope launch 192.168.56.102 192.168.56.103

cAdvisor/Heapster:
谷歌开源的监控工具:
安装:
docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
google/cadvisor:latest
访问地址为 http://[Host_IP]:8080/
web界面查看

Prometheus:
Prometheus 提供了监控数据搜集、存储、处理、可视化和告警一套完整的解决方案的多维数据模型。
重要组件:
Prometheus Server
Prometheus Server 负责从 Exporter 拉取和存储监控数据,并提供一套灵活的查询语言(PromQL)供用户使用。
Exporter
Exporter 负责收集目标对象(host, container…)的性能数据,并通过 HTTP 接口供 Prometheus Server 获取。
node-exporter负责收集主机的信息
cadvisor负责收集容器的主机信息
Grafana
可视化组件,能够与 Prometheus 无缝集成,提供完美的数据展示能力。
Alertmanager
用户可以定义基于监控数据的告警规则,规则会触发告警。一旦 Alermanager 收到告警,会通过预定义的方式发出告警通知。支持的方式包括 Email、PagerDuty、Webhook 等.

node-exporter安装:
docker run -d -p 9100:9100 \
-v "/proc:/host/proc" \
-v "/sys:/host/sys" \
-v "/:/rootfs" \
--net=host \
prom/node-exporter \
--path.procfs /host/proc \
--path.sysfs /host/sys \
--collector.filesystem.ignored-mount-points "^/(sys|proc|dev|host|etc)($|/)"

cadvisor安装见上:

Prometheus Server安装:
docker run -d -p 9090:9090 \
-v /root/prometheus.yml:/etc/prometheus/prometheus.yml \
--name prometheus \
--net=host \
prom/prometheus

安装Grafana :
docker run -d -i -p 3000:3000 \
-e "GF_SERVER_ROOT_URL=http://grafana.server.name" \
-e "GF_SECURITY_ADMIN_PASSWORD=secret1" \
--net=host \
grafana/grafana
按照配置增加prometheus
增加仪表盘:
访问 https://grafana.com/dashboards?dataSource=prometheus&search=docker,将会看到很多用于监控 Docker 的 Dashboard

Docker日志管理:
docker logs
ELK
fluentd
graylog
docker logs:
两种方式: docker attach container-id
docker logs -f container
将容器日志发送到 STDOUT 和 STDERR 是 Docker 的默认日志行为。实际上,Docker 提供了多种日志机制帮助用户从运行的容器中提取日志信息。这些机制被称作 logging driver。
Docker 的默认 logging driver 是 json-file。
命令:
# docker info |grep 'Logging Driver'
Logging Driver: json-file
Host的Jason日志存储路径: /var/lib/docker/containers/<contariner ID>/<contariner ID>-json.log

Docker 支持多种 logging driver
命令:
# docker info | grep -i log
..........
Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog

syslog 和 journald 是 Linux 上的两种日志管理服务。
awslogs、splunk 和 gcplogs 是第三方日志托管服务。
gelf 和 fluentd 是两种开源的日志管理方案。
容器启动时可以通过 --log-driver 指定使用的 logging driver。如果要设置 Docker 默认的 logging driver,需要修改 Docker daemon 的启动脚本,指定 --log-driver 参数,比如:
ExecStart=/usr/bin/dockerd -H fd:// --log-driver=syslog --log-opt ......
每种 logging driver 都有自己的 --log-opt,使用时请参考官方文档。

ELK日志管理系统:
ELK 是三个软件的合称:Elasticsearch、Logstash、Kibana。这三者是核心套件,但并非全部,如还可以加上redis缓存、kafka缓存与zookeeper分布式应用程序协调服务等等。
Elasticsearch
一个近乎实时查询的全文搜索引擎。Elasticsearch 的设计目标就是要能够处理和搜索巨量的日志数据。
Logstash
读取原始日志,并对其进行分析和过滤,然后将其转发给其他组件(比如 Elasticsearch)进行索引或存储。Logstash 支持丰富的 Input 和 Output 类型,能够处理各种应用的日志。
Kibana
一个基于 JavaScript 的 Web 图形界面程序,专门用于可视化 Elasticsearch 的数据。Kibana 能够查询 Elasticsearch 并通过丰富的图表展示结果。用户可以创建 Dashboard 来监控系统的日志。

ELK架构:
一:Logstash -----> Elasticsearch -------> kibana
这种架构方式。优点是搭建简单,易于上手。缺点是Logstash耗资源较大,运行占用CPU和内存高。另外没有消息队列缓存,存在数据丢失隐患。
二:Logstash Agent------->kafka(或者redis缓存) cluster ------>Logstash------->Elasticsearch------>kibana
这种架构方式引入了消息队列机制,即使Logstash宕机,数据也会被保存下来,不会出现数据丢失。
三:Logstash-Forwarder -----> Logstash ------> Elasticsearch -----> kibana
这种架构解决了Logstash在各计算机点上占用系统资源较高的问题,Logstash-Forwarder占用的资源几乎可以忽略不计,而且是ssl加密传输
四:(Package、Top、File) Beats ------> kafka(或者redis缓存) cluster -----> Logstash(或Elasticsearch) ------> Elasticsearch ------kibana
这种架构的扩展性和灵活性有很大提高,Beats和Logstash-Forwarder的负载相当,可二次开发。

最小部署方案,在容器中搭建 ELK:
内存最低4G
mmap计数的限制等于262,144或更多
sysctl vm.max_map_count主机查看当前值
sysctl -w vm.max_map_count=262144
sudo nano /etc/pam.d/common-session
session required pam_limits.so
ulimit -n 131072
docker run -d -p 5601:5601 -p 9200:9200 -p 5044:5044 -v /root/logstash/conf.d/:/etc/logstash/conf.d/ -v /etc/localtime:/etc/localtime --name elk sebp/elk
5601 - Kibana web 接口
9200 - Elasticsearch JSON 接口
------> http://node1:9200/_cat/indices?v
------> http://192.168.218.135:9200/_search?pretty
5044 - Logstash 日志接收接口
节点上安装 Filebeat:
请参考最新的安装文档 https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-installation.html,可yum或者apt安装

容器编排引擎(管理docke集群):
docker swarm
kubernetes
Mesos

Docker Swarm Mode:
docker swarm init --advertise-addr 192.168.56.101
根据提示创建从节点
docker node ls
docker service ls
docker swarm join-token worker
节点上只需运行server:
docker swarm join --token SWMTKN-1-2vxrgw25epfm2a6ecx9jvztd468knhxbg6a2rt01hgu51qdudj-4fb6d9ujfvgd3t42ninta366n 192.168.218.135:2377

创建应用:
主要在manage node上执行:
如:docker service create --name http_wab httpd
暴露端口之 routing mesh:
docker service update --publish-add 8080:80 web_server 或新建的时候执行:
docker service create --name web_server --publish 8080:80 --replicas=2 httpd
当我们访问任何节点的 8080 端口时,swarm 内部的 load balancer 会将请求转发给 web_server 其中的一个副本,即使某个节点没有server,也能访问到。

应用伸缩之scale up/down 命令:
docker service scale http_wab=5/3
默认情况下,manage node也是work node,所以 swarm-manager 上也运行了副本,如果不希望在 manager 上运行 service,可以执行如下命令:
docker node update --availability drain swarm-manager

Docker Swarm内部通信之server discovery:
--服务发现(service discovery)。Docker Swarm 原生就提供了这项功能,通过服务发现,service 的使用者不需要知道 service 运行在哪里,IP 是多少,有多少个副本,就能与 service 通信。
要使用服务发现,需要相互通信的 service 必须属于同一个 overlay 网络,首要创建overlay网络。不能使用inress的overlay网络。ingress网络其作用是让运行在不同主机上的容器可以相互通信。ingress 网络是 swarm 创建时 Docker 为自动我们创建的,swarm 中的每个 node 都能使用 ingress。ingress没有提供服务发现,所以要自己创建。
docker network create --driver overlay myapp_net
docker service create --name 111 --network my_net --replicas=3 busybox sleep 1000000
docker service create --name 222 --network my_net --replicas=3 busybox sleep 1000000
docker exec 7ad5126b5e10 nslookup tasks.222(解析ip的)可以看到副本的ip

滚动更新server:
docker service create --name my_web --replicas=3 httpd:2.2.31
docker service update --image httpd:2.2.32 my_web
回滚:
docker service uptate --rollback my_web
docker service update --replicas 6 --update-parallelism 2 --update-delay 1m30s my_web
service 增加到六个副本,每次更新两个副本,间隔时间一分半钟。

docker swarm 存储数据:
利用 Docker 的 volume driver,由外部 storage provider 管理和提供 volume,所有 Docker 主机 volume 将挂载到各个副本
volume-driver插件参考前面部分。
docker service create --name my_web \
--publish 8080:80 \
--mount "type=volume,volume-driver=rexray,source=web_data,target=/usr/local/apache2/htdocs" \
httpd

docker swarm的global mode模式:
global mode,其作用是强制在每个 node 上都运行一个且最多一个副本,默认是 Replicated。如收集每个容器的日志、daemon 集群环境等。
docker service create --name my_web --mode global --mount type=bind,source=/var/run/docker.sock,destination=/var/run/docker.sock gliderlabs/logspout

用label控制service的运行位置。
1、为每个 node 定义 label。
2、设置 service 运行在指定 label 的 node 上。
docker node update --label-add env=test ubuntu2
docker service update --constraint-add node.labels.env==test 111
docker service create \
--constraint node.labels.env==test \
--replicas 3 \
--name my_web \
--publish 8080:80 \
httpd
注:把111的容器service名都转移到ubuntu2上,把httpd都放到ubuntu2的节点上,还可以配合global模式使用 --mode=global
打印信息:docker service inspect 111 --pretty
更新 service:
docker service update --constraint-rm node.labels.env==test my_web
docker service update --constraint-add node.labels.env==prod my_web

Health Check。从应用的业务层面检查容器的状态。
docker service create --name my_db \
--health-cmd "curl --fail http://localhost:8091/pools || exit 1" \
couchbase
隐含的相关参数:
--timeout 命令超时的时间,默认 30s。
--interval 命令执行的间隔时间,默认 30s。
--retries 命令失败重试的次数,默认为 3,如果 3 次都失败了则会将容器标记为 unhealthy。swarm 会销毁并重建 unhealthy 的副本。
health-check-cmd,可以是任何一个命令,返回 0,容器被认为是 healthy,如果返回 1,则为 unhealthy。

创建secret密码:
echo "my-secret-pw" | docker secret create my_secret_data -
secret向容器传递密码:
docker service create \
--name mysql \
--secret source=my_secret_data,target=mysql_root_password \
-e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \
mysql:latest
注:images要有这个MYSQL_ROOT_PASSWORD_FILE环境变量才支持secret,secret 只能在 swarm service 中使用
secret 可用于管理:
用户名和密码。
TLS 证书。
SSH 秘钥。
其他小于 500 KB 的数据。

创建secret密码:
openssl rand -base64 20 | docker secret create mysql_root_password -
openssl rand -base64 20 > password.txt docker secret create my_password ./password.txt
密码是由 openssl 生成的随机字符串。


Stack:
YAML 中定义的元素,完整列表和使用方法可参考文档 https://docs.docker.com/compose/compose-file/
使用stack:
定义好yml文件:
version: '3.3'

services:
db:
images: mysql
deploy:
replicas: 1
volumes:
- db_data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD_FILE: /run/secrets/db_password
sercrets:
- db_root_password
- db_password
wordpress:
depends_on:
-db
images: wordpress
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_passwd
sercrets:
- db_password


sercrets:
db_password:
file: db_password.txt
db_root_password:
file: db_root_password.txt

volumes:
db_data:
执行:
docker stack deploy -c aaa.yml wapstck
更新:
docker stack deploy -c aaa.yml wapstck 也是执行这个命令
删除:
docker stack rm


容器编排引擎之Kubanetes:
Google 开发了一个叫 Borg 的系统(现在命令为 Omega)来调度如此庞大数量的容器和工作负载。在积累了这么多年的经验后,Google 决定重写这个容器管理系统,这个项目就是 Kubernetes。简单的讲,Kubernetes 是 Google Omega 的开源版本

以下讨论,创建 kubernetes 集群、部署应用、访问应用、扩展应用、滚动更新等最常见的使用场景
官方提供已经安装好的实验环境:https://kubernetes.io/docs/tutorials/kubernetes-basics/
部署应用用kubectl run命令:
kubectl run kubernetes-bootcamp \
--image=docker.io/jocatalin/kubernetes-bootcamp:v1 \
--port=8080

kubernetes术语:deployment(应用)
Pod 通常会将紧密相关的一组容器放到一个 Pod 中,同一个 Pod 中的所有容器共享 IP 地址和 Port 空间,也就是说它们在一个 network namespace 中
Pod 是 Kubernetes 调度的最小单位,同一 Pod 中的容器始终被一起调度。
查看当前Pod:
kubectl get pods
端口映射从外部访问应用:
kubectl expose deployment/kubernetes-bootcamp \
--type="NodePort" \
--port 8080
查看端口映射:
kubectl get services

scale扩展应用:
查看副本数:
kubectl get deployments 、 kubectl get pods
增加副本:
kubectl scale deployments/kubernetes-bootcamp --replicas=3
减少副本:
kubectl scale deployments/kubernetes-bootcamp --replicas=2
滚动更新:
kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=jocatalin/kubernetes-bootcamp:v2
回滚:
kubectl rollout undo deployments/kubernetes-bootcamp

Kubernetes 集群的组成成分:
Cluster:
是计算、存储和网络资源的集合,Kubernetes 利用这些资源运行各种基于容器的应用。
Master:
是 Cluster 的大脑,它的主要职责是调度,即决定将应用放在哪里运行。Master 运行 Linux 操作系统,可以是物理机或者虚拟机。为了实现高可用,可以运行多个 Master。
Node:
是运行容器应用。Node 由 Master 管理,Node 负责监控并汇报容器的状态,并根据 Master 的要求管理容器的生命周期。Node 运行在 Linux 操作系统,可以是物理机或者是虚拟机。
Pod:
是 Kubernetes 的最小工作单元。每个 Pod 包含一个或多个容器。Pod 中的容器会作为一个整体被 Master 调度到一个 Node 上运行。
可管理性。
通信和资源共享。Pod 中的所有容器使用同一个网络 namespace,即相同的 IP 地址和 Port 空间。它们可以直接用 localhost 通信。同样的,这些容器可以共享存储
Controller:
Kubernetes 通常不会直接创建 Pod,而是通过 Controller 来管理 Pod 的。Controller 中定义了 Pod 的部署特性,比如有几个副本,在什么样的 Node 上运行等。为了满足不同的业务场景,Kubernetes 提供了多种 Controller,包括 Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等
Deployment:
是最常用的 Controller,比如前面在线教程中就是通过创建 Deployment 来部署应用的。Deployment 可以管理 Pod 的多个副本,并确保 Pod 按照期望的状态运行。
ReplicaSet:
实现了 Pod 的多副本管理。使用 Deployment 时会自动创建 ReplicaSet,也就是说 Deployment 是通过 ReplicaSet 来管理 Pod 的多个副本,我们通常不需要直接使用 ReplicaSet。
DaemonSet:
用于每个 Node 最多只运行一个 Pod 副本的场景。正如其名称所揭示的,DaemonSet 通常用于运行 daemon。
StatefuleSet:
能够保证 Pod 的每个副本在整个生命周期中名称是不变的。而其他 Controller 不提供这个功能,当某个 Pod 发生故障需要删除并重新启动时,Pod 的名称会发生变化。同时 StatefuleSet 会保证副本按照固定的顺序启动、更新或者删除。
Job :
用于运行结束就删除的应用。而其他 Controller 中的 Pod 通常是长期持续运行。
Service :
Pod 很可能会被频繁地销毁和重启,它们的 IP 会发生变化,所以service定义了外界访问一组特定 Pod 的方式。Service 有自己的 IP 和端口,Service 为 Pod 提供了负载均衡。
Namespace :
可以将一个物理的 Cluster 逻辑上划分成多个虚拟 Cluster,每个 Cluster 就是一个 Namespace。不同 Namespace 里的资源是完全隔离的。
命令:kubectl get namespace

部署k8s集群:
官方安装文档可以参考 https://kubernetes.io/docs/setup/independent/install-kubeadm/

在所有节点上安装 dokcer、kubelet、kubeadm 和 kubectl。
kubelet :
运行在 Cluster 所有节点上,负责启动 Pod 和容器。
kubeadm:
用于初始化 Cluster
kubectl :
命令行工具。通过 kubectl 可以部署和管理应用,查看各种资源,创建、删除和更新各种组件。

k8s安装:
apt-get update && apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

用kubeadm创建cluster:
完整的官方文档可以参考 https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/

初始化Master:
kubeadm init --apiserver-advertise-address 192.168.56.105 --pod-network-cidr=10.244.0.0/16

--apiserver-advertise-address 指明用 Master 的哪个 interface 与 Cluster 的其他节点通信,如果不指定,kubeadm 会自动选择有默认网关的 interface。
--pod-network-cidr,Kubernetes 支持多种网络方案,而且不同网络方案对 --pod-network-cidr 有自己的要求,这里设置为 10.244.0.0/16 是因为我们将使用 flannel 网络方案,必须设置成这个 CIDR。

配置 kubectl:
su - ubuntu
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
为了使用更便捷,启用 kubectl 命令的自动补全功能。
echo "source <(kubectl completion bash)" >> ~/.bashrc
这样 ubuntu 用户就可以使用 kubectl 了。

Kubernetes Cluster 能够工作,必须安装 Pod 网络,否则 Pod 之间无法通信。
执行如下命令部署 flannel:
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

添加nodes:
kubeadm join --token d38a01.13653e584ccc1980 192.168.56.105:6443
查看token命令:
kubeadm token list
查看pod状态:
kubectl get pod --all-namespaces
查看pod具体情况:
kubectl describe pod kube-flannel-ds-v0p3x --namespace=kube-system

Master节点组件:
运行着kube-apiserver、kube-scheduler、kube-controller-manager、etcd、Pod网络(如flannel网络)。
kube-apiserver:
API Server 提供 HTTP/HTTPS Restful API,是 Kubernetes Cluster 的前端接口,各种客户端工具(CLI 或 UI)以及 Kubernetes 其他组件可以通过它管理 Cluster 的各种资源。
kube-scheduler:
Scheduler 负责决定将 Pod 放在哪个 Node 上运行。Scheduler 在调度时会充分考虑 Cluster 的拓扑结构,当前各个节点的负载,以及应用对高可用、性能、数据亲和性的需求。
kube-controller-manager:
Controller Manager 负责管理 Cluster 各种资源,保证资源处于预期的状态。Controller Manager 由多种 controller 组成,包括 replication controller、endpoints controller、namespace controller、serviceaccounts controller 等。不同的 controller 管理不同的资源。例如 replication controller 管理 Deployment、StatefulSet、DaemonSet 的生命周期,namespace controller 管理 Namespace 资源。
etcd:
etcd 负责保存 Kubernetes Cluster 的配置信息和各种资源的状态信息。当数据发生变化时,etcd 会快速地通知 Kubernetes 相关组件
Pod网络:
Pod 要能够相互通信,Kubernetes Cluster 必须部署 Pod 网络,flannel 是其中一个可选方案。

Node节点组件:
kubelet:
kubelet 是 Node 的 agent,当 Scheduler 确定在某个 Node 上运行 Pod 后,会将 Pod 的具体配置信息(image、volume 等)发送给该节点的 kubelet,kubelet 根据这些信息创建和运行容器,并向 Master 报告运行状态。
kube-proxy:
每个 Node 都会运行 kube-proxy 服务,它负责将访问 service 的 TCP/UPD 数据流转发到后端的容器。service 在逻辑上代表了后端的多个 Pod,外界通过 service 访问 Pod。如果有多个副本,kube-proxy 会实现负载均衡。
Pod 网络
Pod 要能够相互通信,Kubernetes Cluster 必须部署 Pod 网络,flannel 是其中一个可选方案。

几乎所有的 Kubernetes 组件本身也运行在 Pod 里,执行如下命令:
kubectl get pod --all-namespaces -o wide

kubectl run nginx-deployment --image=nginx:1.7.9 --replicas=2

kubectl apply -f nginx.yml
删除:
kubectl delete -f nginx.yml

用户通过 kubectl 创建 Deployment。
Deployment 创建 ReplicaSet。
ReplicaSet 创建 Pod。
子对象的名字 = 父对象名字 + 随机字符串或数字。

vi nginx.yml
apiVersion: extensions/v1beta1 ①
kind: Deployment ②
metadata: ③
name: nginx-deployment
spec:
replicas: 2
template:
metadata:
labels:
app: web_server
spec:
containers:
- name: nginx
images: nginx:1.14.1
nodeSelector:
disktype: ssd
① apiVersion 是当前配置格式的版本。
② kind 是要创建的资源类型,这里是 Deployment。
③ metadata 是该资源的元数据,name 是必需的元数据项。
④ spec 部分是该 Deployment 的规格说明。
⑤ replicas 指明副本数量,默认为 1。
⑥ template 定义 Pod 的模板,这是配置文件的重要部分。
⑦ metadata 定义 Pod 的元数据,至少要定义一个 label。label 的 key 和 value 可以任意指定。
⑧ spec 描述 Pod 的规格,此部分定义 Pod 中每一个容器的属性,name 和 image 是必需的。

Controller --Deployment 的 Scale Up/Down:
默认情况下pod不会在主节点,把master当节点用:
kubectl taint node k8s-master node-role.kubernetes.io/master-
不把master当节点用:
kubectl taint node k8s-master node-role.kubernetes.io/master="":NoSchedule
删除应用
kubectl delete deployment nginx-deployment

指定应用到指定节点:
kubernetes通过label来将指定Pod调度到指定node上运行。默认情况Scheduler 会将 Pod 调度到所有可用的 Node,与docker swarm相似,先给节点打标签在运行应用。
打标签:
kubectl label node k8s-node1 disktype=ssd
查看标签:
kubectl get node --show-labels

执行yml文件会将pod运行到指定node上。
删除label:
kubectl label node k8s-node1 disktype-

Controller --DaemonSet的应用场景:
每个 Node 上最多只能运行一个副本。
查看DaemonSet应用:
kubectl get daemonset --namespace=kube-system
查看kube-proxy应用的yml文件:
kubectl edit daemonset kube-proxy --namespace=kube-system

Controller --job的应用:
容器按照持续运行的时间可分为两类:服务类容器和工作类容器。服务类容器通常持续提供服务,需要一直运行,工作类容器则是一次性任务,比如批处理程序,完成后容器就退出。
job是工作类容器
vi myjob.yml
apiVersion: batch/v1
kind: job 或(CronJob计划任务job)
metadata:
name: myjob
spec:
scheduler:"*/1 * * * *" #cronJob
JobTemplate: #cronJob
completions: 6 #总共运行6个
parallelism: 2 #每次运行两个
template:
metadata:
name: myjob
spec:
containers:
- name: hello
images: busybox
command: [ "echo" , "k8s my job"]
restartPolicy: Never(不重启) 或 Onfailure(命令执行失败会重启) 或 Always(容器退出时会重新启动)

这种模式下如果启动失败,即使restartPolicy是Nerver,但是 Job DESIRED 的 Pod 是 1,所以Job controller 会启动新的 Pod,一直创建新的pod,直到 SUCCESS为 1,为了终止这个行为,只能删除 Job。
运行cronJob需要修改kube-api的配置文件/etc/kubernetes/manifests/kube-apiserver.yaml启用--runtime-config=batch/v2alpha1=true,然后重启 kubelet 服务
systemctl restart kubelet.service

启动 Job:
kubectl apply -f myjob.yml
删除:
kubectl delete -f myjob.yml

Kubernetes --Service:
Pod 中的容器很可能因为各种原因发生故障而死掉,Deployment 等 controller 会通过动态创建和销毁 Pod 来保证应用整体的健壮性。换句话说,Pod 是脆弱的,但应用是健壮的。每个 Pod 都有自己的 IP 地址。当 controller 用新 Pod 替代发生故障的 Pod 时,ip会发生变化,而客户端就是通过service来访问后端的pod。无论后端的pod的ip怎么变化,service的ip不会变
vi httpd.yml vi service.yml
apiVersion: v1 apiVersion: v1
kind: Deployment kind: Service
metadata: metadata:
name: httpd name: httpd_svc
spec: spec:
replicas: 3 selector:
template: run: httpd #指明挑选那些 label 为 run: httpd 的 Pod 作为 Service 的后端。
metadata: ports:
- name: httpd - protocol: TCP
labels: port: 8080
run: httpd targetPort: 80
spec:
containers:
- name: httpd
images: httpd
ports:
- containersPort: 80
运行:
kubectl apply -f service.yml
查看:
kubectl get service
详细信息:
kubectl describe service httpd_svc

注:Service Cluster IP是集群内部一个虚拟IP,是由 Kubernetes节点上的iptables规则管理的。每个节点上都配置了相同的iptables规则,通过iptables-save可以看到,负载把虚拟ip的访问端口映射到pod端口;还可以用kube-dns组件通过 <SERVICE_NAME>.<NAMESPACE_NAME> 访问 service IP,如:ping httpd_svc.default:8080 ,default的namespace可以省略,其他的必须要带上。

Kubernetes 提供了多种类型的 Service:
ClusterIP
Service 通过 Cluster 内部的 IP 对外提供服务,只有 Cluster 内的节点和 Pod 可访问,这是默认的 Service 类型。前面实验中的 Service 都是 ClusterIP。
NodePort
Service 通过 Cluster 节点的静态端口对外提供服务。Cluster 外部可以通过 <NodeIP>:<NodePort> 访问 Service。
LoadBalancer
Service 利用 cloud provider 特有的 load balancer 对外提供服务,cloud provider 负责将 load balancer 的流量导向 Service。目前支持的 cloud provider 有 GCP、AWS、Azur 等。

NodePort-----service:
vi service.yml
apiVersion: v1
kind: Service
metadata:
name: httpd_svc
spec:
type: NodePort #指明service类型为NodePort
selector:
run: httpd #指明挑选那些 label 为 run: httpd 的 Pod 作为 Service 的后端。
ports:
- protocol: TCP
nodeport: 3000 #node端口
port: 8080 #CluterIP端口
targetPort: 80 #Pod内部端口

滚动更新rolling update:
滚动更新是一次只更新一小部分副本,成功后,再更新更多的副本,最终完成所有副本的更新。滚动更新的最大的好处是零停机,整个更新过程始终有副本在运行,从而保证了业务的连续性。
编辑yml文件把images版本填写成更新后的,在kubectl apply -f yml,
原理是:
1、创建 Deployment
2、创建 ReplicaSet ,管理pod副本数,旧的减少一个新的增加一个来维持副本总数不变
3、创建 Pod ,旧的副本数为0,新版本维持副本数。


回滚rollback:
默认配置下,Kubernetes 只会保留最近的几个 revision,可以在 Deployment 配置文件中通过 revisionHistoryLimit 属性增加 revision 数量。
vi httpd.yml
apiVersion: v1
kind: Deployment
metadata:
name: httpd
spec:
revisonHistoryLimit: 10
replicas: 3
template:
metadata:
- name: httpd
labels:
run: httpd
spec:
containers:
- name: httpd
images: httpd
ports:
- containersPort: 80
执行 kubectl apply 时加上 --record参数,--record 的作用是将当前命令记录到 revision 记录中,这样我们就可以知道每个 revison 对应的是哪个配置文件
查看当前保存的version:
kubectl rollout history deployment httpd
回滚到某个版本:
kubectl rollout undo deployment httpd --to-revision=1


Health Check:
Liveness 和 Readiness 探测机制设置更精细的健康检查,进而实现如下需求:
零停机部署。
避免部署无效的镜像。
更加安全的滚动升级。
默认的健康检查是容器进程退出时返回码非零,则认为容器发生故障,Kubernetes 就会根据 restartPolicy 重启容器。默认的deployment的restartPolicy是Alway。

如果容器进程不退出返回非0状态码,就要用到liveness。
Liveness 探测让用户可以自定义判断容器是否健康的条件。如果探测失败,Kubernetes 就会重启容器。

liveness探测配置:
vim liveness.yml
..............
livenessProbe:或readinessProbe:
exec:
command:
- cat
- /tem/healthy
initialDelaySeconds: 10
periodSeconds: 5
1、通过 cat 命令检查 /tmp/healthy 文件是否存在。如果命令执行成功,返回值为零,Kubernetes 则认为本次 Liveness 探测成功;否则失败。
2、initialDelaySeconds: 10 指定容器启动 10 之后开始执行 Liveness 探测。
3、periodSeconds: 5 指定每 5 秒执行一次 Liveness 探测。Kubernetes 如果连续执行 3 次 Liveness 探测均失败,则会杀掉并重启容器。

Readiness 探测:
Readiness 探测如果失败则是将容器设置为不可用,不接收 Service 转发的请求,不在service负载均衡之内。
配置与liveness探测是一样的,用 Readiness 探测判断容器是否已经准备好对外提供服务。

注:readiness和liveness探测可以一起用。

在scale up中,新副本会作为 backend 被添加到 Service 的负责均衡中,与已有副本一起处理客户的请求。考虑到应用启动通常都需要一个准备阶段,比如加载缓存数据,连接数据库等,从容器启动到正真能够提供服务是需要一段时间的。我们可以通过 Readiness 探测判断容器是否就绪,避免将请求发送到还没有 ready 的 backend
vim httpd.yml
apiVersion: v1
kind: Deployment
metadata:
name: web
spec:
strategy:
rollingUpdate:
maxSurge: 35%
maxUnavailable: 35%
replicas: 3
template:
metadata:
labels:
run: web
spec:
containers:
- name: web
images: httpd
ports:
- containerPort: 8080
readinessProbe:
httpGet: #返回代码不是 200-400,表示容器没有就绪,不接收 Service web-svc 的请求
scheme: http
path: /healthy #访问路径
port: 8080 #访问端口
initialDelaySeconds: 10 #10秒后开始检测
periodSeconds: 5 #每隔5秒检测一次
---
apiVersion: v1
kind: service
metadata:
name: web-svc
spec:
selector:
run: web
ports:
- protocol: tcp
port: 8080
targetPort: 8080

在Rolling Update中应用Health check:
当rolling update时,新images会替换旧的images,pod启动过程中、pod配置错误导致不正常运行且没有退出时,这时业务是中断的。所以就要用到health check机制。
如果正确配置了 Health Check,新副本只有通过了 Readiness 探测,才会被添加到 Service;如果没有通过探测,现有副本不会被全部替换,业务仍然正常进行。
滚动更新通过参数 maxSurge 和 maxUnavailable 来控制副本替换的数量。
maxSurge:
此参数控制滚动更新过程中副本总数的超过 DESIRED 的上限。maxSurge 可以是具体的整数(比如 3),也可以是百分百,向上取整。maxSurge 默认值为 25%。
DESIRED 为 10,那么副本总数的最大值为:
roundUp(10 + 10 * 25%) = 13
maxUnavailable:
此参数控制滚动更新过程中,不可用的副本相占 DESIRED 的最大比例。 maxUnavailable 可以是具体的整数(比如 3),也可以是百分百,向下取整。maxUnavailable 默认值为 25%。
DESIRED 为 10,那么可用的副本数至少要为:
10 - roundDown(10 * 25%) = 8
如果要定制 maxSurge 和 maxUnavailable,可以如下配置:
............
strategy:
rollingUpdate:
maxSurge: 35%
maxUnavailable: 35%
...........

一、Kubernetes Volume:
Kubernetes Volume 是一个目录,这一点与 Docker Volume 类似。当 Volume 被 mount 到 Pod,Pod 中的所有容器都可以访问这个 Volume。Kubernetes Volume 也支持多种 backend 类型,包括 emptyDir、hostPath、GCE Persistent Disk、AWS Elastic Block Store、NFS、Ceph 等,完整列表可参考 https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes
1、emptyDir Volume
emptyDir 是最基础的 Volume 类型。正如其名字所示,一个 emptyDir Volume 是 Host 上的一个空目录。emptyDir Volume 的生命周期与 Pod 一致。当pod中的某个容器被销毁 Volume还在。当 Pod 从节点删除时,Volume 的内容也会被删除。

apiVersion: v1
kind: Pod
metadata:
name: producer-consumer
spec:
containers:
- image: busybox
name: producer
volumerMounts:
- mountPath: /producer_dir
name: share-volume
args:
- /bin/sh
- -c
- echo "Hello world" > /producer_dir/Hello; sleep 30000
- images: busybox
name: consumer
volumerMounts:
- mountPath: /consumer_dir
name: share-volume
args:
- /bin/sh
- -c
- cat /consumer_dir/Hello; sleep 30000
volumes:
- name: share-volume
emptyDir: {}

因为 emptyDir 是 Docker Host 文件系统里的目录,其效果相当于执行了 docker run -v /producer_dir 和 docker run -v /consumer_dir


2、hostPath Volume
作用是将 Docker Host 文件系统中已经存在的目录 mount 给 Pod 的容器,如果 Pod 被销毁了,hostPath 对应的目录也还会被保留,从这点看,hostPath 的持久性比 emptyDir 强。不过一旦 Host 崩溃,hostPath 也就没法访问了。
例如:
kubectl edit --namespace=kube-system pod kube-apiserver-k8s-master


二、持久性的 Volume
外部 Storage Provider:
1、如果 Kubernetes 部署在诸如 AWS、GCE、Azure 等公有云上,可以直接使用云硬盘作为 Volume,下面是 AWS Elastic Block Store 的例子:
apiVersion: vl
kind: Pod
metadata:
name: using-ebs
spec:
containers:
- image: busybox
name: using-ebs
volumeMounts:
- mountPath: /test-ebs
name: ebs-volume
volumes:
- name : ebs-volume
# This AWS EBS volume must already exist.
awsElasticBlockStore:
volumelD: <volume-id>
fsType: ext4

2、Kubernetes Volume 也可以使用主流的分布式存,比如 Ceph、GlusterFS 等,下面是 Ceph 的例子:
apiVersion: vl
kind: Pod
metadata:
name: using-ceph
spec:
containers:
-image: busybox
name: using-ceph
volumeMounts:
- name : ceph-volume
mountPath: /test-ceph
volumes:
- name : ceph-volume
cephfs:
path: /some/path/in/side/cephfs
monitors: "10.16.154.78:6789"
secretFile: "/etc/ceph/admin.secret"

Ceph 文件系统的 /some/path/in/side/cephfs 目录被 mount 到容器路径 /test-ceph


3、PersistentVolume 和 PersistentVolumeClaim
PersistentVolume (PV) 是外部存储系统中的一块存储空间,由管理员创建和维护。与 Volume 一样,PV 具有持久性,生命周期独立于 Pod。
PersistentVolumeClaim (PVC) 是对 PV 的申请 (Claim)。PVC 通常由普通用户创建和维护。需要为 Pod 分配存储资源时,用户可以创建一个 PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes 会查找并提供满足条件的 PV。

Kubernetes 支持多种类型的 PersistentVolume,比如 AWS EBS、Ceph、NFS 等,完整列表请参考 https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes
创建nfs类型的pv:
apiVersion: v1
kind: persistentvolume
metadata:
name: mypv1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
nfs:
path: /nfsdata/pv1
server:192.168.56.105

1、capacity 指定 PV 的容量为 1G。
2、accessModes 指定访问模式为 ReadWriteOnce,支持的访问模式有:
ReadWriteOnce – PV 能以 read-write 模式 mount 到单个节点。
ReadOnlyMany – PV 能以 read-only 模式 mount 到多个节点。
ReadWriteMany – PV 能以 read-write 模式 mount 到多个节点。
3、persistentVolumeReclaimPolicy 指定当 PV 的回收策略为 Recycle,支持的策略有:
Retain – 需要管理员手工回收。
Recycle – 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*。
Delete – 删除 Storage Provider 上的对应存储资源,例如 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。
4、storageClassName 指定 PV 的 class 为 nfs。相当于为 PV 设置了一个分类,PVC 可以指定 class 申请相应 class 的 PV。
5、指定 PV 在 NFS 服务器上对应的目录。

kubectl apply -f nfspv.yml
kubectl get nfspv
STATUS 为 Available,表示 mypv1 就绪,可以被 PVC 申请。

创建PVC 就很简单了,只需要指定 PV 的容量,访问模式和 class。
PVC mypvc1,配置文件 nfspvc.yml 如下:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: nfs

在pod中使用pvc:pod1.yml
apiVersion: v1
kind: pod
metadata:
name: mypod1
spec:
container:
- name: mypod1
image: busybox
args:
- /bin/sh
- -c
-sleep 3000
volumeMounts:
- mountPath: "/mydata"
name: mydata
volumes:
- name: mydata
persistentvolumeClaim:
claimName: mypvc1

kubectl apply -f pod1.yml
kubectl get pod -o wide
kubectl exec mypod1 touch /mydata/hello

删除pv和pvc
kubectl delete pvc mypvc1
Kubernetes 会启动了一个新 Pod recycler-for-mypv1,这个 Pod 的作用就是清除 PV mypv1 的数据,因为pv的回收策略是:Recycle,希望保留数据,可以将策略设置为 Retain
kubectl get pod -o wide
当数据清除完毕,mypv1 的状态重新变为 Available,此时则可以被新的 PVC 申请

PV 还支持 Delete 的回收策略,会删除 PV 在 Storage Provider 上对应存储空间。NFS 的 PV 不支持 Delete,支持 Delete 的 Provider 有 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。

PV 的动态供给功能:
动态供给(Dynamical Provision),即如果没有满足 PVC 条件的 PV,会动态创建 PV。相比静态供给,动态供给有明显的优势:不需要提前创建 PV,减少了管理员的工作量,效率高。

动态供给是通过 StorageClass 实现的,StorageClass 定义了如何创建 PV,下面是两个例子。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type:gp2
reclaimPolicy: Retain

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: slow
provisioner: kubernetes.io/aws-ebs
parameters:
type: io1
zones: us-east-1d,us-east-1c
iopsPerGB: "10"

未完待续。。。

猜你喜欢

转载自www.cnblogs.com/lobo-hu/p/11673510.html
今日推荐