Kubernetes跨主机通信时的注意事项

我们知道docker的两个主机之间容器是不能直接通讯的,Kubernetes也没有自带解决这个问题,

部署Kubernetes的时候大多使用flannel或者calico插件带来的解决方案,

本文不对这两个解决方案做对比,这是你在选择前应该自己去了解的。本文旨在填网络部分的坑

接受所有ip的数据包转发

新建文件/etc/systemd/system/docker.service.d/iptables.conf并填入以下内容保存

[Service]

ExecStartPost=/sbin/iptables -I FORWARD -s 0.0.0.0/0 -j ACCEPT

这样不同主机都能直接访问到pod的网络了

使用内网穿透技术映射主机端口到公网

内网穿透的技术有很多,常用的方法有:

  • ssh/autossh
  • ngfork
  • frp (本文将介绍该方法)

github地址:https://github.com/fatedier/frp

frp为传统的C/S结构,可分为客户端和服务端,其中

  • frpc(客户端) 运行在内网环境
  • frps(服务端)运行在有公网IP的服务器

编写frpc.ini文件,例如:

[common] server_addr = 公网IP server_port = frps运行的端口 token = 一串随机字符用来防止未经授权的使用  [appName] type = tcp local_ip = 127.0.0.1 local_port = 需要映射的本地端口 remote_port = 映射成公网服务器的端口

服务器端frps.ini就更简单了

[common] bind_port = 服务端运行的端口 token = 一串随机字符用来防止未经授权的使用 ;允许被使用的端口范围 allow_ports = 40000-50000 

假设frps 运行在 1.2.3.4:34567,客户端(192.168.1.5)把本机的80端口映射成了38888端口,则链路如下

192.168.1.5:80 <-> 1.2.3.4:34567 <-> 1.2.3.4:38888

提高映射服务可靠性

请使用supervisor分配守护frpc/frps即可达到理想可靠性

 

 

配置docker使用代理和镜像仓库加速

由于配置、启动k8s的过程中,需要从gcr仓库拉取镜像,而一般情况下是会被墙挡住而造成拉取失败,这时,一种解决方法就是挂上梯子,让docker通过梯子去拉取镜像

启动梯子

此处省略,假设梯子启动后监听本地的1080端口

即 socks5://127.0.0.1:1080

配置docker使用代理

新版docker服务都是使用systemd来管理的,此方法适用于ubuntu 16.04+ / centos7+

# mkdir /etc/systemd/system/docker.service.d

# vim /etc/systemd/system/docker.service.d/http-proxy.conf

填入以下内容

[Service]

Environment="HTTP_PROXY=socks5://127.0.0.1:1080/" "HTTPS_PROXY=socks5://127.0.0.1:1080/"

保存并退出后,执行以下命令重新加载配置并重启docker服务

# systemctl daemon-reload && systemctl restart docker

运行docker info可能看到有HTTP_PROXY和HTTPS_PROXY字样即为成功

最好再docker pull 镜像名 验证下代理网络是否正常

配置镜像仓库加速拉取(可选)

修改dockerd的配置文件(没有就新建一个)

# vim /etc/docker/daemon.json

加上registry-mirrors,例如:(以下使用中科大的docker hub)

{
  "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn/"]
}

保存并退出后,重启docker服务

# systemctl restart docker

安装k8s通用的Web UI(kubernetes-dashboard)

我们打算安装k8s官方的UI界面,这个界面能显示所有的工作负载,包括运行的Nodes,Services,Pods,Jobs,Relica sets等k8s资源。

首先你需要连接VPN,不然的话,运行接下来的 kubectl create命令后,你会发现新建的pod会报ImagePullBackOff的错误

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml

!!!!本文以下内容为原创,不走官方预留的神坑

本文直接给出一份魔改后的kubernetes-dashboard.yaml,已经踩过了ca证书、存活检查、集群账号权限等等一些的坑,并将kubernetes-dashboard锁死在master节点上(为了方便内网穿透)

魔改后:

1. 关闭自动生成ca证书

2. 开启HTTP访问(31110端口)

3. 原HTTPS访问映射到31111端口

4. 心跳检测改为访问HTTP /

5. dashboard使用集群超级管理员cluster-admin,妈妈再也不用担心我不够权限了

6. dashboard锁死在master节点上跑

# kubectl apply -f kubernetes-dashboard.yaml

顺便完善下集群监控

# kubectl apply -f grafana.yaml

# kubectl apply -f heapster-rbac.yaml

# kubectl apply -f heapster.yaml

# kubectl apply -f influxdb.yaml

安装完毕后,访问 http://master节点的IP:31110 即可管理你的k8s集群

部署应用程序到kubernetes集群

第一步:在master 节点上创建一个deployment

