├── .github
└── ISSUE_TEMPLATE
│ ├── 01_feature_request.md
│ ├── 09_bug_report.md
│ └── config.yml
├── .gitignore
├── README.md
├── ci
├── .DS_Store
├── lab03-jenkins
│ ├── README.md
│ ├── images
│ │ ├── .gitkeep
│ │ ├── freestyle-project-config.png
│ │ ├── freestyle-test-print-ip.png
│ │ ├── jenkins-home.png
│ │ ├── jenkins-master-logs.png
│ │ ├── pipeline-project-config.png
│ │ ├── systemctl-status-docker.png
│ │ └── tools.jpg
│ ├── sysctl.conf
│ └── templates
│ │ ├── baseimage
│ │ └── Jenkinsfile
│ │ └── general
│ │ └── Jenkinsfile
├── lab05-tekton
│ ├── README.md
│ ├── demo
│ │ ├── pipeline
│ │ │ └── build-pipeline.yaml
│ │ ├── run
│ │ │ └── run.yaml
│ │ ├── serviceaccount.yaml
│ │ ├── tasks
│ │ │ ├── deploy-to-k8s.yaml
│ │ │ └── source-to-image.yaml
│ │ └── trigger
│ │ │ ├── event-listener.yaml
│ │ │ ├── trigger-binding.yaml
│ │ │ └── trigger-template.yaml
│ └── media
│ │ ├── 16553854211360.jpg
│ │ ├── 16553856425843.jpg
│ │ ├── 16553864459332.png
│ │ ├── 16553875121264.jpg
│ │ ├── 2022-06-26 at 17.39.31.png
│ │ ├── CI:CD流程.png
│ │ └── tekton-concept.jpg
└── lab06-teamcity
│ ├── README.md
│ └── images
│ ├── dsl
│ ├── kotlin-dsl.png
│ └── versioned-settings.png
│ ├── installation
│ ├── post-install-setup-step1.png
│ ├── post-install-setup-step2.png
│ ├── post-install-setup-step3.png
│ ├── post-install-setup-step4.png
│ ├── post-install-setup-step5.png
│ ├── signup-teamcity-cloud-step1.png
│ ├── signup-teamcity-cloud-step2.png
│ ├── signup-teamcity-cloud-step3.png
│ ├── signup-teamcity-cloud-step4.png
│ ├── signup-teamcity-cloud-step5.png
│ └── signup-teamcity-cloud-step6.png
│ ├── integration
│ └── teamcity-plugin.png
│ ├── lab1
│ ├── lab1-step1.png
│ ├── lab1-step2.png
│ ├── lab1-step3.png
│ ├── lab1-step4.png
│ ├── lab1-step5.png
│ ├── lab1-step6.png
│ ├── lab1-step7.png
│ ├── lab1-step8.png
│ └── lab1-step9.png
│ ├── lab2
│ ├── lab2-step1.png
│ ├── lab2-step2.png
│ ├── lab2-step3.png
│ ├── lab2-step4.png
│ ├── lab2-step5.png
│ ├── lab2-step6.png
│ ├── lab2-step7.png
│ └── lab2-step8.png
│ ├── lab3
│ ├── lab3-step1.png
│ ├── lab3-step2.png
│ ├── lab3-step3.png
│ ├── lab3-step4.png
│ ├── lab3-step5.png
│ ├── lab3-step6.png
│ ├── lab3-step7.png
│ ├── lab3-step8.png
│ └── lab3-step9.png
│ ├── teamcity-icon.png
│ ├── teamcity-logo.png
│ └── workflow
│ └── teamcity-workflow.png
├── config
├── lab01-ansible
│ ├── ansible.cfg
│ ├── app-stack.yml
│ ├── hosts.ini
│ ├── img
│ │ ├── 192-1928992_order-66.jpg
│ │ ├── 1_BORbGnI7OfdUdsCk7URXKg.png
│ │ ├── 1_N2yWueFgHi6M_lQGGsnxVQ.png
│ │ ├── ansible-wide.png
│ │ └── t8redb90cc631.jpg
│ ├── init-users.yml
│ ├── inventory.v1
│ ├── inventory.v2
│ ├── readme.md
│ └── vars
│ │ └── default.yml
└── lab09-terraform
│ ├── README.md
│ └── images
│ ├── neworg.jpg
│ ├── plan.jpg
│ ├── tf.JPG
│ ├── var.JPG
│ └── vars.jpg
├── database
└── lab06-liquibase
│ ├── README.md
│ └── images
│ ├── flyway-1.jpg
│ ├── flyway-2.jpg
│ ├── flyway-3.jpg
│ ├── flyway-4.jpg
│ └── liquibase.jpg
├── deploy
└── lab04-argocd
│ ├── 0.necessary_before_start.md
│ ├── 1.install-k8s-cluster.md
│ ├── README.MD
│ ├── crds
│ ├── app-guestbook.yaml
│ ├── apps-matrix-generator.yaml
│ ├── appset-cluster-generator-base.yaml
│ ├── appset-cluster-generator-label.yaml
│ ├── appset-cluster-generator-value.yaml
│ ├── appset-git-generator-base.yaml
│ ├── appset-git-generator-file.yaml
│ ├── appset-git-gernator-exclude.yaml
│ ├── appset-list-generator.yaml
│ ├── argocd.yaml
│ ├── config-monday.yaml
│ └── eip-pool.yaml
│ └── images
│ ├── argocd-ui-create-app.png
│ ├── argocd-ui-login.png
│ ├── guest-book-app-1.png
│ └── guest-book-app-2.png
├── orchestration
└── lab10-k3s
│ └── README.md
└── platform
├── lab02-jihu-gitlab
├── README.md
└── img
│ ├── jihu-gitlab.png
│ ├── pipeline-build-log.png
│ ├── pipeline-build-result.png
│ ├── runner-succ.png
│ └── runner-token.png
└── lab09-atlassian
├── README.md
├── dev-process.png
├── devops-products.png
├── js-management.png
├── scrum.png
└── users.png
/.github/ISSUE_TEMPLATE/01_feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🚀 报名DevOps工具鉴宝分享 💠🪕💎
3 | title: '[Tools_name]
'
4 | labels: new lab, review needed
5 | about: 对工具的独到见解和技巧都值得分享给大家 💡🔥🔥🔥
6 | assignees:
7 | - martinliu
8 | - majinghe
9 | ---
10 |
15 |
16 | ## 概述
17 |
20 | >DevOps 工具
21 | * 名称:
22 | * 版本:
23 |
24 |
25 | >就职公司名称:
26 |
29 |
30 | >分享排期:
31 |
34 |
35 |
36 | >难度级别:
37 |
40 |
41 | >分享目标:
42 |
45 |
46 |
47 |
48 | >分享内容概述:
49 |
52 |
53 |
54 | >是否原创:
55 |
58 |
59 | >参考资料链接:
60 | * URL1:
61 | * URL2:
62 | * URL3:
63 |
64 |
65 |
66 | ## 运行环境
67 |
68 |
71 |
72 | >实操者运行环境:
73 |
74 | * 操作系统:
75 | * 工具版本:
76 | * 编程语言【如果有/需要】:
77 |
78 |
79 | >运行环境描述:
80 |
83 | * 虚拟机/云主机数量:
84 | * 操作系统:
85 | * 编程语言【如果有/需要】:
86 | * 云服务:
87 |
88 |
89 | ## 关于直播
90 |
91 | > 期望分享的时长:
92 |
93 | > 是否需要社区提供云资源支持,需要的话请概述需求:
94 |
95 | > 是否需求社区提供直播环境或者设备:
96 |
97 | 说明:如果对于主办方还有其它诉求,请加社区小助手微信【DevOps-SQ】联系我们。
98 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/09_bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🐜 报告 Bug
3 | about: 如果你发现了某个示例练习的 Bug ,或者值得优化的地方 🔧
4 | ---
5 |
6 | ### Version Information
7 | | Software | Version(s) |
8 | | ------------------------| ---------- |
9 | | NuGet Package | |
10 | | .NET Core? | |
11 | | .NET Full Framework? | |
12 | | Driver Windows OS? | |
13 | | Driver Linux OS? | |
14 | | Visual Studio? | |
15 | | RethinkDB Server | |
16 | | Server Windows OS? | |
17 | | Server Linux OS? | |
18 |
19 | ### What is the expected behavior?
20 |
21 | ### What is the actual behavior?
22 |
23 | ### Please provide a unit test that demonstrates the bug.
24 |
25 | ### Other notes on how to reproduce the issue?
26 |
27 | ### Please provide JSON protocol traces and log files.
28 |
29 | Enable driver logging and JSON protocol traces here:
30 | * https://github.com/bchavez/RethinkDb.Driver/wiki/Protocol-Debugging
31 |
32 | ### Any possible solutions?
33 |
34 | ### Can you identify the location in the driver source code where the problem exists?
35 |
36 | ### If the bug is confirmed, would you be willing to submit a PR?
37 |
38 | Yes / No _(Help can be provided if you need assistance submitting a PR)_
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: 🔖 关注中国DevOps社区官网
4 | url: https://DevOpsChina.org
5 | about: 访问社区官网了解“DevOps工具鉴宝”活动详情 🌐
6 | - name: 🔖 关注社区微信公众号
7 | url: https://mp.weixin.qq.com/s/__h3SpSNMdZ0LzsDEWV83A
8 | about: 与社区保持密切联系 🌐
9 | # name: Bug Report
10 | # description: File a bug report
11 | # title: "[Bug]: "
12 | # labels: ["bug", "triage"]
13 | # assignees:
14 | # - octocat
15 | # body:
16 | # - type: markdown
17 | # attributes:
18 | # value: |
19 | # Thanks for taking the time to fill out this bug report!
20 | # - type: input
21 | # id: contact
22 | # attributes:
23 | # label: Contact Details
24 | # description: How can we get in touch with you if we need more info?
25 | # placeholder: ex. email@example.com
26 | # validations:
27 | # required: false
28 | # - type: textarea
29 | # id: what-happened
30 | # attributes:
31 | # label: What happened?
32 | # description: Also tell us, what did you expect to happen?
33 | # placeholder: Tell us what you see!
34 | # value: "A bug happened!"
35 | # validations:
36 | # required: true
37 | # - type: dropdown
38 | # id: version
39 | # attributes:
40 | # label: Version
41 | # description: What version of our software are you running?
42 | # options:
43 | # - 1.0.2 (Default)
44 | # - 1.0.3 (Edge)
45 | # validations:
46 | # required: true
47 | # - type: dropdown
48 | # id: browsers
49 | # attributes:
50 | # label: What browsers are you seeing the problem on?
51 | # multiple: true
52 | # options:
53 | # - Firefox
54 | # - Chrome
55 | # - Safari
56 | # - Microsoft Edge
57 | # - type: textarea
58 | # id: logs
59 | # attributes:
60 | # label: Relevant log output
61 | # description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
62 | # render: shell
63 | # - type: checkboxes
64 | # id: terms
65 | # attributes:
66 | # label: Code of Conduct
67 | # description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com)
68 | # options:
69 | # - label: I agree to follow this project's Code of Conduct
70 | # required: true
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea/
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## DevOps Tools live show | 工具鉴宝活动
2 |
3 | >Must know DevOps Tools for Developer [codename = *MKT4D*]
4 |
5 | Welcome to the DevOps China code live show! This lab is a collection of hands-on, self-paced exercises that will help you gain practical experience with various DevOps concepts and tools. The exercises are designed to be simple, straightforward, and easy to follow, with step-by-step instructions.
6 |
7 | Season one playlist
8 | * [Bilibili](https://space.bilibili.com/370989874/channel/collectiondetail?sid=338624)
9 | * [YouTube](https://www.youtube.com/watch?v=XBglZDywiXk&list=PLbiCRAJeBtFucYb2W_autUr8G5OGAUFAU&ab_channel=DevOpsChina)
10 |
11 | Season two is now open for summit a new idea at [MKT4D issues](https://github.com/DevopsChina/mkt4d/issues)
12 |
13 | Each code live show is a separate directory in this repository, and each directory contains a README file with detailed instructions, along with any necessary configuration files or sample code. Whether you're new to DevOps or an experienced practitioner, this lab will help you take your skills to the next level and give you the confidence to tackle real-world challenges.
14 |
15 | ### 第二季鉴宝活动的鉴宝人火热招募中,请提交你的分享思路到:[MKT4D issues](https://github.com/DevopsChina/mkt4d/issues)
16 |
17 | ## 活动简介
18 |
19 | 大家想要获取DevOps的理念和技术,收获深刻的理解;社区建议的途径是示例项目实操。这里是直播节目的代码仓库。我们用 DevOps 工具鉴宝的直播方式,请各路实战经验丰富的工程师给社区分享一些列有趣有料的Codelab,并在直播过程中进行生动的讲解和互动问答。
20 |
21 | "DevOps鉴宝活动“的目标是:公开面向社区的所有人,征集DevOps工具链中各种工具的实战操作技能。
22 |
23 | 相关的 DevOps 工具应该包含,但不仅限于以下分类。
24 |
25 | - 软件仓库 | code – 管理软件版本的工具–目前使用最广泛的是Git。
26 | - 构建工具 | build – 有些软件在打包或使用前需要编译,传统的构建工具包括Make、Ant、Maven和MSBuild。
27 | - 持续集成工具 | ci – 在配置好以后,每次将代码提交到存储库中时,它都会对软件进行构建、部署和测试。这通常可以提高软件质量和上市时间。这个市场上最流行的工具是 Jenkins、Travis、TeamCity和Bamboo。
28 | - 代码分析/审查工具 | verify – 这些工具可以查找代码中的错误,检查代码格式和质量,以及测试覆盖率。这些工具因编程语言而异。SonarQube是这个领域的一个流行工具,还有其他各种 “轻量的 “工具。
29 | - 配置管理 | config – 配置管理工具和数据库通常存储所有关于你的硬件和软件项目的信息,以及提供一个脚本和/或模板系统,用于自动化常见任务。在这个领域似乎有很多玩家。传统的玩家是Chef、Puppet和Salt Stack。
30 | - 部署工具 | deploy – 这些工具有助于软件的部署。许多CI工具也是CD(持续部署)工具,它们协助软件的部署。传统上在Ruby语言中,Capistrano工具被广泛使用;在Java语言中,Maven被很多人使用。所有的编排工具也都支持某种形式的部署。
31 | - 编排工具 | release – 这些工具配置、调度和管理计算机系统和软件。它们通常将 “自动化 “和 “工作流 “作为其服务的一部分。Kubernetes是一个非常流行的编排工具,它专注于容器。Terraform是一个非常流行的编排工具,它的关注点更广,包括云编排。另外,每个云提供商都有自己的一套工具(CloudFormation、GCP Deployment Manager, 和ARM)。
32 | - 监控工具 | monitor - 这些工具允许监控硬件和软件。通常,它们包括监控代理程序,用于监视进程和日志文件,以确保系统的健康。Nagios是一种流行的监控工具。
33 | - 测试工具 | test - 测试工具用于管理测试,以及测试自动化,包括性能和负载测试等。
34 |
35 | 
36 |
37 | ## 学习清单
38 |
39 | 以下是所有 DevOps 鉴宝活动直播内容的回放清单,请大家根据需求学习打卡。社区也欢迎你在视频中发表弹幕和留言,分享你对 DevOps 工具的见解。
40 |
41 | ### code
42 |
43 |
44 | ### build
45 |
46 |
47 | ### test
48 |
49 |
50 | ### verify
51 |
52 |
53 | ### 持续集成 - ci
54 |
55 | - 第一季:第 3 集 恐龙级CI/CD工具 Jenkins [【Codelab】](ci/lab03-jenkins) - [【B 站视频】](https://www.bilibili.com/video/BV1MA4y1Z7Fk)
56 | - 第一季:第 5 集 云原生 CI 中的强者 Tekton [【Codelab】](ci/lab05-tekton) - [【B 站视频】](https://www.bilibili.com/video/BV1e94y117tY)
57 | - 第一季:第 6 集 云开发者可快速上手的 TeamCity [【Codelab】](ci/lab06-teamcity) - [【B 站视频】](https://www.bilibili.com/video/BV1pY4y17754)
58 |
59 | ### 配置管理
60 |
61 | - 第一季: 第 1 集 配置管理神器 Ansible - 新手入门指南 [【Codelab】](config/lab01-ansible) - [【B 站视频】](https://www.bilibili.com/video/BV1Uv4y1K7u9)
62 | - 第一季: 第 7 集 数据库变更版本管理利器 Liquibase [【Codelab】](database/lab06-liquibase) - [【B 站视频】](https://www.bilibili.com/video/BV1iT411E7Fk)
63 | - 第一季:第 9 集 - 基础架构自动化编排工具 Terraform [【Codelab】](config/lab09-terraform) - [【B 站视频】](https://www.bilibili.com/video/BV1HU4y1e7wZ)
64 |
65 |
66 | ### 部署 - deploy
67 |
68 | - 第一季:第 4 集 GitOps 的不二之选 ArgoCD [【Codelab】](deploy/lab04-argocd) -[【B 站视频】](https://www.bilibili.com/video/BV11a411L7f5)
69 |
70 | ### 编排 - Orchestration
71 |
72 | - 第一季:第 10 集 品鉴极简风格的容器平台 K3S [【Codelab】](orchestration/lab10-k3s) -[【B 站视频】](https://www.bilibili.com/video/BV11e411g7qx)
73 |
74 | ### 监控 - monitor
75 |
76 | ### 平台 - platform
77 |
78 | - 第一季:第 2 集 - 全能级 DevOps 平台 GitLab [【Codelab】](platform/lab02-jihu-gitlab) - [【B 站视频】](https://www.bilibili.com/video/BV1hR4y1c75b)
79 | - 第一季:第 9 集 - 品鉴 Atlassian 的 DevOps 全家桶的妙用 [【Codelab】](platform/lab09-atlassian) - [【B 站视频】](https://www.bilibili.com/video/BV1vG4y1a7ph)
80 |
81 |
82 |
83 |
84 | ## 贡献说明
85 |
86 | ### 目录结构
87 |
88 | 通过创建 PR 的方式,在以上分类目录中,按编号创建一个新的文件夹,用于容纳一个独立lab的所有相关代码。必须包含清晰的 readme 文件,在 readme 文件中清晰概要的描述相关技术知识要点,不能有意无意的包含任何产品市场宣传的内容。
89 |
90 | ```sh
91 | ├── README.md
92 | ├── build
93 | ├── ci
94 | ├── code
95 | ├── config
96 | │ └── lab01-ansible
97 | │ └── readme.md
98 | ├── deploy
99 | ├── monitor
100 | ├── release
101 | ├── test
102 | └── verify
103 | └── platform
104 | ```
105 |
106 | ### 参与贡献过程
107 |
108 | 本代码库面向所有社区朋友开放。为了让大家能够顺利的参与贡献,请参考以下参与流程。
109 |
110 | 1. 在代码库的 issue 列表中,用模板创建一个新 issue,简单描述 codelab 的内容,必须包含工具、技术、开发语言和难度级别等,让其他人更清晰的了解知识的范围。
111 | 2. Issue 的沟通和确认阶段,社区评审同学和提议者在 issue 的评论区完成讨论确认过程。
112 | 3. 进入 codelab 代码的 PR 提交阶段,请创建符合规则的分支名称 【 分类 - 编号 - 工具名称】,例如: code-lab01-git
113 | 4. 进入 PR 搞了确认,社区评审同学会进行评审和测试,并提出修改建议。
114 | 5. 提交 PR 的合并请求,本代码库的维护同学审批 MR ,代码正式纳入主干。
115 | 6. 进入 Codelab 的学习和宣传阶段,Codelab的提交者和其他鉴宝人,用线上直播的方式演示整个 codelab 的操作过程,并将录播视频在 B 站分享给大家。
116 | 7. 关闭 issue 。
117 | 8. Codelab 的 readme 文件内容和 B 站视频 会分享给社区的所有人。
118 |
119 | ## 鸣谢
120 |
121 | ### 赞助商福利资源
122 |
123 | * Red Hat :欢迎免费注册[红帽开发者账号](https://developers.redhat.com/),可以免费获得开发者个人订阅的详情[「点这里」](https://www.redhat.com/wapps/tnc/viewterms/72ce03fd-1564-41f3-9707-a09747625585?extIdCarryOver=true&intcmp=701f2000001OMHaAAO&sc_cid=701f2000001OH7YAAW);订阅中包含了 16 个物理/虚拟机上 RHEL 操作系统的开发者使用订阅,并且可以访问几乎红帽所有产品的安装包和源代码。官方微信公众号「红帽支持与服务」
124 | * 极狐 GitLab :欢迎[免费注册使用极狐GitLab SaaS](https://gitlab.cn/)。凡是通过 DevOps 社区鉴宝活动注册的用户,可以发邮件至 marketing@gitlab.cn,申请超长(超 1 个月以上)时间的旗舰版试用(发邮件是为了方便获取需要延长旗舰版试用的 Group 等信息)。
125 | * Elastic:欢迎[免费注册 Elastic Cloud 超长(30 天)试用账号](https://info.elastic.co/elasticsearch-service-trial-community-showcase.html?ultron=community-martin&hulk=30d),只需要邮箱,无需输入信用卡号,直接体验当前最新版本的 Elastic Stack 技术栈。官方微信公众号「Elastic搜索」
126 | * JetBrains TeamCity Cloud 平台焕然一新,CI/CD 本色依旧,[免费试用](https://www.jetbrains.com/zh-cn/teamcity/cloud/)DevOps社区成员亮明身份还可通过链接获取[更长试用时间](https://www.jetbrains.com/zh-cn/teamcity/get-in-touch/) 官方微信号「JetBrainsChina」
127 | * 阿里云云起实验室:由阿里云提供的面向个人和企业开发者的零门槛云上实践平台,让开发者能够在“做中学”。实验室提供详细的实验手册指导和免费的实验云资源,一键生成预置实验环境,让开发者能够快速体验云计算、大数据、人工智能等云服务实验场景和解决方案,帮助开发者快速提升使用云服务的能力。[免费体验](https://developer.aliyun.com/adc/?utm_content=g_1000342863)
128 | * Rancher:Rancher 是一个开源的企业级 Kubernetes 管理平台,实现了 K8s 集群在混合云+本地数据中心的集中部署与管理。关注「Rancher 微信公众号」,第一时间了解 Rancher 中文论坛精选内容,公众号后台回复「工具鉴宝」还能免费解锁 K8s 安全防护终极指南哦~
129 |
130 |
131 | ### 赞助商参与
132 |
133 | #### 第一季
134 |
135 | 第一期:
136 |
137 | * Red Hat & 极狐GitLab 赞助了直播抽奖礼品
138 | * JetBrains 赞助鉴宝人礼品
139 |
140 | 第二期:
141 |
142 | * Elastc & 极狐GitLab 赞助了直播抽奖礼品
143 | * JetBrains 赞助鉴宝人礼品
144 |
145 | 第三期:
146 |
147 | * 阿里云云起实验室 & Elastc 赞助了直播抽奖礼品
148 | * JetBrains 赞助鉴宝人礼品
149 |
150 | 第四期:
151 |
152 | * 阿里云云起实验室 & Elastc 赞助了直播抽奖礼品
153 | * JetBrains 赞助鉴宝人礼品
154 |
155 | 第五期:
156 |
157 | * 阿里云云起实验室 & Elastc 赞助了直播抽奖礼品
158 | * JetBrains 赞助鉴宝人礼品
159 |
160 | 第六期:
161 |
162 | * 阿里云云起实验室 & Elastc 赞助了直播抽奖礼品
163 |
164 | 第七期:
165 |
166 | * 阿里云云起实验室 & Elastc 赞助了直播抽奖礼品
167 |
168 | 第八期:
169 |
170 | - 阿里云云起实验室、中国DevOps社区
171 |
172 | 第九期:
173 |
174 | - 阿里云云起实验室 &Rancher
175 |
176 | 第十期:
177 |
178 | - 阿里云云起实验室 &Rancher
179 |
180 | ## 行为准则
181 |
182 | 本项目是面向所有社区参与者的共创学习项目,请任何参与者遵守[《中国DevOps社区行为规范》](https://www.devopschina.org/codeofconduct/)
183 |
--------------------------------------------------------------------------------
/ci/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/.DS_Store
--------------------------------------------------------------------------------
/ci/lab03-jenkins/README.md:
--------------------------------------------------------------------------------
1 | # Jenkins 快速入门和使用技巧
2 |
3 |
4 |
5 |
6 | ## 1. Jenkins 介绍
7 |
8 | ```markdown
9 | # 构建伟大,无所不能。
10 |
11 | Jenkins 是开源 CI&CD 软件领导者, 提供超过1000个插件来支持构建、部署、自动化,满足任何项目的需要。
12 |
13 | > 出自 [Jenkins 官网](https://www.jenkins.io/zh/)
14 |
15 | ```
16 |
17 | ### 1.1 历史考古
18 |
19 | 1. 大约在 2001 年,ThoughtWorks 开源了 CruiseControl(后面出了商业版本叫 Cruise,再后来改名为 GoCD)。
20 | 1. 2004 年夏天由 Sun 公司开发的 Hudson ,在 2005 年 2 月开源并发布第一个版本。
21 | 1. 大约在 2007 年,Hudson 被称为 Cruise Control 和其他开源构建服务器的更好替代品。
22 | 1. 2008 年 5 月的 JavaOne 大会上,Hudson 获得了开发解决方案类的 Duke's Choice 奖项。
23 | 1. 大约在 2010 年,甲骨文声称拥有 Hudson 的商标的权利,所以在 2011 年 1 月通过社区投票改名为 Jenkins (事件起因是因为 2009 年 6月 Oracle 收购 Sun)。
24 | 1. 2011 年 2 月,Jenkins 的第一个版本 1.396 版可供公众使用。
25 | 1. 2015 年 5 月,Jenkins 发布了基于 Java 7 的 1.612 版本。
26 | 1. 2016 年 4 月,Jenkins 发布了 2.0 版本。
27 | 1. 2017 年 4 月,Jenkins 发布了基于 Java 8 的 2.54 版本。
28 | 1. 2019 年 2 月,Jenkins 发布了基于 Java 8 和 Java 11的 2.164 版本。
29 | 1. 2022 年 5 月,截至目前最新版本 Jenkins 2.347 Weekly 和 Jenkins 2.332.3 LTS
30 |
31 | 资料链接
32 |
33 | * https://martinfowler.com/articles/continuousIntegration.html
34 | * http://cruisecontrol.sourceforge.net/download.html
35 | * https://en.wikipedia.org/wiki/Jenkins_(software)
36 | * https://www.jenkins.io/blog/2012/02/02/happy-birthday-jenkins/
37 | * https://www.jenkins.io/2.0/
38 | * https://www.jenkins.io/blog/2017/04/10/jenkins-has-upgraded-to-java-8/
39 | * https://www.jenkins.io/download/
40 | * https://www.jenkins.io/blog/2011/06/16/jenkins-long-term-support-release/
41 | * https://www.jenkins.io/blog/2012/03/13/why-does-jenkins-have-blue-balls/
42 | * https://www.jenkins.io/blog/2017/01/17/Jenkins-is-upgrading-to-Java-8/
43 |
44 | ### 1.3 相关工具对比
45 |
46 | * https://en.wikipedia.org/wiki/Comparison_of_continuous_integration_software
47 | * https://github.blog/2017-11-07-github-welcomes-all-ci-tools/
48 |
49 |
50 | ### 1.4 推荐学习文档
51 |
52 | * https://www.jenkins.io/doc/book/pipeline/
53 | * https://www.bilibili.com/video/BV1fp4y1r7Dd
54 | * https://github.com/cloudbees/groovy-cps/blob/master/doc/cps-model.md
55 | * https://github.com/cloudbees/groovy-cps/blob/master/doc/cps-basics.md
56 |
57 | ## 2. 环境安装
58 |
59 | 本教程推荐使用 `docker` 在 Rocky Linux 8上安装 Jenkins 。
60 |
61 | > 备注:任何安装有 `docker` 工具的环境都可以。
62 |
63 | 测试环境服务器信息:
64 |
65 | * 本地 Rocky Linux 8 虚拟机,配置 4C16G 40G(sys) 100G(data)
66 | * IP:192.168.2.220
67 |
68 | ### 2.1 搭建原理
69 |
70 | 借助 docker 启动 Jenkins 简化服务部署,通过 Swarm 实现 Agent 节点的自动注册。其中 **Swarm** 是一个 **Jenkins** 插件,它允许节点加入附近的 **Jenkins**,从而形成一个特别的集群。通过这个插件我们可以自动向 **Jenkins** 添加 **Agent** 节点,而不用先在 **Jenkins** 上手动创建节点和注册,这个是一个不错的想法。
71 |
72 | ### 2.2 初始环境
73 |
74 | 在执行下面的步骤之前需要先完成节点的初始化,比如:关闭防火墙,性能调优配置(sysctl/ulimit)等
75 |
76 | 1. 安装 docker/docker-compose 工具
77 |
78 | 运行下面的命令:
79 | ```bash
80 | yum install -y yum-utils
81 | yum-config-manager \
82 | --add-repo \
83 | https://download.docker.com/linux/centos/docker-ce.repo
84 |
85 | # 注意命令 docker-compose 已经作为 docker 插件,使用时需要将 docker-compose 改成 docker compose
86 | yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
87 |
88 | mkdir -p /etc/docker
89 | # 配置 docker ,让数据放在数据盘目录,比如:/data
90 | cat << EOF > /etc/docker/daemon.json
91 | {
92 | "bip":"192.168.101.1/24",
93 | "data-root":"/data/var/lib/docker/",
94 | "log-driver": "json-file",
95 | "log-opts": {
96 | "max-size": "10m",
97 | "max-file": "3"
98 |
99 | },
100 | "exec-opts": ["native.cgroupdriver=systemd"],
101 | "default-ulimits": {
102 | "nofile": {
103 | "Name": "nofile",
104 | "Hard": 64000,
105 | "Soft": 64000
106 | }
107 | },
108 | "storage-driver": "overlay2",
109 | "storage-opts": [
110 | "overlay2.override_kernel_check=true"
111 | ],
112 | "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"]
113 | }
114 | EOF
115 | # 注意:
116 | # 1. 在EOF后面输入一个回车键,并且里面的网段可以自己指定,切记不好和主机所在网段冲突。
117 | # 2. 需要将本文档同级目录下文件 sysctl.conf 的内容放到本次演示环境的 /etc/sysctl.conf 中,然后执行 sysctl -p 让其配置生效。
118 |
119 | systemctl stop firewalld
120 | systemctl disable firewalld
121 |
122 | systemctl restart docker
123 | systemctl status docker
124 | systemctl enable docker
125 | ```
126 | 上面的命令执行完成,正常情况会出现如下图:
127 |
128 | 
129 |
130 | > 注:其他发行版本的搭建方式请参见:https://docs.docker.com/engine/install/
131 |
132 | ### 2.3 启动服务
133 |
134 | 1. 创建目录、导入启动文件、启动服务、观察日志
135 |
136 | ```bash
137 | alias docker-compose='docker compose'
138 | # 创建系统目录和数据目录
139 | mkdir -p /data/opsbox-dev/{system,data}/jenkins/
140 | # 设置数据目录权限,因为会将容器数据映射到主机
141 | chown -R 1000:1000 /data/opsbox-dev/data/jenkins
142 |
143 | cd /data/opsbox-dev/system/jenkins
144 | cat << EOF > docker-compose.yml
145 | version: '3'
146 | services:
147 | jenkins-master:
148 | container_name: jenkins
149 | image: registry.jihulab.com/opsbox-dev/oes-jenkins-plus:jenkins-v0.1.1-2.319.1-SNAPSHOT
150 | restart: unless-stopped
151 | ports:
152 | - 30080:8080
153 | - 50000:50000
154 | volumes:
155 | - /data/opsbox-dev/data/jenkins:/var/jenkins_home
156 | environment:
157 | JAVA_OPTS: >-
158 | -server
159 | -Xmx2g -Xms1g
160 | -XX:+UnlockExperimentalVMOptions -XX:+UseContainerSupport
161 | -XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC
162 | -XX:MaxGCPauseMillis=100 -XX:+UseAdaptiveSizePolicy
163 | -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8
164 | -Djenkins.install.runSetupWizard=false
165 | -Dhudson.model.LoadStatistics.clock=2000
166 | -Dhudson.model.ParametersAction.keepUndefinedParameters=true
167 | -Dorg.apache.commons.jelly.tags.fmt.timeZone=Asia/Shanghai
168 | -Duser.timezone=Asia/Shanghai
169 | -Dcom.sun.jndi.ldap.connect.pool.timeout=300000
170 | -Dhudson.security.csrf.DefaultCrumbIssuer.EXCLUDE_SESSION_ID=true
171 |
172 | jenkins-swarm:
173 | image: registry.jihulab.com/opsbox-dev/oes-jenkins-plus:jenkins-swarm
174 | restart: unless-stopped
175 | privileged: true
176 | volumes:
177 | - /tmp:/tmp
178 | - /lib/modules:/lib/modules # 好奇怪的配置在 rockylinux8,如果没有在执行 iptable 时会报异常
179 | depends_on:
180 | - jenkins-master
181 | links:
182 | - jenkins-master
183 | environment:
184 | JENKINS_URL: http://jenkins-master:8080
185 | JENKINS_USR: admin
186 | JENKINS_PSW: jenkins
187 | LABELS: docker
188 |
189 | EOF
190 | # 注意这里要给一个回车键
191 |
192 | # 拉取镜像
193 | docker-compose pull
194 | # 启动服务
195 | docker-compose up -d
196 | # 检查服务
197 | docker-compose ps
198 | # 查看日志
199 | docker-compose logs -f
200 | ```
201 |
202 | > 注:里面使用到的镜像打包源码地址:https://github.com/opsbox-dev/oes-jenkins-plus
203 |
204 | 启动日志效果如下图:
205 |
206 | 
207 |
208 | 2. 打开浏览器访问 http://192.168.2.220:30080
209 |
210 | > 账号:*admin* 密码:*jenkins*
211 |
212 | ### 2.4 测试环境
213 |
214 | 创建一个任务测试环境,主要是确保 docker 服务可用。
215 |
216 | 
217 |
218 | ## 3. 基础概念
219 |
220 | ### 3.1 流程和工具
221 |
222 | 大师 **Martin Fowler** 对持续集成是这样定义的:持续集成是一种软件开发实践,即团队开发成员经常**集成他们的工作**,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括**编译,发布,自动化测试**)来验证,从而尽快地发现集成错误。许多团队发现这个过程可以大大减少集成的问题,让团队能够更快的开发内聚的软件。
223 |
224 | 软件开发和交付过程,开发人员会在不同阶段持续使用如下面图中的工具在实现构建、打包、归档、部署和测试,执行完一次就算一次交付。
225 |
226 | 
227 |
228 | > 注:上图整理了我目前在 CI/CD 工作中用的最多的工具,大家可以根据自己的情况整理出自己的技术栈和相关工具。
229 |
230 | ### 3.2 自由风格工程 和 Pipeline 工程的对比
231 |
232 | #### 1. 自由风格工程特点
233 |
234 | 配置页面分为 6 个区域,包括:工程信息、源码管理、构建触发器、构建环境、构建步骤和构建后动作。配置界面如下图:
235 |
236 | 
237 |
238 | #### 2. Pipeline 工程的特点
239 |
240 | 配置界面分为 4 个区域,包括:工程信息、构建触发器和流水线配置。配置界面如下图:
241 |
242 | 
243 |
244 | #### 3. 两种风格对比演示
245 |
246 | 自由风格配置界面
247 |
248 | 
249 |
250 | 采用流水线风格描述
251 |
252 | ```groovy
253 | pipeline {
254 | agent any
255 |
256 | stages {
257 | stage('Hello') {
258 | environment {
259 | // 目前 credentials 支持 Secret Text/Secret File/Username and password/SSH with Private Key等 4 种类型。
260 | SSHKEY = credentials('vm-220')
261 | }
262 | steps {
263 | echo 'Hello Jenkins'
264 |
265 | // 打印当前 Jenkins Agent 的 IP,在 Jenkins Swarm Agent 容器里面。
266 | sh "ip addr"
267 |
268 | // 打印 192.168.2.220 节点 IP 信息
269 | sh "ssh -o StrictHostKeyChecking=no -i ${SSHKEY} ${SSHKEY_USR}@192.168.2.220 'ip addr'"
270 |
271 | }
272 | }
273 | }
274 | }
275 |
276 | ```
277 |
278 | > 注:执行需要创建登录 192.168.2.220 的密钥,并将私钥录入 Jenkins 的 Credentials 中。
279 |
280 | 相关文档链接:
281 | * https://www.jenkins.io/doc/pipeline/steps/credentials-binding/
282 | * https://www.jenkins.io/doc/book/pipeline/syntax/
283 |
284 | ### 3.3 Jenkins 2.0 中核心的 Jenkinsfile 两种语法背后的历史和原理
285 |
286 | #### 1. Jenkins 2.0 历史
287 |
288 | 历史回顾:
289 |
290 | 1. 2014 年 5 月,groovy-cps 库诞生了 0.1 版本。
291 | 2. 2016 年 4 月,Jenkins 发布了 2.0 版本,对应的 groovy-cps-1.7。
292 | 4. 2016 年 8 月,Jenkins 的 pipeline-model-definition 插件发布 0.1 版本。
293 | 5. 2017 年 2 月,Jenkins 的 pipeline-model-definition 插件发布 1.0 GA 版本。
294 | 6. 2017 年 4 月,Blue Ocean 1.0
295 | 7. 2017 年 4 月,Jenkins 发布了基于 Java 8 的 2.54 版本,对应的 pipeline-model-definition-1.1.1。
296 |
297 | #### 2. Scripted Pipeline 特点和原理
298 |
299 | **特点**
300 |
301 | Scripted Pipeline 支持更多的 Groovy 语言语法,不像 Declarative Pipeline 受那么多的结构化限制。由于可以编写灵活的逻辑,可以认为是高级版的 pipeline。
302 |
303 | 如果打算实现的逻辑比较灵活,比如有判断、分支,或者需要用 Groovy 语言编写复杂的运行步骤,都应该选择使用 Scripted Pipeline。
304 |
305 | **原理**
306 |
307 | 所有的开始都是起源于 KK 的一个叫 groovy-cps 项目。
308 |
309 | CPS(Continuation-Passing-Style, 续体传递风格)是一种编程风格:所有的控制块都通过 continuation 来显式传递。在 CPS 风格中,函数不能有返回语句,它的调用者要想获得它的结果,需要显式传递一个回调函数来获取结果并继续执行。而为了保证整个程序执行下去,这个回调函数还会一直嵌套下去。这里的回调函数就是一个 continuation 。
310 |
311 | 使用 CPS 来实现 Jenkins Pipeline 的原因是期望在任何时候都可以中断代码的执行保存状态,并在适当时候恢复执行。这可以应对 Jenkins Agent 宕机的场景。如果一个函数执行过后就返回了,那么就会丢失一部分状态,CPS 代码由于在中间不返回结果,因此可以解决这个问题。
312 |
313 | 然而,编写 Pipeline 代码的 Groovy 语言,其本身并不是 CPS 风格的,这就需要一个解释器将代码编译成 CPS 风格,在 Jenkins 里面通过 workflow-cps-plugin 包装 groovy-cps 这个库来完成。
314 |
315 | 在 workflow-cps-plugin 插件中,将 Job 配置的 Jenkinsfile 解析转为为 `CpsScript` 对象,并借助 Groovy 强大的 DSL (领域特定语言) 能力,实现对特点关键的解析。
316 |
317 |
318 | 举个栗子:
319 |
320 | ```groovy
321 | node {
322 | def mvnHome = tool 'M3'
323 |
324 | stage('Checkout') {
325 | checkout scm
326 | }
327 |
328 | stage('Build') {
329 | sh "${mvnHome}/bin/mvn -B package"
330 | }
331 | }
332 |
333 | ```
334 | > 代码来源:https://github.com/cloudogu/jenkinsfiles/blob/1-scripted/Jenkinsfile
335 |
336 |
337 | 参考链接:
338 |
339 | * https://docs.groovy-lang.org/3.0.7/html/gapi/index.html?groovy/lang/Script.html
340 | * https://github.com/cloudbees/groovy-cps/blob/master/doc/cps-basics.md
341 | * https://github.com/cloudbees/groovy-cps
342 | * https://github.com/jenkinsci/workflow-cps-plugin
343 | * https://github.com/jenkinsci/pipeline-stage-step-plugin
344 | * https://github.com/cloudogu/jenkinsfiles
345 | * https://www.jenkins.io/blog/2016/09/06/jenkins-world-speaker-blog-pipeline-model-definition/
346 | * https://www.jenkins.io/blog/2016/12/19/declarative-pipeline-beta/
347 | * https://www.jenkins.io/blog/2017/02/03/declarative-pipeline-ga/
348 | * https://www.jenkins.io/blog/2017/02/15/declarative-notifications/
349 | * https://www.jenkins.io/blog/2017/04/05/say-hello-blueocean-1-0/
350 | * https://www.jenkins.io/blog/2017/04/10/jenkins-has-upgraded-to-java-8/
351 | * https://www.jenkins.io/blog/2014/07/08/workflow-plugin-tutorial-writing-a-step-impl/
352 |
353 |
354 | #### 3. Declarative Pipeline 特点和原理
355 |
356 | **特点**
357 |
358 | Declarative Pipeline 设计意图是使用户将所需要的 Pipeline 以各种维度的参数声明出来,而不是编程的方式描述出来。相对 Scripted Pipeline 语法前者更简单, 但是 Declarative Pipeline 缺少灵活性,所以 Scripted Pipeline 中使用的部分语法在 Declarative Pipeline 中都不能直接使用,但是可以通过在 Declarative Pipeline 中使用 `script` Step 来支持。
359 |
360 | Declarative Pipeline 的特点是结构化的声明语句,各模块的从属关系比较固定,类似填写 Jenkins 配置 Job 页面的表单。固定格式的声明语句,还有利于从 BlueOcean 中查看工作流。
361 |
362 | **原理**
363 |
364 | Declarative Pipeline 是在 Scripted Pipeline 基础上开发,通过实现 `pipeline` 块(block)的语法,以此实现配置风格的流水线描述方式。所以在开发 Declarative Pipeline 时可以在 `pipeline` 块之外可以写 Groovy Scripts。
365 |
366 | 语法结构
367 |
368 | ```groovy
369 |
370 | pipeline {
371 | // 运行的节点
372 | agent {}
373 |
374 | // 全局预设环境变量,包括 Credentinal 变量
375 | envrionment {}
376 |
377 | // 触发器
378 | triggers {}
379 |
380 | // 外部库
381 | libraries {}
382 |
383 | // 特效配置
384 | options {
385 | //打开控制台日志的时间戳
386 | timestamps()
387 | // 指定失败后的重试次数
388 | retry(3)
389 | // 指定启动前等待的秒数
390 | quietPeriod(30)
391 | // 指定任务的超时时间,超时将放弃该任务
392 | timeout(time: 1, unit: 'HOURS')
393 | }
394 |
395 | // 构建参数
396 | parameters {}
397 |
398 | // 载入工具
399 | tools {}
400 |
401 | // 构建任务编排
402 | stages {
403 | stage {
404 | agent {}
405 | environment {}
406 | tools {}
407 | input {}
408 | when {}
409 | steps {
410 | sh ""
411 | echo ""
412 | script {
413 | //...
414 | }
415 | withEnv {
416 |
417 | }
418 | }
419 | // 并行任务编排
420 | parallel {}
421 | }
422 | // other stages
423 | }
424 |
425 | // 构建后处理
426 | post {
427 |
428 | }
429 | }
430 |
431 | ```
432 |
433 | 参考链接
434 |
435 | * https://github.com/jenkinsci/pipeline-model-definition-plugin
436 | * https://github.com/jenkinsci/pipeline-model-definition-plugin/blob/master/EXTENDING.md
437 |
438 | #### 4. Jenkinsfile 几种扩展方式
439 |
440 | 1. 直接在 Jenkinsfile 中开发功能函数
441 |
442 | ```groovy
443 | pipeline {
444 |
445 | agent any
446 |
447 | options {
448 | disableConcurrentBuilds()
449 | skipDefaultCheckout true
450 | }
451 |
452 | stages{
453 |
454 | stage("Checkout Code") {
455 | steps {
456 | script {
457 | deleteDir()
458 | cleanWs()
459 | def branch = purgeBranchString(git.branch)
460 | git branch: "${branch}", credentialsId: "${git.auth}", url: "${git.url}"
461 | }
462 | }
463 | }
464 | }
465 | }
466 |
467 | def purgeBranchString(branch) {
468 |
469 | def gitBranch = branch
470 |
471 | if (gitBranch?.startsWith("refs/heads/")) {
472 | gitBranch = gitBranch.replace("refs/heads/", "")
473 | }
474 |
475 | if (gitBranch?.startsWith("refs/tags/")) {
476 | gitBranch = gitBranch.replace("refs/tags/", "")
477 | }
478 |
479 | return gitBranch
480 | }
481 |
482 |
483 | ```
484 |
485 | 2. 通过外部共享库扩展
486 |
487 | * https://github.com/SAP/jenkins-library/tree/0.1
488 |
489 | 3. 通过开发插件,这里面又有两种,一种是兼容自由风格的,一种是直接继承 `Step` 类来实现的。
490 |
491 | * https://github.com/jenkinsci/pipeline-utility-steps-plugin
492 | * https://github.com/opsbox-dev/oes-pipeline-plugin
493 |
494 | ## 4. 实战练习
495 |
496 | >两三句话的简介?
497 |
498 | * https://github.com/seanly/cloudogu-jenkinsfiles
499 |
--------------------------------------------------------------------------------
/ci/lab03-jenkins/images/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab03-jenkins/images/.gitkeep
--------------------------------------------------------------------------------
/ci/lab03-jenkins/images/freestyle-project-config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab03-jenkins/images/freestyle-project-config.png
--------------------------------------------------------------------------------
/ci/lab03-jenkins/images/freestyle-test-print-ip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab03-jenkins/images/freestyle-test-print-ip.png
--------------------------------------------------------------------------------
/ci/lab03-jenkins/images/jenkins-home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab03-jenkins/images/jenkins-home.png
--------------------------------------------------------------------------------
/ci/lab03-jenkins/images/jenkins-master-logs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab03-jenkins/images/jenkins-master-logs.png
--------------------------------------------------------------------------------
/ci/lab03-jenkins/images/pipeline-project-config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab03-jenkins/images/pipeline-project-config.png
--------------------------------------------------------------------------------
/ci/lab03-jenkins/images/systemctl-status-docker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab03-jenkins/images/systemctl-status-docker.png
--------------------------------------------------------------------------------
/ci/lab03-jenkins/images/tools.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab03-jenkins/images/tools.jpg
--------------------------------------------------------------------------------
/ci/lab03-jenkins/sysctl.conf:
--------------------------------------------------------------------------------
1 | # 禁用sysrq
2 | kernel.sysrq = 0
3 | # 为core文件名添加pid扩展
4 | kernel.core_uses_pid = 1
5 | # 设置消息队列
6 | ## 消息队列中最大的字节数
7 | kernel.msgmnb = 65536
8 | ## 一个进程发送到另一个进程的消息最大长度
9 | kernel.msgmax = 65536
10 | ## 参数定义了共享内存段的最大尺寸(以字节为单位),64G
11 | kernel.shmmax = 68719476736
12 | ## 表示统一一次可以使用的共享内存总量(以页为单位)。默认是2097152
13 | kernel.shmall = 4294967296
14 | # 表示将mmap的基址,stack,vdso页面,栈(heap)的随机化
15 | kernel.randomize_va_space = 2
16 | # 检测到soft lockup时自动panic
17 | kernel.softlockup_panic = 1
18 | # softlockup时回溯所有cpu信息
19 | kernel.softlockup_all_cpu_backtrace = 1
20 |
21 | # socket监听(listen)的backlog上限
22 | net.core.somaxconn = 32768
23 | #接收套接字缓冲区大小的默认值(以字节为单位)
24 | net.core.rmem_default = 262144
25 | #发送套接字缓冲区大小的默认值(以字节为单位)。
26 | net.core.wmem_default = 262144
27 | #接收套接字缓冲区大小的最大值(以字节为单位)
28 | net.core.rmem_max = 16777216
29 | #发送套接字缓冲区大小的最大值(以字节为单位)。
30 | net.core.wmem_max = 16777216
31 | # #当网卡接收数据包的速度大于内核处理的速度时,会有一个队列保存这些数据包。这个参数表示该队列的最大值。
32 | net.core.netdev_max_backlog = 20000
33 |
34 | # 开启路由转发
35 | net.ipv4.ip_forward = 1
36 | # 禁用所有ip源路由
37 | net.ipv4.conf.default.accept_source_route = 0
38 | # 决定检查一次相邻层记录的有效性的周期,秒
39 | net.ipv4.neigh.default.gc_stale_time=120
40 | # 关闭rp_filter
41 | net.ipv4.conf.all.rp_filter=0
42 | net.ipv4.conf.default.rp_filter=0
43 | net.ipv4.conf.lo.arp_announce=2
44 | net.ipv4.conf.lo.arp_announce=2
45 | # arp数据包yuanip选择策略
46 | net.ipv4.conf.default.arp_announce = 2
47 | net.ipv4.conf.all.arp_announce=2
48 | # 开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击
49 | net.ipv4.tcp_syncookies = 1
50 | # 内核最多重试几次发送SYN包
51 | net.ipv4.tcp_synack_retries = 2
52 | # 启用时间戳
53 | net.ipv4.tcp_timestamps = 1
54 | # 关闭空闲连接tcp慢启动
55 | net.ipv4.tcp_slow_start_after_idle=0
56 | # socker使用内存大小 最小字节数,默认字节数,最大字节数
57 | net.ipv4.tcp_rmem = 4096 12582912 16777216
58 | net.ipv4.tcp_wmem = 4096 12582912 16777216
59 | # 确定TCP栈应该如何反映内存使用,每个值的单位都是内存页(通常是4KB)。第一个值是内存使用的下限;第二个值是内存压力模式开始对缓冲区使用应用压力的上限;第三个值是内存使用的上限。在这个层次上可以将报文丢弃,从而减少对内存的使用
60 | net.ipv4.tcp_mem = 786432 2097152 3145728
61 | # TCP处于FIN-WAIT-2连接状态的时间
62 | net.ipv4.tcp_fin_timeout = 30
63 | #表示那些尚未收到客户端确认信息的连接(SYN消息)队列的长度,默认为1024,加大队列长度为16384,可以容纳更多等待连接的网络连接数。
64 | net.ipv4.tcp_max_syn_backlog = 16384
65 | # 表示系统同时保持TIME_WAIT套接字的最大数量。如果超过此数,TIME_WAIT套接字会被立刻清除并且打印警告信息。之所以要设定这个限制,纯粹为了抵御那些简单的DoS攻击,不过,过多的TIME_WAIT套接字也会消耗服务器资源,甚至死机。
66 | net.ipv4.tcp_max_tw_buckets = 180000
67 | # 允许重用TIME_WAIT状态的套接字用于新的TCP连接
68 | net.ipv4.tcp_tw_reuse = 1
69 | #关闭TCP连接中TIME_WAIT套接字的快速回收
70 | net.ipv4.tcp_tw_recycle = 0
71 | #允许系统打开的端口范围
72 | net.ipv4.ip_local_port_range = 1024 65535
73 | # 不处理ipv6数据包
74 | #net.bridge.bridge-nf-call-ip6tables = 0
75 | # 不处理数据包
76 | #net.bridge.bridge-nf-call-arptables = 0
77 | # 默认过滤数据包
78 | #net.bridge.bridge-nf-call-iptables = 1
79 |
80 | # iptables对于已建立的连接,1200秒若没有活动,那么则清除掉
81 | net.netfilter.nf_conntrack_tcp_timeout_established = 1200
82 | # iptables最大连接数
83 | net.netfilter.nf_conntrack_max = 1048576
84 |
85 | # 当可用内存小于10%时使用交换空间
86 | vm.swappiness = 10
87 |
88 | # 内存脏数据占比20%时,阻塞io,刷入磁盘
89 | vm.dirty_ratio = 20
90 | # 内存脏数据占比10%时,后台进程会稍后清理脏数据
91 | vm.dirty_background_ratio = 10
92 | # 表示内核允许分配所有的物理内存,不检测当前的内存状态如何
93 | vm.overcommit_memory = 1
94 |
95 | # 一个进程可以拥有的VMA(虚拟内存区域)的数量
96 | vm.max_map_count = 655360
97 | # 该文件表示内核回收用于directory和inode cache内存的倾向
98 | vm.vfs_cache_pressure=300
99 | # Linux VM最低保留多少空闲内存(Kbytes)
100 | vm.min_free_kbytes=1048576
101 |
102 | # 文件系统最大打开句柄数
103 | fs.file-max = 2097152
104 | # 表示每一个real user ID可创建的inotify instatnces的数量上限
105 | fs.inotify.max_user_instances = 8192
106 | # 表示同一用户同时可以添加的watch数目(watch一般是针对目录,决定了同时同一用户可以监控的目录数量
107 | fs.inotify.max_user_watches = 524288
108 | # inotify队列最大长度
109 | fs.inotify.max_queued_events = 16384
110 |
111 |
--------------------------------------------------------------------------------
/ci/lab03-jenkins/templates/baseimage/Jenkinsfile:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | # 功能描述
4 |
5 | 构建基础镜像
6 |
7 | # 参数配置
8 |
9 | ```yaml
10 |
11 | coderepo:
12 | auth: xxx
13 | url: xxx
14 |
15 | dockerpush:
16 | auth: xxx
17 | registry: xxx
18 | namespace: xxx
19 | image: xxx
20 |
21 | build_method: docker-compose
22 | ```
23 |
24 | # 插件依赖
25 |
26 | * https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/
27 | * https://plugins.jenkins.io/docker-workflow/
28 | * https://github.com/opsbox-dev/oes-template-plugin
29 |
30 |
31 | # 使用方法
32 |
33 | */
34 |
35 | def branch = purgeBranchString(coderepo.branch)
36 |
37 | pipeline {
38 |
39 | agent any
40 |
41 | options {
42 | disableConcurrentBuilds()
43 | skipDefaultCheckout true
44 | }
45 |
46 | stages {
47 |
48 | stage("Checkout Code") {
49 | steps {
50 | script {
51 | deleteDir()
52 | def gitParams = [
53 | $class : 'GitSCM',
54 | branches : [[name: "${branch}"]],
55 | doGenerateSubmoduleConfigurations: false,
56 | extensions : [[$class: 'CleanBeforeCheckout']],
57 | submoduleCfg : [],
58 | userRemoteConfigs : [[url: "${coderepo.url}"]]
59 | ]
60 | if (coderepo.auth != null) {
61 | gitParams.userRemoteConfigs = [[credentialsId: "${coderepo.auth}",
62 | url : "${coderepo.url}"]]
63 | }
64 | checkout(gitParams)
65 | }
66 | }
67 | } // end: Checkout Code
68 |
69 | stage("Build Image by Docker Compose") {
70 | when {
71 | expression { build_method == "docker-compose" }
72 | }
73 | steps {
74 | script {
75 | // 检查关键文件是否存在
76 | if (!fileExists('docker-compose.yml')) {
77 | error( "--//ERR: 缺少docker-compose.yml文件")
78 | }
79 |
80 | def _docker_compose_j2 = """
81 | |{% set version = "${branch}" %}
82 | |version: '3'
83 | |services:
84 | |{%- for name, _ in services.items() %}
85 | | {{ name }}:
86 | | {% if version == "main" %}
87 | | image: "${dockerpush.registry}/${dockerpush.namespace}/${dockerpush.image}:{{name}}"
88 | | {% else %}
89 | | image: "${dockerpush.registry}/${dockerpush.namespace}/${dockerpush.image}:{{name}}-{{ version }}"
90 | | {% endif %}
91 | |{%- endfor %}
92 | """.stripMargin().stripIndent()
93 | writeFile(file: 'docker-compose.j2', text: _docker_compose_j2)
94 |
95 | def _dockerfile = '''
96 | FROM rockylinux:8
97 | RUN yum install -y python3 && pip3 install jinja2-cli[yaml]
98 | '''.stripIndent()
99 | writeFile(file: 'Dockerfile', text: _dockerfile)
100 |
101 | def jinja2Image = docker.build("rockylinux8:jinja2")
102 | jinja2Image.inside {
103 | sh """
104 | set -eux
105 | jinja2 ./docker-compose.j2 ./docker-compose.yml > docker-compose.override.yml
106 | """
107 | }
108 |
109 | docker.withRegistry("https://${dockerpush.registry}", "${dockerpush.auth}") {
110 | sh """
111 | set -eux
112 | docker-compose -f docker-compose.yml -f docker-compose.override.yml build
113 | docker-compose -f docker-compose.yml -f docker-compose.override.yml push
114 | """
115 | }
116 | }
117 | }
118 | } // end: Build Image by Docker Compose
119 |
120 | stage("Build Image by Docker") {
121 | when {
122 | expression { build_method == "docker" }
123 | }
124 | steps {
125 | script {
126 | if (!fileExists('Dockerfile')) {
127 | error( "--//ERR: 缺少 Dockerfile 文件")
128 | }
129 | docker.withRegistry("https://${dockerpush.registry}", "${dockerpush.auth}") {
130 | def _tag = branch
131 | if (branch == "master") {
132 | _tag = "latest"
133 | }
134 | def _image = docker.build("${dockerpush.registry}/${dockerpush.namespace}/${dockerpush.image}:${_tag}")
135 | _image.push()
136 | }
137 | }
138 | }
139 | } // end: Build Image by Docker
140 |
141 | }
142 | }
143 |
144 | // looks for string [ci skip] in commit message
145 | boolean getCiSkip() {
146 | sh(returnStdout: true, script: 'git show --pretty=%s%b -s',
147 | label : 'check skip CI?'
148 | ).toLowerCase().contains('[ci skip]')
149 | }
150 |
151 | String getGitCommit() {
152 | sh(
153 | returnStdout: true, script: 'git rev-parse HEAD',
154 | label : 'getting GIT commit'
155 | ).trim()
156 | }
157 |
158 | def purgeBranchString(branch) {
159 | def gitBranch = branch
160 | if (gitBranch?.startsWith("refs/heads/")) {
161 | gitBranch = gitBranch.replace("refs/heads/", "")
162 | if (gitBranch != "main") {
163 | error("--//INFO: 不支持除 main 之外的分支")
164 | }
165 | }
166 | if (gitBranch?.startsWith("refs/tags/")) {
167 | gitBranch = gitBranch.replace("refs/tags/", "")
168 | }
169 | return gitBranch
170 | }
171 |
--------------------------------------------------------------------------------
/ci/lab03-jenkins/templates/general/Jenkinsfile:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | # 功能描述
4 |
5 | 构建基础镜像
6 |
7 | # 参数配置
8 |
9 | ```yaml
10 |
11 | coderepo:
12 | auth: xxx
13 | url: xxx
14 | branch: mkt4d
15 |
16 | registry:
17 | url: xxx
18 | auth: xxx
19 |
20 | pipeline:
21 | build:
22 | script: |
23 | # 配置环境变量
24 | # 使用 dapper 编译代码
25 | dapper -m bind
26 |
27 | archive:
28 | script: |
29 | # 打包镜像
30 | docker build -t $DOCKER_REG/xxx/xxx:version . -f Dockerfile
31 | docker push $DOCKER_REG/xxx/xxx:version
32 |
33 | deploy:
34 | image: xxx/xxx
35 | kubeconfig: xxx # credential id.
36 | script: |
37 | kubectl set image =$DOCKER_REG/xxx/xxx:version -n
38 | kubectl rollout status --timeout=300 -n
39 |
40 | ```
41 |
42 | # 插件依赖
43 |
44 | * https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/
45 | * https://plugins.jenkins.io/docker-workflow/
46 | * https://www.jenkins.io/doc/book/pipeline/docker/
47 | * https://docs.cloudbees.com/docs/admin-resources/latest/plugins/docker-workflow
48 | * https://github.com/opsbox-dev/oes-template-plugin
49 |
50 |
51 | # 使用方法
52 |
53 | 演示样例代码:https://jihulab.com/oes-workspace/spring-demo
54 | */
55 |
56 | def branch = purgeBranchString(coderepo.branch)
57 |
58 | pipeline {
59 |
60 | agent any
61 |
62 | options {
63 | disableConcurrentBuilds()
64 | skipDefaultCheckout true
65 | }
66 |
67 | stages {
68 |
69 | stage("Checkout Code") {
70 | steps {
71 | script {
72 | deleteDir()
73 | def gitParams = [
74 | $class : 'GitSCM',
75 | branches : [[name: "${branch}"]],
76 | doGenerateSubmoduleConfigurations: false,
77 | extensions : [[$class: 'CleanBeforeCheckout']],
78 | submoduleCfg : [],
79 | userRemoteConfigs : [[url: "${coderepo.url}"]]
80 | ]
81 | if (coderepo.auth != null) {
82 | gitParams.userRemoteConfigs = [[credentialsId: "${coderepo.auth}",
83 | url : "${coderepo.url}"]]
84 | }
85 | checkout(gitParams)
86 | }
87 | }
88 | } // end: Checkout Code
89 |
90 | stage("build") {
91 | steps {
92 | script {
93 | docker.withRegistry("https://${registry.url}", "${registry.auth}") {
94 | sh """
95 | ${pipeline.build.script}
96 | """.stripIndent()
97 | }
98 | }
99 | }
100 | }
101 |
102 | stage("archive") {
103 | steps {
104 | script {
105 | docker.withRegistry("https://${registry.url}", "${registry.auth}") {
106 | sh """
107 | export DOCKER_REG=${registry.url}
108 | ${pipeline.build.script}
109 | """.stripIndent()
110 | }
111 | }
112 | }
113 | }
114 |
115 | stage("deploy") {
116 | environment {
117 | KUBECONFIG = credentials("${pipeline.deploy.kubeconfig}")
118 | }
119 | steps {
120 | script {
121 | docker.withRegistry("https://${registry.url}", "${registry.auth}") {
122 | docker.image("${pipeline.deploy.image}").inside("-e KUBECONFIG=/root/.kube/config -v ${KUBECONFIG}:/root/.kube/config") {
123 | sh """
124 | ${pipeline.deploy.script}
125 | """.stripIndent()
126 | }
127 | }
128 | }
129 | }
130 | } // end deploy stage.
131 | }
132 | }
133 |
134 | def purgeBranchString(branch) {
135 | def gitBranch = branch
136 | if (gitBranch?.startsWith("refs/heads/")) {
137 | gitBranch = gitBranch.replace("refs/heads/", "")
138 | if (gitBranch != "main") {
139 | error("--//INFO: 不支持除 main 之外的分支")
140 | }
141 | }
142 | if (gitBranch?.startsWith("refs/tags/")) {
143 | gitBranch = gitBranch.replace("refs/tags/", "")
144 | }
145 | return gitBranch
146 | }
147 |
--------------------------------------------------------------------------------
/ci/lab05-tekton/README.md:
--------------------------------------------------------------------------------
1 |
2 | # 云原生 CI/CD Tekton
3 |
4 | 
5 |
6 | tektōn 在古希腊语中有工匠、手艺人的意思,比如木匠、石匠、建筑工人。
7 |
8 | ## Tekton 介绍
9 |
10 | Tekton 是 Google 开源的 Kubernetes 原生 CI/CD 系统,功能强大扩展性强。前身是 Knative 里的 build-pipeline 项目,后期孵化成独立的项目。并成为 CDF 下的四大初始项目之一,其他三个是 Jenkins, Jenkins X, Spinnaker。
11 |
12 | ### 优势
13 |
14 | * 可定制
15 | * 可重用
16 | * 可扩展
17 | * 标准化
18 | * 可伸缩
19 |
20 | ### 概念
21 |
22 | * `Step`:CI/CD 工作流中的一个操作,比如编译 Java 程序、运行单元测试等等。
23 | * `Task`:有序 Step 的集合。Tekton 在 Kubernetes 的 Pod 中运行 `Task`,每个 `Step` 则对应 Pod 中的容器。如何 Pod 中的容器可以共享环境一样,`Task` 中的 `Step` 也可以彼此间共享数据。比如在 Pod 中挂在一个卷,各个容器都可以访问卷中的内容。
24 | * `Pipeline`:一些列有序 `Task` 的集合。Tekton 将 `Task` 组合成有序无环图(DAG),并按顺序执行。体现在 Kubernetes 中,Tekton 会按顺序依次创建 Pod 来执行 `Task`,并最终完成整个流水线的执行。
25 | * `PipelineRun`:Pipeline 承载流水线的定义,实际每次运行时都需要创建一个 `PipelineRun` 资源,指定要执行的流水线及其所需的入参。
26 | * `TaskRun`:是 `Task` 的执行。
27 |
28 |
29 | 
30 |
31 | ### CRD
32 |
33 | 为什么说 Tekton 是 Kubernetes 原生的,因为其基于 Kubernetes 的 CRD 定义了 Pipeline 流水线。
34 |
35 | * [`Tasks`](https://github.com/tektoncd/pipeline/blob/main/docs/tasks.md)
36 | * [`Pipeline`](https://github.com/tektoncd/pipeline/blob/main/docs/pipelines.md)
37 | * [`TaskRun`](https://github.com/tektoncd/pipeline/blob/main/docs/taskruns.md)
38 | * [`PipelineRun`](https://github.com/tektoncd/pipeline/blob/main/docs/pipelineruns.md)
39 |
40 | ### Tekton CRD VS Native Resource
41 |
42 | 
43 |
44 | ## 工作原理
45 |
46 | 从 `PipelineRun` 到 `TaskRun` 再到 Pod 和容器。
47 |
48 | 
49 |
50 |
51 | 详细分析见[Tekton 的工作原理](https://atbug.com/how-tekton-works/)
52 |
53 | ## Tekton 生态
54 |
55 | ### 组件
56 |
57 | Tekton 包含了多个组件:
58 |
59 | * [Tekton Pipelines](https://github.com/tektoncd/pipeline/blob/main/docs/README.md)
60 | * [Tekton Triggers](https://github.com/tektoncd/triggers/blob/main/README.md)
61 | * [Tekton CLI](https://github.com/tektoncd/cli/blob/main/README.md)
62 | * [Tekton Dashboard](https://github.com/tektoncd/dashboard/blob/main/README.md)
63 | * [Tekton Catalog](https://github.com/tektoncd/catalog/blob/v1beta1/README.md)
64 | * [Tekton Hub](https://github.com/tektoncd/hub/blob/main/README.md)
65 | * [Tekton Operator](https://github.com/tektoncd/operator/blob/main/README.md)
66 | * [Tekton Results](https://github.com/tektoncd/results)
67 |
68 | ## 演示
69 |
70 | 既然 Tekton 是 Kubernetes 原生的框架,在正式开始之前需要创建一个 Kubernetes 集群。
71 |
72 | 在这个集群上我们会安装 Tekton,为了简化架构,在 CD 阶段会将应用也部署这个集群上(实际场景下,CI/CD 的集群基本不会与应用共享集群。当然,共享也没有问题)。
73 |
74 | 这个演示中我们会实现一个简单的 CI/CD 的流水线:完成一个 [Java 项目](https://github.com/addozhang/tekton-demo)从代码到部署的整个流程。
75 |
76 | 这个 Java 项目是个 web 服务,有一个 `/hi` 端点,返回 `hello world`。演示的重点是流水线的实现,所以选用了最简单的项目。
77 |
78 | ### 环境介绍
79 |
80 | * k3s v1.21.13+k3s1
81 | * 2c8g 虚拟机 Ubuntu 20.04
82 | * 本地 macOS
83 |
84 | ### 安装集群
85 |
86 | 我们使用 k3s 作为 Kubernetes 集群,通过下面的命令可以初始化单节点的集群。
87 |
88 | 这里我使用的是 2c8g 的 vm 作为节点,既是控制节点也是计算节点。
89 |
90 | ```shell
91 | export INSTALL_K3S_VERSION=v1.21.13+k3s1
92 | curl -sfL https://get.k3s.io | sh -s - --disable traefik --write-kubeconfig-mode 644 --write-kubeconfig ~/.kube/config
93 | ```
94 |
95 | ### 安装 Tekton Pipeline
96 |
97 | 最新版本是 v0.36,从 v0.33.x 开始要求 Kubernetes 的版本至少是 1.21。
98 |
99 | ```shell
100 | kubectl apply --filename \
101 | https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
102 | ```
103 |
104 | 检查相关的 CRD。
105 |
106 | ```shell
107 | kubectl api-resources --api-group=tekton.dev
108 | NAME SHORTNAMES APIVERSION NAMESPACED KIND
109 | clustertasks tekton.dev/v1beta1 false ClusterTask
110 | conditions tekton.dev/v1alpha1 true Condition
111 | pipelineresources tekton.dev/v1alpha1 true PipelineResource
112 | pipelineruns pr,prs tekton.dev/v1beta1 true PipelineRun
113 | pipelines tekton.dev/v1beta1 true Pipeline
114 | runs tekton.dev/v1alpha1 true Run
115 | taskruns tr,trs tekton.dev/v1beta1 true TaskRun
116 | tasks tekton.dev/v1beta1 true Task
117 | ```
118 |
119 | 检查组件运行
120 |
121 | ```shell
122 | kubectl get po -n tekton-pipelines
123 | NAME READY STATUS RESTARTS AGE
124 | tekton-pipelines-controller-5cfb9b8cfc-q4crs 1/1 Running 0 24s
125 | tekton-pipelines-webhook-6c9d4d5798-7xg8n 1/1 Running 0 24s
126 | ```
127 |
128 | ### 安装 Tekton CLI
129 |
130 | ```shell
131 | brew install tektoncd-cli
132 | ```
133 |
134 | ### 安装 Tekton Dashboard
135 |
136 | 通过 Dashboard 我们可以实时查看 `PipelineRun` 和 `TaskRun` 的状态,以及运行的日志;还可以查看定义的各种 CR。
137 |
138 | ```shell
139 | kubectl apply --filename \
140 | https://storage.googleapis.com/tekton-releases/dashboard/latest/tekton-dashboard-release.yaml
141 | ```
142 |
143 | 创建 NodePort service 以便从集群外进行访问。
144 |
145 | ```shell
146 | kubectl expose deploy tekton-dashboard --name tekton-dashboard-node --port 9097 --target-port 9097 --type NodePort -n tekton-pipelines
147 |
148 | kubectl get svc tekton-dashboard-node -o jsonpath="{.spec.ports[0].nodePort}" -n tekton-pipelines
149 | ```
150 |
151 | ### Hello, Tekton
152 |
153 | 创建 Task
154 |
155 | ```shell
156 | kubectl apply -f - < /tmp/config.json && kubectl create secret generic docker-config --from-file=/tmp/config.json && rm -f /tmp/config.json
270 | ```
271 |
272 | 构建镜像需要指定资源,比如 Dockerfile 的路径、镜像 URL、tag 等,通过 `params` 输入。
273 |
274 | ```yaml
275 | spec:
276 | params:
277 | - name: pathToDockerFile
278 | description: The path to the dockerfile to build (relative to the context)
279 | default: Dockerfile
280 | - name: imageUrl
281 | description: Url of image repository
282 | - name: imageTag
283 | description: Tag to apply to the built image
284 | default: latest
285 | - name: IMAGE
286 | description: Name (reference) of the image to build.
287 | steps:
288 | - name: build-and-push
289 | image: gcr.io/kaniko-project/executor:v1.6.0-debug
290 | imagePullPolicy: IfNotPresent
291 | command:
292 | - /kaniko/executor
293 | args:
294 | - --dockerfile=$(params.pathToDockerFile)
295 | - --destination=$(params.imageUrl):$(params.imageTag)
296 | - --context=$(workspaces.source.path)
297 | - --digest-file=$(results.IMAGE_DIGEST.path)
298 | ```
299 |
300 | #### 0x05 部署
301 |
302 | 在部署阶段,也就是 CD 中的 delivery。我们将使用项目中的 yaml 文件,对应用进行部署。
303 |
304 | 前面提到,应用会部署到当前的集群中。部署成功后,我们可以通过访问 `http://[node-ip]:30080/hi` 来进行验证。
305 |
306 | ```yaml
307 | spec:
308 | params:
309 | - name: pathToYamlFile
310 | description: The path to the yaml file to deploy within the git source
311 | default: deployment.yaml
312 | workspaces:
313 | - name: source
314 | steps:
315 | - name: run-kubectl
316 | image: lachlanevenson/k8s-kubectl:v1.21.11
317 | imagePullPolicy: IfNotPresent
318 | command: ["kubectl"]
319 | args:
320 | - "apply"
321 | - "-f"
322 | - "$(workspaces.source.path)/$(params.pathToYamlFile)"
323 | ```
324 |
325 | #### 0x06 组装流水线
326 |
327 | 在前面我们已经完成了流水线的各个 `step` 和 `task`,接下来就是将所有的 task 组装成真正的流水线 `Pipeline`。
328 |
329 | 在 `Pipeline` 中,我们设定流水线各个 `step` 所需的入参,并按照顺序将 `task` “摆放”。默认情况下这些 `task` 会同时执行,我们通过 `runAfter` 字段对执行顺序进行编排。
330 |
331 | ```yaml
332 | apiVersion: tekton.dev/v1beta1
333 | kind: Pipeline
334 | metadata:
335 | name: build-pipeline
336 | spec:
337 | params:
338 | - name: git-url
339 | - name: git-revision
340 | - name: pathToContext
341 | description: The path to the build context, used by Kaniko - within the workspace
342 | default: .
343 | - name: imageUrl
344 | description: Url of image repository
345 | - name: imageTag
346 | description: Tag to apply to the built image
347 | workspaces:
348 | - name: git-source
349 | - name: docker-config
350 | tasks:
351 | - name: fetch-from-git
352 | taskRef:
353 | name: git-clone
354 | params:
355 | - name: url
356 | value: "$(params.git-url)"
357 | - name: revision
358 | value: "$(params.git-revision)"
359 | workspaces:
360 | - name: output
361 | workspace: git-source
362 | - name: source-to-image
363 | taskRef:
364 | name: source-to-image
365 | params:
366 | - name: imageUrl
367 | value: "$(params.imageUrl)"
368 | - name: IMAGE
369 | value: "$(params.imageUrl)"
370 | - name: imageTag
371 | value: "$(params.imageTag)"
372 | workspaces:
373 | - name: source
374 | workspace: git-source
375 | - name: dockerconfig
376 | workspace: docker-config
377 | runAfter:
378 | - fetch-from-git
379 | - name: deploy-to-k8s
380 | taskRef:
381 | name: deploy-to-k8s
382 | params:
383 | - name: pathToYamlFile
384 | value: deployment.yaml
385 | workspaces:
386 | - name: source
387 | workspace: git-source
388 | runAfter:
389 | - source-to-image
390 | ```
391 |
392 | #### 0x07 执行流水线
393 |
394 | 前面我们已经完成了流水线的定义,在执行的时候,需要通过定义 `PipelineRun` 来为其指定入参。比如这里的 `git-revision`、`git-url`、`imageUrl`、`imageTag`。
395 |
396 | 拉取代码和编译两个 `task` 的运行是在不同的 Pod 中完成的,因此需要出持久化的存储来进行数据(代码仓库)的共享。
397 |
398 | ```yaml
399 | apiVersion: tekton.dev/v1beta1
400 | kind: PipelineRun
401 | metadata:
402 | generateName: generic-pr-
403 | name: generic-pipeline-run
404 | spec:
405 | pipelineRef:
406 | name: build-pipeline
407 | params:
408 | - name: git-revision
409 | value: main
410 | - name: git-url
411 | value: https://github.com/addozhang/tekton-demo.git
412 | - name: imageUrl
413 | value: addozhang/tekton-test
414 | - name: imageTag
415 | value: latest
416 | workspaces:
417 | - name: git-source
418 | volumeClaimTemplate:
419 | spec:
420 | accessModes:
421 | - ReadWriteOnce
422 | resources:
423 | requests:
424 | storage: 1Gi
425 | - name: docker-config
426 | secret:
427 | secretName: docker-config
428 | serviceAccountName: tekton-build
429 | ```
430 |
431 | ### 测试
432 |
433 | 执行下面的命令创建 `PipelineRun` 资源启动流水线。
434 |
435 | ```yaml
436 | kubectl apply -f run/run.yaml
437 | ```
438 |
439 | 在执行的过程中,你会看到下面几个 Pod 被创建:
440 |
441 | * generic-pipeline-run-deploy-to-k8s-xxx
442 | * generic-pipeline-run-fetch-from-git-xxx
443 | * generic-pipeline-run-source-to-image-xxx
444 |
445 | 同时还有我们应用的 Pod `tekton-test-xxx`。
446 |
447 | 尝试发送请求到 `http://[node-ip]:30080/hi`,查看返回结果。
448 |
449 | ## 总结
450 |
451 | Tekton 是个很有意思的项目,其生态也在一步步的壮大,与此同时业界也不断涌现出各种周边的工具。由于时间原因,无法一一介绍。有兴趣的同学,可以看下我之前写过的文档。后续有时间,也希望能在这里继续给大家分享。
452 |
453 | * [CICD 的供应链安全工具 Tekton Chains](https://atbug.com/tekton-chains-secure-supply-chain/)
454 | * [Jenkins 如何与 Kubernetes 集群的 Tekton Pipeline 交互?](https://atbug.com/jenkins-interact-with-tekton-pipelines-via-plugin/)
455 | * [云原生CICD: Tekton Trigger 实战](https://atbug.com/tekton-trigger-practice/)
456 |
457 | CI/CD 平台是一件有挑战且充满乐趣的事情,在这个过程中我们会将现实世界中的工作流程以软件的方式实现出来。
458 |
459 | 
460 |
461 | 各家企业有自己独特的组织架构、管理制度,以及研发流程,即使是发展的不同阶段对平台也会有不同的需求。
462 |
463 | 平台的实现可以简单,也可以很复杂。
464 |
465 | ## FAQ
466 |
467 | 以下问题是直播时社区爱好者的提问,问题中有些工具/产品我过往没有使用或者了解,回答也是基于网络和产品官网的内容。如有问题和不足,欢迎指出。欢迎根据我们的回答继续深入讨论。
468 |
469 | ### 无情的工作机器啊:Tekton目前适合什么样的系统使用?
470 |
471 | Tekton 是个云原生的 CI/CD 框架,运行于 Kubernetes 环境。Tekton 是一个用于构建 CI/CD平台的框架,与其说什么样的系统适合 Tekton,不如说我们对 CI/CD 的平台有什么要求?Tekton 给我们带来的是扩展性、重用性、标准化、伸缩性等方面的优势。如果当面面临的是来自这些方面的问题,我认为 Tekton 是个不错的选择。
472 |
473 |
474 | ### bili_88058603179 : 与Jenkins动态slaver优势在哪?
475 |
476 | Tekton 的创建我觉得在两个方面流水线定义和基础设施资源的使用。在资源使用方面,Tekton 与 Jenkins 动态 slaver 大同小异,都是借助 Kubernetes 的弹性、自动化以及容器来实现动态和隔离。
477 |
478 | - Tekton 通过对流水线的定义,将可重用和标准化的功能粒度变得更小。比如一个流水线拆分成多个可重用 Task 来执行,在同一时间只有一个 Task(非并行)的 Pod 在运行,资源利用方面更精细。
479 | - Jenkins 动态 slaver 的优势在于不改变原有实现(Jenkins)的基础上(成本更低),让原有 CI/CD 平台的资源利用更加高效。
480 |
481 | 二者各有优势。
482 |
483 | ### barbaz : tekton和drone有什么区别?
484 |
485 | 我之前没有了解过 Drone,简单看了下。Drone 的实现与 Tekton 的原理都差不多,都是通过一个 runner/controller 来创建 Pod 来执行 Pipeline。
486 |
487 | 从概念上来看,Drone 的最小组件称为 `Step`,对应的是 Pod 中的 Container。再上一层是 `Pipeline`,对应 Pod。每个 `Pipeline` 都是运行在同一个 Pod 中。组件的重用是通过镜像来实现的。
488 |
489 | Tekton 的最小组件也是 `Step`,再上一层是 `Task`(对应 Kubernetes 中的 Pod)。每个 `Pipeline` 可以由一个或多个 `Task` 组件,也就是说运行时会由一个或者多个 Pod 来完成流水线的执行。重用可以通过 `Step` 使用的镜像,或者 `Task` 来实现功能的重用。
490 |
491 | 还有就是 Tekton 是开源的框架,而 Drone 的 runner 需要 [Drone Enterprice 许可](https://docs.drone.io/enterprise/#what-is-the-difference-between-open-source-and-enterprise)。
492 |
493 | 
494 |
495 | ### 没钱买鱼:有没有缓存加速编译的策略?
496 |
497 | 不知道我对“缓存加速编译”的理解是否正确,如不准确请指正。
498 |
499 | 就拿 Java 项目的编译来说,需要用到的缓存加速应该是各种依赖包。在演示中,我们使用了持久化存储来保存初次编译时下载的依赖包。流水线执行的过程中,这个持久化存储都会通过卷的方式挂在到 Pod 中,不会重新下载依赖包。其他语言也是类似。
500 |
--------------------------------------------------------------------------------
/ci/lab05-tekton/demo/pipeline/build-pipeline.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: tekton.dev/v1beta1
2 | kind: Pipeline
3 | metadata:
4 | name: build-pipeline
5 | spec:
6 | params:
7 | - name: git-url
8 | - name: git-revision
9 | - name: pathToContext
10 | description: The path to the build context, used by Kaniko - within the workspace
11 | default: .
12 | - name: imageUrl
13 | description: Url of image repository
14 | - name: imageTag
15 | description: Tag to apply to the built image
16 | workspaces:
17 | - name: git-source
18 | - name: docker-config
19 | tasks:
20 | - name: fetch-from-git
21 | taskRef:
22 | name: git-clone
23 | params:
24 | - name: url
25 | value: "$(params.git-url)"
26 | - name: revision
27 | value: "$(params.git-revision)"
28 | workspaces:
29 | - name: output
30 | workspace: git-source
31 | - name: source-to-image
32 | taskRef:
33 | name: source-to-image
34 | params:
35 | - name: imageUrl
36 | value: "$(params.imageUrl)"
37 | - name: IMAGE
38 | value: "$(params.imageUrl)"
39 | - name: imageTag
40 | value: "$(params.imageTag)"
41 | - name: CHAINS-GIT_COMMIT
42 | value: "$(tasks.fetch-from-git.results.commit)"
43 | - name: CHAINS-GIT_URL
44 | value: "$(tasks.fetch-from-git.results.url)"
45 |
46 | workspaces:
47 | - name: source
48 | workspace: git-source
49 | - name: dockerconfig
50 | workspace: docker-config
51 | runAfter:
52 | - fetch-from-git
53 | - name: deploy-to-k8s
54 | taskRef:
55 | name: deploy-to-k8s
56 | params:
57 | - name: pathToYamlFile
58 | value: deployment.yaml
59 | workspaces:
60 | - name: source
61 | workspace: git-source
62 | runAfter:
63 | - source-to-image
--------------------------------------------------------------------------------
/ci/lab05-tekton/demo/run/run.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: tekton.dev/v1beta1
2 | kind: PipelineRun
3 | metadata:
4 | # generateName: generic-pr-
5 | name: generic-pipeline-run
6 | spec:
7 | pipelineRef:
8 | name: build-pipeline
9 | params:
10 | - name: git-revision
11 | value: main
12 | - name: git-url
13 | value: https://github.com/addozhang/tekton-demo.git
14 | - name: imageUrl
15 | value: addozhang/tekton-test
16 | - name: imageTag
17 | value: latest
18 | workspaces:
19 | - name: git-source
20 | volumeClaimTemplate:
21 | spec:
22 | accessModes:
23 | - ReadWriteOnce
24 | resources:
25 | requests:
26 | storage: 1Gi
27 | - name: docker-config
28 | secret:
29 | secretName: docker-config
30 | serviceAccountName: tekton-build
31 |
--------------------------------------------------------------------------------
/ci/lab05-tekton/demo/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: tekton-build
5 | namespace: tekton-pipelines
6 |
7 | ---
8 | apiVersion: rbac.authorization.k8s.io/v1
9 | kind: ClusterRoleBinding
10 | metadata:
11 | name: pipeline-admin-binding
12 | roleRef:
13 | apiGroup: rbac.authorization.k8s.io
14 | kind: ClusterRole
15 | name: admin # use cluster role admin
16 | subjects:
17 | - kind: ServiceAccount
18 | name: tekton-build
19 | namespace: tekton-pipelines
--------------------------------------------------------------------------------
/ci/lab05-tekton/demo/tasks/deploy-to-k8s.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: tekton.dev/v1beta1
2 | kind: Task
3 | metadata:
4 | name: deploy-to-k8s
5 | spec:
6 | params:
7 | - name: pathToYamlFile
8 | description: The path to the yaml file to deploy within the git source
9 | default: deployment.yaml
10 | workspaces:
11 | - name: source
12 | steps:
13 | - name: run-kubectl
14 | image: lachlanevenson/k8s-kubectl:v1.21.11
15 | imagePullPolicy: IfNotPresent
16 | command: ["kubectl"]
17 | args:
18 | - "apply"
19 | - "-f"
20 | - "$(workspaces.source.path)/$(params.pathToYamlFile)"
--------------------------------------------------------------------------------
/ci/lab05-tekton/demo/tasks/source-to-image.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: tekton.dev/v1beta1
2 | kind: Task
3 | metadata:
4 | name: source-to-image
5 | spec:
6 | params:
7 | - name: pathToDockerFile
8 | description: The path to the dockerfile to build (relative to the context)
9 | default: Dockerfile
10 | - name: imageUrl
11 | description: Url of image repository
12 | - name: imageTag
13 | description: Tag to apply to the built image
14 | default: latest
15 | - name: IMAGE
16 | description: Name (reference) of the image to build.
17 | - name: CHAINS-GIT_COMMIT
18 | description: Commit value
19 | - name: CHAINS-GIT_URL
20 | description: Git repo URL
21 | workspaces:
22 | - name: source
23 | - name: dockerconfig
24 | mountPath: /kaniko/.docker
25 | results:
26 | - name: IMAGE_DIGEST
27 | description: Digest of the image just built.
28 | - name: IMAGE_URL
29 | description: URL of the image just built.
30 | steps:
31 | - name: maven
32 | image: maven:3.5-jdk-8-alpine
33 | imagePullPolicy: IfNotPresent
34 | workingDir: $(workspaces.source.path)
35 | command:
36 | - mvn
37 | args:
38 | - clean
39 | - install
40 | - -DskipTests
41 | volumeMounts:
42 | - name: m2
43 | mountPath: /root/.m2
44 | - name: build-and-push
45 | image: gcr.io/kaniko-project/executor:v1.6.0-debug
46 | imagePullPolicy: IfNotPresent
47 | command:
48 | - /kaniko/executor
49 | args:
50 | - --dockerfile=$(params.pathToDockerFile)
51 | - --destination=$(params.imageUrl):$(params.imageTag)
52 | - --context=$(workspaces.source.path)
53 | - --digest-file=$(results.IMAGE_DIGEST.path)
54 | - name: write-url
55 | image: bash
56 | script: |
57 | set -e
58 | echo $(params.IMAGE) | tee $(results.IMAGE_URL.path)
59 | volumes:
60 | - name: m2
61 | hostPath:
62 | path: /data/.m2
63 |
--------------------------------------------------------------------------------
/ci/lab05-tekton/demo/trigger/event-listener.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: tekton.dev/v1alpha1
2 | kind: EventListener
3 | metadata:
4 | name: trigger-test-eventlistener
5 | namespace: tekton-pipelines
6 | spec:
7 | serviceAccountName: tekton-test
8 | triggers:
9 | - bindings:
10 | - name: trigger-test-triggerbinding
11 | template:
12 | name: trigger-test-triggertemplate
--------------------------------------------------------------------------------
/ci/lab05-tekton/demo/trigger/trigger-binding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: tekton.dev/v1alpha1
2 | kind: TriggerBinding
3 | metadata:
4 | name: trigger-test-triggerbinding
5 | namespace: tekton-pipelines
6 | spec:
7 | params:
8 | - name: gitrevision
9 | value: $(body.after)
10 | - name: namespace
11 | value: tekton-pipelines
12 | - name: gitrepositoryurl
13 | value: $(body.project.git_http_url)
14 | - name: projectname
15 | value: $(body.project.name)
--------------------------------------------------------------------------------
/ci/lab05-tekton/demo/trigger/trigger-template.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: tekton.dev/v1alpha1
2 | kind: TriggerTemplate
3 | metadata:
4 | name: trigger-test-triggertemplate
5 | namespace: tekton-pipelines
6 | spec:
7 | params:
8 | - name: gitrevision
9 | description: The git revision
10 | default: master
11 | - name: gitrepositoryurl
12 | description: The git repository url
13 | - name: namespace
14 | description: The namespace to create the resources
15 | default: tekton-pielines
16 | - name: projectname
17 | description: The project name
18 | - name: imagetag
19 | description: The image tag
20 | default: latest
21 | resourcetemplates:
22 | - apiVersion: tekton.dev/v1alpha1
23 | kind: PipelineRun
24 | metadata:
25 | name: tekton-test-pipeline-run-$(uid)
26 | namespace: $(params.namespace)
27 | spec:
28 | serviceAccountName: tekton-test
29 | params:
30 | - name: imageUrl
31 | value: addozhang/$(params.projectname)
32 | - name: imageTag
33 | value: $(params.imagetag)
34 | pipelineRef:
35 | name: build-pipeline
36 | resources:
37 | - name: git-source
38 | resourceSpec:
39 | type: git
40 | params:
41 | - name: revision
42 | value: $(params.gitrevision)
43 | - name: url
44 | value: $(params.gitrepositoryurl)
--------------------------------------------------------------------------------
/ci/lab05-tekton/media/16553854211360.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab05-tekton/media/16553854211360.jpg
--------------------------------------------------------------------------------
/ci/lab05-tekton/media/16553856425843.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab05-tekton/media/16553856425843.jpg
--------------------------------------------------------------------------------
/ci/lab05-tekton/media/16553864459332.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab05-tekton/media/16553864459332.png
--------------------------------------------------------------------------------
/ci/lab05-tekton/media/16553875121264.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab05-tekton/media/16553875121264.jpg
--------------------------------------------------------------------------------
/ci/lab05-tekton/media/2022-06-26 at 17.39.31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab05-tekton/media/2022-06-26 at 17.39.31.png
--------------------------------------------------------------------------------
/ci/lab05-tekton/media/CI:CD流程.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab05-tekton/media/CI:CD流程.png
--------------------------------------------------------------------------------
/ci/lab05-tekton/media/tekton-concept.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab05-tekton/media/tekton-concept.jpg
--------------------------------------------------------------------------------
/ci/lab06-teamcity/README.md:
--------------------------------------------------------------------------------
1 | # 面向 DevOps 新手的 TeamCity 快速入门
2 |
3 | 
4 |
5 | ## 本教程学习材料
6 |
7 | * [视频](https://www.bilibili.com/video/BV1pY4y17754)
8 | * [PPT](https://docs.qq.com/pdf/DTmlIRFBJWllsaGJx)
9 | * [练习用代码仓库](https://github.com/shengyou/china-devops-teamcity-lab)
10 |
11 | ## TeamCity 简介
12 |
13 | * 由 JetBrains 推出的团队工具,协助团队做构建管理、持续集成及持续部署的工作。
14 | * 第一版发布于 2006 年,积累 JetBrains 内部超过 15 年构建及部署经验的产品。
15 | * TeamCity 可说是 JetBrains [Dogfooding](https://www.bilibili.com/video/BV1Dg411f7iX) 的代表,在早期没有 CI/CD 解决方案时,由团队自建而生的产品。
16 |
17 | ## 为什么选择 TeamCity?
18 |
19 | * 高颜值 Web UI,新手小白也能立即上手
20 | * 与 JetBrains IDE 深度集成,开发者不需离开 IDE 即可完成工作
21 | * 可用高语意、IDE 友好的 Kotlin DSL 描述设置,大规模设置更轻松
22 |
23 | ## 版本
24 |
25 | * TeamCity (on-premises)
26 | - 可至官网下载打包好的 Jar 文件,搭配 JVM 运行。
27 | - 可至 Docker Hub 下载官方发布的 Image,以 Docker 运行。
28 | - 提供不限用户、不限编译时间、100 个 Build Configuration、3 个 Agent 的免费额度。
29 | - 开源项目可申请免费授权。
30 | * TeamCity Cloud
31 | - TeamCity 团队提供的云服务。
32 | - 免安装、不限用户、并发运行、完全托管。
33 | - 提供 14 天免费试用 (中国 DevOps 社区可申请延长试用)。
34 |
35 | ## 安装
36 |
37 | * 以 Jar 文件安装
38 | - 安装 JDK 8 (推荐以 SDKMAN 安装)。
39 | ```shell
40 | # 安装 SDKMAN
41 | $ curl -s "https://get.sdkman.io" | bash
42 |
43 | # 安装 OpenJDK 8
44 | $ sdk install java 8.0.332-tem
45 | ```
46 | - 至 [TeamCity 官网下载页](https://www.jetbrains.com/teamcity/download/#section=on-premises) 下载 Jar 文件,请选 Linux (.tar.gz) 文件下载。
47 | - 解压缩下载的文件,将解开的目录并放在 `/opt` 底下。
48 | - 开启终端,将目录切换到 TeamCity 文件夹,运行 `bin` 文件夹里的 `runAll` 脚本。
49 | ```shell
50 | $ cd
51 | $ bash ./bin/runAll.sh start
52 | ```
53 | - 以浏览器开启 `http://localhost:8111/` 完成首次启用设置
54 | - 设置 Data 文件夹路径。
55 | 
56 | - 设置数据库。
57 | 
58 | - 同意使用条款。
59 | 
60 | - 设置 admin 帐号密码。
61 | 
62 | - 完成首次启用设置!
63 | 
64 | * 以 Docker 运行
65 | - 安装 Docker (以 Ubuntu 为例)。
66 | ```shell
67 | # 设定 Repository
68 | $ sudo apt-get update
69 | $ sudo apt-get install \
70 | apt-transport-https \
71 | ca-certificates \
72 | curl \
73 | gnupg \
74 | lsb-release
75 |
76 | # 设定 Docker 官方 GPG key
77 | $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
78 |
79 | # 设置 Stable Repository (以 AMD64 为例)
80 | $ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
81 | $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
82 |
83 | # 安装 Docker
84 | $ sudo apt-get update
85 | $ sudo apt-get install docker-ce docker-ce-cli containerd.io
86 | ```
87 | - 运行 TeamCity 容器。
88 | ```shell
89 | $ docker run -it --name teamcity-server-instance \
90 | -v :/data/teamcity_server/datadir \
91 | -v :/opt/teamcity/logs \
92 | -p :8111 \
93 | jetbrains/teamcity-server
94 | ```
95 | - 以浏览器开启 `http://localhost:8111/` 完成首次启用设置
96 | - 设置 Data 文件夹路径。
97 | 
98 | - 设置数据库。
99 | 
100 | - 同意使用条款。
101 | 
102 | - 设置 admin 帐号密码。
103 | 
104 | - 完成首次启用设置!
105 | 
106 | * 开通 TeamCity Cloud
107 | - 在 [TeamCity Cloud 登录页](https://www.jetbrains.com/teamcity/signup/)输入 Email 申请开通。
108 | - 收取邮件并点击邮件里的 URL。
109 | 
110 | - 在注册页面依表单输入个人信息。
111 | 
112 | - 设置 Instance URL。
113 | 
114 | - 设置 admin 帐号密码。
115 | 
116 | - 同意使用条款。
117 | 
118 | - 完成开通 TeamCity Cloud!
119 | 
120 |
121 | ## TeamCity 运作流程
122 |
123 | TeamCity 是一个 Server 搭配 Agent 的架构,在正式使用前,预先了解 Server 及 Agent 的架构与分工,有助于了解整体工作流程。TeamCity 的运作流程可用下图来说明:
124 |
125 | 
126 |
127 | * 在 TeamCity 里创建项目后,TeamCity Server 会持续侦测 (Polling or Webhook) 代码仓库的变更。
128 | * 当 TeamCity 发现有变更时,会将变更信息储存在数据库里。
129 | * 当 Trigger 发现数据里的变更时,就会依照 Build Configuration 初始化构建。
130 | * 被 Trigger 的构建任务就会被放进 Queue 里。
131 | * 构建任务会被指派给一个闲置且符合构建条件的 Agent。
132 | * Agent 依照 Build Configuration 逐一运行,运行时会将生成的报告同步送回 Server。
133 | * 构建完成后,Agent 会将 Artifact 送回 Server 储存。
134 |
135 | ## 重要名词解释
136 |
137 | * **TeamCity Server**:TeamCity 的管理中心,负责监控所有连线到的 Agent,依照 Agent 的环境分配 Queue 里的构建任务并显示报告。
138 | * **Database**:储存包括代码仓库的变更、构建历史、Agent 及 Queue 信息、帐号及权限等信息。
139 | * **Build Agent**:实际运行构建的程序,依项目需求的不同,可以将 Agent 安装在不同平台、不同操作系统并搭配不同运行环境来运行。
140 | * **Build Configuration**:设置 VCS 来源、Trigger、Build Step 的组合。
141 | * **Build Step**:在构建过程中实际执行的任务,每一个步骤会以特定的 Runner 运行特定工具(比方说 Ant、Gradle、MSBuild、NUnit、静态分析)。
142 | * **Build Trigger**:Trigger 用于事件发生时,启动对应的构建任务。TeamCity 支持数种 Trigger,比方说 VCS Trigger 或 Timer Trigger 等。
143 | * **Build Queue**:储放已被 Trigger、等待被运行的任务清单,TeamCity 会将这些任务分配给符合运行条件且闲置的 Agent 运行。
144 | * **Build Artifact**:构建完成后产生的文件,比方说 Jar/War、报表、日志等,可依需求下载使用。
145 |
146 | ## 设计项目的发布流水线
147 |
148 | 不论项目再怎么复杂,为项目建立发布流水线的第一步,就是先用 **人工** 把所有构建任务运行一次,并将所有要运行的命令手写下来。本教程以一个用 Kotlin 编程语言撰写的 ShoppingCart 项目为例,流水线的设计如下:
149 |
150 | * 以 Gradle 运行构建并生成 Artifact
151 | * 以 kotest 运行测试并生成覆率报告
152 | * 以 ktlint 检查 Coding Style
153 | * 以 Qodana 和 detekt 运行静态分析
154 | * 以 Dokka 生成 API 文档
155 | * 部署 API 文档
156 |
157 | ## Lab 1:完成第一个构建
158 |
159 | 有了上面的蓝图后,接下来用三个 Lab 逐步以 TeamCity 将发布流水线搭建起来。第一步要先在 TeamCity 里完成第一个构建,确认项目可顺利编译。
160 |
161 | * 以 Admin 帐号登入 TeamCity,点选上方菜单最右边的 Administration 的链接进入设置,选择左侧栏菜单里的 Projects,点选右边的 Create project 按钮。
162 | 
163 | * TeamCity 支持从 GitHub、Bitbucket Cloud、GitLab 引入代码仓库,或是提供 Repository URL 也行。练习时可直接使用笔者的[代码仓库](https://github.com/shengyou/shopping-cart),输入后按 Process。
164 | 
165 | * 设置 Project Name (自动以 Repo 名称代入)、Build Configuration Name (默认为 Build)、Default Branch (默认为 main)。没有需求的话全以默认值代入即可。
166 | 
167 | * 有了 Build Configuration 后,接着要设置 Build Step,也就是构建过程中要运行的任务步骤。TeamCity 会自动扫描 Repository 使用的开发工具,扫描后列出可运行的 Build Step。以演示项目为例,TeamCity 发现有两个动作可以做,一个是 Gradle、一个是 Command Line。我们只需要 Gradle 即可,勾选 Gradle 选项,点 Use selected 进到下一步。
168 | 
169 | * 在构建完成后,要将生成的 Artifact 储存下来。回到 Build 的 General Settings 设置,在 Artifact paths 设置要储存的文件夹路径为 `+:build/libs => libs.zip`。
170 | 
171 | * 完成后就可以点选划面右上方的 Run 按钮执行第一次的建置工作。
172 | 
173 | * TeamCity 会自动跳转至构建运行的页面,我们可以即时看到 TeamCity 正在运行的任务,TeamCity 会以时间线显示构建过程,并可实时查看终端输出。若构建过程没有发生错误,则那这个建置就会被视为成功,您可以看到 TeamCity 会以绿色字及打勾的图标来表示构建结果。
174 | 
175 | * 切换到 Artifact Tab,可以看到构建生成的 Artifact,可直接点击下载。
176 | 
177 | * 由于 Gradle 在运行构建时,也会一并运行测试,可以在 Tests Tab 里看到该次构建运行测试的结果。
178 | 
179 |
180 | ## Lab 2:依计划增加更多 Build Step
181 |
182 | 第二个 Lab 要依照流水线计划增加更多 Build Step,包括以 ktlint 检查 Coding Style,以 Qodana 和 detekt 运行静态分析,并为测试生成覆盖率报告。
183 |
184 | * 转至项目设置,进入 Build Step 设置,新增一个 Build Step。
185 | 
186 | * 由于演示代码使用 Gradle 集成 ktlint,Runner Type 可使用 Gradle Runner。Step name 可命名为 `Check Code Style`,Gradle tasks 里填入要运行的命令 `lintKotlin`,其余留空按 Save 储存即可。
187 | 
188 | * 再新增一个 Build Step,同样使用 Gradle Runner,Step name 命名为 `Static Analysis`,Gradle tasks 里填入要运行的命令 `detekt`,其余留空按 Save 储存即可。
189 | 
190 | * 再新增一个 Build Step,改用 Qodana Runner,Step name 命名为 `Qodana Scan`,Tools 里选择 Code Inspection,Linter 选 Qodana for JVM,其余留空按 Save 储存即可。
191 | 
192 | * 回到 Build Step 页面,编辑 Build 的设置,下方有一个 Code Coverage 的区块,把 Choose coverage runner 从 改成 IntelliJ IDEA,而 Classes to instrument 则输入 `io.kraftsman.*`,表示只要是在 io.kraftsman 这个 Package 底下的所有 Class 都要生成覆盖率报告,完成后按 Save 储存。
193 | 
194 | * 若有需要可以调整 Step 的顺序,完成后点击右上角 Run 按钮运行构建,并转至 Build 页面看构建结果。页面中间多了一个 Code Coverage 的 Tab,点击 Tab 就可以看到 TeamCity 把覆盖率报告显示在 Tab 内,不需要将生成的报告上传到其他服务器上,非常方便!
195 | 
196 | 
197 | 
198 |
199 | ## Lab 3:生成并部署 API 文档
200 |
201 | 第三个 Lab 要依照流水线计算生成项目的 API 文档,并将文档部署至指定服务器。演示的代码仓库使用的是 Dokka 文件引擎,由于 Dokka 也有提供 Gradle 插件,因此在 TeamCity 里一样使用 Gradle Runner 即可生成文件。
202 |
203 | * 转至项目 Build Step 设置,新增一个 Step,Runner Type 选 Gradle、Step name 输入 `Generate Document`、Gradle tasks 输入 `dokkaHtml`,其他保留默认后按 Save 储存。
204 | 
205 | * 虽然 Build Step 会生成文件,但别忘了要把文件变成 Artifact 的一部份。回到项目的 Build Configuration 设置页,选择左侧边栏的 General Settings,在 UI 下方 Artifact paths 里指定要保存的路径 `+:build/dokka/html => docs.zip`。
206 | 
207 |
208 | 接下来,与前面构建的步骤不同,部署文件的任务不需要跟构建绑在一起,可以单独创建一个 Build Configuration,等需要部署时再「人工部署」。
209 |
210 | * 进入项目设置,在 General Settings 里,创建一个新的 Build Configuration。
211 | 
212 | * 这次部署的来源不是原本的 VCS,所以改成选择 Manually 方式,并把这个 Build Configuration 取名为 Deploy document。
213 | 
214 | * 下一步会转至 Deploy document 设置,这里想将前面 Build Configuration 生成的 Artifact 当成来源,因此要把上一个 Build Configuration 设为相依 (Dependencies)。点选左边侧边栏的 Dependencies,选择画面上的 Add new artifact dependency。
215 | 
216 | * 在弹出式窗口里,设定 Depend on 为 Shopping Cart / Build,Get artifacts from 为 Latest successful build (上一次成功的构建),Artifacts rules 要包含要从 Artifact 拿出的文件路径 `+:docs.zip`,完成后按 Save 储存。
217 | 
218 | * 切换到 Build Steps,并点击 Add build step。第一步先把 `docs.zip` 上传到目标主机上,Runner type 选 SSH Upload、Step name 取名为 Upload,Target、Port、Username 请依照目标服务设置,Paths to sources 则是设定要上传的文件,完成后按 Save 储存。
219 | 
220 | * 上一步只把 API 文件的压缩档上传,还没办法让用户浏览。所以要搭配第二步动作,直接 SSH 进服务器,把压缩档解开放到 Nginx Site 底下。回到 Build Steps 设定再新增第二个 Build Step,Runner type 选 SSH Exec,Step name 取名为 Publish,Target、Port、Username 请依照目标服务器设置,Commands 就直接把在服务器上运行的 Shell Script 直接黏贴上去,设定好后按 Save 储存。(此步骤请依照自己的环境做设置,以下命令仅供参考)
221 |
222 | ```shell
223 | mv upload/docs.zip upload/docs-%build.number%.zip
224 | unzip upload/docs-%build.number%.zip -d upload/docs-%build.number%
225 | mv upload/docs-%build.number% docs/
226 | ```
227 |
228 | 
229 |
230 | * 完成后回到首页,每次在 Build 那步的 API Docs Tab 确认没问题,想要部署 API 文件到服务器上时,就可以点选 Deploy document 旁的 Run,这样 TeamCity 就会把文件部署到服务器。
231 | 
232 |
233 | ## 举一反三
234 |
235 | 由于演示代码是以 Kotlin 编写,所以在设计 Build Step 时,使用的构建工具都是以 Gradle 为核心。而 TeamCity 做为一个通用的持续集成服务器,并没有限制使用的构建工具,其支持多种 Build Runner,开发者可依据项目需求运行所需的构建工具,也可搭配 Docker 搭建运行环境。
236 |
237 | 以下依不同开发生态系举几个例子:
238 |
239 | * JVM 项目:使用 `Gradle`、`Maven` 或 `Ant` Runner
240 | * JavaScript 项目:使用 `Node.js` Runner
241 | * Python 项目:使用 `Python` Runner
242 | * PHP 项目:以 `Command Line` Runner 搭配 `composer` Docker
243 |
244 | 用于部署的 Runner:
245 |
246 | * 打包 Image:使用 `Docker` Runner
247 | * 直接上传:使用 `SSH Upload` 或 `FTP Upload` Runner
248 | * 直接运行命令:使用 `SSH Exec` Runner
249 |
250 | ## 集成 JetBrains IDE
251 |
252 | 开发者若使用 JetBrains IDE,可安装 [TeamCity 插件](https://plugins.jetbrains.com/plugin/1820-teamcity),在 IDE 内会多一个 TeamCity 窗口,登入帐号密码后,即可在 IDE 里查看 TeamCity 的 Build Log,不需离开 IDE、不需中断心流,更高效的完成工作。
253 |
254 | 
255 |
256 | ## 以 Kotlin DSL 描述设置
257 |
258 | TeamCity 也可用设置文件来描述 CI/CD 行为,大规模设置更轻松。但有别于其他解决方案,TeamCity 使用的语法是 Kotlin DSL 而不是 YAML,原因有二:
259 |
260 | * DSL 可依场景设计领域专用语言,让不是开发者的团队成员也能迅速理解并上手,降低维护难度。
261 | * Kotlin DSL 完全是 Kotlin 语法,不需要额外的语法检查器即可用 Kotlin 编译器码证语法,也可以直接在 IDE 做语法提示,编写代码时更安全。
262 |
263 | 新手不需要手动撰写 TeamCity 的 Kotlin DSL,可直接从 Web UI 导出:
264 |
265 | * 转至项目设置 General Settings,点击右上方 Actions 下拉菜单,选择 Download settings in Kotlin format...。
266 | 
267 | * TeamCity 会将项目设置导出成 Zip 文件。
268 | * 将下载下来的 Zip 解压缩,把文件夹重新命名为 `.teamcity` 后,放在项目根文件夹底下。
269 | * 转至项目设置 Versioned Settings,点取 UI 上的 Synchronization enabled 并按下 Apply 按钮,未来 TeamCity 就会以项目内的设置文件运行设置,Web UI 变为只读。
270 | 
271 |
272 | ## 延伸主题讨论
273 |
274 | 本教程以 DevOps 新手快速入门 TeamCity 为目标,以熟悉 TeamCity 基本操作为主。不过 TeamCity 还有更多特性可深入研究,以下列出进阶主题供同学参考:
275 |
276 | * **定制化 Agent**:若项目有用到特殊的环境或工具,可自行定制 Agent 后挂载至 TeamCity Server 上使用。或是定制项目所需的 Docker Image,在设置 Build Step 时使用指定的 Image 运行。
277 | * **调用不同 Trigger**:演示仅用到 VCS Trigger,TeamCity 还支持 Schedule Trigger、Branch Remote Run Trigger 等,可弹性组合以符合更种场景。
278 | * **设定 Build Feature**:TeamCity 支持在构建完成后触发更多动作,比方说合并 PR、自动提交等,可将更多流程自动化。
279 | * **与团队工具集成**:TeamCity 可与其他团队工具集成,比方说与市场上常见的 Issue Tracker 集成,或是与 JetBrains IDE 集成,让开发流程更顺畅。
280 |
281 | ## 官方学习材料
282 |
283 | TeamCity 团队提供丰富的文档供开发者自学,统整学习材料清单如下:
284 |
285 | * **[TeamCity 视频教程](https://www.youtube.com/playlist?list=PLQ176FUIyIUZVX0oSnlZh3mfqE3ZWDEZh)**:由 TeamCity 布道师 Marco 亲自录制的视频教程,是最高效的学习材料!若想学习 TeamCity,可先由这份教程入门。
286 | * **[官方教程](https://www.jetbrains.com/teamcity/tutorials/)**:若您比较喜欢主题式的学习,尤其是想了解如何将 TeamCity 应用于项目的开发生态系,那可以从这份教程开始,直接挑您想看的编程语言即可。
287 | * **[官方文档](https://www.jetbrains.com/help/teamcity/teamcity-documentation.html)**:TeamCity 团队提供完整的官方文档,遇到问题时可用关键字搜索对应的主题。
288 | * **[CI/CD 指南](https://www.jetbrains.com/teamcity/ci-cd-guide/)**:若您对 DevOps 的观念及名称有兴趣想深入,TeamCity 团队整理的这份 CI/CD 很值得做为学习时的补充读物。
289 | * **[TeamCity Technology Day](https://www.youtube.com/playlist?list=PLQ176FUIyIUal1FCy2F8KUgVU1ol0O9sU)** :TeamCity 团队在 2020 年尾举办了一场线上技术日,在这个 YouTube 播放清单里,有很多不同面向的 TeamCity 主题分享,可以挑自己有兴趣的主题来听。
290 | * **[TeamCity Cloud Launch Event](https://www.youtube.com/playlist?list=PLQ176FUIyIUYKymnmoMnzwjyA7jEc39nJ)**:喜欢使用 TeamCity Cloud 的小伙伴,请参考这个 Launch Event 的视频,可以更清楚 TeamCity Cloud 提供的功能与进阶功能。
291 |
292 | ## Q&A
293 |
294 | 1. Artifact Path 的语法要怎么写?
295 | 其语法为 `[+:]source [=> target]`。`+:` 指要包含后面的路径,`source` 指要生成压缩文件的路径,`=>` 指要生成压缩文件,`target` 指压缩文件的文件名。更多说明及用例可以参考[官方文档](https://www.jetbrains.com/help/teamcity/cloud/2022.06/configuring-general-settings.html#Artifact+Paths)。
296 |
297 | 2. 视频里演示时,IDE 的进度条效果是怎么做出来的?
298 | 这是安装了一个名为 [Unicorn Progress Bar](https://plugins.jetbrains.com/plugin/18271-unicorn-progress-bar) 的插件,在 IDE 安装后就能有一样的效果。
299 |
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/dsl/kotlin-dsl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/dsl/kotlin-dsl.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/dsl/versioned-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/dsl/versioned-settings.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/installation/post-install-setup-step1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/installation/post-install-setup-step1.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/installation/post-install-setup-step2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/installation/post-install-setup-step2.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/installation/post-install-setup-step3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/installation/post-install-setup-step3.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/installation/post-install-setup-step4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/installation/post-install-setup-step4.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/installation/post-install-setup-step5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/installation/post-install-setup-step5.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step1.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step2.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step3.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step4.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step5.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/installation/signup-teamcity-cloud-step6.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/integration/teamcity-plugin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/integration/teamcity-plugin.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab1/lab1-step1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab1/lab1-step1.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab1/lab1-step2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab1/lab1-step2.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab1/lab1-step3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab1/lab1-step3.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab1/lab1-step4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab1/lab1-step4.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab1/lab1-step5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab1/lab1-step5.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab1/lab1-step6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab1/lab1-step6.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab1/lab1-step7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab1/lab1-step7.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab1/lab1-step8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab1/lab1-step8.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab1/lab1-step9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab1/lab1-step9.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab2/lab2-step1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab2/lab2-step1.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab2/lab2-step2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab2/lab2-step2.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab2/lab2-step3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab2/lab2-step3.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab2/lab2-step4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab2/lab2-step4.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab2/lab2-step5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab2/lab2-step5.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab2/lab2-step6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab2/lab2-step6.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab2/lab2-step7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab2/lab2-step7.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab2/lab2-step8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab2/lab2-step8.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab3/lab3-step1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab3/lab3-step1.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab3/lab3-step2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab3/lab3-step2.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab3/lab3-step3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab3/lab3-step3.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab3/lab3-step4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab3/lab3-step4.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab3/lab3-step5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab3/lab3-step5.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab3/lab3-step6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab3/lab3-step6.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab3/lab3-step7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab3/lab3-step7.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab3/lab3-step8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab3/lab3-step8.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/lab3/lab3-step9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/lab3/lab3-step9.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/teamcity-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/teamcity-icon.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/teamcity-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/teamcity-logo.png
--------------------------------------------------------------------------------
/ci/lab06-teamcity/images/workflow/teamcity-workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/ci/lab06-teamcity/images/workflow/teamcity-workflow.png
--------------------------------------------------------------------------------
/config/lab01-ansible/ansible.cfg:
--------------------------------------------------------------------------------
1 | # 应该避免本文件在当前目录中存在,这样不安全
2 | [defaults]
3 | host_key_checking = false
4 | inventory = ./hosts.ini
5 | command_warnings=False
6 | deprecation_warnings=False
7 | roles_path = ./roles
8 | nocows = 1
9 | retry_files_enabled = False
10 |
11 | [ssh_connection]
12 | control_path = %(directory)s/%%h-%%p-%%r
13 | pipelining = True
--------------------------------------------------------------------------------
/config/lab01-ansible/app-stack.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # 在所有应用服务器上做配置和部署
3 | - hosts: app
4 | become: true
5 | tasks:
6 | - name: Config NTP Server # 配置 ntp 服务器
7 | yum:
8 | name: chrony
9 | state: present
10 | - name: Start NTP service # 启动 chronyd 服务
11 | service:
12 | name: chronyd
13 | state: started
14 | enabled: yes
15 | - name: Install Python3-pip&git
16 | yum:
17 | name: python3-pip,git
18 | state: present
19 | - name: Install django package
20 | pip:
21 | name: django<4
22 | state: present
23 | - name: Deploy from github
24 | git:
25 | repo: https://github.com/martinliu/hellodjango.git
26 | dest: /opt/hello
27 | update: yes
28 | - name: enable app 8000 port
29 | firewalld:
30 | port: 8000/tcp
31 | permanent: yes
32 | state: enabled
33 | - name: Reload Firewalld service
34 | service:
35 | name: firewalld
36 | state: reloaded
37 | enabled: yes
38 | - name: Start my hello app
39 | command: sh /opt/hello/run-hello.sh
40 |
41 | # 在所有所有服务器上做配置和部署
42 | - hosts: db
43 | become: true
44 | tasks:
45 | - name: Install Mariadb Server
46 | yum:
47 | name: mariadb-server,python3-PyMySQL
48 | state: present
49 | - name: Start DB service
50 | service:
51 | name: mariadb
52 | state: started
53 | enabled: yes
54 | - name: Install firewalld
55 | yum:
56 | name: firewalld
57 | state: present
58 | - name: Start Firewalld service
59 | service:
60 | name: firewalld
61 | state: started
62 | enabled: yes
63 | - name: Open the db port
64 | firewalld:
65 | port: 3306/tcp
66 | permanent: yes
67 | state: enabled
--------------------------------------------------------------------------------
/config/lab01-ansible/hosts.ini:
--------------------------------------------------------------------------------
1 | # 应用服务器组
2 | [app]
3 | 192.168.31.165
4 | 192.168.31.124
5 |
6 | # 数据库服务器组
7 | [db]
8 | 192.168.31.58
9 |
10 | # 名为 localvm 的嵌套组
11 | [localvm:children]
12 | app
13 | db
14 |
15 | # 给嵌套组定义变量,应用于所有服务器
16 | [localvm:vars]
17 | ansible_user=sysops
18 | ansible_ssh_private_key_file=~/.ssh/id_rsa
19 | ansible_ssh_common_args='-o StrictHostKeyChecking=no'
--------------------------------------------------------------------------------
/config/lab01-ansible/img/192-1928992_order-66.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/config/lab01-ansible/img/192-1928992_order-66.jpg
--------------------------------------------------------------------------------
/config/lab01-ansible/img/1_BORbGnI7OfdUdsCk7URXKg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/config/lab01-ansible/img/1_BORbGnI7OfdUdsCk7URXKg.png
--------------------------------------------------------------------------------
/config/lab01-ansible/img/1_N2yWueFgHi6M_lQGGsnxVQ.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/config/lab01-ansible/img/1_N2yWueFgHi6M_lQGGsnxVQ.png
--------------------------------------------------------------------------------
/config/lab01-ansible/img/ansible-wide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/config/lab01-ansible/img/ansible-wide.png
--------------------------------------------------------------------------------
/config/lab01-ansible/img/t8redb90cc631.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/config/lab01-ansible/img/t8redb90cc631.jpg
--------------------------------------------------------------------------------
/config/lab01-ansible/init-users.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - hosts: localvm
3 | become: true
4 | # 引用变量文件
5 | vars_files:
6 | - vars/default.yml
7 | tasks:
8 | # Sudo 用户组配置
9 | - name: Make sure we have a 'wheel' group
10 | group:
11 | name: wheel
12 | state: present
13 | # 允许 'wheel' 组里的用户执行sudo可以不输入用户密码
14 | - name: Make sudo command without password
15 | lineinfile:
16 | path: /etc/sudoers
17 | state: present
18 | regexp: '^%wheel'
19 | line: '%wheel ALL=(ALL) NOPASSWD: ALL'
20 | validate: '/usr/sbin/visudo -cf %s'
21 |
22 | # 创建远程命令执行的用户,并配置ssh密钥
23 | - name: Create a new regular user with sudo privileges
24 | user:
25 | name: "{{ create_user }}"
26 | state: present
27 | groups: wheel
28 | append: true
29 | create_home: true
30 | shell: /bin/bash
31 | # 将本地 ssh 公钥注入远程授权访问秘钥文件
32 | - name: Set authorized key for remote user
33 | authorized_key:
34 | user: "{{ create_user }}"
35 | state: present
36 | key: "{{ copy_local_key }}"
--------------------------------------------------------------------------------
/config/lab01-ansible/inventory.v1:
--------------------------------------------------------------------------------
1 | # 应用服务器组
2 | [app]
3 | 192.168.31.165
4 | 192.168.31.124
5 |
6 | # 数据库服务器组
7 | [db]
8 | 192.168.31.58
9 |
10 | # 名为 localvm 的嵌套组
11 | [localvm:children]
12 | app
13 | db
14 |
15 | # 给嵌套组定义变量,应用于所有服务器
16 | [localvm:vars]
17 | ansible_user=root
18 | ansible_password='devops1234'
--------------------------------------------------------------------------------
/config/lab01-ansible/inventory.v2:
--------------------------------------------------------------------------------
1 | # 应用服务器组
2 | [app]
3 | 192.168.31.165
4 | 192.168.31.124
5 |
6 | # 数据库服务器组
7 | [db]
8 | 192.168.31.58
9 |
10 | # 名为 localvm 的嵌套组
11 | [localvm:children]
12 | app
13 | db
14 |
15 | # 给嵌套组定义变量,应用于所有服务器
16 | [localvm:vars]
17 | ansible_user=sysops
18 | ansible_ssh_private_key_file=~/.ssh/id_rsa
19 | ansible_ssh_common_args='-o StrictHostKeyChecking=no'
--------------------------------------------------------------------------------
/config/lab01-ansible/readme.md:
--------------------------------------------------------------------------------
1 | # Ansible 新手入门指南
2 |
3 | 
4 |
5 | [【查看 B 站视频】](https://www.bilibili.com/video/BV1Uv4y1K7u9)
6 |
7 | ## Ansible 的发音?
8 |
9 | 
10 |
11 |
12 | ## Ansible 究竟是何物?
13 |
14 | [维基百科](https://en.wikipedia.org/wiki/Ansible_(software)):术语 "ansible "是乌苏拉-K-勒古恩在她1966年的小说《罗卡农的世界》中创造的,它指的是虚构的即时通信系统。是一类虚构的设备或技术,能够进行近乎瞬时或比光速更快的通信。
15 |
16 | ## 创始人小传
17 |
18 | 关于 Ansible 的小故事:“摸鱼创业成功的经典案例!”,看下 Founder, CEO & Chairman - Ansible 的 LinkedIn 你就懂了。
19 |
20 | * https://www.linkedin.com/in/saidziouani/
21 | * https://www.linkedin.com/in/timothy-gerla/
22 | * https://www.linkedin.com/in/michaeldehaan/
23 |
24 |
25 | 
26 |
27 |
28 | ## 推荐学习文档
29 |
30 | Ansible 简介文档:
31 |
32 | * https://docs.ansible.com/ansible/latest/index.html
33 | * https://en.wikipedia.org/wiki/Ansible_(software)
34 | * https://www.ansible.com/hubfs//AnsibleFest%20ATL%20Slide%20Decks/Getting%20Started%20with%20Ansible%20-%20Jake.pdf
35 | * https://aap2.demoredhat.com/decks/ansible_best_practices.pdf
36 | * https://www.ansible.com/hubfs/Webinar%20PDF%20slides/%5BWIP%5D%20MBU%20_%20ANA%20_%20Webinar%20-%20Ansible%20Network%20Meta%20Collection.pdf
37 |
38 | Ansible 和其他几种同类工具的对比:
39 |
40 | 
41 |
42 | Ansible 最简化架构图:
43 |
44 | 
45 |
46 |
47 | ## 安装 Ansible
48 |
49 | 本教程推荐使用 `pip` 在 Fedora 35 上安装 Ansible。
50 |
51 | ### 环境说明
52 |
53 | 推荐使用 4 个虚拟机的学习环境,本教程模拟的是上面的架构图中的效果。
54 |
55 | 控制器 - Contorler 【Master】:
56 |
57 | * os : Fedora 35
58 | * ip :192.168.31.30
59 |
60 | 被管理服务器 - Hosts 【node】
61 |
62 | * 本地 Fedora 35 虚拟机
63 | * app1 : 192.168.31.165
64 | * app2 :192.168.31.124
65 | * db :192.168.31.58
66 |
67 | 以上是建议的最佳学习环境配置。而最低配置可以是:本地笔记本电脑(Win/macOS) + 一个虚拟机(Linux)所组成的开发环境。
68 |
69 | 在本地安装开发环境:以操作系统版本 macOS 12.3 (21E230) 的安装配置过程为例,其中第四个步骤需要按实际情况修改路径。
70 |
71 | 步骤:
72 |
73 | 1. 先安装 Python3 (步骤省略)
74 | 2. 确认 Python3 的版本:`python3 --version`
75 | 3. 运行 ` pip3 install ansible`
76 | 4. 在 shell 的环境配置文件加入 Python 的可执行文件路径。例如:使用 zsh 的系统在 ~.zshrc 文件中加入这一行 `export PATH="$PATH:/Users/martinliu/Library/Python/3.8/bin"`,不同的用户名和 Python 版本对应这里的路径不同。
77 | 5. 让配置文件生效,运行 `source ~.zshrc`
78 | 6. 验证 Ansible 安装的版本,运行 `ansible --version`
79 |
80 | 如果你使用的是 Windows 操作系统,请使用 Windows 10/11 的版本自带的 Windows Subsystem for Linux 功能,在 Linux 的子系统里完成以上的操作。
81 |
82 | ### 在 Fedora 35 上安装 【生产环境】
83 |
84 | 本教程推荐用` pip` 安装 Ansible 的方式。同时下面也提供了用 `dnf` 的安装方法。
85 |
86 | #### pip 安装
87 |
88 | 下面,我们在 Master (controler)上安装部署 Ansble 工具集。
89 |
90 | 为了安装到 Ansible 的最新版本,还需要先升级 python 的版本到 >= 3.8;目前 Fedora 35 自带的Python 版本为 3.10.1,已经满足了 Ansible 对 Python 的最低版本需求。
91 |
92 | 步骤如下:
93 |
94 | 1. 安装必要的软件包,运行命令 `dnf install python3-pip sshpass git -y`
95 | 2. 升级 `pip3` 用 `python3 -m pip install --upgrade pip`
96 | 3. 切换到非 root 用户 (如果有的话 )
97 | 4. 先设置国内的 pypi 安装源 `pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple`
98 | 5. 用 `pip3` 安装 Ansible , 运行 `pip3 install ansible`
99 | 6. 验证 Ansible 安装的版本,运行 `ansible --version`
100 |
101 | #### dnf 安装
102 |
103 | 在控制器 (master)上安装部署 Ansble 工具集。
104 |
105 | 步骤如下:
106 |
107 | 1. 运行命令 `dnf install ansible -y`
108 | 2. 验证 Ansible 安装的版本,运行 `ansible --version`
109 | 3. 安装必要的软件包 `dnf install sshpass git -y`
110 |
111 | dnf 安装到的版本会稍微老一些,没有 pip 安装的版本新。
112 |
113 | 而在生产中,往往需要安装特定的某个 Ansible 版本,而非当前的最新版本。
114 |
115 | ## 配置 Ansble 运行环境
116 |
117 | 本教程演示和讲解的是将 4 个空白无任何配置的服务器配置为:单一控制器,三个被管理节点的运行环境。
118 |
119 | ### 初始化控制器
120 |
121 | #### 创建 SSH 无密码访问秘钥对
122 |
123 | Ansible 的控制器(Master)通过 SSH 访问和管理被管理的节点,并完成系统、服务配置工作。
124 |
125 | 首先,在控制器上生成 ssh 访问的秘钥对。ssh 登陆到控制器,最好切换到非root用户,执行 `ssh-keygen` 命令,如果不需要秘钥文件的密码,则需要输入一系列回车即可;新创建 ssh 的密钥对,用于无密码访问其它三个被服务器节点。
126 |
127 | 创建的测试用秘钥对,查看所在位置:
128 |
129 | ```sh
130 | [martin@ctl ~]$ ssh-keygen
131 | [martin@ctl ~]$ ls ~/.ssh
132 | id_rsa id_rsa.pub
133 | ```
134 |
135 | 尝试使用密码的访问其它被管理服务器,确认你拥有所有正确的密码。(如果你已经有一个统一的访问秘钥,请忽略此步骤)
136 |
137 | #### 配置 ansible.cfg 基础配置文件
138 |
139 | Ansible 控制器节点的执行引擎的行为特性的配置文件是 `ansible.cfg` 文件,对此文件路径的搜索顺序如下:
140 |
141 | 1. ANSIBLE_CONFIG (环境变量中)
142 | 2. ansible.cfg (当前目录中) 。
143 | 3. ~/.ansible.cfg (当前用户的 home 目录下)
144 | 4. /etc/ansible/ansible.cfg (操作系统的路径)- 本教程中使用的方式
145 |
146 | 在当前用户的` Home `目录中创建一个内容如下的 `.ansible.cfg` 配置文件 (注意是以句点开头的隐藏文件)
147 |
148 | ```yml
149 | [defaults]
150 | host_key_checking = false
151 | inventory = ./hosts.ini
152 | command_warnings = False
153 | deprecation_warnings = False
154 | roles_path = ./roles
155 | nocows = 1
156 | retry_files_enabled = False
157 |
158 | [ssh_connection]
159 | control_path = %(directory)s/%%h-%%p-%%r
160 | pipelining = True
161 | ```
162 |
163 | #### 编写主机清单文件 - Inventory
164 |
165 | 主机清单文件就是所谓的 “Inventory”,它是描述所有被管理节点的数据文件。
166 |
167 | 创建内容如下的 `inventory.v1` 配置文件
168 |
169 | ```yml
170 | # 组织方式:功能、地域、环境
171 | # 应用服务器组
172 | [app]
173 | 192.168.31.165
174 | 192.168.31.124
175 |
176 | # 数据库服务器组
177 | [db]
178 | 192.168.31.58
179 |
180 | # 名为 localvm 的嵌套组
181 | [localvm:children]
182 | app
183 | db
184 |
185 | # 给嵌套组定义变量,应用于所有服务器
186 | [localvm:vars]
187 | ansible_user=root
188 | ansible_password='devops1234'
189 |
190 | ```
191 |
192 | 其他可用的定义方法详见:https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html
193 |
194 |
195 | 执行首个 Ansible 命令 `ansible -i inventory.v1 all -m ping` ,如果能正常使用 inventory 文件中的用户名和密码登录所有被管理节点的话,改命令的结果应该如下:
196 |
197 | ```sh
198 | [martin@ctl live]$ ansible -i inventory.v1 all -m ping
199 | 192.168.31.58 | SUCCESS => {
200 | "ansible_facts": {
201 | "discovered_interpreter_python": "/usr/bin/python3"
202 | },
203 | "changed": false,
204 | "ping": "pong"
205 | }
206 | 192.168.31.165 | SUCCESS => {
207 | "ansible_facts": {
208 | "discovered_interpreter_python": "/usr/bin/python3"
209 | },
210 | "changed": false,
211 | "ping": "pong"
212 | }
213 | 192.168.31.124 | SUCCESS => {
214 | "ansible_facts": {
215 | "discovered_interpreter_python": "/usr/bin/python3"
216 | },
217 | "changed": false,
218 | "ping": "pong"
219 | }
220 | ```
221 |
222 | #### 创建 Ansible 专用的用户
223 |
224 | 在拥有所有节点 root 访问的基础上,在所有被管理节点上进一步配置一个 Ansible 专用的账号。
225 |
226 | inventory.v1 配置文件中携带密码是很危险的,下面使用 Ansible 来解决这个问题,并配置好所有的被管理节点。
227 |
228 | 编写 Playbook 实现下面的工作:
229 |
230 | * 创建一个 Ansible 专用的名为 `sysops` 的用户账号 (不建议使用 root 用户,而是非 root 用户)
231 | * 将其配置为 sudo 提权限并不需要密码的用户。
232 | * 将控制器当前用户新创建的秘钥对的公钥配置部署到所有被管理节点的 sysops 的授权用户中。
233 |
234 |
235 | 创建第一个 Playbook `init-users.yml` 。
236 |
237 | * 使用到的Ansible模块有 group, lineinfile, user 和 authorized_key
238 | * 引用了变量文件
239 |
240 | 文件的内容如下:
241 |
242 | ```yml
243 | ---
244 | - hosts: localvm
245 | become: true
246 | # 引用变量文件
247 | vars_files:
248 | - vars/default.yml
249 | tasks:
250 | # Sudo 用户组配置
251 | - name: Make sure we have a 'wheel' group
252 | group:
253 | name: wheel
254 | state: present
255 | # 允许 'wheel' 组里的用户执行sudo可以不输入用户密码
256 | - name: Set sudo without password
257 | lineinfile:
258 | path: /etc/sudoers
259 | state: present
260 | regexp: '^%wheel'
261 | line: '%wheel ALL=(ALL) NOPASSWD: ALL'
262 | validate: '/usr/sbin/visudo -cf %s'
263 |
264 | # 创建远程命令执行的用户,并配置ssh密钥
265 | - name: Create a new regular user with sudo privileges
266 | user:
267 | name: "{{ create_user }}"
268 | state: present
269 | groups: wheel
270 | append: true
271 | create_home: true
272 | shell: /bin/bash
273 |
274 | - name: Set authorized key for remote user
275 | authorized_key:
276 | user: "{{ create_user }}"
277 | state: present
278 | key: "{{ copy_local_key }}"
279 | ```
280 |
281 | 这个文件引用了一个变量文件 `vars/default.yml` ,下面创建这个目录和文件,文件的内容如下:
282 |
283 | ```yml
284 | create_user: sysops
285 | copy_local_key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/id_rsa.pub') }}"
286 | ```
287 |
288 | 下一步执行这个 Playbook 完成被管理节点的初始化配置 :`ansible-playbook -i inventory.v1 init-users.yml` ,结果如下:
289 |
290 | ```sh
291 | [martin@ctl live]$ ansible-playbook -i inventory.v1 init-users.yml
292 |
293 | PLAY [localvm] *********************************************************************************
294 |
295 | TASK [Gathering Facts] *************************************************************************
296 | ok: [192.168.31.124]
297 | ok: [192.168.31.165]
298 | ok: [192.168.31.58]
299 |
300 | TASK [Make sure we have a 'wheel' group] *******************************************************
301 | ok: [192.168.31.165]
302 | ok: [192.168.31.58]
303 | ok: [192.168.31.124]
304 |
305 | TASK [允许 'wheel' 组里的用户执行sudo可以不输入用户密码] ***************************************
306 | changed: [192.168.31.58]
307 | changed: [192.168.31.124]
308 | changed: [192.168.31.165]
309 |
310 | TASK [Create a new regular user with sudo privileges] ******************************************
311 | changed: [192.168.31.165]
312 | changed: [192.168.31.124]
313 | changed: [192.168.31.58]
314 |
315 | TASK [Set authorized key for remote user] ******************************************************
316 | changed: [192.168.31.124]
317 | changed: [192.168.31.58]
318 | changed: [192.168.31.165]
319 |
320 | PLAY RECAP *************************************************************************************
321 | 192.168.31.124 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
322 | 192.168.31.165 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
323 | 192.168.31.58 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
324 | ```
325 |
326 | `ansible-playbook` 命令是解析和执行 Playbook 脚本文件的命令。我们可以看到 Playbook 是一个 yml 格式的状态声明式定义文件。它描述了被管理节点的操作系统中的各种配置细节。
327 |
328 | 在控制器上验证无密码SSH密钥认证登陆,选取任何一个被管理节点的 ip 地址,执行 `ssh sysops@192.168.31.124`;登录后查看 .ssh 目录中的内容。
329 |
330 | 在所有host上我们配置好了一个Ansible专用的无sudo密码的普通用户。优化 inventory.v1 文件,删除其中的用户名和密码,创建内容如下的 inventory.v2 文件:
331 |
332 | ```yml
333 | # 组织方式:功能、地域、环境
334 | # 应用服务器组
335 | [app]
336 | 192.168.31.165
337 | 192.168.31.124
338 |
339 | # 数据库服务器组
340 | [db]
341 | 192.168.31.58
342 |
343 | # 名为 localvm 的嵌套组
344 | [localvm:children]
345 | app
346 | db
347 |
348 | # 给嵌套组定义变量,应用于所有服务器
349 | [localvm:vars]
350 | ansible_user=sysops
351 | ansible_ssh_private_key_file=~/.ssh/id_rsa
352 | ansible_ssh_common_args='-o StrictHostKeyChecking=no'
353 | ```
354 |
355 | 最后用首个执行的 Ansible 命令 `ansible -i inventory.v2 all -m ping` 验证所有主机是否可以用SSH正常访问,确认得到全绿的输出结果。
356 |
357 | ```sh
358 | [martin@ctl live]$ ansible -i inventory.v1 all -m ping
359 | 192.168.31.58 | SUCCESS => {
360 | "ansible_facts": {
361 | "discovered_interpreter_python": "/usr/bin/python3"
362 | },
363 | "changed": false,
364 | "ping": "pong"
365 | }
366 | 192.168.31.124 | SUCCESS => {
367 | "ansible_facts": {
368 | "discovered_interpreter_python": "/usr/bin/python3"
369 | },
370 | "changed": false,
371 | "ping": "pong"
372 | }
373 | 192.168.31.165 | SUCCESS => {
374 | "ansible_facts": {
375 | "discovered_interpreter_python": "/usr/bin/python3"
376 | },
377 | "changed": false,
378 | "ping": "pong"
379 | }
380 | ```
381 |
382 | 到此为止,我们完成了 Ansible 运行环境的配置,包括:
383 |
384 | * 准备 ssh 登录的秘钥
385 | * 配置控制器节点的基础配置文件
386 | * 初始化三个被管理几点的远程登录用户账号
387 | * 创建了优化的 Inventory 主机清单文件
388 | * 使用 ping 模块再次确认所有被管理主机的 ssh 登录
389 |
390 | ## 用 Ansible 命令执行运维工作 | Ad-hoc
391 |
392 | 用下面的命令体会 Ansible 的特性和内置模块的功能。在执行下面的命令之前,复制 inventory.v2 文件为 hosts.ini 文件【ansible.cnf 参数中已做配置】。这样在执行命令的时候就不需要用参数制定 inventory 文件的位置,因此可以更加简洁。
393 |
394 | ### 默认并发执行特性
395 |
396 | 运行多次下面相同的命令,了解 Ansible 的多线程并发特性。
397 |
398 | * 使用 -a 参数远程执行 Linux 原生命令
399 |
400 | ```sh
401 | ansible localvm -a "hostname"
402 | ansible localvm -a "hostname"
403 | ansible localvm -a "hostname"
404 |
405 | ansible localvm -a "hostname" -f 1
406 | ansible localvm -a "hostname" -f 1
407 | ansible localvm -a "hostname" -f 1
408 | ```
409 |
410 | 从以上结果中观察 node 节点的执行顺序。
411 |
412 | ### 环境状况检查
413 |
414 | 使用 -a 参数的远操作系统里的原生命令。
415 |
416 | ```sh
417 | ansible localvm -a "df -h"
418 |
419 | ansible localvm -a "free -m"
420 |
421 | ansible localvm -a "date"
422 | ```
423 |
424 | ### 使用 Ansible 模块做变更
425 |
426 | 使用 Ansible 的核心模块变更系统。
427 |
428 | * yum 和 servce 模块混用
429 | * 搭配 -a 的命令行执行
430 | * 在需要提权的地方,使用 -b 参数
431 |
432 | ```sh
433 | ansible localvm -a "date"
434 |
435 | ansible localvm -b -m yum -a "name=chrony state=present"
436 |
437 | ansible localvm -b -m service -a "name=chronyd state=started enabled=yes"
438 |
439 | ansible localvm -b -a "chronyc tracking"
440 |
441 | ansible localvm -a "date"
442 | ```
443 |
444 | ## 部署目标应用系统
445 |
446 | 本教程在 GitHub 上准备了一个简单的 hellodjango 应用程序。
447 |
448 | 应用系统配置部署所需的流程如下:
449 |
450 | * 在 App1 和 App2 上配置好 Django 运行环境
451 | * 在 DB 上安装 Mariadb
452 | * 在所有服务器上启动防火墙服务,并配置好需要开放的端口
453 | * 在两个 App 服务器上安装并启动 Django 应用
454 |
455 | ### 配置 Django 运行环境
456 |
457 | 开始编写第一个应用系统在一套服务器上的综合配置 Playbook。
458 |
459 | 配置应用服务器:安装 python3 和 django
460 |
461 | * yum 和 pip 模块的混用
462 | * 辅助 -a 的命令行执行
463 |
464 | ```sh
465 | ansible app -b -m yum -a "name=python3-pip state=present"
466 |
467 | ansible app -b -m pip -a "name=django<4 state=present"
468 |
469 | ansible app -a "python3 -m django --version"
470 |
471 | ```
472 |
473 | 本教程中使用了先用逐条 Ansible 配置指令调试的方式,然后在将其翻译到 Playbook 中的方式,在熟悉了这个开发过程和 Ansible 的常用模块后,我们则可以直接开发 Playbook 了。
474 |
475 | 根据以上的所有 Ansible 指令,创建名为 app-stack.yml 的文件,内容如下:
476 |
477 | ```yml
478 | ---
479 | - hosts: app
480 | become: true
481 | tasks:
482 | - name: Config NTP Server # 配置 ntp 服务器
483 | yum:
484 | name: chrony
485 | state: present
486 | - name: Start NTP service # 启动 chronyd 服务
487 | service:
488 | name: chronyd
489 | state: started
490 | enabled: yes
491 | - name: Install Python3-pip&git
492 | yum:
493 | name: python3-pip,git
494 | state: present
495 | - name: Install django package
496 | pip:
497 | name: django<4
498 | state: present
499 | ```
500 |
501 | 下面执行 ansible-play app-stack.yml 可以得到相同的结果状态。
502 |
503 | ### 配置数据库服务器
504 |
505 | 接着我们执行安装 Mariadb 服务器的操作。
506 |
507 | * yum、service 和 防火墙模块混用
508 |
509 | 逐条执行下面的调试命令:
510 |
511 | ```sh
512 | ansible db -b -m yum -a "name=mariadb-server state=present"
513 |
514 | ansible db -b -m service -a "name=mariadb state=started enabled=yes"
515 |
516 | ansible db -b -m yum -a "name=firewalld state=present"
517 |
518 | ansible db -b -m service -a "name=firewalld state=started enabled=yes"
519 |
520 | ansible db -b -m firewalld -a "port=3306/tcp zone=public state=enabled permanent=yes"
521 |
522 | ansible db -b -m yum -a "name=python3-PyMySQL state=present"
523 |
524 | ```
525 |
526 | firewall-cmd --list-all
527 |
528 |
529 | 在以上命令的结果都符合预期后,在 app-stack.yml 中增加如下内容
530 |
531 | ```yml
532 |
533 | - hosts: db
534 | become: true
535 | tasks:
536 | - name: Install Mariadb Server
537 | yum:
538 | name: mariadb-server,python3-PyMySQL
539 | state: present
540 | - name: Start DB service
541 | service:
542 | name: mariadb
543 | state: started
544 | enabled: yes
545 | - name: Install firewalld
546 | yum:
547 | name: firewalld
548 | state: present
549 | - name: Start Firewalld service
550 | service:
551 | name: firewalld
552 | state: started
553 | enabled: yes
554 | - name: Open the db port
555 | firewalld:
556 | port: 3306/tcp
557 | permanent: yes
558 | state: enabled
559 | ```
560 |
561 | 在控制器上执行更新后的 Playbook,运行命令 `ansible-playbook app-stack.yml` ,确保执行结果输出正常。
562 |
563 | ### 部署 Django 应用系统
564 |
565 | 从 GitHub 中部署目标应用代码:
566 |
567 | * 运用 git ,yum , serviice 和 firewalld 模块
568 | * 用命令行方式启动应用
569 |
570 | ```sh
571 | ansible localvm -b -m yum -a "name=git state=present"
572 |
573 | ansible app -b -m git -a "repo=https://github.com/martinliu/hellodjango.git \
574 | dest=/opt/hello update=yes"
575 |
576 | ansible app -b -m firewalld -a "port=8000/tcp state=enabled permanent=yes"
577 |
578 | ansible app -b -m service -a "name=firewalld state=reloaded enabled=yes"
579 |
580 | ansible app -b -a "sh /opt/hello/run-hello.sh"
581 | ```
582 |
583 | 在浏览器中输入应用的访问网址: http://192.168.31.165:8000/hello/ ,应该在两个 app 服务器上都可以看到相同的结果。
584 |
585 |
586 | 在 app-satck.yml 中的 App 部署部分加入下面的内容
587 |
588 | ```yml
589 | - name: Deploy from github
590 | git:
591 | repo: https://github.com/martinliu/hellodjango.git
592 | dest: /opt/hello
593 | update: yes
594 | - name: enable app 8000 port
595 | firewalld:
596 | port: 8000/tcp
597 | permanent: yes
598 | state: enabled
599 | - name: Reload Firewalld service
600 | service:
601 | name: firewalld
602 | state: reloaded
603 | enabled: yes
604 | - name: Start my hello app
605 | command: sh /opt/hello/run-hello.sh
606 | ```
607 |
608 | 执行最后的应用部署 `ansible-playbook app-stack.yml` 确认执行后的结果正常,用浏览器可以正常访问 Django 应用页面。
609 |
610 | ## 总结
611 |
612 | 希望大家通过本教程学会:
613 |
614 | * Ansible 运行环境的基础配置
615 | * Ansible 的 ad-hoc 方式用法
616 | * Ansible 核心中的几个常用模块
617 | * 逐步编写部署目标应用的 Ansible Playbook
618 |
619 | ## 呼唤下一位鉴宝人
620 |
621 | 建议分享的内容如下(不限于此):
622 |
623 | * Role 的开发
624 | * CI/CD 工具中执行 Playbook
625 | * 容器,k8s 相关主题
626 | * AWX Ansible 相关主题
627 | * 生产项目中的经验分享
628 |
--------------------------------------------------------------------------------
/config/lab01-ansible/vars/default.yml:
--------------------------------------------------------------------------------
1 | create_user: sysops
2 | copy_local_key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/id_rsa.pub') }}"
--------------------------------------------------------------------------------
/config/lab09-terraform/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | ## 1. Terraform 简介
4 |
5 | ----------------------------------------------------------------------
6 |
7 | [Terraform](https://www.terraform.io/)是一个开源工具,用于安全高效地预览、配置和管理(CRUD)多云基础架构和各类其他[资源](https://registry.terraform.io/browse/providers)。
8 |
9 | Terraform是一个IT基础架构自动化编排工具,可以用代码来管理和维护IT资源。它编写了描述云资源拓扑的配置文件,例如虚拟机、负载均衡器。Terraform的命令行接口(Command Line Interface,CLI)提供一种简单机制,用于将配置文件部署到AWS、阿里云或其他任意支持的云上,并对其进行版本控制。
10 |
11 | 同时,Terraform是一个高度可扩展的工具,通过Terraform提供的SDK,编写Go代码,调用任意的API,实现[自研的provider](https://www.hashicorp.com/blog/writing-custom-terraform-providers)。也就是说只要提供了API,就可以成为一个provider。
12 |
13 | ## 2. 基本概念
14 |
15 | -------------------------------------------------------------------------------------------
16 |
17 | ### 2.1 Provider
18 |
19 | `provider`其实就是某个资源的API集合,比如[Alicloud Provider](https://registry.terraform.io/providers/aliyun/alicloud/1.173.0)
20 |
21 | 初始化 provider,每种provider的初始化方式不一样,阿里云支持AK/SK, Credentials, etc.
22 |
23 | ```shell
24 | # init with AK/SK
25 | terraform {
26 | required_providers {
27 | alicloud = {
28 | source = "aliyun/alicloud"
29 | version = "1.156.0"
30 | }
31 | }
32 | }
33 |
34 | provider "alicloud" {
35 | access_key = "xxxxxxxxxxxxxx"
36 | secret_key = "xxxxxxxxxxxxxx"
37 | region = "cn-shanghai"
38 | }
39 | ```
40 |
41 | ```shell
42 | # init with profile, the path is $HOME/.aliyun/config.json
43 | terraform {
44 | required_providers {
45 | alicloud = {
46 | source = "aliyun/alicloud"
47 | version = "1.156.0"
48 | }
49 | }
50 | }
51 |
52 | provider "alicloud" {
53 | region = "cn-shanghai"
54 | profile = "customprofile"
55 | }
56 | ```
57 |
58 | 由于terraform本身的版本在不断升级,以及provider的版本升级,不同的版本组合下,terraform预览资源可能会出现不一样的视图。解决方法,[lock文件](https://www.terraform.io/language/files/dependency-lock),`.terraform.lock.hcl`。 建议在git仓库下,将这个文件一并上传以此保证版本的一致性。
59 |
60 | ### 2.2 Resource
61 |
62 | `resource`就是具体某一个API的调用,创建(Create)一个具体的资源,比如[VPC](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/vpc),[NAT Gateway](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/nat_gateway),[ECS](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/resources/instance)等。
63 |
64 | ```shell
65 | resource "alicloud_vpc" "vpc" {
66 | vpc_name = var.name
67 | cidr_block = "10.0.0.0/8"
68 | }
69 | ```
70 |
71 | ### 2.3 Data Sources
72 |
73 | `data`就是读取(Read/Retrieve)某个已经存在的可用资源,比如[虚拟机镜像](https://registry.terraform.io/providers/aliyun/alicloud/latest/docs/data-sources/images)
74 |
75 | ```shell
76 | data "alicloud_images" "images_ds" {
77 | owners = "system"
78 | name_regex = "^centos_6"
79 | }
80 | ```
81 |
82 | ### 2.4 Variables
83 |
84 | `variable` 就是定义参数(arguments),terraform支持各种[类型](https://www.terraform.io/language/expressions/types)的参数。
85 |
86 | ```shell
87 | variable "vpc_name" {
88 | type = string
89 | description = "variable for vpc name"
90 | default = "test_vpc"
91 | }
92 | ```
93 |
94 | terraform支持几种传递参数的方式,第一大类,自动传参。第二大类,手动传参。
95 |
96 | 自动传参: `terraform.tfvars`, `*.auto.tfvars`
97 |
98 | 手动传参: `-var="instance_type=t2.large"`, `export TF_VAR_image_id=ami-abc123` , 最后在都没有找到的情况下,在交互界面上要求给出变量值
99 |
100 | 
101 |
102 | ### 2.5 locals
103 |
104 | 有变量就会有常量,`locals`定义会重复使用到的常量。
105 |
106 | ```shell
107 | locals {
108 | service_name = "forum"
109 | owner = "Community Team"
110 | }
111 | ```
112 |
113 | ### 2.6 Output
114 |
115 | 有了输入(var),就会有输出。`output`支持输出具体的资源信息(attributes)。
116 |
117 | ```shell
118 | output "vpc_id" {
119 | value = alicloud_vpc.vpc.id
120 | }
121 | ```
122 |
123 | ### 2.7 State file
124 |
125 | Terraform和Ansible一样,它们的操作都支持幂等性。这种幂等性其实是通过现实的状态与state file中的预期状态进行比对得到的。
126 |
127 | Terraform支持两大类的state file,第一大类,本地state file。第二大类,远程state file。
128 |
129 | 本地state file: `terraform.tfstate`, `terraform.tfstate.backup`, 就你一个人用
130 |
131 | 远程state file: `state.tf` , 支持[AWS S3](https://www.terraform.io/language/settings/backends/s3),[Alicloud OSS](https://www.terraform.io/language/settings/backends/oss), 适合团队开发,上传到git仓库,并且支持锁机制,可以确保互斥,同一时刻只能有一个人在CRUD云资源。
132 |
133 | ```shell
134 | terraform {
135 | backend "oss" {
136 | bucket = "remote-state-dns"
137 | prefix = "mystate/state"
138 | key = "terraform.tfstate"
139 | region = "cn-beijing"
140 | }
141 | }
142 | ```
143 |
144 | ## 3. Terraform命令行(实战)
145 |
146 | ------------------------------------------------------
147 |
148 | ### 3.1 安装Terraform
149 |
150 | 安装terraform非常简单,支持手动安装下载zip包,解压zip包,添加到环境变量中即可。也支持在线安装,`apt-get install terraform`, 按照这篇[install guide](https://learn.hashicorp.com/tutorials/terraform/install-cli)即可。
151 |
152 | ### 3.2 Terraform 命令
153 |
154 | #### 3.2.1 terraform init
155 |
156 | 进入到包含`tf`文件的目录下,初始化terraform,执行`terraform init`, 它会下载对应的provider,验证你的credential,初始化remote state file。
157 |
158 | `-upgrade`参数决定是否升级模块代码以及provider版本
159 |
160 | #### 3.2.2 terraform fmt
161 |
162 | `terraform fmt`命令用来格式化Terraform代码文件的格式和规范,增加可读性。
163 |
164 | #### 3.2.3 terraform validate
165 |
166 | `terraform validate`命令用来检查目录下Terraform代码,只检查语法文件,不会真正访问远程资源。逻辑上对即可,并不会真正判断现实情况。
167 |
168 | #### 3.2.4 terraform plan
169 |
170 | `terraform plan`命令用来预览资源的变化情况,它会真正检查state file以及现实情况。比如新增(Create)一个资源,更新(Update)一个资源,删除(Destroy)一个资源。
171 |
172 | `-out`参数将变更计划保存到指定路径下的文件中,随后可以使用terraform apply执行该计划
173 |
174 | #### 3.2.5 terraform apply/destroy
175 |
176 | `terraform apply`和`terraform destroy`命令是terraform真正干活的两个命令。apply命令用来生成执行计划(可选)并执行之,使得基础设施资源状态符合代码的描述。destroy命令用来销毁并回收所有Terraform管理的基础设施资源。
177 |
178 | `-target`参数指定特定的某一个资源,当terraform已经管理了非常多的资源下,很有用
179 |
180 | `-auto-approve`参数指定自动同意执行,慎用!建议在jenkinsfile中加入`input`来手动同意。
181 |
182 | #### 3.2.6 terraform show
183 |
184 | `terraform show`命令用来展示(Read)当前所有归terraform控制的资源的状态信息。
185 |
186 | #### 3.2.7 terraform state
187 |
188 | `terraform state`命令用来进行复杂的状态管理操作。直接修改state file是不推荐的,如果确实需要改动state file,使用`terraform state`命令来修改。
189 |
190 | `terraform state list`: 列出所有资源的状态信息,同`terraform show`
191 |
192 | `terraform state show`: 列出具体某一个资源的状态信息
193 |
194 | `terraform state mv`: 重命名一个资源
195 |
196 | `terraform state rm`: 从状态文件中删除一个或多个对象,删除对象并非删除实际基础设施对象,而只是状态不再由Terraform管理,从状态文件中删除而已。
197 |
198 | #### 3.2.8 terraform import
199 |
200 | `terraform import`命令用来将已经存在的手动创建的资源对象导入Terraform,由terraform来控制。
201 |
202 | ## 4. Terraform Cloud
203 |
204 | ------------------------------------------------------------
205 |
206 | [Terraform Cloud](https://www.terraform.io/cloud-docs)是一个帮助团队一起使用 Terraform 的应用程序。它在一个可靠的云上环境中运行Terraform,包括提供轻松访问tfstate、团队审批基础设施的更改、自动关联VCS(GitHub, GitLab, etc.)、云上资源预算评估、执行哨兵等功能。
207 |
208 | Terraform官方提供了非常详尽的使用[guide](https://learn.hashicorp.com/tutorials/terraform/cloud-sign-up?in=terraform/cloud-get-started),请自行参考guide进行实验。
209 |
210 | 基本的使用步骤如下:
211 |
212 | 1. 登录Terraform Cloud
213 |
214 | 2. 新建一个 Org
215 |
216 |
217 |
218 | 3. 新建一个workspace,并且关联到GitHub repo
219 |
220 | 4. 设置AK/SK两个环境变量
221 |
222 |
223 |
224 | 5. 执行Plan/Apply
225 |
226 |
227 |
228 | ## 5. Terraform Module
229 |
230 | ------------------------------------------------------------
231 |
232 | 为了能够复用某些resource,terraform支持将一个目录下的所有tf文件封装成一个module。每个tf文件和平时的用法一致。然后通过关键字mudole来调用这个目录下的所有resource。
233 |
234 | ```shell
235 | module "tsj_demo" {
236 | source = "git::https://jihulab.com/dhutsj/terraform-practice.git//alicloud_vpc_nat_sg?ref=main"
237 |
238 | vpc_name = var.vpc_name
239 | }
240 |
241 | ```
242 |
243 |
244 |
245 | ## 6. 鸣谢及推荐
246 |
247 | ------------------------------------------------
248 |
249 | 非常感谢 DevOps 中国社区举办此次鉴宝活动,我才有这次机会和大家见面,很高兴认识这么多热爱开源的工程师。
250 |
251 | 如果在学习/使用Terraform时有任何疑问或想法,欢迎和我交流,微信(wechat):dhutsj。
252 |
253 | Terraform 版本管理工具 tfswitch: https://tfswitch.warrensbox.com/
254 |
255 | Terraform 多环境管理工具 terragrunt: https://terragrunt.gruntwork.io/
256 |
257 |
258 |
259 |
260 |
261 |
--------------------------------------------------------------------------------
/config/lab09-terraform/images/neworg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/config/lab09-terraform/images/neworg.jpg
--------------------------------------------------------------------------------
/config/lab09-terraform/images/plan.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/config/lab09-terraform/images/plan.jpg
--------------------------------------------------------------------------------
/config/lab09-terraform/images/tf.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/config/lab09-terraform/images/tf.JPG
--------------------------------------------------------------------------------
/config/lab09-terraform/images/var.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/config/lab09-terraform/images/var.JPG
--------------------------------------------------------------------------------
/config/lab09-terraform/images/vars.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/config/lab09-terraform/images/vars.jpg
--------------------------------------------------------------------------------
/database/lab06-liquibase/images/flyway-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/database/lab06-liquibase/images/flyway-1.jpg
--------------------------------------------------------------------------------
/database/lab06-liquibase/images/flyway-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/database/lab06-liquibase/images/flyway-2.jpg
--------------------------------------------------------------------------------
/database/lab06-liquibase/images/flyway-3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/database/lab06-liquibase/images/flyway-3.jpg
--------------------------------------------------------------------------------
/database/lab06-liquibase/images/flyway-4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/database/lab06-liquibase/images/flyway-4.jpg
--------------------------------------------------------------------------------
/database/lab06-liquibase/images/liquibase.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/database/lab06-liquibase/images/liquibase.jpg
--------------------------------------------------------------------------------
/deploy/lab04-argocd/0.necessary_before_start.md:
--------------------------------------------------------------------------------
1 | Gitops 工具链中, ArgoCD 非常受欢迎。虽然其功能强大,操作简单,但想要真正掌握它,还需要把基础打牢,融会贯通才能理解得更加深刻。
2 |
3 | # Kubernetes (k8s)
4 |
5 | 学习中所有实验,都运行在 k8s 集群中,所以要求诸位对 kubernetes 基本概念有所了解,如 Deployment, Service, Ingress 等等。然而这仅仅是听懂课程的前提,最理想的状态,是有独立部署 k8s 集群及基本的排错能力。
6 |
7 | 部署 k8s 集群有多种方式,kubeadmin,kubeasz 等等,大家各显神通,用自己最熟悉的方案即可。本次分享中我们使用 kubesphere 全家桶中的 [kubekey](https://github.com/kubesphere/kubekey) 及 [openelb](https://github.com/kubesphere/openelb)。
8 |
9 | # Git 版本管理
10 |
11 | 无论是 Github 还是 Gitlab,抑或是极狐 Gitlab,它们的底层都基于 Git 这个版本管理工具。而我们要探讨的 Gitops,更是把 Git 版本管理的理念作为单一可信任源。
12 |
13 | Git 命令不能仅限于 pull 和 push,还应对其原理近一步了解。如 什么是 gitflow,优缺点都有哪些等等;用成熟的 Git 最佳实践来规范团队多人协作,是实践 Gitops 的首要工作。
14 |
15 | # Gitops
16 |
17 | Gitops 日趋火热,但这是一种仍然发展中的技术实践,成熟度仍待完善。如果仅学习 ArgoCD 这个工具,其意义本身并不大。笔者建议更应从 Gitops 发展历史入手,进而弄明白何为“推模式”,何为“拉模式”,各有什么优缺点,最后再来看 ArgoCD 解决了哪些问题,又引入了哪些问题。
18 |
19 | 诸位要对这些问题有所思考,带着问题学习 ArgoCD,最终才能知其然,知其所以然。
20 |
21 | # Helm & Kubestomize
22 |
23 | 就像 Linux 一切皆文件,在 k8s 中一切皆 “配置清单”。部署应用时,组织配置清单的方案有两种,就是 helm 和 kustomize。helm 通过 golang 模板渲染的方式,把 charts 渲染成为配置清单,而 kustomize 则更接近原生的 k8s 配置清单。个中差异,还需要在课前有所了解。
24 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/1.install-k8s-cluster.md:
--------------------------------------------------------------------------------
1 | # 1. 安装工具
2 |
3 | 开始动手之前,我们来介绍两款工具,kubekey 和 k9s。
4 |
5 | kubeykey 是 KubeSphere 团队基于 GoLang 语言开发的 kubernetes 集群部署工具,使用 KubeKey,您可以轻松、高效、灵活地单独安装和管理 Kubernetes,当然如果你部署 Kubesphere 也是分厂方便的。
6 |
7 | k9s 是一款命令行下的 k8s 集群管理工具,可以非常有效地提高你对 k8s 的管理效率。本次分享我们对 k8s 资源的观察和操作,就是通过 k9s 来实现的。
8 |
9 | > [kubekey release](https://github.com/kubesphere/kubekey)
10 |
11 | > [k9s release](https://github.com/derailed/k9s)
12 |
13 | ```shell
14 | # kubekey
15 | curl -sfL https://get-kk.kubesphere.io | sh -
16 |
17 | # k9s
18 | curl -sS https://webinstall.dev/k9s | bash
19 | ```
20 |
21 | # 2. 部署 k8s 环境
22 |
23 | ## 2.1. 生成 kubekey 配置
24 |
25 | ```shell
26 | # 创建集群配置,集群名称为 monday
27 | ./kk create config --name monday
28 | ```
29 |
30 | ## 2.2. 修改集群配置
31 |
32 | ```yaml
33 | # 修改配置如下
34 | apiVersion: kubekey.kubesphere.io/v1alpha1
35 | kind: Cluster
36 | metadata:
37 | name: monday
38 | spec:
39 | hosts:
40 | - {
41 | name: tm-opsinit-01,
42 | address: 10.10.14.99,
43 | internalAddress: 10.10.14.99,
44 | }
45 | roleGroups:
46 | etcd:
47 | - tm-opsinit-01
48 | master:
49 | - tm-opsinit-01
50 | worker:
51 | - tm-opsinit-01
52 | controlPlaneEndpoint:
53 | domain: monday-api.automan.fun
54 | address: ""
55 | port: 6443
56 | kubernetes:
57 | version: v1.21.5
58 | imageRepo: kubesphere
59 | clusterName: cluster.local
60 | network:
61 | plugin: calico
62 | kubePodsCIDR: 10.233.64.0/18
63 | kubeServiceCIDR: 10.233.0.0/18
64 | registry:
65 | registryMirrors: []
66 | insecureRegistries: []
67 | addons: []
68 | ```
69 |
70 | ## 2.3. 检查 docker 配置
71 |
72 | docker daemon 默认创建的 docker0 网桥,使用 172.17.0.0 网段地址,如果你的服务器使用的 172.17.0.0 的网段,可以通过修改 docker daemon 的配置来修改 docker0 网桥的地址段,避免 地址冲突。
73 |
74 | ```json
75 | # /etc/docker/daemon.json
76 |
77 | {
78 | "log-opts": {
79 | "max-size": "5m",
80 | "max-file":"3"
81 | },
82 | "exec-opts": ["native.cgroupdriver=systemd"],
83 | "bip":"192.168.0.1/24"
84 | }
85 | ```
86 |
87 | 修改完配置后,如果服务器上已安装 docker 服务,执行如下命令重载配置。如无运行 docker 服务,请忽略。
88 |
89 | ```shell
90 | systemctl daemon-reload && systemctl restart docker
91 | ```
92 |
93 | ## 2.4. 创建集群
94 |
95 | 创建集群前,有三个点需要检查:
96 |
97 | 1. 禁用 selinux
98 | 2. 禁用防火墙
99 | 3. 安装相关系统级依赖
100 |
101 | ```shell
102 | # 临时禁用 selinux
103 | setenforce 0
104 | sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
105 |
106 | # 禁用防火墙
107 | systemctl disable firewalld && systemctl stop firewalld && systemctl status firewalld
108 |
109 | # 安装系统依赖
110 | yum install socat conntrack ebtables ipset
111 |
112 | # 创建集群
113 | export KK_ZONE=cn
114 | ./kk create cluster -f config-monday.yaml
115 | ```
116 |
117 | ## 2.5. 安装 kubectl 客户端
118 |
119 | > k8s 集群部署好后,我们来安装相关 kubectl 管理工具。
120 |
121 | ```shell
122 |
123 | # 添加 k8s yum 源
124 | cat < /etc/yum.repos.d/kubernetes.repo
125 | [kubernetes]
126 | name=Kubernetes
127 | baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
128 | enabled=1
129 | gpgcheck=0
130 | repo_gpgcheck=0
131 | gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
132 | EOF
133 |
134 | # 安装 kubectl
135 | yum install -y kubectl
136 |
137 | # k8s 命令行参数很多,可以通过 bash-completion 来自动补全命令
138 | # 命令行代码补全
139 | yum install bash-completion -y
140 | echo "source <(kubectl completion bash)" >> ~/.bashrc
141 | source ~/.bashrc
142 | ```
143 |
144 | # 3. 部署 OpenELB
145 |
146 | 集群中的应用,如果要在集群外部访问,可以采用 NodePort 方式暴露服务,也可以采用 LoadBalancer 的方式。为了更好的模拟生产环境,咱们使用 LoadBalancer 的方式暴露服务。OpenLB 是由 Kubesphere 团队开发的支持裸金属服务器提供 LoadBalancer 类型服务的工具。具体功能细节就不额外讲解,大家可以自行参考官方文档。国人主导开发的工具,中文支持非常好。
147 |
148 | > Github: `https://github.com/kubesphere/openelb`
149 |
150 | ```shell
151 | kubectl apply -f https://raw.githubusercontent.com/openelb/openelb/master/deploy/openelb.yaml
152 | ```
153 |
154 | ## 3.1 OpenELB layer2 原理讲解
155 |
156 | 我们实验中使用 OpenLB 的 layer2 模式。这种模式需要配置一些集群主机网段的空地址,也就是说这些 IP 不能绑定物理网卡。OpenLB 提供 Eip 这个 CRD 来配置这些空 IP。为什么需要这样的 IP 呢?我们来简单讲解下 Layer2 模式的原理。
157 |
158 | 当外部有流量请求某个空 IP 时,路由器会发出 ARP 广播报文,也就是到集群服务器网段内询问,数据要发给谁。显然不会有任何一个主机响应,此时,OpenLB 的
159 | port-manager 就会相应这个 ARP 报文。通过这种 ARP 报文欺骗的黑客手段,实现流量的劫持。剩下的步骤,就由 PortLB 来转发流量到相应的 Service 中。
160 |
161 | PortLB 的 Layer2 模式,就是这样工作的。
162 |
163 | ```yaml
164 | apiVersion: network.kubesphere.io/v1alpha2
165 | kind: Eip
166 | metadata:
167 | name: eip-pool
168 | spec:
169 | address: 10.10.14.91-10.10.14.92
170 | protocol: layer2
171 | interface: ens192
172 | disable: false
173 | ```
174 |
175 | # 4. 部署 nginx-ingress
176 |
177 | OpenLB 可以方便地暴露 4 层协议,比如 TCP 协议等等,但在 7 层协议中的一些操作,就无能为力啦,比如卸载 https 证书,路由分发等等。
178 |
179 | > https://kubernetes.github.io/ingress-nginx/deploy/
180 |
181 | ```shell
182 | # 1. 应用配置清单
183 |
184 | kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/cloud/deploy.yaml
185 |
186 | # 2. service.metadata.annotations 中指定 OpenELB 配置
187 |
188 | lb.kubesphere.io/v1alpha1: openelb
189 | protocol.openelb.kubesphere.io/v1alpha1: layer2
190 | ```
191 |
192 | > PortELB 通过这两条 annotation 信息来识别要提供服务的 Service
193 |
194 | # 5. 部署 OpenEBS
195 |
196 | Kubernates 集群中,对于有状态应用,需要申请 PV 支持。openEBS 支持把节点主机的文件系统映射为存储服务,这对我们的 All In One 实验来说,是个非常好的支持。
197 |
198 | > https://openebs.io/docs/user-guides/installation
199 |
200 | ```shell
201 | # 推荐使用 operator 部署应用
202 | kubectl apply -f https://openebs.github.io/charts/openebs-operator.yaml
203 | ```
204 |
205 | ## 5.1 验证 hostpath
206 |
207 | ```shell
208 | # /var/openebs/local
209 | kubectl apply -f https://openebs.github.io/charts/examples/local-hostpath/local-hostpath-pvc.yaml
210 | kubectl apply -f https://openebs.github.io/charts/examples/local-hostpath/local-hostpath-pod.yaml
211 | ```
212 |
213 | # 6. 安装 Metric Server
214 |
215 | ```shell
216 | # Installation
217 |
218 | kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
219 | ```
220 |
221 | > bx509: cannot validate certificate for because it doesn't contain any IP SANs"
222 |
223 | 上述异常因证书验证未通过导致,可以配置合法域名 SSL 证书,也可通过如下方式禁用 Metric Server 证书验证.
224 |
225 | ```yaml
226 | # Metric Server deployment 添加镜像启动参数
227 | ---
228 | spec:
229 | containers:
230 | - args:
231 | # 添加如下参数
232 | - --kubelet-insecure-tls
233 | ```
234 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/README.MD:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # 1. ArgoCD 简介
4 |
5 | 基于 kubernetes 的声明式 Gitops 持续部署工具。
6 |
7 | 持续部署工具有很多,如 Jenkins 等等,我们为什么选择 ArgoCD 呢?
8 |
9 | 1. 应用定义,配置和环境变量管理等等,都是声明式的,基于云原生的。
10 | 2. 所有声明清单都存储在代码仓库中,受版本管理
11 | 3. 应用发布和生命周期管理都是自动化的,可审计的。
12 |
13 | 最重要的,ArgoCD 操作简单,非常易用。
14 |
15 | # 2. 工作原理
16 |
17 | 
18 |
19 | ArgoCD 被设计并实现为 Kubernetes 控制器,它会持续监控 ArgoCD 应用状态。ArgoCD 中的应用会对应一个 Git 仓库,ArgoCD 控制器确保应用状态始终同步。此处的 Git 仓库,并不存放项目源码,它保存的是项目在 Kubernetes 中的运行状态,也就是配置清单。Git 仓库内容的组织形式,支持 Helm, Kustomize 等;
20 |
21 | 当用户向 Git 仓库提交合并请求,合并被受理后,Git 仓库中应用状态的配置清单发生变化,此时 Git 仓库可以通过 WebHook 触发 ArgoCD 的应用同步。如果未配置 WebHook,ArgoCD 会轮询检测 Git 仓库的变更,检测周期默认为 3 分钟。当然,用户也可以通过 UI 或 CLI 的方式手动触发应用同步。
22 |
23 | ArgoCD 的 Hook 机制,会在应用状态同步前,同步中,同步后及同步失败后,触发响应的钩子方法,用来完成一些额外操作,可以实现更加复杂的应用控制。ArgoRollouts 的蓝绿发布,就非常好的利用了 hooks 机制。
24 |
25 | ArgoCD 不仅可以将应用发布到它所在的 Kubernates 集群,它也可以托管其他集群,实现多集群的应用部署。该功能由 ApplicationSet 实现。
26 |
27 | # 3. 安装 ArgoCD
28 |
29 | > [k8s 集群部署参考文档](install-k8s-cluster.md)
30 |
31 | 推荐用 operator 的方式部署 ArgoCD。推荐理由如下:
32 |
33 | - 使用默认配置快速安装并启动 ArgoCD
34 | - 无缝升级 ArgoCD 所有组件
35 | - 支持定期计划备份和恢复 ArgoCD 集群
36 | - 聚合并发布 ArgoCD 及 Operator 本身的指标,供 Prometheus 和 Grafana 使用
37 | - 根据需要自动缩放对应组件
38 |
39 | ## 3.1 安装 ArgoCD Operator
40 |
41 | > ref: https://operatorhub.io/operator/argocd-operator
42 |
43 | ```shell
44 |
45 | curl -sL https://github.com/operator-framework/operator-lifecycle-manager/releases/download/v0.21.2/install.sh | bash -s v0.21.2
46 |
47 | kubectl create -f https://operatorhub.io/install/argocd-operator.yaml
48 |
49 | kubectl get csv -n operators
50 | ```
51 |
52 | > !!! 注: 如果不配置环境变量,则 ArgoCD 无法创建 Namespace
53 |
54 | > ref: https://github.com/argoproj/argo-cd/issues/5886
55 |
56 | 默认使用 Operator 部署的 ArgoCD,没有集群资源的控制权限;找到 `Subscription` 类型的资源,给 Operator 添加环境变量配置;
57 |
58 | ```yaml
59 | apiVersion: operators.coreos.com/v1alpha1
60 | kind: Subscription
61 | metadata:
62 | name: argocd
63 | namespace: argocd
64 | spec:
65 | channel: alpha
66 | name: argocd-operator
67 | source: operatorhubio-catalog
68 | sourceNamespace: olm
69 | config:
70 | env:
71 | - name: ARGOCD_CLUSTER_CONFIG_NAMESPACES
72 | value:
73 | # 此处案例中 value 配置为 argocd
74 | ```
75 |
76 | ## 3.2 创建 ArgoCD 实例
77 |
78 | > https://argocd-operator.readthedocs.io/en/latest/usage/ingress/
79 |
80 | ```yaml
81 | apiVersion: argoproj.io/v1alpha1
82 | kind: ArgoCD
83 | metadata:
84 | name: monday-argocd
85 | namespace: argocd
86 | spec:
87 | server:
88 | insecure: true
89 | ingress:
90 | enabled: true
91 | ```
92 |
93 | ## 3.3 修改配置导出服务
94 |
95 | ArgoCD Operator 默认 Ingress 域名为资源名,此处即为 `monday-argocd`。Operator 官方文档中说可以 `overwrite` 域名,但翻遍了 CRD 的描述信息,也没找到。翻源码才发现 Operator 并没有控制 `host` 字段。直接 `kubectl edit` 即可 @\_@
96 |
97 | > !!! 注:官方文档言辞模糊,竟然可以直接修改
98 |
99 | > ingress 域名: argo.monday.fun
100 |
101 | 本地主机配置 hosts 如下:
102 |
103 | ```shell
104 | # /etc/hosts
105 |
106 | 10.10.14.91 argo.monday.fun
107 | ```
108 |
109 | > > 看到下图请为自己鼓掌 !!!
110 |
111 | 
112 |
113 | # 3.4. 获取登录密码
114 |
115 | > 默认 admin 密码存放在 `-cluster` secret 里
116 |
117 | ```shell
118 |
119 | kubectl -n argocd get secret monday-argocd-cluster -o jsonpath='{.data.admin\.password}' | base64 -d
120 | ```
121 |
122 | # 4. 部署样例仓库
123 |
124 | > ref: https://github.com/argoproj/argocd-example-apps.git
125 |
126 | 可以通过 UI 界面或者直接 `kubectl apply` 下方配置清单,创建 ArgoCD 应用清单。
127 |
128 | ```yaml
129 | apiVersion: argoproj.io/v1alpha1
130 | kind: Application
131 | metadata:
132 | name: guestbook
133 | spec:
134 | destination:
135 | name: ""
136 | namespace: guestbook
137 | server: "https://kubernetes.default.svc"
138 | source:
139 | path: kustomize-guestbook
140 | repoURL: "https://github.com/argoproj/argocd-example-apps.git"
141 | targetRevision: HEAD
142 | project: default
143 | syncPolicy:
144 | automated:
145 | prune: true
146 | selfHeal: true
147 | syncOptions:
148 | - CreateNamespace=true
149 | ```
150 |
151 | > 常见问题: Namespace "guestbook" for Service "guestbook-helm-guestbook" is not managed
152 |
153 | > !!! 注: 这个问题就是 3.1 步骤中没有添加环境导致的
154 |
155 | ```shell
156 | # 通过给 Namespace 打标签的方式,给 ArgoCD 授权
157 | # 默认情况下 $NAMESPACE=argocd
158 | kubectl label ns guestbook argocd.argoproj.io/managed-by=$NAMESPACE
159 | ```
160 |
161 | 上述配置清单也可以通过 UI 界面生成,具体操作见下图:
162 |
163 | 
164 | 
165 | 
166 |
167 | # 5. app-of-apps 模式
168 |
169 | 在 argocd 中,用户所管理的对象,叫做应用。应用的状态,由它对应的资源清单描述。我们可以创建一个仓库,集中管理这些应用配置清单,而这个仓库,也可以当做应用来看待。
170 |
171 | 这种模式,就是 app of apps 模式。
172 |
173 | > https://github.com/argoproj/argocd-example-apps/tree/master/apps
174 |
175 | 官方示例中,使用 Helm Chart 来实现 app of apps 模式,templates 目录下每个文件都是一个 ArgoCD Application 配置清单。
176 |
177 | ```text
178 | ├── Chart.yaml
179 | ├── templates
180 | │ ├── guestbook.yaml
181 | │ ├── helm-dependency.yaml
182 | │ ├── helm-guestbook.yaml
183 | │ └── kustomize-guestbook.yaml
184 | └── values.yaml
185 | ```
186 |
187 | 当我们删除 app of apps 应用时,对应的其他应用,也会被级联删除。
188 |
189 | ## 5.1 应用场景
190 |
191 | 1. 集群应用迁移
192 |
193 | 微服务开发模式中,一个项目往往对应多个子项目。我们可以为创建 app of apps 应用,管理项目的微服务。当项目需要迁移时,只需要在新集群或者新 Namespace 中应用即可。
194 |
195 | 2. 集群初始化
196 |
197 | 生产环境中,k8s 集群部署好后,还会安装一些必要的支撑服务应用。此时可以把集群的初始化工作,使用 app of apps 应用描述。这样,新集群的初始化工作,也仅仅是创建个 argocd 应用而已。
198 |
199 | ## 5.2 俄罗斯套娃模式
200 |
201 | 在容器云原生的世界里,俄罗斯套娃模式很常见。例如,docker in docker,k8s in k8s。我们刚讲过的 app of apps 也是类似套娃模式。我们是否可以再套一层呢?
202 |
203 | 答案是肯定的。app of apps 应用,本质上仍然是 argocd Application,我们依旧可以将它放在更上层的 app of apps 应用中。
204 |
205 | 这里的想象空间就有点过于复杂了,这里仅仅给大家提供一种思考的方向,目前还没有听说哪个团队这么实践过。
206 |
207 | # 6. ArgoCD 添加多集群
208 |
209 | ArgoCD 在 Web UI 界面上无法添加 Kubernetes 集群,目前仅支持通过 argocd 命令行客户端工具;
210 |
211 | ## 6.1 安装 argocd 命令行客户端工具
212 |
213 | ```shell
214 | # ref: https://argo-cd.readthedocs.io/en/stable/cli_installation/
215 |
216 | curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
217 | chmod +x /usr/local/bin/argocd
218 | ```
219 |
220 | ## 6.2 添加集群方法一
221 |
222 | argocd 命令行客户端,提供 cluster add 方法,可以从 kubectl 的连接上下文或者认证文件中添加集群信息。
223 | 当我们在 kubectl 的上下文中,添加 tuesday 集群的上下文后,就可以使用 argocd cluster add 命令了;
224 |
225 | ```shell
226 | # 拷贝 Tuesday 集群的认证秘钥到
227 | scp 10.10.15.153:~/.kube/config ~/.kube/tuesday.config
228 |
229 | # 通过环境变量配置 kubectl
230 | export KUBECONFIG=$HOME/.kube/config:$HOME/.kube/tuesday.config
231 |
232 | # 查看 kubectl 上下文
233 | kubectl config get-contexts
234 |
235 | CURRENT NAME CLUSTER AUTHINFO NAMESPACE
236 | * kubernetes-admin@cluster.monday cluster.monday kubernetes-admin
237 | kubernetes-admin@cluster.tuesday cluster.tuesday kubernetes-admin
238 |
239 | # 导出 argocd-server 443 服务
240 | kubectl port-forward svc/monday-argocd-server -n argocd 9999:443
241 |
242 | # 登录 argocd,输入 admin 账号密码
243 | argocd login 127.0.0.1:9999
244 |
245 | # 通过 kubeconfig 添加集群
246 | argocd cluster add kubernetes-admin@cluster.tuesday
247 |
248 | # optional: 也可以不配置 kubectl 而直接通过 Kubeconfig 文件添加集群
249 | argocd cluster add --kubeconfig tuesday.config --name tuesday kubernetes-admin@cluster.tuesday
250 | ```
251 |
252 | ## 6.3 添加集群方法二
253 |
254 | argocd-cli 客户端支持从 kubeconfig 文件直接添加集群信息;
255 |
256 | ```shell
257 | $ argocd cluster add --kubeconfig tuesday.config
258 |
259 | ERRO[0000] Choose a context name from:
260 | CURRENT NAME CLUSTER SERVER
261 | * kubernetes-admin@cluster.tuesday cluster.tuesday https://tuesday-api.automan.fun:6443
262 |
263 | $ argocd cluster add --kubeconfig tuesday.config kubernetes-admin@cluster.tuesday
264 | ```
265 |
266 | ## 6.4 查看集群列表
267 |
268 | ```shell
269 | # 查看集群列表
270 | argocd cluster list
271 |
272 | SERVER NAME VERSION STATUS MESSAGE
273 | https://tuesday-api.automan.fun:6443 tuesday Unknown Cluster has no application and not being monitored.
274 | https://kubernetes.default.svc in-cluster Unknown Cluster has no application and not being monitored.
275 | ```
276 |
277 | > 由于 ArgoCD 并未在集群中部署应用,所以对集群的健康检查是关闭的。
278 |
279 | # 7. ApplicationSet
280 |
281 | 说到 ArgoCD 多集群部署应用,首先想到的方案可能在 UI 界面上配置多个应用,选择不同的集群发布即可;其次还可能想到,针对不同集群,写不同的 Application 配置清单,直接 `kubectl apply` 即可;我们不能说上述的两种方法不能用,但绝对不符合程序员对优雅的审美。程序员的优雅到底是有多优雅呢? ArgoCD 官方用一个子项目给出了答案。这个项目,就是我们今天要讲的 ArgoCD ApplicationSet。
282 |
283 | 当然跨集群部署应用,只是 ApplicationSet 的功能之一。我们将全面地把它讲透。
284 |
285 | 顾名思义,ApplicationSet 就是 Application 的集合,它控制器和相应的 CRD 构成。
286 |
287 | ## 7.1 ArgoCD 添加 ApplicationSet 控制器
288 |
289 | 只需在 ArgoCD CR 资源中添加 applicationSet 字段即可。
290 |
291 | ```shell
292 | apiVersion: argoproj.io/v1alpha1
293 | kind: ArgoCD
294 | metadata:
295 | name: monday-argocd
296 | namespace: argocd
297 | spec:
298 | version: v2.3.4
299 | server:
300 | insecure: true
301 | ingress:
302 | enabled: true
303 | applicationSet: {} # 增加
304 | ```
305 |
306 | ## 7.2 ApplicationSet 特性
307 |
308 | 针对于跨集群部署应用和 monorepo,ApplicationSet 这个 CRD 可以实现自动化和更大的灵活性。
309 |
310 | 官方给出四个特性:
311 |
312 | 1. 使用单个 ApplicationSet 配置清单控制多个 kubernetes 集群的能力
313 | 2. 使用单个 ApplicationSet 配置清单从一个或多个 Git 存储仓库部署多个应用程序
314 | 3. 在多租户集群中,提高单个集群租户使用 ArgoCD 部署应用程序的能力。无需让特权集群管理员参与启用目标集群或命名空间。假如我们有 A B 两个集群,通过 ApplicationSet,A 集群中的租户,不需要拥有 B 集群的权限,就可以在 B 集群中发布应用。这样就可以把持续发布的权限提前,放到持续集成阶段管理。
315 | 4. 增强对 monorepo 的支持
316 |
317 | > monorepo: 单个 Git 仓库中定义多个 ArgoCD 应用程序资源
318 |
319 | 一个项目常常由多个微服务构成,这些微服务的部署配置清单,可以放到各自独立的仓库中,也可以化零为整,在同一个仓库中管理。独立仓库管理,对单个微服务开发团队来说,可以更方便发版和回滚,但对于整个项目来说,高灵活度会带来不稳定性。ArgoCD 则推荐使用 MonoRepo 的方式,统一管理微服务的配置。原因也很简单,统一管理能更好的控制各微服务之间的依赖关系,从而提高整个项目的稳定性。
320 |
321 | ## 7.3 工作原理
322 |
323 | 当创建,更新或删除 ApplicationSet CRD 资源时,ApplicationSet 控制器会通过创建,更新或删除一个或多个对应的 ArgoCD Application 资源来响应。
324 |
325 | 实际上,ApplicationSet 的唯一职责就是操作 ArgoCD Application,类似 kubernetes 中 Replicaset 和 Replicas 一样。
326 |
327 | 
328 |
329 | - ApplicationSet 并不会操作 kubernetes 资源
330 | - 除 ArgoCD 部署的集群外,ApplicationSet 不会连接其他集群
331 | - 除 ArgoCD 部署的命名空间外,ApplicationSet 不与其他命名空间交互。
332 |
333 | ## 7.4 生成器介绍
334 |
335 | ApplicationSet 生成器负责生成参数,然后将这些参数根据模板渲染成 ArgoCD Application 资源。
336 |
337 | ApplicationSet 控制器当前支持多个生成器:
338 |
339 | 1. 列表生成器:根据列表中的元素生成参数,列表参数由用户自定义。
340 | 2. 集群生成器:基于 ArgoCD 中定义的集群自动生成集群参数,可以看做列表生成器的一个特例。
341 | 3. Git 生成器:根据 ApplicationSet CRD 中定义的 Git 仓库中包含的文件或文件夹生成参数。
342 | - 包含 JSON 值的各个目录将会被解析成模板参数
343 | - Git 仓库中的各目录路径也可以作为参数
344 | 4. 矩阵生成器: 矩阵生成器结合了两个子生成器的生成参数,迭代每个生成器生成的参数的每个组合。通过组合两个升起参数,生成所有可能的组合。
345 |
346 | 这是四个常用的生成器,更多生成器可以参考官方文档。接下来将针对这四种生成器分别进行试验。
347 |
348 | ## 7.5 列表生成器介绍
349 |
350 | 列表生成器基于一些键值对来生成参数,不过要求键对应的值必须为字符串类型。
351 |
352 | ```yaml
353 | apiVersion: argoproj.io/v1alpha1
354 | kind: ApplicationSet
355 | metadata:
356 | name: guestbook
357 | namespace: argocd
358 | spec:
359 | generators:
360 | - list:
361 | elements:
362 | - cluster: monday
363 | url: https://kubernetes.default.svc
364 | - cluster: tuesday
365 | url: https://tuesday-api.automan.fun:6443
366 | template:
367 | metadata:
368 | name: "{{cluster}}-guestbook"
369 | namespace: guestbook
370 | spec:
371 | project: default
372 | source:
373 | repoURL: https://github.com/argoproj/argocd-example-apps.git
374 | targetRevision: HEAD
375 | path: kustomize-guestbook
376 | destination:
377 | server: "{{url}}"
378 | namespace: guestbook
379 | syncPolicy:
380 | automated: {}
381 | syncOptions:
382 | - CreateNamespace=true
383 | ```
384 |
385 | ## 7.6 集群生成器介绍
386 |
387 | 在 ArgoCD 中,托管集群存储在 ArgoCD 被部署的 Secret 中,ApplicationSet 控制器根据这些信息生成参数来识别和定位多集群。
388 |
389 | 对于每个注册到 ArgoCD 中的集群,都会提供一下参数:
390 |
391 | ```shell
392 | 1. name: 集群名
393 | 2. server: 集群服务器
394 | 3. metadata.labels.
395 | 4. metadata.annotations.
396 | ```
397 |
398 | ## 7.6.1 基础用法
399 |
400 | ```yaml
401 | apiVersion: argoproj.io/v1alpha1
402 | kind: ApplicationSet
403 | metadata:
404 | name: guestbook-cluster
405 | namespace: argocd
406 | spec:
407 | generators:
408 | - clusters: {} # Automatically use all clusters defined within Argo CD
409 | template:
410 | metadata:
411 | name: "{{name}}-guestbook"
412 | namespace: guestbook
413 | spec:
414 | project: default
415 | source:
416 | repoURL: https://github.com/argoproj/argocd-example-apps.git
417 | targetRevision: HEAD
418 | path: kustomize-guestbook
419 | destination:
420 | server: "{{server}}"
421 | namespace: guestbook
422 | syncPolicy:
423 | automated: {}
424 | syncOptions:
425 | - CreateNamespace=true
426 | ```
427 |
428 | ## 7.6.2 标签选择器
429 |
430 | 标签选择器可以将目标集群的范围缩小到匹配特定标签的集群。
431 |
432 | ```yaml
433 | apiVersion: argoproj.io/v1alpha1
434 | kind: ApplicationSet
435 | metadata:
436 | name: guestbook-cluster
437 | namespace: argocd
438 | spec:
439 | generators:
440 | - clusters:
441 | selector:
442 | matchLabels:
443 | argocd.argoproj.io/secret-type: cluster
444 | template:
445 | metadata:
446 | name: "{{name}}-guestbook"
447 | namespace: guestbook
448 | spec:
449 | project: default
450 | source:
451 | repoURL: https://github.com/argoproj/argocd-example-apps.git
452 | targetRevision: HEAD
453 | path: kustomize-guestbook
454 | destination:
455 | server: "{{server}}"
456 | namespace: guestbook
457 | syncPolicy:
458 | automated: {}
459 | syncOptions:
460 | - CreateNamespace=true
461 | ```
462 |
463 | ## 7.6.3 values 字段
464 |
465 | 可以通过`values`集群生成器的字段传递额外的、任意的字符串键值对。通过该`values`字段添加的值添加为`values.(field)`
466 |
467 | ```yaml
468 | apiVersion: argoproj.io/v1alpha1
469 | kind: ApplicationSet
470 | metadata:
471 | name: guestbook-cluster
472 | namespace: argocd
473 | spec:
474 | generators:
475 | - clusters:
476 | selector:
477 | matchLabels:
478 | name: tuesday
479 | values:
480 | version: v1
481 | template:
482 | metadata:
483 | name: "{{name}}-guestbook"
484 | namespace: guestbook
485 | spec:
486 | project: default
487 | source:
488 | repoURL: https://github.com/argoproj/argocd-example-apps.git
489 | targetRevision: HEAD
490 | path: kustomize-guestbook
491 | destination:
492 | server: "{{server}}"
493 | namespace: guestbook
494 | syncPolicy:
495 | automated: {}
496 | syncOptions:
497 | - CreateNamespace=true
498 | info:
499 | - name: version
500 | value: "{{values.version}}"
501 | ```
502 |
503 | Git 生成器有两个子生成器:Git 目录生成器和 Git 文件生成器。
504 |
505 | # 7.7 Git 目录生成器
506 |
507 | 它使用指定 Git 仓库的目录结构生成参数。
508 |
509 | ## 7.7.1 基本使用
510 |
511 | ```yaml
512 | apiVersion: argoproj.io/v1alpha1
513 | kind: ApplicationSet
514 | metadata:
515 | name: cluster-addons
516 | namespace: argocd
517 | spec:
518 | generators:
519 | - git:
520 | repoURL: https://github.com/argoproj-labs/applicationset.git
521 | revision: HEAD
522 | directories:
523 | - path: examples/git-generator-directory/cluster-addons/*
524 | template:
525 | metadata:
526 | name: "{{path.basename}}"
527 | spec:
528 | project: default
529 | source:
530 | repoURL: https://github.com/argoproj-labs/applicationset.git
531 | targetRevision: HEAD
532 | path: "{{path}}"
533 | destination:
534 | server: https://kubernetes.default.svc
535 | namespace: "{{path.basename}}"
536 | ```
537 |
538 | ```text
539 | 1. {{path}}: 与 path 通配符匹配的 Git 仓库目录路径
540 | 2. {{path.basename}}: path 路径的目录名。
541 | ```
542 |
543 | ## 7.7.2 排除目录
544 |
545 | 有时并非所有的目录都需要生成参数,可以通过如下两种方式排除目录:
546 |
547 | 1. Git 目录生成器会自动排除 `.` 开头的文件夹;
548 | 2. 通过 exclude 选项排除单个目录;
549 |
550 | 需要注意,exclude 的优先级最高,即一个目录一旦被排除,其子目录也会被排除,而且即使明确写明包含目录也无效。exclude 不受 path 的先后顺序影响。
551 |
552 | ```yaml
553 | apiVersion: argoproj.io/v1alpha1
554 | kind: ApplicationSet
555 | metadata:
556 | name: cluster-addons
557 | namespace: argocd
558 | spec:
559 | generators:
560 | - git:
561 | repoURL: https://github.com/argoproj-labs/applicationset.git
562 | revision: HEAD
563 | directories:
564 | - path: examples/git-generator-directory/excludes/cluster-addons/*
565 | - path: examples/git-generator-directory/excludes/cluster-addons/exclude-helm-guestbook
566 | exclude: true
567 | template:
568 | metadata:
569 | name: "{{path.basename}}"
570 | spec:
571 | project: default
572 | source:
573 | repoURL: https://github.com/argoproj-labs/applicationset.git
574 | targetRevision: HEAD
575 | path: "{{path}}"
576 | destination:
577 | server: https://kubernetes.default.svc
578 | namespace: "{{path.basename}}"
579 | ```
580 |
581 | ## 7.7.3 Git 文件生成器
582 |
583 | 在 git 仓库中找到 JSON/YAML 文件并使用其内容生成参数。
584 |
585 | ```yaml
586 | apiVersion: argoproj.io/v1alpha1
587 | kind: ApplicationSet
588 | metadata:
589 | name: guestbook
590 | namespace: argocd
591 | spec:
592 | generators:
593 | - git:
594 | repoURL: https://github.com/argoproj-labs/applicationset.git
595 | revision: HEAD
596 | files:
597 | - path: "examples/git-generator-files-discovery/cluster-config/**/config.json"
598 | template:
599 | metadata:
600 | name: "{{cluster.name}}-guestbook"
601 | spec:
602 | project: default
603 | source:
604 | repoURL: https://github.com/argoproj-labs/applicationset.git
605 | targetRevision: HEAD
606 | path: "examples/git-generator-files-discovery/apps/guestbook"
607 | destination:
608 | server: "{{cluster.address}}"
609 | namespace: guestbook
610 | ```
611 |
612 | 上述 cluster-config 目录下找到的任何 config.json 文件,都讲会根据其内容生成参数。JSON 字段被扁平化为键值对。
613 |
614 | 除了来自配置文件的扁平化键值对之外,还提供了 Git 目录生成器的参数`{{path}}`, `{{path.basename}}`
615 |
616 | # 7.8 矩阵生成器
617 |
618 | ```yaml
619 | apiVersion: argoproj.io/v1alpha1
620 | kind: ApplicationSet
621 | metadata:
622 | name: list-git
623 | namespace: argocd
624 | spec:
625 | generators:
626 | - matrix:
627 | generators:
628 | - clusters: {}
629 | - list:
630 | elements:
631 | - color: red
632 | size: middle
633 | - color: green
634 | size: large
635 | template:
636 | metadata:
637 | name: "{{name}}-{{color}}-guestbook"
638 | namespace: guestbook
639 | spec:
640 | project: default
641 | source:
642 | repoURL: https://github.com/argoproj/argocd-example-apps.git
643 | targetRevision: HEAD
644 | path: kustomize-guestbook
645 | destination:
646 | server: "{{server}}"
647 | namespace: "{{color}}-{{size}}"
648 | syncPolicy:
649 | syncOptions:
650 | - CreateNamespace=true
651 | info:
652 | - name: "color"
653 | value: "{{color}}"
654 | - name: "size"
655 | value: "{{size}}"
656 | ```
657 |
658 | # 8. 鸣谢及推荐
659 |
660 | 非常感谢 Devops 中国社区的 @martinliu 和 极狐布道师 @小马哥,正是两位前辈不遗余力地推送此次鉴宝活动,这次分享才能如约与大家见面,于我个人而言,也才有幸认识诸位鉴宝讲师以及更多热爱开源的“技术人”。
661 |
662 | 如果在学习 ArgoCD 时有任何疑问或想法,欢迎加我的微信 - hsdtsyl ("黑色的碳酸饮料" 首字母) - 交流。
663 |
664 | > 推荐: ArgoCD 相关视频教程
665 |
666 | https://space.bilibili.com/322351901
667 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/app-guestbook.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: Application
3 | metadata:
4 | name: guestbook
5 | spec:
6 | destination:
7 | name: ""
8 | namespace: guestbook
9 | server: "https://kubernetes.default.svc"
10 | source:
11 | path: kustomize-guestbook
12 | repoURL: "https://github.com/argoproj/argocd-example-apps.git"
13 | targetRevision: HEAD
14 | project: default
15 | syncPolicy:
16 | automated:
17 | prune: true
18 | selfHeal: true
19 | syncOptions:
20 | - CreateNamespace=true
21 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/apps-matrix-generator.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: ApplicationSet
3 | metadata:
4 | name: list-git
5 | namespace: argocd
6 | spec:
7 | generators:
8 | - matrix:
9 | generators:
10 | - clusters: {}
11 | - list:
12 | elements:
13 | - color: red
14 | size: middle
15 | - color: green
16 | size: large
17 | template:
18 | metadata:
19 | name: "{{name}}-{{color}}-guestbook"
20 | namespace: guestbook
21 | spec:
22 | project: default
23 | source:
24 | repoURL: https://github.com/argoproj/argocd-example-apps.git
25 | targetRevision: HEAD
26 | path: kustomize-guestbook
27 | destination:
28 | server: "{{server}}"
29 | namespace: "{{color}}-{{size}}"
30 | syncPolicy:
31 | syncOptions:
32 | - CreateNamespace=true
33 | info:
34 | - name: "color"
35 | value: "{{color}}"
36 | - name: "size"
37 | value: "{{size}}"
38 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/appset-cluster-generator-base.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: ApplicationSet
3 | metadata:
4 | name: guestbook-cluster
5 | namespace: argocd
6 | spec:
7 | generators:
8 | - clusters: {} # Automatically use all clusters defined within Argo CD
9 | template:
10 | metadata:
11 | name: "{{name}}-guestbook"
12 | namespace: guestbook
13 | spec:
14 | project: default
15 | source:
16 | repoURL: https://github.com/argoproj/argocd-example-apps.git
17 | targetRevision: HEAD
18 | path: kustomize-guestbook
19 | destination:
20 | server: "{{server}}"
21 | namespace: guestbook
22 | syncPolicy:
23 | automated: {}
24 | syncOptions:
25 | - CreateNamespace=true
26 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/appset-cluster-generator-label.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: ApplicationSet
3 | metadata:
4 | name: guestbook-cluster
5 | namespace: argocd
6 | spec:
7 | generators:
8 | - clusters:
9 | selector:
10 | matchLabels:
11 | argocd.argoproj.io/secret-type: cluster
12 | template:
13 | metadata:
14 | name: "{{name}}-guestbook"
15 | namespace: guestbook
16 | spec:
17 | project: default
18 | source:
19 | repoURL: https://github.com/argoproj/argocd-example-apps.git
20 | targetRevision: HEAD
21 | path: kustomize-guestbook
22 | destination:
23 | server: "{{server}}"
24 | namespace: guestbook
25 | syncPolicy:
26 | automated: {}
27 | syncOptions:
28 | - CreateNamespace=true
29 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/appset-cluster-generator-value.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: ApplicationSet
3 | metadata:
4 | name: guestbook-cluster
5 | namespace: argocd
6 | spec:
7 | generators:
8 | - clusters:
9 | selector:
10 | matchLabels:
11 | name: tuesday
12 | values:
13 | version: v1
14 | template:
15 | metadata:
16 | name: "{{name}}-guestbook"
17 | namespace: guestbook
18 | spec:
19 | project: default
20 | source:
21 | repoURL: https://github.com/argoproj/argocd-example-apps.git
22 | targetRevision: HEAD
23 | path: kustomize-guestbook
24 | destination:
25 | server: "{{server}}"
26 | namespace: guestbook
27 | syncPolicy:
28 | automated: {}
29 | syncOptions:
30 | - CreateNamespace=true
31 | info:
32 | - name: version
33 | value: "{{values.version}}"
34 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/appset-git-generator-base.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: ApplicationSet
3 | metadata:
4 | name: cluster-addons
5 | namespace: argocd
6 | spec:
7 | generators:
8 | - git:
9 | repoURL: https://github.com/argoproj-labs/applicationset.git
10 | revision: HEAD
11 | directories:
12 | - path: examples/git-generator-directory/cluster-addons/*
13 | template:
14 | metadata:
15 | name: "{{path.basename}}"
16 | spec:
17 | project: default
18 | source:
19 | repoURL: https://github.com/argoproj-labs/applicationset.git
20 | targetRevision: HEAD
21 | path: "{{path}}"
22 | destination:
23 | server: https://kubernetes.default.svc
24 | namespace: "{{path.basename}}"
25 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/appset-git-generator-file.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: ApplicationSet
3 | metadata:
4 | name: guestbook
5 | namespace: argocd
6 | spec:
7 | generators:
8 | - git:
9 | repoURL: https://github.com/argoproj-labs/applicationset.git
10 | revision: HEAD
11 | files:
12 | - path: "examples/git-generator-files-discovery/cluster-config/**/config.json"
13 | template:
14 | metadata:
15 | name: "{{cluster.name}}-guestbook"
16 | spec:
17 | project: default
18 | source:
19 | repoURL: https://github.com/argoproj-labs/applicationset.git
20 | targetRevision: HEAD
21 | path: "examples/git-generator-files-discovery/apps/guestbook"
22 | destination:
23 | server: "{{cluster.address}}"
24 | namespace: guestbook
25 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/appset-git-gernator-exclude.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: ApplicationSet
3 | metadata:
4 | name: cluster-addons
5 | namespace: argocd
6 | spec:
7 | generators:
8 | - git:
9 | repoURL: https://github.com/argoproj-labs/applicationset.git
10 | revision: HEAD
11 | directories:
12 | - path: examples/git-generator-directory/excludes/cluster-addons/*
13 | - path: examples/git-generator-directory/excludes/cluster-addons/exclude-helm-guestbook
14 | exclude: true
15 | template:
16 | metadata:
17 | name: "{{path.basename}}"
18 | spec:
19 | project: default
20 | source:
21 | repoURL: https://github.com/argoproj-labs/applicationset.git
22 | targetRevision: HEAD
23 | path: "{{path}}"
24 | destination:
25 | server: https://kubernetes.default.svc
26 | namespace: "{{path.basename}}"
27 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/appset-list-generator.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: argoproj.io/v1alpha1
2 | kind: ApplicationSet
3 | metadata:
4 | name: guestbook
5 | namespace: argocd
6 | spec:
7 | generators:
8 | - list:
9 | elements:
10 | - cluster: monday
11 | url: https://kubernetes.default.svc
12 | - cluster: tuesday
13 | url: https://tuesday-api.automan.fun:6443
14 | template:
15 | metadata:
16 | name: "{{cluster}}-guestbook"
17 | namespace: guestbook
18 | spec:
19 | project: default
20 | source:
21 | repoURL: https://github.com/argoproj/argocd-example-apps.git
22 | targetRevision: HEAD
23 | path: kustomize-guestbook
24 | destination:
25 | server: "{{url}}"
26 | namespace: guestbook
27 | syncPolicy:
28 | automated: {}
29 | syncOptions:
30 | - CreateNamespace=true
31 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/argocd.yaml:
--------------------------------------------------------------------------------
1 | # ref: https://operatorhub.io/operator/argocd-operator
2 | apiVersion: argoproj.io/v1alpha1
3 | kind: ArgoCD
4 | metadata:
5 | name: monday-argocd
6 | spec: {}
7 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/config-monday.yaml:
--------------------------------------------------------------------------------
1 | # kk create config -f config-monday.yaml
2 | apiVersion: kubekey.kubesphere.io/v1alpha1
3 | kind: Cluster
4 | metadata:
5 | name: monday
6 | spec:
7 | hosts:
8 | - {
9 | name: tm-opsinit-01,
10 | address: 10.10.14.99,
11 | internalAddress: 10.10.14.99,
12 | }
13 | roleGroups:
14 | etcd:
15 | - tm-opsinit-01
16 | master:
17 | - tm-opsinit-01
18 | worker:
19 | - tm-opsinit-01
20 | controlPlaneEndpoint:
21 | domain: monday-api.automan.fun
22 | address: ""
23 | port: 6443
24 | kubernetes:
25 | version: v1.19.8
26 | imageRepo: kubesphere
27 | clusterName: cluster.local
28 | network:
29 | plugin: calico
30 | kubePodsCIDR: 10.233.64.0/18
31 | kubeServiceCIDR: 10.233.0.0/18
32 | registry:
33 | registryMirrors: []
34 | insecureRegistries: []
35 | addons: []
36 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/crds/eip-pool.yaml:
--------------------------------------------------------------------------------
1 | # ref: https://openelb.github.io/docs/getting-started/configuration/configure-ip-address-pools-using-eip/
2 | # 集群中所有节点的网卡名必须一致
3 | apiVersion: network.kubesphere.io/v1alpha2
4 | kind: Eip
5 | metadata:
6 | name: eip-pool
7 | spec:
8 | address: 10.10.14.91-10.10.14.92
9 | protocol: layer2
10 | interface: ens192
11 | disable: false
12 |
--------------------------------------------------------------------------------
/deploy/lab04-argocd/images/argocd-ui-create-app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/deploy/lab04-argocd/images/argocd-ui-create-app.png
--------------------------------------------------------------------------------
/deploy/lab04-argocd/images/argocd-ui-login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/deploy/lab04-argocd/images/argocd-ui-login.png
--------------------------------------------------------------------------------
/deploy/lab04-argocd/images/guest-book-app-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/deploy/lab04-argocd/images/guest-book-app-1.png
--------------------------------------------------------------------------------
/deploy/lab04-argocd/images/guest-book-app-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/deploy/lab04-argocd/images/guest-book-app-2.png
--------------------------------------------------------------------------------
/orchestration/lab10-k3s/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | ---
4 |
5 | # K3s 介绍
6 |
7 | K3s 是一个经过 CNCF 认证的轻量级的 Kubernetes 发行版,可用于生产、易于安装、内存减半,2020 年捐献给 CNCF。
8 |
9 | **非常适合:**
10 |
11 | - Edge
12 | - IoT
13 | - CI
14 | - Development
15 | - ARM
16 | - Embedding k8s
17 |
18 | **特点:**
19 |
20 | - CNCF 认证的 Kubernetes 发行版
21 | - 不到 100MB 二进制包,500MB 内存消耗
22 | - 单一进程包含 Kubernetes master, Kubelet 和 containerd
23 | - 支持 SQLite/Mysql/PostgreSQL/MariaDB 和 etcd
24 | - 同时为 x86_64, Arm64, 和 Armv7 平台发布
25 |
26 | 
27 |
28 | ## 为什么叫 K3s?
29 |
30 | 我们希望安装的 Kubernetes 在内存占用方面只是一半的大小。Kubernetes 是一个 10 个字母的单词,简写为 K8s。所以,有 Kubernetes 一半大的东西就是一个 5 个字母的单词,简写为 K3s。K3s 没有全称,也没有官方的发音。
31 |
32 | ## 为什么比 Kubernetes 节省资源?
33 |
34 | - 通过在单个进程内运行许多组件来减少内存占用。这消除了每个组件会重复的大量开销。
35 | - 通过删除第三方存储驱动程序和云提供商,二进制文件变得更小。
36 |
37 | ## 发布周期
38 |
39 | K3s 与上游 Kubernetes 版本保持同步。目标是在几天内与上游版本和次要版本在同一天发布补丁版本。
40 |
41 | **v1.20.4+k3s1**: `v1.20.4` 为 K8s 版本,`k3s1` 为补丁版本,如果我们在 `v1.20.4+k3s1` 中发现了一个严重程度较高的错误并需要立即发布修复,我们将发布 `v1.20.4+k3s2`。
42 |
43 | ## 架构
44 |
45 | 
46 |
47 | ## 参考文档
48 |
49 | - 中文文档:https://docs.rancher.cn/k3s
50 | - 英文文档:https://rancher.com/docs/k3s/latest/en/
51 | - Github 地址:https://github.com/k3s-io/k3s
52 |
53 | # K3s 安装
54 |
55 | ## 安装要求
56 |
57 | ### OS
58 |
59 | K3s 有望在大多数现代 Linux 系统上运行:
60 |
61 | - SLES: 15 SP3, 15 SP2, 15 SP1
62 | - SLE Micro: 5.1
63 | - OpenSUSE Leap: 15.3
64 | - Ubuntu: 18.04, 20.04
65 | - CentOS: 7.8, 7.9
66 | - Oracle Linux: 8.3、7.9
67 | - RHEL: 7.8, 7.9, 8.2, 8.3, 8.4, 8.5
68 | - Rocky Linux: 8.4
69 |
70 | ### CPU 和内存
71 |
72 | - CPU: 最低 1
73 | - 内存: 最低 512MB(建议至少为 1GB)
74 |
75 | ### 磁盘
76 |
77 | K3s 的性能取决于数据库的性能。为了确保最佳速度,我们建议尽可能使用 SSD。在使用 SD 卡或 eMMC 的 ARM 设备上,磁盘性能会有所不同。
78 |
79 | ## 单节点安装
80 |
81 | 
82 |
83 | **官方安装脚本:**
84 |
85 | ```
86 | # 安装 k3s server 节点:
87 | curl -sfL https://get.k3s.io | sh -
88 |
89 | # 安装 k3s agent 节点:
90 | curl -sfL https://get.k3s.io | \
91 | K3S_URL=https://myserver:6443 \
92 | K3S_TOKEN=mynodetoken \
93 | sh -
94 | ```
95 |
96 | #### 安装环境
97 |
98 | | 角色 | 主机名 | IP |
99 | | ---------- | ------------- | ------------ |
100 | | k3s server | k3s-single-m | 10.24.12.139 |
101 | | k3s agent | k3s-single-w1 | 10.24.12.140 |
102 | | k3s agent | k3s-single-w2 | 10.24.12.142 |
103 |
104 | #### 部署结构图
105 |
106 | 
107 |
108 | #### 启动 K3s Server
109 |
110 | 国内推荐使用:
111 |
112 | ```
113 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | \
114 | INSTALL_K3S_MIRROR=cn \
115 | K3S_TOKEN=devops \
116 | sh -s - \
117 | --system-default-registry "registry.cn-hangzhou.aliyuncs.com"
118 | ```
119 |
120 | #### 添加 K3s Agent 节点
121 |
122 | 分别在两个 agent 主机上执行以下安装 k3s agent 命令:
123 |
124 | 国内推荐使用:
125 |
126 | ```
127 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn \
128 | K3S_URL=https://10.24.12.139:6443 \
129 | K3S_TOKEN=devops \
130 | sh -s -
131 | ```
132 |
133 | ## 高可用安装
134 |
135 | ### 使用外部数据库实现高可用安装
136 |
137 | 
138 |
139 | K3s 支持以下外部数据存储选项:
140 |
141 | - PostgreSQL (经过认证的版本:10.7 和 11.5)
142 | - MySQL (经过认证的版本:5.7)
143 | - MariaDB (经过认证的版本:10.3.20)
144 | - etcd (经过认证的版本:3.3.15)
145 |
146 | 单节点 k3s server 集群可以满足各种用例,但是对于需要 Kubernetes control-plane 稳定运行的重要环境,您可以在 HA 配置中运行 K3s。一个 K3s HA 集群由以下几个部分组成:
147 |
148 | - 两个或多个 server 节点,将为 Kubernetes API 提供服务并运行其他 control-plane 服务。
149 | - 零个或多个 agent 节点,用于运行您的应用和服务。
150 | - 外部数据存储 (与单个 k3s server 设置中使用的嵌入式 SQLite 数据存储相反)
151 | - 固定的注册地址,位于 server 节点的前面,以允许 agent 节点向集群注册
152 |
153 | **安装环境:**
154 |
155 | | 角色 | 主机名 | IP |
156 | | ------------ | -------- | ------------ |
157 | | k3s server 1 | k3s-ha-1 | 10.24.12.141 |
158 | | k3s server 2 | k3s-ha-2 | 10.24.12.143 |
159 | | k3s agent | k3s-ha-2 | 10.24.12.144 |
160 | | DB | k3s-ha-4 | 10.24.12.145 |
161 |
162 | 安装 mysql 数据库:
163 |
164 | > 在 DB
165 |
166 | ```
167 | docker run --name some-mysql --restart=unless-stopped -p 3306:3306 -e MYSQL_ROOT_PASSWORD=password -d mysql:5.7
168 | ```
169 |
170 | 添加第一个 server 节点:
171 |
172 | ```
173 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn \
174 | sh -s - \
175 | server \
176 | --token=devops \
177 | --datastore-endpoint="mysql://root:password@tcp(10.24.12.145:3306)/k3s_db" \
178 | --system-default-registry "registry.cn-hangzhou.aliyuncs.com"
179 | ```
180 |
181 | 加入其他的 server 节点:
182 |
183 | ```
184 | # 然后可以使用 token添加其他 server 节点:
185 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn \
186 | sh -s - \
187 | server \
188 | --token=devops \
189 | --datastore-endpoint="mysql://root:password@tcp(10.24.12.145:3306)/k3s_db" \
190 | --system-default-registry "registry.cn-hangzhou.aliyuncs.com"
191 | ```
192 |
193 | 加入 agent 节点:
194 |
195 | ```
196 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn \
197 | K3S_URL=https://10.24.12.141:6443 \
198 | K3S_TOKEN=devops \
199 | sh -s -
200 | ```
201 |
202 | 更多集群数据存储选项,请参考 [K3s 文档](https://docs.rancher.cn/docs/k3s/installation/datastore/_index/)
203 |
204 | **生产案例:** https://mp.weixin.qq.com/s/0Wk2MzfWqMqt8DfUK_2ICA
205 |
206 | ### 嵌入式 DB 的高可用
207 |
208 | 要在这种模式下运行 K3s,你必须有奇数的 server 节点。我们建议从三个节点开始。
209 |
210 | 要开始运行,首先启动一个 server 节点,使用 cluster-init 标志来启用集群,并使用一个标记作为共享的密钥来加入其他服务器到集群中。
211 |
212 | ```
213 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn \
214 | K3S_TOKEN=SECRET sh -s - \
215 | server \
216 | --cluster-init \
217 | --system-default-registry "registry.cn-hangzhou.aliyuncs.com"
218 | ```
219 |
220 | 启动第一台 server 后,使用共享密钥将第二台和第三台 server 加入集群。
221 |
222 | ```
223 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn \
224 | K3S_TOKEN=SECRET sh -s - server \
225 | --server https://:6443 \
226 | --system-default-registry "registry.cn-hangzhou.aliyuncs.com"
227 | ```
228 |
229 | 查询 ETCD 集群状态:
230 |
231 | ```
232 | ETCDCTL_ENDPOINTS='https://< server ip >:2379,https://< server ip >:2379,https://< server ip >:2379' \
233 | ETCDCTL_CACERT='/var/lib/rancher/k3s/server/tls/etcd/server-ca.crt' \
234 | ETCDCTL_CERT='/var/lib/rancher/k3s/server/tls/etcd/server-client.crt' \
235 | ETCDCTL_KEY='/var/lib/rancher/k3s/server/tls/etcd/server-client.key' \
236 | ETCDCTL_API=3 etcdctl endpoint status --write-out=table
237 | ```
238 |
239 | > etcd 证书默认目录:/var/lib/rancher/k3s/server/tls/etcd etcd 数据默认目录:/var/lib/rancher/k3s/server/db/etcd
240 |
241 | # 访问集群
242 |
243 | 存储在/etc/rancher/k3s/k3s.yaml 的 kubeconfig 文件用于对 Kubernetes 集群的访问。如果你已经安装了上游的 Kubernetes 命令行工具,如 kubectl 或 helm,你需要用正确的 kubeconfig 路径配置它们。这可以通过导出 KUBECONFIG 环境变量或调用--kubeconfig 命令行标志来完成。详情请参考下面的例子。
244 |
245 | ```
246 | export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
247 | kubectl get pods --all-namespaces
248 | helm ls --all-namespaces
249 | ```
250 |
251 | # 网络选项
252 |
253 | 默认情况下,K3s 将以 flannel 作为 CNI 运行,使用 VXLAN 作为默认后端。CNI 和默认后端都可以通过参数修改。
254 |
255 | ## Flannel 选项
256 |
257 | Flannel 的默认后端是 VXLAN。要启用加密,请使用下面的 IPSec(Internet Protocol Security)或 WireGuard 选项。
258 |
259 | | CLI Flag 和 Value | 描述 |
260 | | :---------------------------- | :---------------------------------------------------------------------- |
261 | | `--flannel-backend=vxlan` | (默认) 使用 VXLAN 后端。 |
262 | | `--flannel-backend=ipsec` | 使用 IPSEC 后端,对网络流量进行加密。 |
263 | | `--flannel-backend=host-gw` | 使用 host-gw 后端。 |
264 | | `--flannel-backend=wireguard` | 使用 WireGuard 后端,对网络流量进行加密。可能需要额外的内核模块和配置。 |
265 |
266 | ```
267 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | \
268 | INSTALL_K3S_EXEC="--flannel-backend=host-gw" \
269 | INSTALL_K3S_MIRROR=cn sh -
270 | ```
271 |
272 | ## 自定义 CNI
273 |
274 | 使用 `--flannel-backend=none` 运行 K3s,然后在安装你选择的 CNI。
275 |
276 | #### Calico
277 |
278 | 参考:https://docs.projectcalico.org/getting-started/kubernetes/k3s/quickstart
279 |
280 | #### Cilium
281 |
282 | 参考:https://docs.cilium.io/en/v1.9/gettingstarted/k3s/
283 |
284 | # 仪表盘
285 |
286 | ## 仪表盘
287 |
288 | - Kubernetes Dashboard
289 | - Rancher UI
290 | - kube-explorer
291 |
292 | ## 1. Kubernetes Dashboard
293 |
294 | 参考 [K3s 官网](http://docs.rancher.cn/docs/k3s/installation/kube-dashboard/_index/)
295 |
296 | ## 2. Rancher UI
297 |
298 | 可以将 K3s 导入到 Rancher UI 中去管理,参考 [Rancher 官网](http://docs.rancher.cn/docs/rancher2/cluster-provisioning/imported-clusters/_index/#%E5%AF%BC%E5%85%A5-k3s-%E9%9B%86%E7%BE%A4)
299 |
300 | 导入 K3s 集群时,Rancher 会将其识别为 K3s,除了其他导入的集群支持的功能之外,Rancher UI 还提供以下功能:
301 |
302 | - 能够升级 K3s 版本。
303 | - 能够配置在升级集群时,同时可以升级的最大节点数。
304 | - 在主机详情页,能够查看(不能编辑)启动 K3s 集群时每个节点的 K3s 配置参数和环境变量。
305 |
306 | ## 3. kube-explorer
307 |
308 | 项目地址:https://github.com/cnrancher/kube-explorer
309 |
310 | kube-explorer 是 Kubernetes 的便携式资源管理器,没有任何依赖。 并提供了一个几乎完全无状态的 Kubernetes 资源管理器。
311 |
312 | #### 使用
313 |
314 | 从[发布页面](https://github.com/cnrancher/kube-explorer/releases)下载二进制文件
315 |
316 | 运行:
317 |
318 | ```
319 | ./kube-explorer --kubeconfig=xxxx --http-listen-port=9898 --https-listen-port=0
320 | ```
321 |
322 | 然后,打开浏览器访问 http://x.x.x.x:9898
323 |
324 | # K3s 升级
325 |
326 | ## 使用安装脚本升级 K3s
327 |
328 | 要从旧版本升级 K3s,你可以使用相同的标志重新运行安装脚本,例如:
329 |
330 | ```
331 | curl -sfL https://get.k3s.io | sh -
332 |
333 | # 国内环境可使用:
334 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn sh -
335 | ```
336 |
337 | 如果你想升级到一个特定 channel 的较新版本(如最新),你可以指定 channel:
338 |
339 | ```
340 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=c \
341 | INSTALL_K3S_CHANNEL=latest sh -
342 | ```
343 |
344 | 如果你想升级到特定的版本,你可以运行以下命令:
345 |
346 | ```
347 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=c | \
348 | INSTALL_K3S_VERSION=vX.Y.Z-rc1 sh -
349 | ```
350 |
351 | ## 使用二进制文件手动升级 K3s
352 |
353 | 1. 从[发布](https://github.com/rancher/k3s/releases)下载所需版本的 K3s 二进制文件
354 | 2. 将下载的二进制文件复制到 `/usr/local/bin/k3s`(或您所需的位置)
355 | 3. 重启 k3s
356 |
357 | ## 自动升级
358 |
359 | 使用 Rancher 的 system-upgrad-controller 来管理 K3s 集群升级。
360 |
361 | #### 安装 system-upgrade-controller
362 |
363 | ```
364 | kubectl apply -f https://github.com/rancher/system-upgrade-controller/releases/latest/download/system-upgrade-controller.yaml
365 | ```
366 |
367 | #### 配置计划
368 |
369 | 建议您最少创建两个计划:升级 server(master)节点的计划和升级 agent(worker)节点的计划。根据需要,您可以创建其他计划来控制跨节点的滚动升级。以下两个示例计划将把您的集群升级到 K3s v1.17.4+k3s1。创建计划后,控制器将接收这些计划并开始升级您的集群。
370 |
371 | ```
372 | # Server plan
373 | apiVersion: upgrade.cattle.io/v1
374 | kind: Plan
375 | metadata:
376 | name: server-plan
377 | namespace: system-upgrade
378 | spec:
379 | concurrency: 1
380 | cordon: true
381 | nodeSelector:
382 | matchExpressions:
383 | - key: node-role.kubernetes.io/master
384 | operator: In
385 | values:
386 | - "true"
387 | serviceAccountName: system-upgrade
388 | upgrade:
389 | image: rancher/k3s-upgrade
390 | version: v1.17.4+k3s1
391 | ---
392 | # Agent plan
393 | apiVersion: upgrade.cattle.io/v1
394 | kind: Plan
395 | metadata:
396 | name: agent-plan
397 | namespace: system-upgrade
398 | spec:
399 | concurrency: 1
400 | cordon: true
401 | nodeSelector:
402 | matchExpressions:
403 | - key: node-role.kubernetes.io/master
404 | operator: DoesNotExist
405 | prepare:
406 | args:
407 | - prepare
408 | - server-plan
409 | image: rancher/k3s-upgrade
410 | serviceAccountName: system-upgrade
411 | upgrade:
412 | image: rancher/k3s-upgrade
413 | version: v1.17.4+k3s1
414 | ```
415 |
416 | # 备份和恢复
417 |
418 | K3s 的备份和恢复方式取决于使用的数据存储类型:
419 |
420 | - 使用嵌入式 SQLite 数据存储进行备份和恢复
421 | - 使用外部数据存储进行备份和恢复
422 | - 使用嵌入式 etcd 数据存储进行备份和恢复
423 |
424 | ## 使用嵌入式 SQLite 数据存储进行备份和恢复
425 |
426 | #### 方式 1:备份/恢复数据目录
427 |
428 | - 备份
429 |
430 | ```
431 | # cp -rf /var/lib/rancher/k3s/server/db /opt/db
432 | ```
433 |
434 | - 恢复
435 |
436 | ```
437 | # systemctl stop k3s
438 | # rm -rf /var/lib/rancher/k3s/server/db
439 | # cp -rf /opt/db /var/lib/rancher/k3s/server/db
440 | # systemctl start k3s
441 | ```
442 |
443 | #### 方式 2:通过 SQLite cli
444 |
445 | - 备份
446 |
447 | ```
448 | # sqlite3 /var/lib/rancher/k3s/server/db/state.db
449 | SQLite version 3.22.0 2018-01-22 18:45:57
450 | Enter ".help" for usage hints.
451 | sqlite> .backup "/opt/kine.db"
452 | sqlite> .exit
453 | ```
454 |
455 | - 恢复
456 |
457 | ```
458 | # systemctl stop k3s
459 |
460 | # sqlite3 /var/lib/rancher/k3s/server/db/state.db
461 | SQLite version 3.22.0 2018-01-22 18:45:57
462 | Enter ".help" for usage hints.
463 | sqlite> .restore '/opt/kine.db'
464 | sqlite> .exit
465 |
466 | # systemctl start k3s
467 | ```
468 |
469 | ## 使用外部数据存储进行备份和恢复
470 |
471 | 当使用外部数据存储时,备份和恢复操作是在 K3s 之外处理的。数据库管理员需要对外部数据库进行备份,或者从快照或转储中进行恢复。我们建议将数据库配置为执行定期快照。
472 |
473 | - 备份
474 |
475 | ```
476 | # mysqldump -uroot -p --all-databases --master-data > k3s-dbdump.db
477 | ```
478 |
479 | - 恢复
480 |
481 | 停止 K3s 服务
482 |
483 | ```
484 | # systemctl stop k3s
485 | ```
486 |
487 | 恢复 mysql 数据
488 |
489 | ```
490 | mysql -uroot -p < k3s-dbdump.db
491 | ```
492 |
493 | 启动 K3s 服务
494 |
495 | ```
496 | # systemctl start k3s
497 | ```
498 |
499 | ## 使用嵌入式 etcd 数据存储进行备份和恢复
500 |
501 | - 创建快照
502 |
503 | K3s 默认启用快照。快照目录默认为 `/var/lib/rancher/k3s/server/db/snapshots`。要配置快照间隔或保留的快照数量,请参考:
504 |
505 | | 参数 | 描述 |
506 | | :------------------------------ | :----------------------------------------------------------------------------------------------------------------------------- |
507 | | `--etcd-disable-snapshots` | 禁用自动 etcd 快照 |
508 | | `--etcd-snapshot-schedule-cron` | 以 Cron 表达式的形式配置触发定时快照的时间点,例如:每 5 小时触发一次`* */5 * * *`,默认值为每 12 小时触发一次:`0 */12 * * *` |
509 | | `--etcd-snapshot-retention` | 保留的快照数量,默认值为 5。 |
510 | | `--etcd-snapshot-dir` | 保存数据库快照的目录路径。(默认位置:`${data-dir}/db/snapshots`) |
511 | | `--cluster-reset` | 忘记所有的对等体,成为新集群的唯一成员,也可以通过环境变量`[$K3S_CLUSTER_RESET]`进行设置。 |
512 | | `--cluster-reset-restore-path` | 要恢复的快照文件的路径 |
513 |
514 | - 从快照恢复集群
515 |
516 | 当 K3s 从备份中恢复时,旧的数据目录将被移动到`/var/lib/rancher/k3s/server/db/etcd-old/`。然后 K3s 会尝试通过创建一个新的数据目录来恢复快照,然后从一个带有一个 etcd 成员的新 K3s 集群启动 etcd。
517 |
518 | 要从备份中恢复集群,运行 K3s 时,请使用`--cluster-reset`选项运行 K3s,同时给出`--cluster-reset-restore-path`,如下:
519 |
520 | ```shell
521 | ./k3s server \
522 | --cluster-reset \
523 | --cluster-reset-restore-path=
524 | ```
525 |
526 | **结果:** 日志中出现一条信息,**Etcd 正在运行,现在需要在没有 `--cluster-reset` 标志的情况下重新启动。备份和删除每个对等 etcd 服务器上的 ${datadir}/server/db 并重新加入节点**
527 |
528 | ### S3 兼容 API 支持
529 |
530 | K3s 支持向具有 S3 兼容 API 的系统写入 etcd 快照和从系统中恢复 etcd 快照。S3 支持按需和计划快照。
531 |
532 | 下面的参数已经被添加到 `server` 子命令中。这些标志也存在于 `etcd-snapshot` 子命令中,但是 `--etcd-s3` 部分被删除以避免冗余。
533 |
534 | ```
535 | k3s etcd-snapshot \
536 | --s3 \
537 | # --s3-endpoint minio.kingsd.top:9000 \
538 | --s3-bucket= \
539 | --s3-access-key= \
540 | --s3-secret-key=
541 | ```
542 |
543 | 要从 S3 中执行按需的 etcd 快照还原,首先确保 K3s 没有运行。然后运行以下命令:
544 |
545 | ```
546 | k3s server \
547 | --cluster-init \
548 | --cluster-reset \
549 | --etcd-s3 \
550 | # --etcd-s3-endpoint minio.kingsd.top:9000 \
551 | --cluster-reset-restore-path= \
552 | --etcd-s3-bucket= \
553 | --etcd-s3-access-key= \
554 | --etcd-s3-secret-key=
555 | ```
556 |
557 | # 使用 docker 作为容器运行时
558 |
559 | ```
560 | curl -sfL https://rancher-mirror.oss-cn-beijing.aliyuncs.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn \
561 | sh -s - \
562 | --docker
563 | ```
564 |
565 | # 自动部署清单
566 |
567 | 在 `/var/lib/rancher/k3s/server/manifests` 中找到的任何文件都会以类似 `kubectl apply` 的方式自动部署到 Kubernetes,在启动和在磁盘上更改文件时都是如此。从该目录中删除文件不会从集群中删除相应的资源。
568 |
569 | # Service Load Balancer
570 |
571 | K3s 提供了一个名为[Klipper Load Balancer](https://github.com/rancher/klipper-lb)的负载均衡器,它可以使用可用的主机端口。 允许创建 LoadBalancer 类型的 Service,但不包括 LB 的实现。某些 LB 服务需要云提供商,例如 Amazon EC2 或 Microsoft Azure。相比之下,K3s service LB 使得可以在没有云提供商的情况下使用 LB 服务。
572 |
573 | ## 示例
574 |
575 | ```
576 | # service_lb_demo.yaml
577 | apiVersion: apps/v1
578 | kind: Deployment
579 | metadata:
580 | name: nginx-deployment
581 | labels:
582 | app: nginx
583 | spec:
584 | replicas: 3
585 | selector:
586 | matchLabels:
587 | app: nginx
588 | template:
589 | metadata:
590 | labels:
591 | app: nginx
592 | spec:
593 | containers:
594 | - name: nginx
595 | image: kingsd/nginx:install-tools
596 | ports:
597 | - containerPort: 80
598 |
599 | ---
600 | apiVersion: v1
601 | kind: Service
602 | metadata:
603 | name: nginx
604 | spec:
605 | type: LoadBalancer
606 | selector:
607 | app: nginx
608 | ports:
609 | - port: 8000
610 | targetPort: 80
611 | ```
612 |
613 | ## Service LB 如何工作
614 |
615 | K3s 创建了一个控制器,该控制器为 service load balancer 创建了一个 Pod,这个 Pod 是[Service](https://kubernetes.io/docs/concepts/services-networking/service/)类型的 Kubernetes 对象。
616 |
617 | 对于每个 service load balancer,都会创建一个[DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/)。 DaemonSet 在每个节点上创建一个前缀为`svc`的 Pod。
618 |
619 | Service LB 控制器会监听其他 Kubernetes Services。当它找到一个 Service 后,它会在所有节点上使用 DaemonSet 为该服务创建一个代理 Pod。这个 Pod 成为其他 Service 的代理,例如,来自节点上 8000 端口的请求可以被路由到端口 8888 上的工作负载。
620 |
621 | 如果创建多个 Services,则为每个 Service 创建一个单独的 DaemonSet。
622 |
623 | 只要使用不同的端口,就可以在同一节点上运行多个 Services。
624 |
625 | 如果您尝试创建一个在 80 端口上监听的 Service LB,Service LB 将尝试在集群中找到 80 端口的空闲主机。如果该端口没有可用的主机,LB 将保持 Pending 状态。
626 |
627 | ### 从节点中排除 Service LB
628 |
629 | 要排除节点使用 Service LB,请将以下标签添加到不应排除的节点上:
630 |
631 | ```
632 | svccontroller.k3s.cattle.io/enablelb
633 | ```
634 |
635 | 如果使用标签,则 service load balancer 仅在标记的节点上运行。
636 |
637 | ## 禁用 Service LB
638 |
639 | 要禁用嵌入式 LB,请使用`--disable servicelb`选项运行 k3s server。
640 |
641 | 如果您希望运行其他 LB,例如 MetalLB,这是必需的。
642 |
643 | # 周边项目
644 |
645 | - [Rancher Desktop](https://github.com/rancher-sandbox/rancher-desktop):Rancher Desktop 是一款在桌面上提供容器和 Kubernetes 管理的应用。它可以在 Windows、macOS 和 Linux 上运行
646 | - [K3d](https://github.com/k3d-io/k3d):K3d 创建容器化的 k3s 集群。这意味着,你可以使用 docker 在单台机器上启动多节点 k3s 集群。
647 | - [K3sup](https://github.com/alexellis/k3sup):K3sup 是一个轻量级应用程序,可以在任何本地或远程主机上安装和使用 k3s。你只需要 ssh 访问权限和 k3sup 二进制文件即可立即获得 kubectl 访问权限。
648 | - [AutoK3s](https://github.com/cnrancher/autok3s):AutoK3s 是用于简化 K3s 集群管理的轻量级工具,你可以使用 AutoK3s 在任何地方运行 K3s 服务。支持:阿里云、腾讯云、AWS、Google、K3d、Harvester、Native
649 |
650 | # 关注 K3s
651 |
652 | 
653 |
--------------------------------------------------------------------------------
/platform/lab02-jihu-gitlab/README.md:
--------------------------------------------------------------------------------
1 |
2 | # DevOps工具鉴宝之极狐GitLab
3 |
4 | 全过程验证项目在 GitLab 中从初始化设置、计划、需求和代码管理、持续构建和扫描等全流程。
5 |
6 |
7 | ## 极狐GitLab 和 GitLab CE/EE
8 |
9 |
10 |
11 | ## 鉴宝剧本
12 |
13 | 模拟一个创业团队从零开始使用**极狐GitLab**的场景
14 |
15 | ### 前序准备
16 | 0. 注册极狐SaaS
17 | `https://jihulab.com/users/sign_up`
18 |
19 | 1. 登陆极狐SaaS
20 | `https://jihulab.com`
21 |
22 | 2. 设置语言环境(可选)
23 | **用户设置(User Setting) > 偏好设置(Preferences) > 本地化(Localization) > 语言(Language)**
24 |
25 | 3. 申请旗舰版试用
26 | **创建群组(Group) > 群组设置(Group Setting) > 计费(Billing) > 开始试用(Start Free Trail)**
27 | > 此处创建的群组为根群组,根群组下面可以创建子群组或项目
28 |
29 | ## 计划阶段
30 | ### 群组和项目(Group and Project)
31 | 1. 创建名为`电商BU`的群组(Group)
32 | 2. 在`电商BU`群组下面创建两个子群组(Sub Group)
33 | - 支付团队
34 | - 订单团队
35 | 3. 在`订单团队`子群组下面分别创建项目
36 | - hello-order-service
37 | 4. 在`支付团队`子群组下面分别创建项目
38 | - hello-pay-service
39 | > 项目的创建可以考虑使用项目模板(Project Template),模板有内置的,同时也支持自定义
40 |
41 | ### 标签(Label)
42 | > 本示例中创建的标签均在Group层级,Project层级也可以创建标签
43 | 1. 任务类型标签,用于标记任务的类型,如Feature,Bug,TechDebt等
44 | 2. 优先级标签,用于标记任务的优先级
45 | 3. 价值流标签,用于标记任务的状态
46 |
47 | ### 里程碑与迭代(Milestone and Iteration)
48 | 1. 创建两个`群组里程碑`,以每个月为一个里程碑,设置里程碑开始和结束的时间,类似部门级的里程碑规划
49 | 2. 基于时间创建迭代,创建4个迭代,模拟2周一个迭代,两个迭代一个里程碑的敏捷开发周期。
50 |
51 | ## 需求阶段
52 | ### 史诗与子史诗(Epics and Sub-Epics)
53 | 1. 回到`电商BU`群组,创建名为`B2B电商系统`的史诗,代表电商部门一个比较大的商业想法
54 | 2. 创建两个名为`订单功能`和`支付功能`的子史诗,代表商业想法的需求初步拆分
55 |
56 | ### 议题(Issues)
57 | 1. 在`hello-order-service`项目下创建名为`订单查询功能`的议题,代表一个用户故事
58 | 2. 关联议题到史诗、里程碑、迭代
59 | 3. 设置议题指派人、截止日期、预计投入时间、权重和标签等
60 |
61 | ### 路线图(Roadmap)
62 | 1. 为创建的史诗、子史诗和议题分别设定开始和结束时间,会自动生成产品的路线图
63 |
64 | ### 史诗看板(Epic Boards)
65 | 1. 在史诗看板中创建列表,并选择对应的标记
66 | 2. 将史诗和子史诗拖拽到对应的看板泳道中
67 |
68 | ### 议题看板(Issue Boards)
69 | 1. 在议题看板中创建列表,并选择对应的标记
70 | 2. 将议题拖拽到对应的看板泳道中
71 |
72 | ### 价值流分析
73 | 1. 回到`电商BU`群组 -> 分析(Analytics) -> 价值流(Value Stream Analytics) ->创建新的价值流(Create New Value Stream)
74 | 2. 不使用模板创建(Create from no template) -> 填入阶段名称-->选择开始和结束事件
75 |
76 | ## 开发阶段
77 | ### 推送规则(Push Rules)
78 | 推送规则可以在实例级、群组级和项目级进行配置,并批量向下继承,低层级的配置会覆盖高层级。以下以项目级为例:
79 | `hello-order-service`项目 -> 设置(Settings) -> 仓库(Repository) -> 推送规则(Push Rules)
80 |
81 | - 设置一个提交信息的规则 `^\[(([a-z,A-Z]+))\]\s#(\d*)`
82 | - 设置一个文件推送的规则 `(jar|exe)$`
83 |
84 | ### 受保护分支(Protected Branches)
85 | 受保护分支用于在分支层面更加细粒度的权限管理,仅允许指定的角色、组或用户对收到保护的分支进行推送(Push)和合并(Merge)
86 | `hello-order-service`项目 -> 设置(Settings) -> 仓库(Repository) -> 受保护分支(Protected branches)
87 |
88 | ### 审批规则(Merge Request Approval Rules)
89 | 审批规则定义在合并请求(Merge Request)在合并之前需要经过的审批配置。审批规则可以在实例级、项目级和合并请求级配置。以下以项目级为例:
90 | `hello-order-service`项目 -> 设置(Settings) -> 通用(General) -> 合并请求审批(Merge request approvals)
91 |
92 | - 禁止MR提交人审批
93 | - 指定MR的审批人
94 |
95 | ---
96 | # 极狐GitLab Runner 介绍及使用
97 |
98 | 极狐GitLab Runner 是极狐GitLab 的重要组件,是实现 CI/CD 的“瑞士军刀”,具有安装简单、使用灵活的特点,而且支持多种 CPU 架构、多种 Linux 发行版以及多种 OS。
99 |
100 | * 支持的 CPU 架构有:x86, AMD64, ARM64, ARM, s390x, ppc64le
101 | * 支持的 Linux 发行版有:CentOS, Debian, Ubuntu, RHEL, Fedora, Mint
102 | * 支持如下的 OS:Linux, Windows, macOS, FreeBSD
103 |
104 | 极狐GitLab Runner 的安装使用方式也很灵活,可以通过安装包安装,也可以用 docker 来运行,甚至都支持 Kubernetes。
105 |
106 |
107 | ## 极狐GitLab Runner 的多种安装和运行方式
108 |
109 |
110 | - [用 k3s 来运行极狐GitLab Runner](https://about.gitlab.cn/blog/2022/02/03/k3s-runner/)
111 | - [以 docker 的方式来运行极狐GitLab Runner](https://about.gitlab.cn/blog/2021/12/09/runner-docker/)
112 | - [以 Kubernetes 的方式来运行极狐GitLab Runner](https://about.gitlab.cn/blog/2021/12/09/runner-k8s/)
113 | - [用 Omnibus 来安装和运行极狐GitLab Runner](https://about.gitlab.cn/blog/2021/12/07/runner-ubuntu/)
114 |
115 |
116 |
117 | ## 用 docker 的方式来安装和运行极狐GitLab Runner
118 |
119 | ### 前提条件
120 |
121 | * docker 环境
122 |
123 | docker 的安装可以根据不同 OS 在[docker 官网上](https://docs.docker.com/engine/install/ubuntu/)找到对应的安装方式,本次分享以在 Ubuntu 20.04 上安装 docker 为例来讲述。执行如下命令即可完成安装:
124 |
125 | ```
126 | $ apt-get update
127 | $ apt-get install \
128 | ca-certificates \
129 | curl \
130 | gnupg \
131 | lsb-release
132 | $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
133 | $ echo \
134 | "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
135 | $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
136 |
137 | $ apt-get update && apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
138 | ```
139 |
140 | * 极狐GitLab SaaS 账号
141 |
142 | * Runner Token
143 |
144 | 可以通过 Project --> Settings --> CI/CD --> Runners(中文对应项目 --> 设置 --> CI/CD --> Runners)找到:
145 |
146 | 
147 |
148 |
149 | ### Runner 安装
150 |
151 | 执行如下命令启动一个 Runner 容器:
152 |
153 | ```
154 | $ docker run -d --name jh-gitlab-runner-docker --restart always -v $PWD:/etc/gitlab-runner -v /var/run/docker.sock:/var/run/docker.sock gitlab/gitlab-runner:latest
155 | ```
156 | 然后进入启动的容器内并进行 Runner 的注册:
157 |
158 | ```
159 | $ docker exec -it jh-gitlab-runner-docker sh
160 | gitlab-runner register
161 | Runtime platform arch=amd64 os=linux pid=38 revision=c6bb62f6 version=14.10.0
162 | Running in system-mode.
163 |
164 | Enter the GitLab instance URL (for example, https://gitlab.com/):
165 | https://jihulab.com
166 | Enter the registration token:
167 | GR1348941MUKFzfxSkyXjs7k1_oxr
168 | Enter a description for the runner:
169 | [07530386ce76]: devops community and jh
170 | Enter tags for the runner (comma-separated):
171 | devops,jh,community
172 | Enter optional maintenance note for the runner:
173 | xiaomage
174 | Registering runner... succeeded runner=GR1348941MUKFzfxS
175 | Enter an executor: docker, parallels, docker+machine, docker-ssh+machine, custom, shell, ssh, virtualbox, kubernetes, docker-ssh:
176 | docker
177 | Enter the default Docker image (for example, ruby:2.7):
178 | docker:20.10.7-dind
179 | Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
180 | ```
181 |
182 | 上面是通过 `register` 这个命令来根据注册一步步完成注册,也可以直接将需要的参数全部传入来完成注册,如下所示:
183 |
184 | ```
185 | $ gitlab-runner register -n \
186 | --url https://jihulab.com/ \
187 | --registration-token GR1348941MUKFzfxSkyXjs7k1_oxr \
188 | --executor docker \
189 | --description "devops community and jihu gitlab" \
190 | --tag-list "devops,jihu,gitlab" \
191 | --docker-image "docker:20.10.7-dind" \
192 | --docker-volumes /var/run/docker.sock:/var/run/docker.sock
193 | ```
194 |
195 | 注册成功,可以在极狐GitLab Runner 界面看到:
196 |
197 | 
198 |
199 |
200 | ## Runner 的使用
201 |
202 | 下面讲述使用自建 Runner 来构建 CI/CD 的过程。
203 |
204 | ### 前提条件
205 |
206 | * 一个用于构建 CI/CD 的项目。
207 |
208 | Demo 项目也托管在极狐GitLab SaaS 上,地址为:https://jihulab.com/jh-xiaomage-devops/go-demo。
209 |
210 |
211 | ### 运行 CI/CD
212 |
213 | 在代码根目录中添加一个 `.gitlab-ci.yml` 文件,内容如下:
214 |
215 |
216 | ```
217 | services:
218 | - docker:20.10.7-dind
219 |
220 | stages:
221 | - build
222 |
223 | build:
224 | tags:
225 | - devops
226 | stage: build
227 | script:
228 | - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
229 | - docker build -t $CI_REGISTRY_IMAGE:v1.0.0 .
230 | - docker push $CI_REGISTRY_IMAGE:v1.0.0
231 | ```
232 |
233 | 可以在 CI/CD Pipeline 中看到构建结果:
234 |
235 | 
236 |
237 | 以及构建日志,而且在构建日志中可以看到使用的是 self-host 的runner 而非极狐GitLab SaaS 默认的 runner 完成的整个构建:
238 |
239 | 
240 |
241 |
242 |
243 |
244 |
245 |
--------------------------------------------------------------------------------
/platform/lab02-jihu-gitlab/img/jihu-gitlab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/platform/lab02-jihu-gitlab/img/jihu-gitlab.png
--------------------------------------------------------------------------------
/platform/lab02-jihu-gitlab/img/pipeline-build-log.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/platform/lab02-jihu-gitlab/img/pipeline-build-log.png
--------------------------------------------------------------------------------
/platform/lab02-jihu-gitlab/img/pipeline-build-result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/platform/lab02-jihu-gitlab/img/pipeline-build-result.png
--------------------------------------------------------------------------------
/platform/lab02-jihu-gitlab/img/runner-succ.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/platform/lab02-jihu-gitlab/img/runner-succ.png
--------------------------------------------------------------------------------
/platform/lab02-jihu-gitlab/img/runner-token.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/platform/lab02-jihu-gitlab/img/runner-token.png
--------------------------------------------------------------------------------
/platform/lab09-atlassian/README.md:
--------------------------------------------------------------------------------
1 | # DevOps 工具鉴宝之 Atlassian Jira
2 |
3 | 从 DevOps 角度,体验 Atlassian 全家桶核心用户场景和产品功能,了解大型企业的需求管理和研发工具链落地实施。
4 |
5 | ## 产品介绍 (5 min)
6 |
7 | Atlassian Corporation Plc 成立于 2002 年,旨在帮助软件团队更好地合作。该公司的产品可帮助团队组织,讨论和完成他们的工作,从而为组织带来卓越的成果。该公司的主要产品包括针对软件团队的 Jira Software 和针对其他业务团队的 Jira Work Management,用于内容创建和共享的 Confluence,用于捕获并快速添加结构的 Trello。团队的形成工作,团队服务和支持应用程序的 Jira Service Management,事件管理的 Opsgenie,企业敏捷计划的 Jira Align,用于代码共享和管理的 Bitbucket,以及用于企业级安全和集中管理的 Atlassian Access。**公司的产品在一起构成了一个用于组织,讨论和完成共享工作的集成系统,从而深深地扎根于人们如何协作以及组织如何运作**。21 年底,Atlassian Marketplace 累计销售额超过 **20 亿 美元**,拥有 **5,300+** 应用程序。
8 |
9 | - user case
10 |
11 | 
12 |
13 | ## 产品选择和配置管理 (10 min - yy)
14 |
15 | 
16 |
17 | - plan 如何规划
18 | - process 如何实施
19 | - result 效果展示(后续演示)
20 |
21 | ## 全流程交付场景演示 (40 min)
22 |
23 | ### 需求管理 - requirement management (yy)
24 |
25 | 
26 |
27 | - 产品路线规划 product roadmap (set fix version)
28 | - 产品文档管理 PRD in confluence => user story => backlog
29 | - 敏捷研发模式选择 scrum board /kanban
30 | - 站会跟进 active sprint (Kanban - WIP,开发流程后续演示)
31 | - 拉取分支时,自动更新 Jira Story 卡片到 In Progress 状态
32 | - PR Merged 时,自动更新 Jira Story 卡片到 Resolved 状态
33 | - 冲刺结束 close sprint (后续演示)
34 | - 冲刺回顾 retrospective (后续演示)
35 |
36 | ### 研发集成 development integration (toby)
37 |
38 | 
39 |
40 | - 选择需求 select user story as example
41 | - 创建分支 create feature branch
42 | - 本地开发 IDE integration with Jira and Bitbucket
43 | - VSCode 前端
44 | - Intellij IDEA 后端
45 | - SourceTree 官方客户端
46 | - 提交规范 commit convention
47 | - 代码审核 code push & code review in bitbucket (jira in progress)
48 | - 流水线自动化 Bitbucket pipeline (provided by atlassian)
49 | - build
50 | - test
51 | - scan
52 | - publish
53 | - deploy
54 | - 审核注释和任务跟进 fix review comment and push again, resolve review tasks
55 | - 合并到主分支 merge to main branch (jira revolved)
56 | - 部署到 Staging 环境 CD triggered in main branch, go to staging environment
57 | - 回归测试 start regression testing in staging (mention testing plugin)
58 | - 生产环境变更审核 pause prod deployment & gating
59 | - 变更管理和自动化流程 release management => change ticket
60 | - 生产环境部署 validate ticket and go production, create tag in Bitbucket
61 | - 自动完成需求卡片 close jira
62 |
63 | 
64 |
65 | ### 部署管理 deployment management (toby)
66 |
67 | - 在 CD 中,到 Production 部署时,会自动创建线上变更申请单;
68 | - CD 关联的代码仓库对应的服务变更的 Approvers 收到审批提醒 (邮件,站内信)
69 | - Service Approvers 审批通过
70 | - JSM Change workflow 变更过程自动化
71 | - CD 生产环境部署继续
72 | - CD 生成环境部署完成(成功),Jira Story 卡片自动更新到 Done 状态
73 |
74 | ### 敏捷迭代 sprint closing (toby)
75 |
76 | - 查看需求所关联研发流程数据 Review Jira detail
77 | - 自动状态流转 Status change to done
78 | - 开发分支和提交记录 Development panel
79 | - 自动化历史记录 Automation history
80 | - 发布上线记录 Review deployment status and deployment environment
81 | - 关闭一个冲刺迭代 Closing sprint
82 | - 创建回顾会议记录 Create retrospective
83 | - 查看敏捷迭代报告 Review Jira reports
84 |
--------------------------------------------------------------------------------
/platform/lab09-atlassian/dev-process.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/platform/lab09-atlassian/dev-process.png
--------------------------------------------------------------------------------
/platform/lab09-atlassian/devops-products.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/platform/lab09-atlassian/devops-products.png
--------------------------------------------------------------------------------
/platform/lab09-atlassian/js-management.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/platform/lab09-atlassian/js-management.png
--------------------------------------------------------------------------------
/platform/lab09-atlassian/scrum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/platform/lab09-atlassian/scrum.png
--------------------------------------------------------------------------------
/platform/lab09-atlassian/users.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevopsChina/lab/c10de9119a233abe255482e5e021228890919e94/platform/lab09-atlassian/users.png
--------------------------------------------------------------------------------