共计 7926 个字符,预计需要花费 20 分钟才能阅读完成。
将项目迁移到 k8s 平台是怎样实现的?
- 制作镜像
- 控制器管理 Pod
- Pod 数据持久化
- 暴露应用
- 对外发布应用
- 日志 / 监控
1、制作镜像分为三步
- 第一基础镜像,是基于哪个操作系统,比如 Centos7 或者其他的
- 第二步中间件镜像,比如服务镜像,跑的像 nginx 服务,tomcat 服务
- 第三步项目镜像,它是服务镜像之上的,将你的项目打包进去,那么这个项目就能在你这个服务镜像里面运行了
一般运维人员都是提前将镜像做好,而开发人员就能直接拿这个镜像去用,这个镜像一定要符合现在环境部署的环境。
2、控制器管理 pod
也就是 k8s 去部署这个镜像了,一般我们都会去拿控制器去部署,用的最多的就是 deployment
- Deployment:无状态部署
- StatefulSet:有状态部署
- DaemonSet:守护进程部署
- Job & CronJob:批处理
无状态和有状态的有什么区别?
有状态的是有身份的,比如网络 ID、存储、这个两个是提前规划好的,有序启动 / 停止
持久化与非持久化
3、Pod 数据持久化
pod 数据持久化主要是因对一个应用程序说的,比如开发一个项目,这个项目有没有落地到本地文件,如果有落的话,就保证他持久的有了,那就必须要用到 pod 数据的持久化了。
容器部署过程中一般有以下三种数据:
- 启动时需要的初始数据,可以是配置文件
- 启动过程中产生的临时数据,该临时数据需要多个容器间共享
- 启动过程中产生的持久化数据
4、暴露应用
在 k8s 中,部署一个 deployment,它是无法对外进行访问的,即其他应用程序要想访问部署的 deployment,它找不到该怎么去访问。为什么去这么讲,因为 deployment 一般都是多副本的去部署,有可能会分布在不同的节点之上,而且重建 pod ip 也会变,重新发布一下也会变了,所以没有办法去固定去访问哪个 pod,即使固定了,其他的 pod 也访问不了。
要想做到多个 pod 都去提供服务的话,前面有必须要加一个负载均衡,提供一个访问入口,只有访问这个统一入口,才能转发到后端多个 pod 上,只要访问这个 Cluster IP 就能转发到后端的 pod 上。
Service
- Service 定义了 Pod 的逻辑集合和访问这个集合的策略
- Service 引入为了解决 Pod 的动态变化,提供服务发现和负载均衡
- 使用 CoreDNS 解析 Service 名称
5、对外发布应用
暴露出去之后呢,也就是需要让用户去访问,比如搭建一个电商网站,让用户去访问,ingress 相对于 service,它是一个互补的状态,弥补了各自,service 主要提供了集群内部的访问,也可以暴露一个 TCP/UDP 的端口,而 ingress 主要是一个 7 层的转发,也就是提供一个统一的入口,只要访问 ingress controller,它就能帮你转发你部署所有的项目,也就是所有的项目都使用域名去访问。
首先开发者将代码部署到你的代码仓库中,主流的用的 Git 或者 gitlab,提交完代码通过 CI/CD 平台需要对代码进行拉取、编译、构建,产生一个 War 包,然后交给 Ansible 然后发送到云主机上 / 物理机, 然后通过负载均衡将项目暴露出去,然后会有数据库,监控系统,日志系统来提供相关的服务。
首先也是开发将代码放在代码仓库,然后通过 jenkins 去完成拉取代码,编译,上传到我们的镜像仓库。
这里是将代码打包成一个镜像,而不是可以执行的 war 或者 jar 包,这个镜像包含了你的项目的运行环境和项目代码,这个镜像可以放在任何 docker 上去 run 起来,都可以去访问,首先得保证能够在 docker 上去部署起来,再部署到 k8s 上,打出来的镜像去放在镜像仓库中,来集中的去管理这些镜像。
因为每天会产生几十个或者上百个镜像,必须通过镜像仓库去管理,这里可能会去写一个脚本去连接 k8smaster,而 k8s 会根据自己的部署去调度这些 pod, 然后通过 ingress 去发布我们的应用,让用户去访问,每个 ingress 会关联一组 pod,而 service 会创建这组 pod 的负载均衡,通过 service 去区分这些节点上的 Pod。
然后数据库是放在集群之外,监控系统日志系统也可以放在 k8s 集群放在去部署,也可以放在之外,我们是放在 k8s 集群内的,也不是特别敏感,主要用来运维和开发调试用的,不会影响到我们的业务,所以我们优先去 k8s 中去部署。
现在以部署一个 JAVA 项目到我们的 k8s 中
一、安装一个 openjdk
[root@k8s-master ~]# yum -y install java-1.8.0-openjdk.x86_64 maven
[root@k8s-master ~]# java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)
然后我们将代码拉到本地一般 Dockerfile 中跟我们的代码都放在同一目录下,
[root@k8s-master tomcat-java-demo-master]# ls
db Dockerfile LICENSE pom.xml README.md src
[root@k8s-master tomcat-java-demo-master]# vim Dockerfile
FROM lizhenliang/tomcat
LABEL maintainer zhaochengcheng
RUN rm -rf /usr/local/tomcat/webapps/*
ADD target/*.war /usr/local/tomcat/webapps/ROOT.war
二、进行编译
这里我们需要配置 maven 的国内源,这样的话就比较快一点
[root@k8s-master CI]# vim /etc/maven/settings.xml
<mirror>
<id>central</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
[root@k8s-master tomcat-java-demo-master]# mvn clean package -D maven test.skip=true
[root@k8s-master tomcat-java-demo-master]# ls
db Dockerfile LICENSE pom.xml README.md src target
[root@k8s-master tomcat-java-demo-master]# cd target/
[root@k8s-master target]# ls
classes generated-sources ly-simple-tomcat-0.0.1-SNAPSHOT ly-simple-tomcat-0.0.1-SNAPSHOT.war maven-archiver maven-status
[root@k8s-master tomcat-java-demo-master]# cd target/
我们就使用这个编译好的 war 包, 然后打成镜像,上传到我们的 Harbor 仓库里
[root@k8s-master target]# ls
classes ly-simple-tomcat-0.0.1-SNAPSHOT maven-archivergenerated-sources
ly-simple-tomcat-0.0.1-SNAPSHOT.war maven-status
[root@k8s-master tomcat-java-demo-master]# docker build -t 192.168.30.24/library/java-demo:latest .
三、上传到镜像仓库
[root@k8s-master tomcat-java-demo-master]# docker login 192.168.30.24
Username: admin
Password:
Error response from daemon: Get https://192.168.30.24/v2/: dial tcp 192.168.30.24:443: connect: connection refused
这里报错,其实我们需要在每台 docker 下都要写入对 harbor 仓库的信任才可以,后面上传镜像也会用
[root@k8s-master java-demo]# vim /etc/docker/daemon.json
{"registry-mirrors":["http://f1361db2.m.daocloud.io"],
"insecure-registries": ["192.168.30.24"]
}
再等录一下 push 就可以了
[root@k8s-master tomcat-java-demo-master]# docker push 192.168.30.24/library/java-demo:latest
四、控制器管理 pod
编写 deployment, 一般项目都写到自定义的命名空间下,名称写项目名称,方便记忆,name: tomcat-java-demo
namespace: test
另外就是下一个项目名称,这里分为多个,一般有很多的组件组成,所以下面可以写个 app 的名称,比如组件 1、2、3,起码标签有这两个维度
project: www
app: java-demo
另外就是镜像拉取,在哪个仓库去下载,这里我建议镜像仓库的项目名称和我们定义的是一种,避免混了。我重新打个标签,并传到我们的私有镜像仓库中
[root@k8s-master java-demo]# docker tag 192.168.30.24/library/java-demo 192.168.30.24/tomcat-java-demo/java-demo
[root@k8s-master java-demo]# docker push 192.168.30.24/tomcat-java-demo/java-demo:latest
镜像地址也改一下地址
imagePullSecrets:
- name: registry-pull-secret
containers:
- name: tomcat
image: 192.168.30.24/tomcat-java-demo/java-demo:latest
现在开始创建 yaml
创建项目的命名空间
[root@k8s-master java-demo]# vim namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: test
[root@k8s-master java-demo]# kubectl create -f namespace.yaml
namespace/test created
[root@k8s-master java-demo]# kubectl get ns
NAME STATUS AGE
default Active 22h
kube-node-lease Active 22h
kube-public Active 22h
kube-system Active 22h
test Active 5s
创建一个 secret 来保证我们 harbor 镜像仓库的认证信息,这里一定要写上我们的项目的命名空间。
[root@k8s-master java-demo]# kubectl create secret docker-registry registry-pull-secret --docker-username=admin --docker-password=Harbor12345 --docker-email=111@qq.com --docker-server=192.168.30.24 -n test
secret/registry-pull-secret created
[root@k8s-master java-demo]# kubectl get ns
NAME STATUS AGE
default Active 23h
kube-node-lease Active 23h
kube-public Active 23h
kube-system Active 23h
test Active 6m39s
[root@k8s-master java-demo]# kubectl get secret
NAME TYPE DATA AGE
default-token-2vtgm kubernetes.io/service-account-token 3 23h
registry-pull-secret kubernetes.io/dockerconfigjson 1 46s
[root@k8s-master java-demo]# vim deployment.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: tomcat-java-demo
namespace: test
spec:
replicas: 3
selector:
matchLabels:
project: www
app: java-demo
template:
metadata:
labels:
project: www
app: java-demo
spec:
imagePullSecrets:
- name: registry-pull-secret
containers:
- name: tomcat
image: 192.168.30.24/tomcat-java-demo/java-demo:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
name: web
protocol: TCP
resources:
requests:
cpu: 0.5
memory: 1Gi
limits:
cpu: 1
memory: 2Gi
livenessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 20
readinessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 60
timeoutSeconds: 20
[root@k8s-master java-demo]# kubectl get pod -n test
NAME READY STATUS RESTARTS AGE
tomcat-java-demo-6d798c6996-fjjvk 1/1 Running 0 2m58s
tomcat-java-demo-6d798c6996-lbklf 1/1 Running 0 2m58s
tomcat-java-demo-6d798c6996-strth 1/1 Running 0 2m58s
另外就是暴露一个 Service, 这里的标签也要保持一致,不然他找不到相应的标签就提供不了服务,这里我们是使用 ingress 来访问发布应该,直接使用 ClusterIP 就可以
[root@k8s-master java-demo]# vim service.yaml
apiVersion: v1
kind: Service
metadata:
name: tomcat-java-demo
namespace: test
spec:
selector:
project: www
app: java-demo
ports:
- name: web
port: 80
targetPort: 8080
[root@k8s-master java-demo]# kubectl get pod,svc -n test
NAME READY STATUS RESTARTS AGE
pod/tomcat-java-demo-6d798c6996-fjjvk 1/1 Running 0 37m
pod/tomcat-java-demo-6d798c6996-lbklf 1/1 Running 0 37m
pod/tomcat-java-demo-6d798c6996-strth 1/1 Running 0 37m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/tomcat-java-demo ClusterIP 10.1.175.191 <none> 80/TCP 19s
测试访问我们的项目,是可以的,现在要发布出去通过 ingress
测试访问我们的项目,是可以的,现在要发布出去通过 ingress
[root@k8s-master java-demo]# curl 10.1.175.191
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title> 把美女带回家应用案例 </title>
<meta name="description" content="把美女带回家应用案例">
<meta name="keywords" content="index">
现在部署一个 ingress-nginx 的控制器,这个网上都可以找到,官方也有,我这里是按 DaemonSet 的方式去部署的,所以每个节点都会跑一个控制器。
[root@k8s-master java-demo]# kubectl get pod -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-g95pp 1/1 Running 0 3m6s
nginx-ingress-controller-wq6l6 1/1 Running 0 3m6s
发布应用
这里注意两点,第一个就是网站域名,一个是 service 的命名空间。
[root@k8s-master java-demo]# kubectl get pod,svc -n test
NAME READY STATUS RESTARTS AGE
pod/tomcat-java-demo-6d798c6996-fjjvk 1/1 Running 0 53m
pod/tomcat-java-demo-6d798c6996-lbklf 1/1 Running 0 53m
pod/tomcat-java-demo-6d798c6996-strth 1/1 Running 0 53m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/tomcat-java-demo ClusterIP 10.1.175.191 <none> 80/TCP 16m
[root@k8s-master java-demo]# vim service.yaml
[root@k8s-master java-demo]# kubectl create -f ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: tomcat-java-demo
namespace: test
spec:
rules:
- host: java.maidikebi.com
http:
paths:
- path: /
backend:
serviceName: tomcat-java-demo
servicePort: 80
另外我这边是测试的,所以绑定我本地的 hosts 来进行访问,在 hosts 文件里面加入域名和和节点 ip 就能访问到我们的项目了。