Kubernetes 企業級線下環境落地實踐

2019.11.07晚21:00直播。

一、Kubernetes 環境配置

https://github.com/easzlab/kubeasz
https://github.com/opsnull/follow-me-install-kubernetes-cluster

二、通過dockerfile構建BaseImage,服務鏡像

容器服務的基礎鏡像構建

FROM harbor.qa.com.cn/public/centos:6.9
LABEL vendor=OC \
      sgplm-ep.is-production="" \
      sgplm-ep.version="1.0.2" \
      sgplm-ep.release-date="2018-10-24"

COPY sysctl.conf /etc/sysctl.conf
RUN rpm -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm && yum -y update && yum install -y \
    iperf \
    mtr \
    python-devel \
    python-markupsafe \
    python-pip \
    openssl-devel \
    swig \
    python-setuptools \
    wget \
    ssmtp \
    man \
    openssh-clients \
    subversion \
    git \
    libtool \
    cmake \
    openssl-devel \
    lua-filesystem \
    yum-utils \
    rpm-build \
    patch \
    make \
    gcc \
    gcc-c++ \
    iftop \
    telnet \
    vim-enhanced \
    lua-socket \
    tree \
    bc \
    iotop \
    logrotate \
    rsync \
    haproxy \
    vixie-cron \
    && yum clean all \
    && /bin/cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone \
    && useradd -s /sbin/nologin redis \
    && echo '10 00 * * * sync && echo 1 > /proc/sys/vm/drop_caches >/dev/null 2>&1' >> /var/spool/cron/root \
    && echo '23 30 * * * find /data/logs/ ! -path "/data/logs/redis/*" -mtime +5 -name "*.log.*" -exec rm -f {} \; >/dev/null 2>&1' >> /var/spool/cron/root && /etc/init.d/crond restart \
    && mkdir /tmp/pkgs && cd /tmp/pkgs && wget http://172.31.0.19:8555/jdk-8u144-linux-x64.tar.gz \
    && tar zxvf jdk-8u144-linux-x64.tar.gz -C /usr/local/ \
    && mv /usr/local/jdk1.8.0_144/ /usr/local/jdk1.8 && echo -e 'export JAVA_HOME="/usr/local/jdk1.8" \nPATH=$JAVA_HOME/bin:$PATH \nexport PATH\nCLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar\nexport CLASSPATH' >>/etc/profile.d/java.sh && source /etc/profile.d/java.sh \
    && wget http://172.31.0.19:8555/libzmq.tar.gz && tar zxf libzmq.tar.gz -C /usr/local/ && cd /usr/local/libzmq \
    && if [ ! -d cmake-build ];then mkdir cmake-build;fi && cd cmake-build && cmake .. && make -j 4 && make test && make install && ldconfig \
    && cd - && temp=`find / -name libzmq.so.5.1.3 | grep cmake-build/lib | tail -n 1` && ln -s $temp /usr/lib/ && ldconfig \
    && wget http://172.31.0.19:8555/go1.8.3.linux-amd64.tar.gz && tar -C /usr/local -xzf go1.8.3.linux-amd64.tar.gz \
    && mkdir /home/gospace \
    && echo -e 'export PATH=$PATH:/usr/local/go/bin \nexport GOPATH=/home/gospace \nexport GOROOT=/usr/local/go/' >>/etc/profile.d/go.sh \
    && source /etc/profile.d/go.sh && export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig/ && go get "github.com/pebbe/zmq4" \
    #&& temp=`find / -name libzmq.so.5.1.3 | grep cmake-build/lib` && ln -s $temp /usr/lib/ && ldconfig \
    && wget http://172.31.0.19:8555/apache-maven-3.5.0-bin.tar.gz && tar zxf apache-maven-3.5.0-bin.tar.gz -C /usr/local/ \
    && ln -s /usr/local/apache-maven-3.5.0 /usr/local/maven3 \
    && echo -e 'export M3_HOME=/usr/local/maven3 \nexport PATH=${M3_HOME}/bin:${PATH}' >> /etc/profile.d/maven3.sh && source /etc/profile.d/maven3.sh \
    && rm -rf /tmp/pkgs/*

CMD [ "bash" ]

sysctl.conf

net.ipv4.ip_forward = 0
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.default.accept_source_route = 0
kernel.sysrq = 0
kernel.core_uses_pid = 1
net.ipv4.tcp_syncookies = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
#kernel.shmmax = 4294967295
#kernel.shmall = 268435456
kernel.printk = 2
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv4.conf.all.promote_secondaries = 1
net.ipv4.conf.default.promote_secondaries = 1
net.ipv6.neigh.default.gc_thresh3 = 4096 
net.ipv4.neigh.default.gc_thresh3 = 4096
kernel.softlockup_panic = 1
kernel.watchdog_thresh = 60
net.ipv4.tcp_keepalive_time = 30
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_max_tw_buckets = 180000
kernel.core_pattern = /var/core/%e.%p-%c-%t.core
vm.swappiness = 0
vm.overcommit_memory = 1
net.core.somaxconn= 1024
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 262144
net.netfilter.nf_conntrack_max = 655350 
net.netfilter.nf_conntrack_tcp_timeout_established = 300

編輯好dockerfile,準備好相關的文件,執行Build

docker build -t harbor.qa.com.cn/public/sgplm-ep:v1.2 .

容器服務(GO)使用baseimage構建

FROM harbor.qa.com.cn/public/sgplm-ep:v1.2
LABEL vendor=OC \
      sgplm-signalproxy.is-production="" \
      sgplm-signalproxy.version="1.1" \
      sgplm-signalproxy.release-date="2019-06-06"
MAINTAINER SignalingTeam "@s.com.cn"

RUN mkdir -p /usr/local/signalproxy/cert /data/logs/signalproxy
COPY signalproxy conf.json /usr/local/signalproxy/
COPY cert /usr/local/signalproxy/cert

容器服務(JAVA)使用baseimage構建

FROM harbor.qa.com.cn/public/sgplm-ep:v1.2
LABEL vendor=OC \
      sgplm-dispatcher.is-production="" \
      sgplm-dispatcher.version="<build_tag>" \
      sgplm-dispatcher.release-date="2019-06-06"
MAINTAINER SignalingTeam "@s.com.cn"

RUN mkdir -p /usr/local/dispatcher/ /data/logs/dispatcher
COPY dispatcher /usr/local/dispatcher/dispatcher-etcd.jar
COPY keyStore.p12 logback-spring.xml application.properties /usr/local/dispatcher/

三、Kubernetes 部署Jenkins,配置動態slave(docker in docker)

新建一個 Deployment:(jenkins2.yaml)

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: jenkins2
  namespace: ops
spec:
  template:
    metadata:
      labels:
        app: jenkins2
    spec:
      terminationGracePeriodSeconds: 10
      serviceAccount: jenkins2
      containers:
      - name: jenkins
        image: jenkins/jenkins:lts
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          name: web
          protocol: TCP
        - containerPort: 50000
          name: agent
          protocol: TCP
        resources:
          limits:
            cpu: 2
            memory: 2Gi
          requests:
            cpu: 2
            memory: 2048Mi
        livenessProbe:
          httpGet:
            path: /login
            port: 8080
          initialDelaySeconds: 60
          timeoutSeconds: 5
          failureThreshold: 12
        readinessProbe:
          httpGet:
            path: /login
            port: 8080
          initialDelaySeconds: 60
          timeoutSeconds: 5
          failureThreshold: 12
        volumeMounts:
        - name: jenkinshome
          subPath: jenkins2
          mountPath: /var/jenkins_home
        env:
        - name: LIMITS_MEMORY
          valueFrom:
            resourceFieldRef:
              resource: limits.memory
              divisor: 1Mi
        - name: JAVA_OPTS
          value: -Xmx$(LIMITS_MEMORY)m -XshowSettings:vm -Dhudson.slaves.NodeProvisioner.initialDelay=0 -Dhudson.slaves.NodeProvisioner.MARGIN=50 -Dhudson.slaves.NodeProvisioner.MARGIN0=0.85 -Duser.timezone=Asia/Shanghai
      securityContext:
        fsGroup: 1000
      volumes:
      - name: jenkinshome
        persistentVolumeClaim:
          claimName: jenkinspvc

---
apiVersion: v1
kind: Service
metadata:
  name: jenkins2
  namespace: ops
  labels:
    app: jenkins2
spec:
  selector:
    app: jenkins2
  type: NodePort
  ports:
  - name: web
    port: 8080
    targetPort: web
    nodePort: 30302
  - name: agent
    port: 50000
    targetPort: agent

資源對象都放置在一個名爲 ops 的 namespace 下面,所以我們需要添加創建一個 namespace:

kubectl create namespace ops

這裏使用一個名爲 jenkins/jenkins:lts 的鏡像,這是 jenkins 官方的 Docker 鏡像,然後也有一些環境變量,當然我們也可以根據自己的需求來定製一個鏡像,比如我們可以將一些插件打包在自定義的鏡像當中,可以參考文檔:https://github.com/jenkinsci/docker,我們這裏使用默認的官方鏡像就行,另外一個還需要注意的是我們將容器的 /var/jenkins_home 目錄掛載到了一個名爲 opspvc 的 PVC 對象上面,所以我們同樣還得提前創建一個對應的 PVC 對象,當然我們也可以使用我們前面的 StorageClass 對象來自動創建:(pvc.yaml)

apiVersion: v1
kind: PersistentVolume
metadata:
  name: jenkinspv
spec:
  capacity:
    storage: 50Gi
  accessModes:
  - ReadWriteMany
  persistentVolumeReclaimPolicy: Delete
  nfs:
    server: 172.31.0.41
    path: /data/jenkins2

---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: jenkinspvc
  namespace: ops
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 50Gi

創建需要用到的 PVC 對象:

kubectl create -f pvc.yaml

另外我們這裏還需要使用到一個擁有相關權限的 serviceAccount:jenkins2,這裏只是給 jenkins 賦予了一些必要的權限,當然如果你對 serviceAccount 的權限不是很熟悉,給這個 sa 綁定一個 cluster-admin 的集羣角色權限也是可以的,當然這樣具有一定的安全風險:(rbac.yaml)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins2
  namespace: ops

---

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: jenkins2
rules:
  - apiGroups: ["extensions", "apps"]
    resources: ["deployments"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["create","delete","get","list","patch","update","watch"]
  - apiGroups: [""]
    resources: ["pods/exec"]
    verbs: ["create","delete","get","list","patch","update","watch"]
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get","list","watch"]
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get"]

---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: jenkins2
  namespace: ops
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: jenkins2
subjects:
  - kind: ServiceAccount
    name: jenkins2
    namespace: ops

創建 rbac 相關的資源對象:

kubectl create -f rbac.yaml

創建資源之前更改一下nfs服務共享目錄的屬主

chown -R 1000 /data/k8s/jenkins2

爲了方便我們測試,我們這裏通過 NodePort 的形式來暴露 Jenkins 的 web 服務,固定爲30302端口,另外還需要暴露一個 agent 的端口,這個端口主要是用於 Jenkins 的 master 和 slave 之間通信使用
資源準備好後,我們直接創建 Jenkins 服務:

kubectl create -f jenkins2.yaml

創建完成後,要去拉取鏡像可能需要等待一會兒,然後我們查看下 Pod 的狀態:

kubectl get pods -n ops

NAME                        READY     STATUS    RESTARTS   AGE
jenkins2-6fd324fg31-poqtr   1/1       Running   0          2m

如果pod狀態有問題,使用kubectl describe pod jenkins2-6fd324fg31-poqtr -n ops 和 kubectl logs -f jenkins2-6fd324fg31-poqtr -n ops 指令來排查問題

服務啓動成功後,我們就可以根據任意節點的 IP:30302 端口就可以訪問 jenkins 服務了,可以根據提示信息進行安裝配置即可:
Kubernetes 企業級線下環境落地實踐

初始化的密碼我們可以在 jenkins 的容器的日誌中進行查看,也可以直接在 nfs 的共享數據目錄中查看:

cat /data/k8s/jenkins2/secrets/initAdminPassword

然後選擇安裝推薦的插件即可
Kubernetes 企業級線下環境落地實踐

安裝完成後添加管理員帳號即可進入到 jenkins 主界面:

配置過程

第1步. 我們需要安裝kubernetes plugin, 點擊 Manage Jenkins -> Manage Plugins -> Available -> Kubernetes plugin 勾選安裝即可

Kubernetes 企業級線下環境落地實踐

第2步. 安裝完畢後,點擊 Manage Jenkins —> Configure System —> (拖到最下方)Add a new cloud —> 選擇 Kubernetes,然後填寫 Kubernetes 和 Jenkins 配置信息
Kubernetes 企業級線下環境落地實踐

注意 namespace,我們這裏填 ops,然後點擊Test Connection,如果出現 Connection test successful 的提示信息證明 Jenkins 已經可以和 Kubernetes 系統正常通信了,然後下方的 Jenkins URL 地址:http://jenkins2.kube-ops.svc.cluster.local:8080,這裏的格式爲:服務名.namespace.svc.cluster.local:8080,根據上面創建的jenkins 的服務名填寫,我這裏是之前創建的名爲jenkins,如果是用上面我們創建的就應該是jenkins2

另外需要注意,如果這裏 Test Connection 失敗的話,很有可能是權限問題,這裏就需要把我們創建的 jenkins 的 serviceAccount 對應的 secret 添加到這裏的 Credentials 裏面。

第3步. 配置 Pod Template,其實就是配置 Jenkins Slave 運行的 Pod 模板,命名空間我們同樣是用 kube-ops,Labels 這裏也非常重要,對於後面執行 Job 的時候需要用到該值,然後我們這裏使用的是 zhangchuan/jenkins:jnlp 這個鏡像,這個鏡像是在官方的 jnlp 鏡像基礎上定製的,加入了 kubectl 等一些常用的工具。

Kubernetes 企業級線下環境落地實踐

Kubernetes 企業級線下環境落地實踐

這裏需要注意我們這裏需要在下面掛載兩個主機目錄,一個是 /var/run/docker.sock,該文件是用於 Pod 中的容器能夠共享宿主機的 Docker,這就是大家說的 docker in docker 的方式,Docker 二進制文件我們已經打包到上面的鏡像中了,另外一個目錄下 /root/.kube 目錄,我們將這個目錄掛載到容器的 /home/jenkins/.kube 目錄下面這是爲了讓我們能夠在 Pod 的容器中能夠使用 kubectl 工具來訪問我們的 Kubernetes 集羣,方便我們後面在 Slave Pod 部署 Kubernetes 應用。

因爲 Jenkins Slave Pod 中沒有配置權限,所以需要配置上 ServiceAccount,在 Slave Pod 配置的地方點擊下面的高級,添加上對應的 ServiceAccount 即可:
Kubernetes 企業級線下環境落地實踐

至此,Kubernetes插件配置就完成了。

測試

在 Jenkins 首頁點擊 創建一個任務,創建一個測試的任務,輸入任務名稱,然後我們選擇 構建一個自由風格的軟件項目 類型的任務:
Kubernetes 企業級線下環境落地實踐

注意在下面的 Label Expression 這裏要填入oc,就是前面我們配置的 Slave Pod 中的 Label,這兩個地方必須保持一致

Kubernetes 企業級線下環境落地實踐

在 構建 區域選擇 執行shell

Kubernetes 企業級線下環境落地實踐

.........

完成的安裝文檔鏈接: https://pan.baidu.com/s/1GZfOl7Ry3J-2xlqRY3N6OA 提取碼: iwy9

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章