无状态服务
有状态服务
1、宠物和牛的类比,农场主的牛如果病了可以丢掉再重新买一头,如果宠物主的宠物病死了是没法找到一头一模一样的宠物的;有状态服务 可以说是 需要数据存储功能的服务、或者指多线程类型的服务,队列等(mysql数据库、kafka、zookeeper等)
2、每个实例都需要有自己独立的持久化存储,并且在k8s中是通过申明模板来进行定义;持久卷申明模板在创建pod之前创建,绑定到pod中,模板可以定义多个
说明: 有状态的 pod是用来运行有状态应用的,所以其在数据卷上存储的数据非常重要,在 Statefulset缩容时删除这个声明将是灾难性的,特别是对于 Statefulset来说,缩容就像减少其 replicas 数值一样简单。基于这个原因,当你需要释放特定的持久卷时,需要手动删除对应的持久卷声明
3、相关的k8s资源为:statefulSet,由于是有状态的服务,所以每个pod都有特定的名称和网络标识。比如pod名是由statefulSet名+有序的数字组成(0、1、2…)
4、在进行缩容操作的时候,可以明确知道会缩容哪一个pod,从数字最大的开始。并且Stat巳fulset 在有实例不健康的情况下是不允许做缩容操作的
第一步:创建存储卷pvc和配置configMap
configMap的内容就是之前docker方式启动的 my.cnf
#mysql 主节点
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection=utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
server-id=1
log-bin=mysql-bin
read-only=0
binlog-do-db=touch-air-mall-ums
binlog-do-db=touch-air-mall-pms
binlog-do-db=touch-air-mall-oms
binlog-do-db=touch-air-mall-sms
binlog-do-db=touch-air-mall-wms
binlog-do-db=demo_ds_0
binlog-do-db=demo_ds_1
replicate-ignore-db=mysql
replicate-ignore-db=sys
replicate-ignore-db=information_schema
replicate-ignore-db=performance_schema
第二步:创建有状态服务
第三步:配置主从
进入master容器,连接mysql,授权账户
mysql -uroot -p
GRANT REPLICATION SLAVE ON *.* TO 'backup'@'%' IDENTIFIED BY '123456';
进入slaver容器,配置同步数据
#host使用master的域名(DNS)
CHANGE MASTER TO MASTER_HOST='mysql-master.touch-air-mall',
MASTER_USER='backup',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.000005',MASTER_LOG_POS=439,master_port=3306;
#开启从节点
start slave;
#查看slave状态
show slave status\G;
在主库master中创建数据库
CREATE DATABASE demo_ds_0;
创建表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '主键',
`been_deleted` int(11) NULL DEFAULT 0 COMMENT '逻辑删除 0表示逻辑未删除 1表示逻辑删除',
`create_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建者',
`created` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`update_by` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新者',
`updated` datetime(0) NULL DEFAULT NULL COMMENT '修改时间',
`version` int(11) NULL DEFAULT NULL COMMENT '版本号',
`last_logged_in` datetime(0) NULL DEFAULT NULL COMMENT '上次登录时间',
`nick_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '用户昵称',
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码',
`phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '手机号',
`first_sign_in` int(11) NULL DEFAULT NULL COMMENT '首次登录:0表示未登录,1表示首次登录,2表示非首次登录',
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '账号',
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '邮箱',
`sys_dept_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '部门id',
`sys_dept_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '部门名称',
PRIMARY KEY (`id`) USING BTREE,
INDEX `idx_username_password`(`username`, `password`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '系统用户表' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
插入数据
INSERT INTO `demo_ds_0`.`user`(`id`, `been_deleted`, `create_by`, `created`, `remark`, `update_by`, `updated`, `version`, `last_logged_in`, `nick_name`, `password`, `phone`, `first_sign_in`, `username`, `email`, `sys_dept_id`, `sys_dept_name`) VALUES ('402881f773b383ae0173b383d019001b', 0, NULL, '2020-08-03 16:50:27', NULL, NULL, '2021-03-23 15:01:08', 11007, '2021-03-23 15:01:08', '管理员', '$2a$10$H57iIdDN5QigR7QOxjFtceRA1l4MSjPSJSm3t3AtyW9RaoIuc4m5y', NULL, 2, 'admin', NULL, NULL, NULL);
确认从库是否同步
由于测试机内存有限,接下来的服务就都不以集群的形式启动了,但大同小异,步骤都和MySQL主从一样
第一步:创建redis的配置文件configMap
redis-conf: appendonly yes
第二步:创建存储卷 pvc
第三步:创建有状态服务,拉取redis镜像、设置内存、挂载数据、挂载配置文件
第一步:创建es的配置文件 configMap
第二步:创建es的存储卷pvc
第三步:创建有状态服务,拉取es镜像…
kibana是ElasticSearch的可视化服务,无需挂载数据与配置,因此只需要启动无状态服务
浏览器访问暴露端口
http://192.168.83.133:31061/
部署流程图
操作步骤
Dockerfile
;Docker
按照这个Dockerfile
将项目制作成镜像jenkinsfile
基于NodePort的工作负载,创建供集群内访问的服务
mall-nacos-service
mall-sentinel-service
mall-zipkin-service
添加生产环境配置文件
将之前本地调试的所有服务host与端口号信息,切换成集群中的自定义的域名
spring.rabbitmq.host=mall-rabbitmq.touch-air-mall
spring.datasource.url=jdbc:mysql://mysql-master.touch-air-mall:3306/touch_air_mall_sms?serverTimezone=Asia/Shanghai
spring.cloud.nacos.discovery.server-addr=mall-nacos-service.touch-air-mall:8848
spring.cloud.sentinel.transport.dashboard=mall-sentinel-service:8858
spring.zipkin.base-url=http://mall-zipkin.touch-air-mall:9411/
spring.redis.host=mall-redis.touch-air-mall
renren-fast
微服务
每个微服务的根目录下新建Dockerfile
FROM java:8
#容器内暴露8080,所有微服务都一样,互不影响
EXPOSE 8080
VOLUME /tmp
ADD target/*.jar /app.jar
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-jar","/app.jar","--spring.profiles.active=prod"]
参考文件
部署Deployment
描述文件
kind: Deployment
apiVersion: apps/v1
metadata:
name: mall-auth-server
namespace: touch-air-mall
labels:
app: mall-auth-server
spec:
replicas: 1
selector:
matchLabels:
app: mall-auth-server
template:
metadata:
labels:
app: mall-auth-server
spec:
containers:
- name: mall-auth-server
image: $REGISTRY/$DOCKERHUB_NAMESPACE/$APP_NAME:latest
ports:
- name: tcp-mall-auth-server
containerPort: 8080
protocol: TCP
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 10m
memory: 10Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
restartPolicy: Always
terminationGracePeriodSeconds: 30
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
revisionHistoryLimit: 10
progressDeadlineSeconds: 600
---
kind: Service
apiVersion: v1
metadata:
name: mall-auth-server
namespace: touch-air-mall
labels:
app: mall-auth-server
annotations:
kubesphere.io/alias-name: 认证服务
kubesphere.io/serviceType: statelessservice
spec:
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
nodePort: 20001
selector:
app: mall-auth-server
type: NodePort
sessionAffinity: None
TargetPort
、Port
、NodePort
port
:【clusterIP:port】,service暴露在clusterIP
targerPort
:【容器映射端口】在pod上相当于(Dockerfile中Expose)
nodePort
:【nodeIP:nodePort】提供给外部流量访问k8s集群中service的入口
除了
NodePort
不可用重复,Port
与TargertPort
都是可以重复的
编写Jenkinsfile
pipeline {
agent {
node {
label 'maven'
}
}
environment {
DOCKER_CREDENTIAL_ID = 'dockerhub-id'
GITHUB_CREDENTIAL_ID = 'gitee-id'
KUBECONFIG_CREDENTIAL_ID = 'kubeconfig-id'
REGISTRY = 'docker.io'
DOCKERHUB_NAMESPACE = 'wlfctothemoon'
GITHUB_ACCOUNT = 'OK12138'
SONAR_CREDENTIAL_ID='sonar-qube'
BRANCH_NAME='main'
}
stages {
stage('拉取代码') {
steps {
git(url: 'https://gitee.com/OK12138/touch-air-mall.git', credentialsId: 'gitee-id', branch: 'main', changelog: true, poll: false)
sh 'echo 正在构建 $PROJECT_NAME 版本号:$PROJECT_VERSION 将会提交给 $REGISTRY 镜像仓库'
container ('maven') {
sh "mvn clean install -Dmaven.test.skip=true -gs `pwd`/mvn-settings.xml"
}
}
}
stage('sonar代码质量分析') {
steps {
container ('maven') {
withCredentials([string(credentialsId: "$SONAR_CREDENTIAL_ID", variable: 'SONAR_TOKEN')]) {
withSonarQubeEnv('sonar') {
sh "echo 当前目录 `pwd` "
sh "mvn sonar:sonar -gs `pwd`/mvn-settings.xml -Dsonar.login=$SONAR_TOKEN"
}
}
}
}
}
stage ('build & push 构建镜像并推送') {
steps {
container ('maven') {
sh 'mvn -Dmaven.test.skip=true -gs `pwd`/mvn-settings.xml clean package'
sh 'cd $PROJECT_NAME && docker build -f Dockerfile -t $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER .'
withCredentials([usernamePassword(passwordVariable : 'DOCKER_PASSWORD' ,usernameVariable : 'DOCKER_USERNAME' ,credentialsId : "$DOCKER_CREDENTIAL_ID" ,)]) {
sh 'echo "$DOCKER_PASSWORD" | docker login $REGISTRY -u "$DOCKER_USERNAME" --password-stdin'
sh 'docker tag $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:latest '
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:latest '
}
}
}
}
stage('部署到k8s') {
steps {
input(id: "deploy-to-dev-$PROJECT_NAME", message: "是否将$PROJECT_NAME部署到集群中?")
kubernetesDeploy(configs: "$PROJECT_NAME/deploy/**", enableConfigSubstitution: true, kubeconfigId: "$KUBECONFIG_CREDENTIAL_ID")
}
}
stage('push with tag 打上TAG标签,发布版本'){
when{
expression{
return params.PROJECT_VERSION =~ /v.*/
}
}
steps {
container ('maven') {
input(id: 'release-image-with-tag', message: '发布当前版本镜像吗?')
withCredentials([usernamePassword(credentialsId: "$GITHUB_CREDENTIAL_ID", passwordVariable: 'GIT_PASSWORD', usernameVariable: 'GIT_USERNAME')]) {
sh 'git config --global user.email "[email protected]" '
sh 'git config --global user.name "kubesphere" '
sh 'git tag -a $PROJECT_VERSION -m "$PROJECT_VERSION" '
sh 'git push http://$GIT_USERNAME:$GIT_PASSWORD@gitee.com/$GITHUB_ACCOUNT/touch-air-mall.git --tags --ipv4'
}
sh 'docker tag $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:SNAPSHOT-$BRANCH_NAME-$BUILD_NUMBER $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:$PROJECT_VERSION '
sh 'docker push $REGISTRY/$DOCKERHUB_NAMESPACE/$PROJECT_NAME:$PROJECT_VERSION '
}
}
}
}
}
使用Dockerfile生成自定义的nginx镜像
可以结合阿里云镜像仓库,将本地(虚拟机的docker镜像),部署至k8s集群中
推送镜像到dockerhub(阿里云镜像仓库)
#标记镜像
docker tag local-image:tag username/new-repo:tag
#上传镜像
docker push username/new-repo:tag
修改nginx的上游服务器,保证在k8s集群中,路由到网关
登录阿里云镜像容器服务,开通、创建个人镜像仓库
推送镜像至阿里云
以mall-gateway
网关服务为例
上面的参数化构建很重要,这样我们部署服务,可以选择我们想要部署的一个或多个服务
部署不同服务时,只需要修改PROJECT_NAME
变为想要部署的项目名称(mall-gateway、mall-cart、mall-seckill
)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CCIaWoCq-1631764858230)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0e27a61c07094d128930280eea35fd1b~tplv-k3u1fbpfcp-watermark.image)]
重复运行流水线构建所有商城微服务
将阿里云仓库的微服务权限修改为公开,方便k8s集群访问
接口测试
#商品三级分类数据
http://192.168.83.133:30007/index/catalog.json
利用我们之前打包推送到阿里云上的nginx镜像,在k8s集群中部署nginx服务
在创建应用路由之前,需要先启用外网访问入口,即网关。这一步是创建对应的应用路由控制器,用来负责将请求转发到对应的后端服务
注意:由于使用 Load Balancer 需要在安装前配置与安装与云服务商对接的 cloud-controller-manage 插件,参考 安装负载均衡器插件 来安装和使用负载均衡器插件(暂不演示)
以项目管理员的身份,开启应用路由
第一步:修改线上网关环境
修改 index-prod.js
中的api请求地址
第二步:编译打包,生成dist目录
npm run build
第三步:编写Dockerfile
FROM nginx
MAINTAINER leifengyang
ADD dist.tar.gz /usr/share/nginx/html
EXPOSE 80
ENTRYPOINT nginx -g "daemon off;"
第四步:打包成镜像
docker build -t touch-air-mall-vue-app:v1.0 -f Dockerfile .
上传阿里云镜像仓库,kubesphere创建无状态服务