• Jenkins从放弃到入门:部署、配置与应用


    目录

    Jenkins详解

    一、Jenkins介绍

    1、Jenkins 功能

    2、Jenkins 概念

    3、Jenkins 目的

    4、Jenkins 特性

    5、产品发布流程

    二、Jenkins CI/CD 流程

    三、部署Jenkins

    git

    1、jenkins 安装

    yum 安装 jenkins *jenkins 依赖 java 环境 #注意2.346之后的版本不再支持jdk8

    2、配置文件

    1、查询 yum 下载 Jenkins 安装的文件

    2、修改配置文件

    3、启动 jenkins

    3、验证安装

    3、jenkins配置(web页面)

    1、管理员密码获取

    2、安装插件 (选择在线安装)

    1、修改 /var/lib/jenkins/updates/default.json

    2、 修改/var/lib/jenkins/hudson.model.UpdateCenter.xml

    3、创建第一个管理员用户

    4、url 配置

    5、安装完成

    6、配置 jdk、git、maven

    7、jenkins 下载插件失败处理办法

    四、使用Jenkins

    1、Jenkins 用户权限管理

    1、 用户管理背景

    2、 安装用户管理插件

    3、 开启该插件功能

    4、 验证用户管理

    1、策略改回原来的(全局安全配置)

    2、开启允许用户注册(全局安全配置)

    3、注册一个新用户

    4、登录之后,其默认就是管理员用户,可以进行任何操作

    5、开启 Role-Based Strategy

    6、重新登录新创建 test1 用户,显示已经没有任何权限了

    5、 权限划分

    1、Manage Roles(管理角色)

    1、Global roles

    2、Item roles

    2、Assigin roles(分配角色)

    1、给予test用户分配 user 角色

    2、针对指定用户分配项目角色(一般最常用的就是针对不同用户进行项目角色分配)

    2、Jenkins 参数化构建

    1、 参数化构建背景

    2、安装插件

    1、项目配置

    2、构建选择分支进行测试,添加branch参数 git配置中选$branch参数

    3、参数化配置已经生效

    3、Git 插件

    1、安装插件 Git Parameter

    2、进行配置

    3、Jenkins pipeline

    1、概览

    2、安装

    3、实操

    1、新建任务

    2、编写 pipeline 脚本

    3、构建测试

    4、Jenkins 构建邮件状态通知

    1、 前提

    2、 基础配置


    Jenkins详解

    一、Jenkins介绍

    简单历史

    Jenkins 的前身是 Hudson,一个采用 Java 编写的开源持续集成工具。Hudson 项目由 Sun 公司在 2004 年启动,2005 年发布了第一个版本,并逐渐在持续集成工具领域占据主导地位。2008 年,Hudson 在 JavaOne 大会上获得了杜克选择大奖(Duke's Choice Award)。

    2010 年 11 月,Oracle 收购 Sun 后,Hudson 的所有权问题引发了争议。主要项目贡献者和 Oracle 之间在“Hudson”商标名称上存在分歧。2011 年 1 月,社区投票决定将项目名称改为“Jenkins”,并于 1 月 29 日获得批准,正式创建了 Jenkins 项目。

    Oracle 继续开发 Hudson,认为 Jenkins 只是一个分支。随着时间的推移,Jenkins 社区迅速壮大,到 2013 年 12 月,GitHub 上的 Jenkins 项目成员远超 Hudson。如今,Jenkins 已全面超越 Hudson,成为持续集成工具领域的领导者。

    为什么 Jenkins 更受欢迎

    由开发者主导、面向开发者

    首先,曾经是Hudson开发人员中的99%都转向了Jenkins的开发,其中包括最初的创建者川口清子(Kohsuke Kawaguchi)。他独自写了大部分代码,并且他的经验是Hudson各种高级特性的关键来源。Jenkins的开发社区更活跃。所以对很多人而言,从血统上看Hudson是后娘养的,Jenkins才是亲生的!

    治理和社区

    • Jenkins 开发社区管理开放,设有独立董事会,定期举行治理会议并征求公众意见,所有代码捐赠给公共利益软件组织(SPI),确保社区持续开放。

    稳定性

    • Jenkins 社区不断贡献新功能和改进,定期发布长期支持版本,确保稳定性和可靠性。

    丰富的插件生态

    • Jenkins 支持超过 1000 个插件,覆盖构建、部署、测试等各个环节,使其成为开发生命周期的核心工具。

    1、Jenkins 功能

    Jenkins 是一个开源的自动化服务器,可以通过插件支持构建、部署和自动化的各个方面。它的主要功能包括:

    • 持续集成/持续交付(CI/CD):自动化的软件版本发布和测试项目,确保每次代码变更都能快速且可靠地集成和交付。

    • 构建自动化:支持各种构建工具和语言,如 Maven、Gradle、Ant、以及 shell 脚本等。

    • 测试自动化:能够集成各种测试工具和框架,如 JUnit、TestNG 等,自动化执行测试并生成报告。

    • 部署自动化:自动化应用程序的部署过程,可以集成 Docker、Kubernetes 等工具。

    • 监控和报告:监控外部调用的执行工作,生成详细的构建和测试报告,帮助快速定位和处理问题。

    2、Jenkins 概念

    Jenkins是一个功能强大的应用程序,允许持续集成和持续交付项目,旨在实现持续集成和持续交付。通过丰富的插件生态系统,Jenkins 可以集成各种构建、测试和部署工具,满足不同团队的需求。其主要概念包括:

    • Pipeline(流水线):定义构建、测试和部署的过程,可以通过代码(Jenkinsfile)配置。

    • Node(节点):执行构建任务的机器,可以是主节点(Master)或从节点(Agent)。

    • Job(任务):具体的构建任务,可以配置多个步骤和触发条件。

    • Plugin(插件):扩展 Jenkins 功能的组件,支持多种第三方工具和平台。

    3、Jenkins 目的
    • 持续、自动地构建和测试软件项目:每次代码变更后,自动触发构建和测试,确保代码的持续集成和交付。

    • 监控软件开发流程:通过监控构建和测试过程,快速定位和处理问题,提高开发效率。

    4、Jenkins 特性
    • 开源的java语言开发持续集成工具,支持CI,CD。

    • 易于安装部署配置:可通过yum安装,或下载war包以及通过docker容器等快速实现安装部署,可方便web界面配置管理。

    • 消息通知及测试报告:集成RSS/E-mail通过RSS发布构建结果或当构建完成时通过e-mail通知,生成JUnit/TestNG测试报告。

    • 分布式构建:支持Jenkins能够让多台计算机一起构建/测试。

    • 文件识别:Jenkins能够跟踪哪次构建生成哪些jar,哪次构建使用哪个版本的jar等。

    • 丰富的插件支持:支持扩展插件,你可以开发适合自己团队使用的工具,如git,svn,maven,docker等。

    5、产品发布流程

    产品设计成型 -> 开发人员开发代码 -> 测试人员测试功能 -> 运维人员发布上线

    • 持续集成(Continuous integration,简称CI):每次代码变更后,自动构建和测试。

    • 持续交付(Continuous delivery):在 CI 的基础上,自动化部署到预生产环境,确保代码随时可发布。

    • 持续部署(continuous deployment):在 CD 的基础上,进一步自动化部署到生产环境,实现无缝发布。

    二、Jenkins CI/CD 流程

    说明:这张图稍微更形象一点,上线之前先把代码git到版本仓库,然后通过Jenkins将Java项目通过maven去构建,这是在非容器之前,典型的自动化的一个版本上线流程。那它有哪些问题呢?

    如:它的测试环境,预生产环境,测试环境。会存在一定的兼容性问题 (环境之间会有一定的差异)

    说明:阿里云镜像仓库,把环境打包为一个镜像,通过镜像的方式来部署。

    三、部署Jenkins

    IP主机名
    10.1.0.25k8s-master-node1
    git

    linux(centos7.9)下载安装git2.32.0_git下载 linux-CSDN博客

    1. #拉取代码
    2. [root@k8s-master-node1 ~]# yum install -y git #首先还是安装git
    3. [root@k8s-master-node1 ~]# mkdir -p test
    4. [root@k8s-master-node1 ~]# cd test
    5. [root@k8s-master-node1 ~]# git clone git@xxx.xx.xx.x:/xx/xx/xx/xx ##测试clone仓库
    6. #push 测试
    7. [root@k8s-master-node1 ~]# touch index.html
    8. [root@k8s-master-node1 ~]# git add .
    9. [root@k8s-master-node1 ~]# git commit -m "test"
    10. #第一次有报错警告,让配置邮箱和姓名。配置一下即可,或者直接执行给出的命令执行。
    11. [root@k8s-master-node1 ~]# git push origin master #提交到主分支(默认分支)
    1、jenkins 安装

    官网: https://jenkins.io

    插件:Index of /download/plugins

    yum 安装 jenkins *jenkins 依赖 java 环境 #注意2.346之后的版本不再支持jdk8
    1. 卸载旧jenkins
    2. #查询以前是否安装jenkins
    3. rpm -qa |grep jenkins
    4. #卸载 jenkins
    5. yum -y remove jenkins
    6. rpm -e jenkins
    7. #彻底删除jenkins残留文件
    8. find / -iname jenkins | xargs -n 1000 rm -rf
    9. # 导入jenkins源
    10. wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo
    11. # 导入jenkins官方证书
    12. rpm --import https://pkg.jenkins.io/redhat/jenkins.io-2023.key
    13. #安装jdk11
    14. yum install fontconfig java-17-openjdk -y
    15. wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.rpm
    16. #有点慢,可以在Windows上提前下载导入。
    17. sudo yum -y install ./jdk-17_linux-x64_bin.rpm
    18. java -version
    19. #安装jenkins
    20. yum install jenkins -y
    21. #设置开机自启动
    22. systemctl enable jenkins
    23. #rpm安装
    24. wget http://pkg.jenkins-ci.org/redhat-stable/jenkins-2.346.1-1.1.noarch.rpm
    25. #安装
    26. rpm -ivh jenkins-2.346.1-1.1.noarch.rpm
    2、配置文件
    1、查询 yum 下载 Jenkins 安装的文件
    1. [root@k8s-master-node1 ~]# rpm -ql jenkins
    2. /usr/bin/jenkins # Jenkins 服务二进制文件
    3. /usr/lib/systemd/system/jenkins.service #systemd 服务单元文件,定义Jenkins启动参数
    4. /usr/share/java/jenkins.war # war 包
    5. /var/cache/jenkins # war包解压目录 jenkins网页代码目录
    6. /var/lib/jenkins # jenkins 工作目录
     
    
    2、修改配置文件

    配置文件说明

    1. [root@k8s-master-node1 ~]# grep -Ev "^(#|$)" /usr/lib/systemd/system/jenkins.service
    2. [Unit]
    3. Description=Jenkins Continuous Integration Server # Jenkins 持续集成服务器的描述
    4. Requires=network.target # 依赖于网络服务,表示网络必须先启动
    5. After=network.target # 在网络服务启动后再启动 Jenkins
    6. [Service]
    7. Type=notify # 服务类型为 notify,表示服务启动后会通知
    8. NotifyAccess=main # 仅监听主进程的通知
    9. ExecStart=/usr/bin/jenkins # 启动 Jenkins 的命令
    10. Restart=on-failure # 在服务失败时自动重启
    11. SuccessExitStatus=143 # 指定退出状态码 143 为正常退出
    12. User=root # 以 root 用户身份运行 Jenkins
    13. Group=root # 以 root 用户组身份运行 Jenkins
    14. Environment="JENKINS_HOME=/var/lib/jenkins" # 设置 Jenkins 主目录的环境变量
    15. WorkingDirectory=/var/lib/jenkins # 指定工作目录为 /var/lib/jenkins
    16. Environment="JENKINS_WEBROOT=%C/jenkins/war" # 设置 Jenkins Web 根目录的环境变量
    17. Environment="JAVA_OPTS=-Djava.awt.headless=true" # 设置 Java 选项为无头模式
    18. Environment="JENKINS_PORT=3333" # 设置 Jenkins 监听的端口为 3333
    19. [Install]
    20. WantedBy=multi-user.target # 在多用户目标(运行级别)下启动 Jenkins
    3、启动 jenkins
    • 启动之前修改以 root 用户、群组身份运行 Jenkins, 确保后面 Jenkins 有权限使用 Docker 服务。

    接下来启动:

    [root@k8s-master-node1 ~]# systemctl start jenkins
    3、验证安装
    1. [root@k8s-master-node1 /data]# ps -ef|grep jenkins
    2. root 3523 7329 0 14:04 pts/0 00:00:00 grep --color=auto jenkins
    3. jenkins 12697 1 7 14:01 ? 00:00:15 /usr/local/java/jdk1.8.0_121/bin/java -Dcom.sun.akuma.Daemon=daemonized -Djava.awt.headless=true -DJENKINS_HOME=/var/lib/jenkins -jar /usr/lib/jenkins/jenkins.war --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war --daemon --httpPort=8080 --debug=5 --handlerCountMax=100 --handlerCountMaxIdle=20
     
    
    3、jenkins配置(web页面)
    1、管理员密码获取

    [root@k8s-master-node1 ~]# cat /var/lib/jenkins/secrets/initialAdminPassword
    2、安装插件 (选择在线安装)

    如果采用最新版的 一般不一会出现这个情况

    出现离线安装解决方法:

    1、修改 /var/lib/jenkins/updates/default.json

    jenkins 在下载插件之前会先检查网络连接,其会读取这个文件中的网址。默认是访问谷歌,肯定监测失败,所以将图下的google改为www.baidu.com即可,更改完重启服务。

    2、 修改/var/lib/jenkins/hudson.model.UpdateCenter.xml

    该文件为jenkins下载插件的源地址,默认为:https://updates.jenkins.io/update-center.json,就是因为https的问题,此处我们将其改为http即可,之后重启jenkins服务即可。

    其他国内备用地址(也可以选择使用):

    https://mirrors.tuna.tsinghua.edu.cn/jenkins/updates/update-center.json

    http://mirror.esuni.jp/jenkins/updates/update-center.json

    在修复完之后,我们发现离线问题已经解决

    选择安装推荐的插件:

    3、创建第一个管理员用户

    4、url 配置

    之前版本没有这个选项,这里默认即可:

    5、安装完成

    出现如下页面时,表示安装完成

    6、配置 jdk、git、maven

    系统管理->全局工具配置

    jdk:可以自动安装,但是选择本地安装的适合项目jdk版本,写入我们jdk的路径即可

    git:

    maven:

    7、jenkins 下载插件失败处理办法

    jenkins 下载插件失败,提示:

    java.io.IOException: Downloaded file /app/jenkins_home/plugins/jacoco.jpi.tmp does not match expected SHA-1, expected 'CtK02wHdFOxTutqhUQzmue6uvpg=', actual 'YGO05utKyaaFzpGCgCE95GS0WsU='
        at hudson.model.UpdateCenter.verifyChecksums(UpdateCenter.java:1783)
        at hudson.model.UpdateCenter.access$1100(UpdateCenter.java:147)
        at hudson.model.UpdateCenter$InstallationJob.replace(UpdateCenter.java:1934)
        at hudson.model.UpdateCenter$UpdateCenterConfiguration.install(UpdateCenter.java:1178)
        at hudson.model.UpdateCenter$DownloadJob._run(UpdateCenter.java:1653)
        at hudson.model.UpdateCenter$InstallationJob._run(UpdateCenter.java:1848)
        at hudson.model.UpdateCenter$DownloadJob.run(UpdateCenter.java:1624)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at hudson.remoting.AtmostOneThreadExecutor$Worker.run(AtmostOneThreadExecutor.java:110)
        at java.lang.Thread.run(Thread.java:745)

    中国源的问题。需要换个源就可,换源方法:

    jenkins->系统管理->管理插件->高级 选择升级站点

    把:http://updates.jenkins-ci.org/update-center.json

    换成:http://mirror.esuni.jp/jenkins/updates/update-center.json

    镜像地址查询:

    http://mirrors.jenkins-ci.org/status.html

    四、使用Jenkins

    1、Jenkins 用户权限管理

    1、 用户管理背景

    针对开发、运维、测试针对不同角色进行不同权限划分,

    基于插件: Role-based Authorization Strategy ,Authorize Project 来实现。

    2、 安装用户管理插件

    安装该插件:

    系统管理->管理插件-可选插件->搜索该插件选中直接安装即可。

    3、 开启该插件功能

    系统管理->全局安全设置-授权策略->选中该插件功能即可->保存

    4、 验证用户管理

    关闭用户管理功能来进行实践测试

    1、策略改回原来的(全局安全配置)

    2、开启允许用户注册(全局安全配置)

    3、注册一个新用户

    4、登录之后,其默认就是管理员用户,可以进行任何操作

    5、开启 Role-Based Strategy
    6、重新登录新创建 test1 用户,显示已经没有任何权限了

    5、 权限划分

    安装 Role-Based Strategy 插件后,系统管理 中多了如图下所示的一个功能,用户权限的划分就是靠他来做的。

    1、Manage Roles(管理角色)
    • Manage Roles:管理角色,相当于针对角色赋予不同权限,然后在将该角色分配给用户。角色就相当于一个组。其里面又有Global roles(全局)、Project roles(项目)、Slave roles(),来进行不同划分。

    默认如图下所示:

    1、Global roles

    默认是有一个admin用户的,是所有权限都有的,所有权限都是勾选了的。

    接下来我们来添加一个角色:user

    给其一个读的权限。

    2、Item roles
    • roles to add:表示项目角色

    • Pattern:是用来做正则匹配的(匹配的内容是Job(项目名)),比如说根据正则匹配到的项目项目角色就都有权限;

    接下来新建一个island 项目角色,改项目角色一般给其构建、取消、读取、读取空间权限,一般配置这4个即可

    • Agent roles (代理角色):节点相关的权限

    • roles to add:表示项目角色

    • Pattern:是用来做正则匹配的(匹配的内容是节点(Agent节点)),比如说根据正则匹配到的项目项目角色就都有权限;

    2、Assigin roles(分配角色)
    1、给予test用户分配 user 角色

    这样其就有 manage roles 中刚才创建的user角色的权限了。

    此时再去看 test1用户,已有查看的权限了

    2、针对指定用户分配项目角色(一般最常用的就是针对不同用户进行项目角色分配)

    比如将test用户分配有 island 项目角色,这样其就可以有刚才我们创建的island 项目角色正则匹配到的项目的权限了。

    2、Jenkins 参数化构建

    1、 参数化构建背景

    如果只是简单的构建,jenkins自己默认的插件可以做,但是如果我们想要在构建过程中有更多功能,比如说:选择性构建、传参、项目指定变量等等其他功能,基础的参数化构建可以实现一些简单功能,但是要想使用更多功能这时候我们就需要借助参数化构建来实现交互的功能。此处我们来借助以下插件来进行实现:

    • Extended Choice Parameter(更丰富的参数化构建插件)

    • Git Parameter

    2、安装插件

    首先还是安装该插件,去管理插件里面进行安装 Extended Choice Parameter

    1、项目配置

    2、构建选择分支进行测试,添加branch参数 git配置中选$branch参数

    3、参数化配置已经生效

    3、Git 插件

    再用 git 时使用该插件是非常方便的。

    1、安装插件 Git Parameter

    2、进行配置

    在配置之前有一个坑,当我们在配置git中写了远端地址后,会有报错:

    这个是和前面docker报错是一样的

    这是因为 jenkins 我们 yum 装的运行用户是 jenkins 用户,此处是 jenkins 用户去 git 仓库进行拉取,而 jenkins 用户的话默认是 /bin/false 的,不但不能登录,也没有 git 命令权限,所以肯定是失败的。

    解决此问题两种办法:

    • 更改jenkins用户为root用户;

    • 更改jenkins用户为正常的普通用户/bin/bash,将其的公钥加入到git服务器的git用户中。

    此处暂时先用第一种解决办法,更改 jenkins 的运行用户为 root 用户,通过如下方式进行更改:

    • 将/usr/lib/systemd/system/docker.service;文件中user和group改为root

    • 然后再重启即可。

    3、Jenkins pipeline

    1、概览

    2、安装

    在对 jenkins 进行初始化安装时,默认已经安装了 jenkins 的相关插件,如下图所示:

    3、实操
    1、新建任务

    2、编写 pipeline 脚本

    可以借助流水线语法去做。

    roads流水线脚本:

    1. pipeline {
    2. agent any
    3. // 参数化
    4. parameters {
    5. // string defaultValue: '2.0.0', description: '选择版本', name: 'version'
    6. gitParameter branchFilter: 'origin/(.*)', defaultValue: 'master', name: 'BRANCH', type: 'PT_BRANCH'
    7. string(name: 'version', defaultValue: '2.0.0', description: '选择版本')
    8. }
    9. tools {
    10. jdk 'jdk1.8'
    11. maven 'maven-3.9.6'
    12. }
    13. stages {
    14. stage('pull code') {
    15. steps {
    16. cleanWs() //清空workspace
    17. echo 'pull start'
    18. git branch: "${params.BRANCH}", credentialsId: 'xxxxxxxxxxxxxxxxxxxx', url: 'xxxxxxxxxxxxxxxxxxxxxxx'
    19. echo 'pull end'
    20. }
    21. }
    22. stage('mvn install xxxxxxxxxx') {
    23. steps {
    24. echo 'build xxxxxxxx'
    25. dir('xxxxxxxx') {
    26. sh "mvn -v"
    27. sh "mvn clean install -Dmaven.test.skip=true"
    28. }
    29. }
    30. }
    31. stage('mvn install xxxxxxxxxx') {
    32. steps {
    33. echo 'build xxxxxxxx'
    34. dir('xxxxxxxxxxx') {
    35. sh "mvn clean install -Dmaven.test.skip=true"
    36. }
    37. }
    38. }
    39. stage('mvn install xxxxx') {
    40. steps {
    41. echo 'build xxxxxxxxx'
    42. dir('xxxxxxxx') {
    43. sh "mvn clean install -Dmaven.test.skip=true"
    44. }
    45. }
    46. }
    47. stage('mvn install island-opple') {
    48. steps {
    49. echo 'build island-opple'
    50. sh "mvn clean install -Dmaven.test.skip=true"
    51. }
    52. }
    53. // stage('login docker') {
    54. // steps {
    55. // echo 'start login docker'
    56. // sh "docker login --username=xxxxxxxxxxxx --password=xxxxxxxxx registry.cn-hangzhou.aliyuncs.com"
    57. // }
    58. }
    59. stage('make image and push') {
    60. steps {
    61. echo 'start build image'
    62. script {
    63. def selectedProjects = "${project_name}".split(',')
    64. if(selectedProjects.size()>0){
    65. for(int i=0;i
    66. aaa = selectedProjects[i].replace("\"", "")
    67. dir(aaa){
    68. sh "pwd"
    69. sh '''
    70. sed -i "1c FROM xxxxxxxxxxxxxxxxxx" Dockerfile
    71. '''
    72. sh "mvn -Ddocker.image.tag=${version} dockerfile:build"
    73. sh '''
    74. sleep 3
    75. image=$(docker images | sed -n '2p' | awk '{print $1":"$2}')
    76. echo $image
    77. '''
    78. // docker push $image
    79. }
    80. }
    81. }
    82. }
    83. }
    84. }
    85. }
    86. }
    3、构建测试

    具体配置详解请参考 Pipeline

    4、Jenkins 构建邮件状态通知

    1、 前提

    前提:服务器开启邮箱服务

    (如果启动失败修改/etc/postfix/main.cf,确保 inet_interfaces 参数正确设置。默认是inet_interfaces = localhost,

    如果你的服务器只想监听 IPv4 地址,可以将该参数设置为 inet_interfaces = 127.0.0.1

    如果想监听所有地址(包括 IPv4 和 IPv6),可以将其设置为 inet_interfaces = all

    2、 基础配置

    需要安装一个插件:

    插件: Email Extension Plugin

    进行配置:

    系统管理->系统设置->相关配置如下图:

    可以在此处进行测试发送!检验配置是否正确

    未完待续。。。。。。。。。

  • 相关阅读:
    SpringBoot-32-shiro整合mybatis
    Linux aarch64交叉编译之 qlibc 基础C/C++库
    【MySQL】MySQL操作库
    【教程】如何在服务器上部署豆瓣小组抢沙发聊天机器人
    065:mapboxGL在一个图层中随机添加100个标记(marker)
    原型继承
    用Python写个爬虫,赚了!
    Python实战系列-获取单页和多页京东评论
    安卓开发实例:高德地图
    C语言实现扫雷小游戏
  • 原文地址:https://blog.csdn.net/m0_63004677/article/details/139350534