# kubectl create deployment nginx --image=nginx deployment.apps/nginx created

检查执行效果,可以看到一个叫nginx的deployment创建成功了

# kubectl get deployments NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE nginx     1         1         1            1           1m

第二步:创建一个service,并暴露80端口

kubectl create service nodeport nginx --tcp 80:80

检查执行效果,可以看到一个叫nginx的service创建成功了,这里kubectl get svc是kubectl get services的简写

# kubectl create service nodeport nginx --tcp 80:80 service/nginx created

# kubectl get svc NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        1d nginx        NodePort    10.96.248.169    <none>        80:31088/TCP   11s

执行下面的命令验证一下nginx有没有部署成功(顺带测试下容器间网络通信)

# curl 10.96.248.169 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style>     body {         width: 35em;         margin: 0 auto;         font-family: Tahoma, Verdana, Arial, sans-serif;     } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p>  <p><em>Thank you for using nginx.</em></p> </body> </html>

清理现场

# kubectl delete deployments/nginx services/nginx deployment.extensions "nginx" deleted service "nginx" deleted

kubeadm生成的token过期后,集群增加节点

通过kubeadm初始化后,都会提供node加入的token。

默认token的有效期为24小时,当过期之后,该token就不可用了。解决方法如下:

重新生成新的token

root@kube-master:~# kubeadm token create
4e3g83.rp37cbe2d0nvb6qj

获取ca证书sha256编码hash值

root@kube-master:~# openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'

82f7e8c7570d9316b374407c7c4e5e1eb5d394239764e693a269e060ba9837fb

将节点加入集群

[root@walker-4 kubernetes]# kubeadm join --token 4e3g83.rp37cbe2d0nvb6qj --discovery-token-ca-cert-hash sha256:82f7e8c7570d9316b374407c7c4e5e1eb5d394239764e693a269e060ba9837fb 10.71.11.84:6443

快速搭建Kubernetes集群(基于Ubuntu)

K8s集群部署有三种方式:

  • kubeadm (联网安装,本文以此为基础)
  • minikube(联网安装)
  • 二进制包(通常离线安装)

本文只使用两台虚拟机,一台是Master节点,一台是Node节点:

主机名 ip 系统 配置 工作目标
kube-master 10.71.11.84 Ubuntu 16.04 2C4G Master节点
kube-slave 10.71.11.83 Ubuntu 16.04 4C8G Node节点

准备工作

1. 修改主机名及配置主机名映射

例如对于Master节点

echo kube-master > /etc/hostname
vim /etc/hosts
 127.0.0.1    kube-master 10.71.11.83  kube-slave

在Node节点上执行类似操作,注意不要搞混ip和主机名

2. 配置软件源(这里用了中科大的源)

cat <<EOF > /etc/apt/sources.list.d/kubernetes.list deb [trusted=yes] http://mirrors.ustc.edu.cn/kubernetes/apt kubernetes-xenial main EOF

3.关闭系统 Swap

因为Kubernetes v1.8+ 要求关闭系统 Swap

① 临时关闭swap swapoff -a

② 永久关闭swap vim /etc/fstab 注释所有带swap字样的行

更新源并安装kubeadm, kubectl, kubelet软件包

apt-get update -y && apt-get install -y kubelet kubeadm kubectl --allow-unauthenticated

安装docker(当前kubeadm不支持docker.ce)

apt-get install docker.io -y

加载内核模块(可选)

modprobe ip_vs modprobe ip_vs_rr modprobe ip_vs_wrr modprobe ip_vs_sh modprobe nf_conntrack_ipv4

正式开始

使用kubeadmin初始化master节点

这个下载镜像的过程涉及翻墙,因为会从gcr的站点下载容器镜像,不然初始化不成功, 这里要指定apiserver-advertise-address 及pod的虚拟子网pod-network-cidr

kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=10.71.11.84

如果出错,请根据错误信息查询错误详情,解决错误后执行kubeadmin reset还原至错误前状态

如果看到”Your Kubernetes master has initialized successfully!”字样,说明master节点已创建成功,可以进入下一步

配置kubectl

mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config

将slave节点加入到集群

在kube-slave上运行:

kubeadm join --token aa78f6.8b4cafc8ed26c34f --discovery-token-ca-cert-hash sha256:0fd95a9bc67a7bf0ef42da968a0d55d92e52898ec37c971bd77ee501d845b538  10.71.11.84:6443

上面的token和sha256都需要根据实际情况生成并填入,具体请看kubeadm生成的token过期后,集群增加节点

在Master 上运行kube get nodes, 可以看到结果如下:

NAME          STATUS   ROLES    AGE     VERSION kube-master   Ready    master   15h     v1.13.4 kube-slave    Ready    <none>   15h     v1.13.4

安装网络插件canal

