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 对象:

扫描二维码关注公众号,回复: 7770564 查看本文章
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

猜你喜欢

转载自blog.51cto.com/51reboot/2448273