k8s搭配traefik

Monday, November 15, 2021

概述

这篇文章是记录ubuntu系统从头安装k8s及traefik,通过一个小示例完成全部操作。

开始之前,先说明下本次用到的硬件及软件环境:

  1. 服务器:腾讯云CVM,4核8G,至少4核,核心太少后续 prometheus 和 traefik 都起不来。

  2. ubuntu:20.0.4 lts

  3. kubernetes:v1.21.5

  4. kubesphere:v3.2.0

  5. kubekey:v1.2.0

  6. traefik:v2.5.4

整体的架构如下:

  1. 所有的自定义内容都在 demo 这个命名空间下

  2. 启动一个服务 music,访问时打印 this is music server!

  3. 启动一个服务 video,访问时打印 this is video server!

  4. 启用 ingress,定义两个路由

    • music.demo.wcxst.com: 对应 music 服务

    • video.demo.wcxst.com: 对应 video 服务

  5. 启动 traefik,监听 80 和 443 端口

要实现的目标:

  1. traefik.demo.wcxst.com/dashboard 访问到 video 的 dashboard
  2. music.demo.wcxst.com 访问到 music 服务
  3. video.demo.wcxst.com 访问到 video 服务

本文章的所有代码都在 https://github.com/jormin/k8s-traefik-demo

开始

解析域名

开始之前先将要用到的三个域名解析到对应的服务器IP:

  1. traefik.demo.wcxst.com
  2. music.demo.wcxst.com
  3. Video.demo.wcxst.com

搞定服务器

测试时,我是在腾讯云买了一个实时计费的4核8G服务器,测试完毕后就释放了,费用一小时¥0.5左右。

配置安全组端口

开始之前先配置下服务器安全组的端口,kubesphere 需要某些端口用于服务之间的通信。如果您的网络配置有防火墙规则,则需要确保基础设施组件可以通过特定端口相互通信。这些端口用作某些进程或服务的通信端点。

服务 协议 行为 起始端口 结束端口 备注
ssh TCP allow 22
etcd TCP allow 2379 2380
apiserver TCP allow 6443
calico TCP allow 9099 9100
bgp TCP allow 179
nodeport TCP allow 30000 32767
master TCP allow 10250 10258
dns TCP allow 53
dns UDP allow 53
local-registry TCP allow 5000 离线环境需要
local-apt TCP allow 5080 离线环境需要
rpcbind TCP allow 111 使用 NFS 时需要
ipip IPENCAP / IPIP allow Calico 需要使用 IPIP 协议
metrics-server TCP allow 8443
启用root账号

服务器启动后默认是 ubuntu 账号,需要登录后启动 root 账号并设置密码,之后用root登录。

用root操作仅仅是因为方便,没有考虑安全因素,实际情况依据具体情况操作。

# 启动 root
sudo sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
sudo service sshd restart

# 设置root密码
sudo passwd root
安装软件

设置好密码后退出用root登录,接着进行初始化,安装依赖的常用软件,并且安装 docker、docker-compose、kubernetes、kubesphere 等等,安装时会要求输入两项内容:

  1. hostname:修改服务器的hostname,这里我设置的是 demo,可以改为自己喜欢的,这个也是 k8s 的节点名称。
  2. ssh公钥:用于免密登录

脚本如下:

#!/bin/bash

# 设置主机名
echo "1. 设置hostname"
currentHostname=$(hostname)
echo "当前hostname:$currentHostname"
read -p "请输入hostname(直接回车不修改):" hostname
if [ -z "${hostname}" ];then
    hostname=$currentHostname
fi
hostnamectl set-hostname $hostname
echo ""

# 设置sshd
echo "2. 设置sshd"
ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa
sed -i -e 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' -e 's/PasswordAuthentication yes/PasswordAuthentication no/' -e 's/#ClientAliveInterval 0/ClientAliveInterval 60/' -e 's/#ClientAliveCountMax 3/ClientAliveCountMax 30/' /etc/ssh/sshd_config
service sshd restart
read -p "请输入免密登录公钥:" pubkey
cat > ~/.ssh/authorized_keys <<EOF
$pubkey
EOF
echo ""

echo "3. 设置时区为 Asia/Shanghai"
sudo timedatectl set-timezone Asia/Shanghai
echo ""