canal官方文档参考,如下网址下载2个文件并且安装,其中一个是配置canal的RBAC权限,一个是部署canal的DaemonSet。但笔者是从这里(Installing a pod network add-on)参考的,根据kubeadm init时用到的--pod-network-cidr=10.244.0.0/16,所以选择了canal

kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/canal/rbac.yaml kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/canal/canal.yaml

可以看到输出:

clusterrole.rbac.authorization.k8s.io "calico" created clusterrole.rbac.authorization.k8s.io "flannel" created clusterrolebinding.rbac.authorization.k8s.io "canal-flannel" created clusterrolebinding.rbac.authorization.k8s.io "canal-calico" created configmap "canal-config" created daemonset.extensions "canal" created customresourcedefinition.apiextensions.k8s.io "felixconfigurations.crd.projectcalico.org" created customresourcedefinition.apiextensions.k8s.io "bgpconfigurations.crd.projectcalico.org" created customresourcedefinition.apiextensions.k8s.io "ippools.crd.projectcalico.org" created customresourcedefinition.apiextensions.k8s.io "clusterinformations.crd.projectcalico.org" created customresourcedefinition.apiextensions.k8s.io "globalnetworkpolicies.crd.projectcalico.org" created customresourcedefinition.apiextensions.k8s.io "networkpolicies.crd.projectcalico.org" created serviceaccount "canal" created

执行如下命令,可以就可以查看canal的安装状态

# kubectl get pod -n kube-system -o wide NAME                                    READY   STATUS    RESTARTS   AGE     IP            NODE          NOMINATED NODE   READINESS GATES canal-547kn                             3/3     Running   34         47h     10.71.11.84   kube-master   <none>           <none> canal-j76k9                             3/3     Running   15         47h     10.71.11.83   kube-slave    <none>           <none> coredns-86c58d9df4-5mnm4                1/1     Running   14         2d15h   10.244.0.45   kube-master   <none>           <none> coredns-86c58d9df4-b76qw                1/1     Running   14         2d15h   10.244.0.44   kube-master   <none>           <none> etcd-kube-master                        1/1     Running   15         2d15h   10.71.11.84   kube-master   <none>           <none> kube-apiserver-kube-master              1/1     Running   17         2d15h   10.71.11.84   kube-master   <none>           <none> kube-controller-manager-kube-master     1/1     Running   19         2d15h   10.71.11.84   kube-master   <none>           <none> kube-proxy-q2v5x                        1/1     Running   11         2d15h   10.71.11.83   kube-slave    <none>           <none> kube-proxy-sqvbh                        1/1     Running   16         2d15h   10.71.11.84   kube-master   <none>           <none> kube-scheduler-kube-master              1/1     Running   15         2d15h   10.71.11.84   kube-master   <none>           <none>

第一步大功告成!

策略路由 – 让你的服(ti)务(zi)器用两条腿走路

对于PC来说,一台电脑一般最多就两张网卡(有线+无线)。只要能上网,哪管是走的哪张网卡。然鹅,对于服务器来说,N多张网卡(N > 2)是正常不过的事情,如何在多网卡多网关下正常、合理地工作,这就就需要各种交换机以及本文的策略路由来配合了。

  • 首先来科普下 策略路由路由策略 的区别。

路由策略。(Route-Policy)
路由策略是通过修改路由表的路由条目来控制数据流量的可达性。即对接受和发布的路由进过滤。这种方式称为路由策略

策略路由。(Traffic-Policy)
策略路由是通过用户制定的策略进行转发,且该策略优于路由表的转发。这种方式称为策略路由
由此可知,路由策略是基于路由表进行流量的转发,而策略路由是基于策略进行流量的转发。两者都为了控制网络流量的可达性或调整网络流量的路径。

  • 首先来张图,介绍下本文的网络环境

服务器有两个网口,eth0和eth1

eth0 : 地址10.16.0.5 ,网关 10.16.0.1 ,掩码 255.255.255.0,对应公网IP 1.2.3.4

eth1 : 地址10.16.254.5,网关10.16.254.1,掩码255.255.255.0,对应公网IP 5.6.7.8

  • 正式开始:
  1. 修改/etc/iproute2/rt_tables文件,追加以下两行
252  e0
251  e1

解释:这里我们自定义了两个策略路由表,假设e0对应eth0,e1对应eth1,以便操作

2.编辑启动脚本 /etc/rc.local,增加下面内容

ip route flush table e0
ip route add default via 10.16.0.1 dev eth0 src 10.16.0.5 table e0
ip rule add from 10.16.0.1 table e0

ip route flush table e1
ip route add default via 10.16.254.1 dev eth1 src 10.16.254.5 table e1
ip rule add from 10.16.254.5 table e1

OK,理论上重启后服务器就能被不同的IP访问到并正常收发数据

