Gitlab 部署与使用

Gitlab 部署与使用:

Gitlab 服务的安装文档:https://about.gitlab.com/install/
安装环境要求:https://docs.gitlab.com/ce/install/requirements.html

下载并部署 gitlab:

新安装好的ubuntu系统

Ubuntu 系统环境准备:

  1. 配置 ubuntu root远程连接:
# sudo su - root
[sudo] password for jack:
# passwd
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
  1. 配置文件
vim /etc/ssh/sshd_config
...
PermitRootLogin yes
...
PasswordAuthentication yes
...
  1. 配置 ubuntu 网卡和主机名:
vim /etc/netplan/01-netcfg.yaml
network:
  ethernets:
    eth0:
      dhcp4: no
      addresses: [192.168.99.26/24]
      gateway4: 192.168.99.2
      nameservers:
        addresses: [192.168.99.2]
  version: 2
  1. 修改主机名
# cat /etc/hostname
myhost
  1. 配置 ubuntu18.04 仓库
    其它版本:https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/
vim /etc/apt/sources.list
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ bionic-security main restricted universe multiverse
  1. 更新源并安装常用工具
apt update
apt install iproute2 ntpdate tcpdump telnet traceroute nfs-kernel-server \ 
    nfs-common lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev ntpdate \
    tcpdump telnet traceroute gcc openssh-server lrzsz tree openssl libssl-dev libpcre3 \
    libpcre3-dev zlib1g-dev ntpdate tcpdump telnet traceroute iotop unzip zip ipmitool

Centos 系统环境准备

  1. 配置网卡
  2. 安装常用工具
yum -y install vim gcc gcc-c++ wget net-tools lrzsz iotop lsof \
    iotop bash-completion curl policycoreutils openssh-server openssh-clients postfix
  1. 下载epel源
wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
  1. 关闭防火墙selinux
systemctl stop firewalld
systemctl disable firewalld
sed -i '/SELINUX/s/enforcing/disabled/' /etc/sysconfig/selinux
  1. 配置主机名
hostnamectl set-hostname gitlab.example.com

gitlab 安装及使用

安装包下载地址: https://packages.gitlab.com/gitlab/gitlab-ce
rpm 包国内下载地址: https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/
ubuntu 国内下载地址: https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/ubuntu/pool/

  1. ubuntu安装
dpkg -i gitlab-ce_11.11.8-ce.0_amd64.deb

在这里插入图片描述

  1. gitlab 配置使用
grep "^[a-Z]" /etc/gitlab/gitlab.rb
# 写本地ip或域名,域名需要可解析
external_url 'http://192.168.99.26'

# 以下配置可选,邮件通知设置
gitlab_rails['gitlab_email_from'] = "[email protected]"
...
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.qq.com"
gitlab_rails['smtp_port'] = 465
gitlab_rails['smtp_user_name'] = "[email protected]"
gitlab_rails['smtp_password'] = "zdhudwexecjbdhda"
gitlab_rails['smtp_domain'] = "qq.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true
gitlab_rails['smtp_tls'] = true
...
user["git_user_email"] = "[email protected]"
  1. 初始化服务
    修改完配置文件要执行此操作
gitlab-ctl reconfigure

在这里插入图片描述
4. gitlab 相关的目录有哪些

/etc/gitlab #配置文件目录
/run/gitlab #运行 pid 目录
/opt/gitlab #安装目录
/var/opt/gitlab #数据目录
/var/log/gitlab #日志目录
  1. 常用命令
    gitlab-rails:用于启动控制台进行特殊操作,比如修改管理员密码、打开数据库控制台( gitlab-rails dbconsole)等
    gitlab-psql:数据库命令行
    gitlab-rake: 数据备份恢复等数据操作
    gitlab-ctl: 客户端命令行操作行
      gitlab-ctl stop: 停止 gitlab
      gitlab-ctl start: 启动 gitlab
      gitlab-ctl restar: 重启 gitlab
      gitlab-ctl status: 查看组件运行状态
      gitlab-ctl tail nginx: 查看某个组件的日志
