第一部分:配置 docker
1.1、配置Nginx,转发 nexus 上传包的请求
sudo tee /etc/nginx/conf.d/k8s.conf <<-‘EOF’
HTTPS 服务器块
server {
listen 443 ssl;
server_name sls.registry.k8s;
# SSL 证书配置
ssl_certificate /home/projectname/server/mydomain.crt;
ssl_certificate_key /home/projectname/server/mydomain.key;
# 反向代理设置
location / {
proxy_pass http://192.168.1.205:8082;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
EOF
nginx -s reload
1.2、配置Nexus 调整上传附件的大小,确保能上传镜像
http {
// 新增下面这一行
client_max_body_size 2000M;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
// 修改这一行的值
keepalive_timeout 100;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
1.3、配置docker 让docker 能访问nexus
1.3.1、nginx + nexus + docker 服务器
sudo tee /etc/docker/daemon.json <<-‘EOF’
{
“insecure-registries”: [ “sls.registry.k8s:443”,“192.168.1.205:8082”],
“registry-mirrors”: [ “https://sls.registry.k8s”,“http://192.168.1.205:8082”,“https://7e9g5tmw.mirror.aliyuncs.com”,“https://registry.docker-cn.com”],
“exec-opts”: [“native.cgroupdriver=systemd”]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
1.3.2、k8s 服务器:
sudo tee /etc/docker/daemon.json <<-‘EOF’
{
“insecure-registries”:[“sls.registry.k8s:5000”,“192.168.1.205:8082”],
“registry-mirrors”: [“https://sls.registry.k8s:5000”,“http://192.168.1.205:8082”,“https://7e9g5tmw.mirror.aliyuncs.com”]
}
EOF
sudo systemctl daemon-reload
第二部分: 安装NFS
2.1、安装NFS 服务器:
搭建一个 NFS(Network File System)服务器通常需要在 Linux 系统上进行操作。下面是一个基本的步骤指南:
步骤 1: 安装 NFS 服务器软件
-
使用包管理器安装 NFS 服务器软件。具体命令取决于你使用的 Linux 发行版。以 Ubuntu 为例,可以使用以下命令:
sudo apt update sudo apt install nfs-kernel-server
步骤 2: 配置 NFS 服务器
-
编辑 NFS 服务器的配置文件。在 Ubuntu 上,配置文件位于
/etc/exports
。sudo nano /etc/exports
-
在配置文件中添加要共享的目录及其权限。例如,如果要共享
/srv/nfs_share
目录,可以添加类似以下内容:
/srv/nfs_share *(rw,sync,no_subtree_check)
- `/srv/nfs_share`: 要共享的目录路径。
- `*`: 允许所有客户端访问。
- `rw`: 可读写权限。
- `sync`: 同步写入。
- `no_subtree_check`: 不检查子目录。
3. 保存并关闭文件。
4. 更新 NFS 服务器配置:
sudo exportfs -a
### 步骤 3: 启动 NFS 服务器
1. 启动 NFS 服务器:
sudo systemctl start nfs-server
2. 如果需要,设置 NFS 服务器在系统启动时自动启动:
sudo systemctl enable nfs-server
### 步骤 4: 配置防火墙
1. 如果有防火墙启用,确保允许 NFS 流量通过。NFS 使用 UDP 和 TCP 端口 2049。
### 步骤 5: 配置客户端
1. 在客户端系统上安装 NFS 客户端软件。同样地,命令取决于你的 Linux 发行版。
2. 挂载 NFS 共享到客户端:
sudo mount <NFS服务器的IP或主机名>:<共享的目录> <本地挂载点>
例如:
sudo mount 192.168.1.205:/srv/nfs_share/projectname /mnt/nfs
### 注意事项:
- 确保网络中的所有主机能够解析 NFS 服务器的主机名或 IP 地址。
- 请根据实际需求调整配置,例如添加访问控制、更改权限等。
- 对于生产环境,确保数据的安全性和完整性。
- 测试 NFS 服务器和客户端之间的连接和数据访问,以确保一切正常运行。
以上是基本的 NFS 服务器搭建指南,具体步骤可能会因操作系统版本、网络环境等因素而略有不同。
2.2、在k8s集群上安装NFS 工具:
要在 Kubernetes 中挂载 NFS,你首先需要在你的 Kubernetes 集群所在的节点上安装 NFS 客户端。NFS 客户端软件通常在大多数 Linux 发行版的默认软件仓库中都可以找到。以下是在常见的几个 Linux 发行版上安装 NFS 客户端的方法:
1. **在 Ubuntu 上安装 NFS 客户端:**
sudo apt update
sudo apt install nfs-common
2. **在 CentOS/RHEL 上安装 NFS 客户端:**
sudo yum install nfs-utils
安装完成后,你就可以在 Kubernetes 节点上使用 `mount` 命令手动挂载 NFS 共享,以确保 NFS 客户端已经正确安装并且可以正常工作。例如:
sudo mount -t nfs <NFS服务器IP地址或域名>:/path/to/nfs/share /local/mount/point
这里的 `/local/mount/point` 是你希望将 NFS 共享挂载到的本地目录。
安装 NFS 客户端后,你可以按照之前提供的 Kubernetes 配置示例,在 Pod 中使用 Volume 来挂载 NFS 共享。确保在配置中正确设置了 NFS 服务器的地址和共享路径,并且在 Kubernetes 节点上已经可以通过 NFS 客户端正常访问该共享路径。
请注意,你需要确保在 Kubernetes 集群中的每个节点上都安装了 NFS 客户端,以便能够在所有节点上挂载 NFS 共享。
2.3、应用到POD:
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-app-projectname-keycloak-pv
配置标签供pvc选择
labels:
pv: local-app-projectname-keycloak-pv
spec:
capacity:
storage: 30Gi
accessModes: # 访问模式
- ReadWriteMany # 读写权限,可以被多个节点挂载
persistentVolumeReclaimPolicy: Retain
存储类型,与底层真正存储对应(nfs只是一个代表,这里还可以配置cifs、clusterfs或者其他存储类型)
nfs:
path: /srv/nfs_share/projectname
server: 192.168.1.205
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
pvc的名字,提供给pod用于绑定
name: local-app-projectname-keycloak-pvc
namespace: local-app
spec:
accessModes:
- ReadWriteMany
resources: # 请求的空间
requests:
storage: 30Gi
selector: # 标签选择器绑定对应的PV
matchLabels:
pv: local-app-projectname-keycloak-pv
2.4、keycloak 配置分布式缓存:
<?xml version="1.0" encoding="UTF-8"?><jgroups>
<!-- 定义一个名为"prod"的自定义JGroups堆栈 -->
<stack name="prod">
<!-- 使用TCP协议 -->
<TCP bind_port="7800" port_range="30" recv_buf_size="20000000" send_buf_size="640000"/>
<!-- RED插件 -->
<RED/>
<!-- MPING插件 -->
<!-- 多播地址,默认为239.2.4.6 -->
<!-- 多播端口,默认为43366 -->
<!-- 发现运行次数,默认为3 -->
<!-- IP数据包生存时间,默认为2 -->
<MPING break_on_coord_rsp="true"
mcast_addr="${jgroups.mping.mcast_addr:239.2.4.6}"
mcast_port="${jgroups.mping.mcast_port:43366}"
num_discovery_runs="3"
ip_ttl="${jgroups.udp.ip_ttl:2}"/>
<!-- MERGE3插件 -->
<MERGE3 />
<!-- FD_SOCK2插件 -->
<FD_SOCK2 />
<!-- FD_ALL3插件 -->
<FD_ALL3 timeout="3000" interval="1000" timeout_check_interval="1000" />
<!-- VERIFY_SUSPECT2插件 -->
<VERIFY_SUSPECT2 timeout="1000" />
<!-- pbcast.NAKACK2插件 -->
<pbcast.NAKACK2 use_mcast_xmit="false" xmit_interval="200" xmit_table_num_rows="50"
xmit_table_msgs_per_row="1024" xmit_table_max_compaction_time="30000" />
<!-- UNICAST3插件 -->
<UNICAST3 conn_close_timeout="5000" xmit_interval="200" xmit_table_num_rows="50"
xmit_table_msgs_per_row="1024" xmit_table_max_compaction_time="30000" />
<!-- pbcast.STABLE插件 -->
<pbcast.STABLE desired_avg_gossip="2000" max_bytes="1M" />
<!-- pbcast.GMS插件 -->
<pbcast.GMS print_local_addr="false" join_timeout="${jgroups.join_timeout:2000}" />
<!-- UFC插件 -->
<UFC max_credits="4m" min_threshold="0.40" />
<!-- MFC插件 -->
<MFC max_credits="4m" min_threshold="0.40" />
<!-- FRAG4插件 -->
<FRAG4 />
</stack>
</jgroups>
<cache-container name="keycloak">
<transport cluster="my-cluster"/>
<local-cache name="default">
<transaction transaction-manager-lookup="org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup"/>
</local-cache>
<local-cache name="realms">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<local-cache name="users">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<distributed-cache name="sessions" owners="2" mode="SYNC" statistics="true">
<expiration lifespan="-1"/>
<persistence>
<file-store path="/projectname/sessions" preload="true"/>
</persistence>
</distributed-cache>
<distributed-cache name="authenticationSessions" mode="SYNC" owners="2" statistics="true">
<expiration lifespan="-1"/>
<persistence>
<file-store path="/projectname/authenticationSessions" preload="true"/>
</persistence>
</distributed-cache>
<distributed-cache name="offlineSessions" owners="2" mode="SYNC" statistics="true">
<expiration lifespan="-1"/>
<persistence>
<file-store path="/projectname/offlineSessions" preload="true"/>
</persistence>
</distributed-cache>
<distributed-cache name="clientSessions" owners="2" mode="SYNC" statistics="true">
<expiration lifespan="-1"/>
<persistence>
<file-store path="/projectname/clientSessions" preload="true"/>
</persistence>
</distributed-cache>
<distributed-cache name="offlineClientSessions" owners="2" mode="SYNC" statistics="true">
<expiration lifespan="-1"/>
<persistence>
<file-store path="/projectname/offlineClientSessions" preload="true"/>
</persistence>
</distributed-cache>
<distributed-cache name="loginFailures" owners="2" mode="SYNC" statistics="true">
<expiration lifespan="-1"/>
<persistence>
<file-store path="/projectname/loginFailures" preload="true"/>
</persistence>
</distributed-cache>
<local-cache name="authorization" statistics="true">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<memory max-count="10000"/>
</local-cache>
<distributed-cache name="work" owners="2" mode="SYNC" statistics="true">
<expiration lifespan="-1"/>
<persistence>
<file-store path="/projectname/work" preload="true"/>
</persistence>
</distributed-cache>
<local-cache name="keys">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<expiration max-idle="3600000"/>
</local-cache>
<distributed-cache name="actionTokens" owners="2" mode="SYNC" statistics="true">
<encoding>
<key media-type="application/x-java-object"/>
<value media-type="application/x-java-object"/>
</encoding>
<persistence>
<file-store path="/projectname/actionTokens" preload="true"/>
</persistence>
</distributed-cache>
</cache-container>
3、配置 jenkins
def pom
def version = “0.1.4”;
def verDateStr = “20240401”;
pipeline {
agent any
stages {
stage('Checkout') {
steps {
// 检出Keycloak代码
git credentialsId: 'MyCredentialsId', url: 'http://192.168.1.205:9980/projectname/porsso1903.git', branch: 'load_test'
}
}
stage('Build') {
steps {
sh 'cp -f conf/keycloak.conf quarkus/runtime/src/main/resources/META-INF/keycloak.conf'
sh 'cp -rf conf/api.properties services/src/main/resources/api.properties'
// 构建Keycloak
sh 'mvn clean install -DskipTests'
}
}
stage('Docker Build & Push image to Nexus'){
steps {
script {
version = params.version
echo "--------------Docker Build & Push image to Nexus-----------"+ version;
// pom = readMavenPom file: "./pom.xml"
// version = "${pom.properties.deployversion}"
echo "docker阶段获取到的版本号:${version}"
withCredentials([usernamePassword(credentialsId: 'Nexus', passwordVariable: 'password', usernameVariable: 'user')]) {
sh "docker -v"
sh "id jenkins"
sh "docker build --build-arg JAR_VERSION=0.0.0.1.0 -f dockerfile2 -t sls.registry.k8s/projectname:${version} ."
sh "docker login sls.registry.k8s -u $user -p admin*****"
sh "docker push sls.registry.k8s/projectname:${version}"
sh "docker rmi sls.registry.k8s/projectname:${version}"
echo "镜像删除成功"
}
echo "--------------------输出pom version:${version}---------------------"
}
}
}
stage('Deploy to k8s'){
steps {
script{
if(version == null){
version = input id: 'Version-Input', message: '版本号为空,请输入要部署的版本号,如:1.0.0', ok: 'yes', parameters: [string(description: '拉取镜像的版本号', name: 'input-version')], submitter: 'projectname'
echo "input已经执行version=${version}"
}
version = params.version
verDateStr = "20240331";
withCredentials([usernamePassword(credentialsId: 'k8s-master-login', passwordVariable: 'pass', usernameVariable: 'user')]) {
sh "echo $user"
sh "echo $pass"
def remote = [:]
remote.name = 'k8smaster'
remote.host = '192.168.1.222'
remote.user = "$user"
remote.password = "$pass"
remote.allowAnyHosts = true
remote.pty=true
try {
echo "k8s阶段获取到的版本号:${version}"
sshCommand remote: remote, sudo: false, command: "sed -i -E 's/^( *image:.*projectname:)[0-9]+(\\.[0-9]+)*(.*)\$/\\1'${version}'\\3/' /home/projectname/keycloak/local-app-projectname-keycloak.yaml"
sshCommand remote: remote, sudo: false, command: "sed -i -E 's/v[0-9]+\\.[0-9]+\\.[0-9]+_[0-9]+/v${verDateStr}/g' /home/projectname/keycloak/local-app-projectname-keycloak.yaml"
sshCommand remote: remote, sudo: true, command: "kubectl delete -f /home/projectname/keycloak/local-app-projectname-keycloak.yaml"
sshCommand remote: remote, sudo: true, command: "kubectl apply -f /home/projectname/keycloak/local-app-projectname-keycloak.yaml"
sshCommand remote: remote, sudo: true, command: "kubectl get pods --all-namespaces -o wide|grep app-projectname-keycloak"
echo "try已执行!项目部署完成.."
}catch (err){
echo "我是catch发生错误了:${err}"
}finally {
echo "我是finally,yaml的镜像版本为${version}"
}
}
}
}
}
}
}