echo "4. 切换阿里源"
sudo cp -ra /etc/apt/sources.list /etc/apt/sources.list.bak
sudo sed -i -e 's#http://cn.archive.ubuntu.com/ubuntu#http://mirrors.aliyun.com/ubuntu#' -e 's#http://mirrors.tencentyun.com/ubuntu#http://mirrors.aliyun.com/ubuntu#' /etc/apt/sources.list
sudo apt-get update
sudo apt-get upgrade
echo ""

echo "5. 关闭防火墙和Selinux"
sudo ufw disable
sudo ufw status
sudo apt install -y policycoreutils
sudo sestatus -v
echo ""

echo "6. 关闭swap"
swapoff -a
echo ""

echo "7. 设置 alias"
echo "alias ll=\"ls -la\"" >> ~/.bash_profile
source ~/.bash_profile
echo ""

echo "8. 安装 docker"
sudo apt-get remove docker docker-engine docker.io containerd runc
sudo apt-get update
sudo apt-get install -y \
    net-tools \
    unzip \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg \
    lsb-release \
    conntrack
sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
mkdir /etc/docker
sudo cat > /etc/docker/daemon.json <<EOF
{
    "exec-opts": ["native.cgroupdriver=systemd"],
    "log-driver": "json-file",
    "log-opts": {
    "max-size": "100m"
    },
    "storage-driver": "overlay2",
    "registry-mirrors":[
        "https://mirror.ccs.tencentyun.com",
        "https://docker.mirrors.ustc.edu.cn",
        "https://registry.docker-cn.com"
    ]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo systemctl enable docker
echo ""

echo "9. 安装 docker compose"
sudo curl -L "http://download.lerzen.com/docker-compose-Linux-x86_64" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
echo ""

echo "10. 处理dns"
sed -i 's/#DNS=/DNS=114.114.114.114/' /etc/systemd/resolved.conf
service systemd-resolved restart
systemctl enable systemd-resolved
mv /etc/resolv.conf /etc/resolv.conf.bak
ln -s /run/systemd/resolve/resolv.conf /etc/
echo ""

echo "11. 安装kubernetes和kubesphere"
export KKZONE=cn
curl -sfL https://get-kk.kubesphere.io | VERSION=v1.2.0 sh -
chmod +x kk
./kk create cluster --with-kubernetes v1.21.5 --with-kubesphere v3.2.0
echo ""

安装完成后访问 [公网ip:30880] 访问 kubesphere,初始账号密码为 admin/P@88w0rd,首次登录会要求重置密码,正常操作即可。

image-20211116110436308

修改 kubenetes 默认端口范围

kubenetes 默认的端口范围为 30000-32767,修改为 1-65535,因为我们后续的 traefik 需要监听 80 和 443 端口,不修改的话会报如下错:

Invalid value: 80: provided port is not in the valid range. The range of valid ports is 30000-32767

修改方法:

编辑 /etc/kubernetes/manifests/kube-apiserver.yaml,找到 –service-cluster-ip-range 这行,在这行下面新增 - –service-node-port-range=1-65535

vi /etc/kubernetes/manifests/kube-apiserver.yaml

修改后如下:

spec:
  containers:
  - command:
    ...
    - --service-cluster-ip-range=10.233.0.0/18
    - --service-node-port-range=1-65535
    ...
    image: registry.cn-beijing.aliyuncs.com/kubesphereio/kube-apiserver:v1.21.5
    imagePullPolicy: IfNotPresent
    livenessProbe:

重新加载

systemctl daemon-reload
systemctl restart kubelet

创建demo命名空间

服务器上执行 kubectl apply -f namespace.yaml 创建命名空间,配置文件如下:

apiVersion: v1
kind: Namespace
metadata:
  name: demo

两个小服务

上述操作后我们已经有了一个部署好 kubenetes 和 kubesphere 的服务器,接下来我们写两个小服务并部署到 kubenetes 上。

这里仅用于测试,我用 go 写了两个很简单的http服务,分别打印 musicvideo 服务的内容,然后编译打包为镜像上传到 dockerhub,两个镜像我已经上传,可以直接使用:

  1. jormin/music:latest
  2. jormin/video:latest

以下是 music 内容,video 服务类似,修改对应内容即可。

  1. main.go

    package main
    
    import (
    	"fmt"
    	"net/http"
    )
    
    // handler 根处理器
    func handler(w http.ResponseWriter, r *http.Request) {
    	_, _ = fmt.Fprintf(w, "this is music server!")
    }
    
    func main() {
    	http.HandleFunc("/", handler)
    	_ = http.ListenAndServe(":80", nil)
    }
    
  2. dockerfile

    FROM alpine:latest
    
    # 设置固定的项目路径
    ENV WORKDIR /app
    
    # 添加应用可执行文件,并设置执行权限
    ADD ./video   $WORKDIR/video
    RUN chmod +x $WORKDIR/video
    
    RUN echo -e http://mirrors.ustc.edu.cn/alpine/v3.7/main/ > /etc/apk/repositories \
        && apk update \
        && apk add tzdata \
        && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
        && echo "Asia/Shanghai" > /etc/timezone
    
    WORKDIR $WORKDIR
    CMD ./video
    
  3. k8s

    service 里面给服务指定了 nodePort,仅仅用于部署 traefik 前验证服务是否正确。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: music
      namespace: demo
    spec:
      replicas: 1
      minReadySeconds: 1
      strategy:
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 0
      selector:
        matchLabels:
          app: music
      template:
        metadata:
          name: music
          labels:
            app: music
        spec:
          containers:
            - name: music
              image: jormin/music:latest
              ports:
                - containerPort: 80
                  protocol: TCP
              readinessProbe:
                periodSeconds: 60
                httpGet:
                  path: /
                  port: 80
    
    ---
    
    apiVersion: v1
    kind: Service
    metadata:
      name: music
      namespace: demo
    spec:
      type: NodePort
      selector:
        app: music
      # 端口
      ports:
        - port: 80
          targetPort: 80
          nodePort: 31801
    

服务器上使用 kubectl apply -f 部署两个服务,部署后如下:

image-20211116111018953

创建 ingress

这里创建了两个路由,music.demo.wcxst.comvideo.demo.wcxst.com,配置文件如下,使用 kubectl apply -f xxx.yaml 执行即可。

ingress-rbac.yaml

apiVersion: v1
kind: ServiceAccount
metadata:
  name: ingress
  namespace: kube-system

---

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: ingress
subjects:
  - kind: ServiceAccount
    name: ingress
    namespace: kube-system
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: traefik-ingress
  namespace: demo
spec:
  rules:
    - host: music.demo.wcxst.com
      http:
        paths:
          - path: /
            pathType: Exact
            backend:
              service:
                name: music
                port:
                  number: 80
    - host: video.demo.wcxst.com
      http:
        paths:
          - path: /
            pathType: Exact
            backend:
              service:
                name: video
                port:
                  number: 80

traefik

这里我们使用 helm 创建 traefik,使用指定的配置文件,命令如下:

# 添加仓库
helm repo add traefik https://helm.traefik.io/traefik
# 更新
helm repo update
# 
# 使用配置文件安装
helm install --namespace=demo traefik traefik/traefik -f config.yaml

config.yaml

ports:
  traefik:
    expose: true
  web:
    nodePort: 80
  websecure:
    nodePort: 443

安装完成后,启动dashboard,增加的路由是 traefik.demo.wcxst.com/dashboard,配置文件如下:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: dashboard
  namespace: demo
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`traefik.demo.wcxst.com`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
      kind: Rule
      services:
        - name: api@internal
          kind: TraefikService

完成后如下图所示:

image-20211116113538281

此时访问 http://traefik.demo.wcxst.com/dashboard 即可看见music 和 video 两个路由

image-20211116113644087

测试

此时访问 music.demo.wcxst.com 和 video.demo.wcxst.com,即可得到预期的响应内容。

➜  ~ curl http://music.demo.wcxst.com
this is music server!%               
➜  ~ curl http://video.demo.wcxst.com                                                                                                                                                                   ➜  ~ curl http://video.demo.wcxst.com
this is video server!%                                                                                                                                                                                  ➜  ~
Kubernetes Linux Kubernetes Traefik

K8s零散小知识R620搭建K8s集群