然鹅too young,第2中rc.local这种N多年的老掉牙的东东,一点也不好用,时灵时不灵的,而且一点也不优雅(rc.local万金油时代已经过去了_(:з」∠)_

3.现代化的网络管理,当然是得用network或者NetworkManager啦,无视第二步,我们继续来

(1)新增 /etc/sysconfig/network-scripts/rule-eth0 文件,增加以下内容

from 10.16.0.5 table e0

(2)新增 /etc/sysconfig/network-scripts/rule-eth1 文件,增加以下内容

from 10.16.254.5 table e1

(3)编辑或新增 /etc/sysconfig/network-scripts/route-eth0 文件,增加以下内容

10.16.0.0/24 dev eth0 src 10.16.0.5 table e0
default via 10.16.0.1 table e0

(4)编辑或新增 /etc/sysconfig/network-scripts/route-eth1 文件,增加以下内容

10.16.254.0/24 dev eth1 src 10.16.254.5 table e1
default via 10.16.254.1 table e1

至此大功告成,service network restart 重启网络体验一下

At last,你说不知道服务器访问外网默认走哪个网关?骚年,给你的网卡加个Metric,爱往哪走往哪走~

参考资料:《CentOS双线双IP配置

ポリシーベースルーティングの設定について

制作Nginx+PHP的Docker镜像

一、准备工作:

使用工具:

1.主流版本的docker,本人使用的是 最新稳定版18.03

2.Centos的官方docker镜像作为基础镜像,这里选的版本是7.2

3.putty或Xshell作为SSH工具

思路:

众所周知,docker镜像的制作有2种方法,一种是启动一个容器并在容器里操作,再将容器提交为一个新的镜像;一种是写Dockerfile,然后执行dockerfile由docker给我们一步步自动生成新的镜像;显然第二种方法更高大上,也更适合容器需要不断版本更替的场景。本人在安装nginx和php的时候,习惯用第三方yum源,所以编译安装这里写Dockerfile实在是繁琐,而且nginx+php并不是需要频发更替版本,通常在制作容器前,跟开发确定好版本号,制作好容器可以一直使用;所以以下我的操作里,前半部分,nginx和php的安装,我会在容器里操作;最后让nginx和php同时启动起来,我则是写了一个Dockerfile。

二、制作容器

1、启动一个centos容器作为基础镜像

docker pull centos:7.2

docker run -it –name LNP centos:7.2 bash

2、这样就创建了一个以centos的官方镜像为基础的容器,并进如容器;在容器里用yum安装wget命令和编译安装需要的命令,替换成内网yum源,加上epel源、nginx源和php源
在附录中给出改好repo文件

3、更新yum源

yum update

4、yum安装nginx:

yum -y install nginx

5、yum安装php 7.1
yum -y install php71

6、yum安装常用的php扩展
yum -y install php71-php-mbstring php71-php-pdo php71-php-mcrypt php71-php-json php71-php-cli php71-php-gd php71-php-phpiredis php71-php-mysqlnd
7、安装PHP-FPM
yum -y install php71-php-fpm
8、配置整合nginx和PHP-FPM
nginx的配置文件放在/etc/nginx/conf.d/下,我们可以新增一个php.conf,内容参考如下

server{
    listen 80;
    #server_name domain.com;
    root /opt/php;

    location / {
        index index.php index.html index.htm;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass 127.0.0.1:9000;
        #fastcgi_index index.php;
    }
}

9、整理,清理yum缓存,退出容器

   yum clean all

  exit

10、提交容器
docker commit -m “nginx-php” LNP yourname/nginx-php:v1
三、让这个镜像可以跑起来!

1、Dockefile如下:在宿主机下创建一个nginx目录,并到目录下vim Dockefile

FROM yourname/nginx-php:v1

# Install supervisor
RUN yum install -y python-setuptools
RUN easy_install supervisor

EXPOSE 80 443

CMD [“/usr/bin/supervisord”]

2.修改/etc/nginx/nginx.conf,加上“daemon off;”,如下:

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

daemon off;

events {
    use epoll;
    worker_connections  1024;
}

3、创建/etc/supervisor.conf,内容为:

[supervisord]
nodaemon=true

[program:nginx]
command=/usr/sbin/nginx
stopsignal=QUIT

[program:php-fpm]
command=/opt/remi/php71/root/sbin/php-fpm –nodaemonize
stopsignal=QUIT

4、运行Dockerfile

docker build -t yourname/nginx-php .

到这里,这个镜像就完成了,可以简单的测试一下:

docker run -d –name LNP -p 80:80 yourname/nginx-php

然后用命令docker ps -a 查看下这个容器是否正常启动,如果有问题,可以docker logs -f nginx-php 查看下这个容器启动在哪里出了问题。