# gitlab-psql

#退出
gitlabhq_production-# \q

在这里插入图片描述

  1. 验证gitlab安装完成
gitlab-ctl status

在这里插入图片描述

  1. 登录gitlab web界面并设置密码:直接ip访问
    在这里插入图片描述

  2. 登录gitlab,默认用户为root
    在这里插入图片描述

  3. 关闭账号注册(默认情况是可以注册帐号,不安全)
    在这里插入图片描述

  4. 验证是否还有注册选项
    在这里插入图片描述

创建用户

在这里插入图片描述

  1. 重置链接将生成并发送给用户。用户将被迫在首次登录时设置密码。
    在这里插入图片描述

  2. 如果前面没有设置邮件服务,将收不到邮件
    在这里插入图片描述

  3. 点击Reset password即可设置密码
    在这里插入图片描述

创建组

在这里插入图片描述
使用管理员 root 创建组,一个组里面可以有多个项目分支,可以将开发添加到组里面进行设置权限,不同的组就是公司不同的开发项目或者服务模块,不同的组添加不同的开发即可实现对开发设置权限的管理。
在这里插入图片描述

创建项目

在这里插入图片描述
在这里插入图片描述

添加用户到组

在这里插入图片描述

添加一个测试页面到项目

在这里插入图片描述

添加README
在这里插入图片描述

git 客户端测试 clone 项目

在这里插入图片描述

git clone http://192.168.99.26/testgroup/test-project.git

在这里插入图片描述

  1. 配置帐号密码
cd test-project/
git config --global user.name "root"
git config --global user.email [email protected]
  1. 修改index.html并提交到git lab
vim index.html
git add index.html
git commit -m "v2"
git push
  1. 网页端验证
    在这里插入图片描述

git 常用命令

#设置全局用户名
git config --global user.name "name" 
#设置全局邮箱
git config --global user.email [email protected] 
#列出用户全局设置
git config --global --list 
#添加指定文件、 目录或当前目录下所有数据到暂存区
git add index.html / . 
#提交文件到工作区
git commit -m "11"
#查看工作区的状态
git status 
#提交代码到服务器
git push 
#获取代码到本地
git pull 
#查看操作日志
git log 
#定义忽略文件
vim .gitignore 
#git 版本回滚, HEAD 为当前版本,加一个^为上一个, ^^为上上一个版本
git reset --hard HEAD^^ 
#获取每次提交的 ID,可以使用--hard 根据提交的 ID 进行版本回退
git reflog #
#回退到指定 id 的版本
git reset --hard 5ae4b06 
#查看当前所处的分支
git branch 
#创建并切换到一个新分支
git checkout -b develop 
#切换分支
git checkout develop 

gitlab 数据备份恢复

  1. 停止 gitlab 数据服务
gitlab-ctl stop unicorn
gitlab-ctl stop sidekiq
  1. 手动备份数据
cd /var/opt/gitlab/backups/
#在任意目录即可备份当前 gitlab 数据
gitlab-rake gitlab:backup:create 
#备份完成后启动 gitlab
gitlab-ctl start sidekiq
gitlab-ctl start unicorn

在这里插入图片描述

  1. 查看要恢复的文件
# Gitlab 数据备份目录, 需要使用命令备份的
/var/opt/gitlab/backups/ 
# nginx 配置文件
/var/opt/gitlab/nginx/conf 
# gitlab 配置文件
/etc/gitlab/gitlab.rb 
  1. 执行恢复,恢复数据之前停止服务
gitlab-ctl stop unicorn
gitlab-ctl stop sidekiq 
  1. 恢复
cd /var/opt/gitlab/backups/
gitlab-rake gitlab:backup:restore BACKUP=备份文件名

注意文件名写法
在这里插入图片描述
输出yes回车
在这里插入图片描述
恢复完成
在这里插入图片描述

  1. 备份或恢复完成后启动服务
gitlab-ctl start sidekiq
gitlab-ctl start unicorn

gitlab 汉化

  1. 下载语言包替换

地址:https://gitlab.com/xhang/gitlab
在这里插入图片描述

  1. 首次安装 gitlab 步骤
vim /etc/gitlab/gitlab.rb #修改配置
gitlab-ctl reconfigure
  1. 已经安装 gitlab 步骤
gitlab-ctl stop
tar xvf gitlab-vX.Y.Z-zh.tar
cp -rp /opt/gitlab/embedded/service/gitlab-rails /opt/gitlab-rails.bak #备份源文件
cp -rf gitlab-vX.Y.Z-zh/* /opt/gitlab/embedded/service/gitlab-rails/ #替换文件
gitlab-ctl reconfigure
gitlab-ctl start
  1. Web 界面更改语言
    在这里插入图片描述
  2. 通过源码汉化
git clone https://gitlab.com/xhang/gitlab.git
head -1 /opt/gitlab/version-manifest.txt #查看当前 gitlab 版本
cd gitlab
git diff v11.9.8 v11.9.8-zh
git diff v11.9.8 v11.9.8-zh > /root/v11.9.8-zh.diff
gitlab-ctl stop
patch -d /opt/gitlab/embedded/service/gitlab-rails -p1 < /root/v11.9.8-zh.diff
gitlab-ctl reconfigure
gitlab-ctl start

常见的代码部署方式

蓝绿部署:

蓝绿部署指的是不停老版本代码(不影响上一个版本访问), 而是在另外一套环境部署新版本然后进行测试,测试通过后将用户流量切到新版本, 其特点为业务无中断,升级风险相对较小。
具体过程:

1、 当前版本业务正常访问(V1)
2、 在另外一套环境部署新代码(V2),代码可能是增加了功能或者是修复了某些 bug
3、 测试通过之后将用户请求流量切到新版本环境
4、 观察一段时间,如有异常直接切换旧版本
5、 下次升级, 将旧版本升级到新版本(V3)

蓝绿部署适用的场景:

1、不停止老版本,额外部署一套新版本,等测试发现新版本 OK 后,删除老版本。
2、蓝绿发布是一种用于升级与更新的发布策略,部署的最小维度是容器,而发布的最小维度是应用。
3、蓝绿发布对于增量升级有比较好的支持,但是对于涉及数据表结构变更等等不可逆转的升级,并不完全合适用蓝绿发布来实现,需要结合一些业务的逻辑以及数据迁移与回滚的策略才可以完全满足需求。
在这里插入图片描述

金丝雀发布:

金丝雀发布也叫灰度发布, 是指在黑与白之间,能够平滑过渡的一种发布方式, 灰度发布是增量发布的一种类型,灰度发布是在原有版本可用的情况下,同时部署一个新版本应用作为“金丝雀” (小白鼠),测试新版本的性能和表现,以保障整体系统稳定的情况下,尽早发现、调整问题。

“金丝雀”的由来: 17 世纪,英国矿井工人发现,金丝雀对瓦斯这种气体十分敏感。空气中哪怕有极其微量的瓦斯,金丝雀也会停止歌唱;而当瓦斯含量超过一定限度时,虽然鲁钝的人类毫无察觉,金丝雀却早已毒发身亡。当时在采矿设备相对简陋的条件下,工人们每次下井都会带上一只金丝雀作为“瓦斯检测指标”,以便在危险状况下紧急撤离。

金丝雀发布、灰度发布步骤组成:

1、准备好部署各个阶段的工件,包括:构建工件,测试脚本,配置文件和部署清单文件。
2、从负载均衡列表中移除掉“金丝雀”服务器。
3、升级“金丝雀”应用(排掉原有流量并进行部署)。
4、对应用进行自动化测试。
5、将“金丝雀”服务器重新添加到负载均衡列表中(连通性和健康检查)。
6、如果“金丝雀”在线使用测试成功,升级剩余的其他服务器。(否则就回滚)
灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

灰度发布/金丝雀部署适用的场景:

1、不停止老版本,额外搞一套新版本,不同版本应用共存。
2、灰度发布中,常常按照用户设置路由权重,例如 90%的用户维持使用老版本, 10%的用户尝鲜新版本。
3、经常与 A/B 测试一起使用,用于测试选择多种方案。
在这里插入图片描述

滚动发布:
滚动发布,一般是取出一个或者多个服务器停止服务,执行更新,并重新将其投入使用。周而复始,直到集群中所有的实例都更新成新版本。

A/B 测试:
A/B 测试也是同时运行两个 APP 环境,但是蓝绿部署完全是两码事, A/B 测试是用来测试应用功能表现的方法,例如可用性、受欢迎程度、可见性等等,蓝绿部署的目的是安全稳定地发布新版本应用,并在必要时回滚, 即蓝绿部署是一套正式环境环境在线, 而A/B 测试是两套正式环境在线。


部署 web 服务器环境

  • 新鲜的服务器一台
  1. java 环境:各 web 服务器准备 tomcat 运行环境
    准备jdk源码包上传到/usr/local/src
#创建账户
useradd -m www -u 2019 -s /bin/bash 
cd /usr/local/src
tar xvf jdk-8u211-linux-x64.tar.gz
ln -sv /usr/local/src/jdk1.8.0_211 /usr/local/jdk
  1. 配置profile
vim /etc/profile

结尾追加

export HISTTIMEFORMAT="%F %T `whoami` "
export LANG="en_US.utf-8"
export JAVA_HOME=/usr/local/jdk
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin
  1. 验证java版本
source /etc/profile 
java -version
  1. 准备tomcat源码包,上传到/usr/local/src
cd /usr/local/src
tar xvf apache-tomcat-8.5.42.tar.gz
ln -sv /usr/local/src/apache-tomcat-8.5.42 /usr/local/tomcat
  1. 准备 tomcat 启动脚本:
touch /etc/init.d/tomcat
chmod +x /etc/init.d/tomcat
vim /etc/init.d/tomcat
#!/bin/bash

JDK_HOME=/usr/local/jdk
CATALINA_HOME=/usr/local/tomcat
export JDK_HOME CATALINA_HOME
source /etc/profile
#PID=`ps -ef  | grep  -v grep  | grep java | awk  '{print $2}'`
#NUM=`ps -ef  | grep  -v grep  | grep java | awk  '{print $2}' | wc -l`

#case $1 in
start() {
    	echo "正在判断服务状态,请稍等!"	
    	echo "请稍等3秒钟"
    	echo "3";sleep 1;echo "2";sleep 1;echo "1";sleep 1
   	if	netstat -an | grep 8080 | grep LISTEN >/dev/null
     	then
   		echo "Tomcat已经正在运行了!"  
  	else 
   		echo "Tomcat没有运行,1秒后启动!"
		echo 1;sleep 1  
  		$CATALINA_HOME/bin/catalina.sh start 
  		echo  "Tomcat 已经成功启动完成,5秒后判断是否启动成功"
  		echo "5";sleep 1;echo "4";sleep 1
        echo "3";sleep 1;echo "2";sleep 1;echo "1";sleep 1
	if  netstat -an | grep 8080 | grep LISTEN >/dev/null
	    then
		PID=`ps -ef | grep  tomcat | grep jdk | awk '{print $2}'`
		NUM=`ps -ef | grep  tomcat | grep jdk | awk '{print $2}' | wc -l`
		echo "Tomcat 已经成功启动${NUM} 个Tomcat进程!,PID为${PID}"
	    else
		echo "Tomcat启动失败,请重新启动!"
        	echo 1
	fi
 	fi
	}
stop() {
		PID=`ps -ef  | grep  -v grep  | grep java | awk  '{print $2}'`
		NUM=`ps -ef | grep  -v "color"  | grep tomcat | awk '{print $2}' | wc -l`
		echo "正在判断服务状态,请稍等3秒钟!"	
		echo "3";sleep 1;echo "2";sleep 1;echo "1";sleep 1
	if  netstat -an | grep 8080 | grep LISTEN >/dev/null 
	   then	
		echo "Tomcat运行中,1秒后关闭!"
		echo  1;sleep 1 
		echo "即将关闭Tomcat服务,请稍等!" 
        $CATALINA_HOME/bin/catalina.sh stop ;echo "已经执行关闭命令,正在检查关闭了多少Tomcat进程,请稍等30秒钟!"
		sleep 27
        echo "3";sleep 1;echo "2";sleep 1;echo "1";sleep 1
		pkill java && pkill tomcat
		if  netstat -an | grep 8080 | grep LISTEN >/dev/null;then
			PID=`ps -ef  | grep  -v grep  | grep java | awk  '{print $2}'`
			NUM=`ps -ef | grep  -v "color"  | grep tomcat | awk '{print $2}' | wc -l`
			kill -9 $PID ;echo "已成功关闭${NUM} 个tomcat进程"
		else
  			echo  "Tomcat 已经关闭完成!" 
        	echo "3";sleep 1;echo "2";sleep 1;echo "1";sleep 1 
		fi
	else
		echo "Tomcat 没有运行"
		echo 1
	fi
	if  netstat -an | grep 8080 | grep LISTEN >/dev/null;then
            PID=`ps -ef  | grep  -v grep  | grep java | awk  '{print $2}'`
            #NUM=`ps -ef | grep  -v "color"  | grep tomcat | awk '{print $2}' | wc -l`
            echo "关闭失败,即将强制删除tomcat进程!"
            sleep 2
            pkill tomcat ;sleep 2 
            if  netstat -an | grep 8080 | grep LISTEN >/dev/null;then
                echo "强制关闭失败,即将再次强制删除tomcat进程!"
                pkill java; sleep 2
            fi
	fi
	}
restart() {
	stop 
	start 
 }

case "$1" in 
start) 
start 
;; 

stop) 
stop 
;; 

restart) 
restart 
;; 

*) 
echo $"Usage: $0 {start|stop|restart|status}" 
esac

web 部署:

  1. 部署 web 服务器并确认各 web 服务器访问正常
#保存 web 压缩包
mkdir /data/tomcat/tomcat_appdir -p 
#保存解压后的 web 目录
mkdir /data/tomcat/tomcat_webdir 
#tomcat app 目录
mkdir /data/tomcat/tomcat_webapps 
#Java 代码目录
mkdir /data/tomcat/tomcat_webdir/myapp 
echo "Tomcat test page" > /data/tomcat/tomcat_webdir/myapp/index.html
  1. 配置 tomcat 配置文件:
vim /usr/local/tomcat/conf/server.xml
appBase="/data/tomcat/tomcat_webdir"

在这里插入图片描述

  1. 启动 tomcat:
/etc/init.d/tomcat start
  1. 确认各 web 服务器访问正常:
    在这里插入图片描述

部署 keepalived:

  • 新鲜的服务器一台
  1. 可选择yum/apt安装或编译安装
  2. 安装编译环境
yum install libnfnetlink-devel libnfnetlink ipvsadm libnl libnl-devel libnl3 libnl3-devel lm_sensors-libs net-snmp-agent-libs net-snmp-libs open server openssh-clients openssl openssldevel automake iproute
  1. 编译安装keepalived
cd keepalived-2.0.7 
./configure --prefix=/usr/local/keepalived --disable-fwmark
make && amke install
  1. 复制启动脚本
mkdir /usr/local/keepalived/etc/sysconfig – p
cp keepalived/etc/init.d/keepalived.rh.init /usr/local/keepalived/etc/sysconfig/keepalived
cp keepalived/keepalived.service /usr/lib/systemd/system/
mkdir /usr/local/keepalived/sbin && cp bin/keepalived /usr/local/keepalived/sbin/keepalived
mkdir /etc/keepalived
  1. keepalived配置文件
vim /etc/keepalived/keepalived.conf

global中添加vrrp_iptables注释了vrrp_strict

global_defs {
  ...
  vrrp_iptables
# vrrp_strict
  ...
}
vrrp_instance VI_1 {
  state MASTER
  interface eth0
  virtual_router_id 80
  priority 100
  advert_int 1
  unicast_src_ip 192.168.99.111
  unicast_peer {
    192.167.99.112
  }
  authentication {
    auth_type PASS
    auth_pass 1111
  }
  virtual_ipaddress {
    192.168.99.200 dev eth0 label eth0:0
  } 
}
  1. 启动keepalived
systemctl restart keepalived
systemctl enable keepalived

部署 haproxy

  • 还是keepalived那台
  1. 可以apt/yum安装haproxy也可以编译安装
  2. 编译安装
tar xvf haproxy-1.8.13.tar.gz
cd haproxy-1.8.13
make ARCH=x86_64 TARGET=linux2628 USE_PCRE=1 USE_OPENSSL=1 \
  USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 PREFIX=/usr/local/haproxy
make install PREFIX=/usr/local/haproxy
  1. 启动脚本
vim /usr/lib/systemd/system/haproxy.service
[Unit]
Description=HAProxy Load Balancer
After=syslog.target network.target
[Service]
#支持多配置文件读取,类似于从侧面是实现配置文件的 include 功能。
ExecStartPre=/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf -c -q
ExecStart=/usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf -p
/run/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID
[Install]
WantedBy=multi-user.target
  1. 记录 HAProxy 访问日志
# vim/etc/rsyslog.conf
14 # Provides UDP syslog reception
15 $ModLoad imudp #去掉注释
16 $UDPServerRun 514 #去掉注释
18 # Provides TCP syslog reception
19 $ModLoad imtcp #去掉注释
20 $InputTCPServerRun 514 #去掉注释
93 local3.* /var/log/haproxy.log
  1. 配置文件
mkdir /etc/haproxy
vim /etc/haproxy/haproxy.cfg
global
    log 127.0.0.1 local3 info
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats

defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000
listen stats
    mode http
    bind 0.0.0.0:9999
    stats enable
    log global
    stats uri /haproxy-status
    stats auth haadmin:abc123

listen web_port
  bind 0.0.0.0:80
  mode http
  log global
  option httplog
  server 192.168.99.110 192.168.99.110:8080 check inter 3000 fall 2 rise 5
  server 192.168.99.25 192.168.99.25:8080 check inter 3000 fall 2 rise 5
  1. 启动服务
systemctl restart haproxy
systemctl enable haproxy
  1. 测试 haproxy 反向代理 web 服务器:
    编辑本机 hosts 文件,将 myapp.web.com 解析到对应的 IP 负载 IP:
C:\Windows\System32\drivers\etc\hosts
192.168.99.200 myapp.web.com
  1. 验证 HAProxy 统计页面
    http://myapp.web.com:9009/haproxy-status

在这里插入图片描述

  1. 记录 HAProxy 访问日志:
# vim /etc/rsyslog.conf
15 $ModLoad imudp #去掉注释
16 $UDPServerRun 514 #去掉注释
...
19 $ModLoad imtcp #去掉注释
20 $InputTCPServerRun 514 #去掉注释
...
74 local3.* /var/log/haproxy.log  #添加一条
  1. 重启日志服务
systemctl restart rsyslog
发布了254 篇原创文章 · 获赞 346 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_42758707/article/details/102719685