diff --git a/.DS_Store b/.DS_Store index c99f8c8b1ead6ed4dda21dd48859c82613eecaee..d0153a4cb732306fee059831bb5a22b39364135d 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..df6ce0e64a51e535cba022700cda40a374b96077 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +_book/ +node_modules/ diff --git a/README.md b/README.md index ece31c4873293323d80f7147d4548ac84cca9b47..0e2427cb67211d2219e2e54ce2faae239f7b892c 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,10 @@ -# CODEChina +# 关于CODEChina 欢迎使用CodeChina代码托管平台,本产品基于 Gitlab CE 版本 (13.2 stable) 开发并,目前版本提供了代码仓库管理、组织管理等基本功能,欢迎体验使用。 - - 体验使用过程中如果遇到任何问题,请与我们联系。 - -### 联系方式 +## 联系我们 - [点此向 CODEChina 产品提交 issue](https://codechina.csdn.net/codechina/beta/~/issues) diff --git a/SUMMARY.md b/SUMMARY.md index c6d352208c0ee468e8a41f158f0b8bea57ad3f44..4b13358a262b50e11ca6c3557a68255c6f5dc2ad 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,5 +1,6 @@ # Summary -* [Introduction](README.md) +* [首页](README.md) * [概览](docs/002.md) +* [组织](docs/033.md) diff --git a/_book/docs/002.html b/_book/docs/002.html index 0980c3c4e74895bb5607b4b0d3c89ccc7387d201..c4f026764b2f3fb6140be83702ab026a52395090 100644 --- a/_book/docs/002.html +++ b/_book/docs/002.html @@ -1,14 +1,14 @@ - + - 概览 · GitBook + 概览 · CODEChina帮助文档 - + @@ -21,6 +21,10 @@ + + + + @@ -66,6 +70,8 @@ + + @@ -99,14 +105,14 @@ @@ -122,6 +128,8 @@ @@ -209,8 +230,8 @@

帮助文档

-

访问codechina.csdn.net/docs,以获得优化的导航,可发现性和可读性.

-

概览

+

访问codechina.csdn.net/docs,以获得优化的导航,可发现性和可读性。

+

概览

欢迎您使用CODEChina,如果您是 Github 或 GitLab 的初级用户,我们建议您从查看本文档开始学习如何使用 CODEChina。如果您熟悉以上两个产品中的一个或多个,您可以直接开始 CODEChina 产品,在产品中我们也会为您设置帮助提示,您可以随时回来查看我们的产品文档。

@@ -221,24 +242,24 @@ - - + + - - + + - +
用户文件熟悉CODEChina 中的功能和概念.管理员文件管理员入门.用户文件熟悉CODEChina 中的功能和概念.管理员文件管理员入门
为 CODEChina 做贡献为CODEChina开源贡献力量!是 Git 和 GitLab/GitHub 的新手吗?我们有资源可以帮助您入门.为 CODEChina 做贡献为CODEChina开源贡献力量!是 Git 和 GitLab/GitHub 的新手吗?我们有资源可以帮助您入门
从另一个平台进入 CODEChina?请查阅我们的便捷指南.从另一个平台进入 CODEChina?请查阅我们的便捷指南  
-

热门话题

+

热门话题

以下是我们推荐的一些主题:

-

计划

-

无论您使用 Waterfall,敏捷还是会话开发,CODEChina 均可简化您的协作工作流程.

-

使用 CODEChina 灵活的项目管理工具可视化,确定优先级,协调和跟踪进度.

+

计划

+

无论您使用 Waterfall,敏捷还是会话开发,CODEChina 均可简化您的协作工作流程。

+

使用 CODEChina 灵活的项目管理工具可视化,确定优先级,协调和跟踪进度。

以下文档与 DevOps 计划阶段有关:

@@ -250,39 +271,39 @@ - + - + - - + + - + - + - + - + - + - + @@ -290,24 +311,24 @@ - + - + - +
Burndown Charts在特定的里程碑中观察项目的进度.在特定的里程碑中观察项目的进度
讨论问题,提交和合并请求中的线程,注释和可解决线程.问题,提交和合并请求中的线程,注释和可解决线程
截止日期]跟踪发行期限.截止日期跟踪发行期限
Epics跟踪共享主题的问题组.跟踪共享主题的问题组
问题 ,包括机密问题发布和合并请求模板 ,和移动的问题项目问题并限制对问题的访问,并创建用于提交新问题和合并请求的模板. 此外,在项目之间转移问题.项目问题并限制对问题的访问,并创建用于提交新问题和合并请求的模板。 此外,在项目之间转移问题。
标签分类问题或使用描述性标签合并请求.分类问题或使用描述性标签合并请求
里程碑设置发布问题和合并请求的里程碑,并带有可选的截止日期.设置发布问题和合并请求的里程碑,并带有可选的截止日期
看板在 Scrum 或看板上显示问题.在 Scrum 或看板上显示问题
快捷方式针对问题或合并请求的常见操作的快捷方式,而无需单击按钮或在WEB界面中使用下拉菜单.针对问题或合并请求的常见操作的快捷方式,而无需单击按钮或在WEB界面中使用下拉菜单。
关联 Issue
Roadmap可视化史诗般的时间表.可视化史诗般的时间表
时间跟踪跟踪花费在问题和合并请求上的时间.跟踪花费在问题和合并请求上的时间
代办事项通过在简单仪表板上显示的时间顺序列表,跟踪需要注意的工作.通过在简单仪表板上显示的时间顺序列表,跟踪需要注意的工作。

返回概览

-

新建

-

将源代码整合到一个易于管理和控制的分布式版本控制系统中 ,而不会中断您的工作流程.

-

CODEChina 存储库随附分支工具和访问控制,可为项目和代码的协作提供可扩展的单一事实来源.

+

新建

+

将源代码整合到一个易于管理和控制的分布式版本控制系统中 ,而不会中断您的工作流程。

+

CODEChina 存储库随附分支工具和访问控制,可为项目和代码的协作提供可扩展的单一事实来源。

以下文档与 DevOps 新建阶段有关:

-

项目和组织

+

项目和组织

@@ -318,52 +339,52 @@ - + - + - + - + - + - + - + - + - + - + - +
全局搜索利用 Elasticsearch 在整个 CODEChina 实例上进行更快,更高级的代码搜索.利用 Elasticsearch 在整个 CODEChina 实例上进行更快,更高级的代码搜索
语法检索使用高级查询获得更具针对性的搜索结果.使用高级查询获得更具针对性的搜索结果
Contribution analytics请参阅小组贡献者的详细统计信息.请参阅小组贡献者的详细统计信息
创建fork项目,以及导入项目 实例之间创建,复制和移动项目.创建,复制和移动项目
锁定文件锁定文件以避免合并冲突.锁定文件以避免合并冲突
组织 and 子组织分组组织您的项目.分组组织您的项目
Issue 分析检查每月创建了多少个问题.检查每月创建了多少个问题
项目 ,包括项目访问设置托管源代码,并控制项目的可见性和设置配置.托管源代码,并控制项目的可见性和设置配置。
Search through CODEChina搜索问题,合并请求,项目,组和待办事项.搜索问题,合并请求,项目,组和待办事项。
Web IDE在 WebIDE 中编辑文件.在 WebIDE 中编辑文件
Wikis使用内置的 Wiki 来管理您的文档.使用内置的 Wiki 来管理您的文档

返回概览

-

代码仓库

+

代码仓库

@@ -374,43 +395,43 @@ - + - + - + - + - + - + - + - + - + - + @@ -418,12 +439,12 @@ - +
分支默认分支如何在 CODEChina 中使用分支.如何在 CODEChina 中使用分支
提交 and 署名提交处理提交,并使用 GPG 对您的提交进行签名.处理提交,并使用 GPG 对您的提交进行签名。
创建分支创建上传文件,并创建目录创建分支,创建和上传文件以及创建目录.创建分支,创建和上传文件以及创建目录。
删除已合并的分支合并更改后的批量删除分支.合并更改后的批量删除分支
文件模板通用文件的文件模板.通用文件的文件模板
文件文件管理.文件管理
Jupyter Notebook 文件.ipynb文件的支持..ipynb文件的支持
保护分支使用受保护的分支.使用受保护的分支
推送规则对项目推送的附加控制.对项目推送的附加控制
代码仓库在网页中管理源代码仓库.在网页中管理源代码仓库
镜像代码仓库
处理合并请求在提交时启动合并请求.在提交时启动合并请求

返回概览

-

合并请求

+

合并请求

@@ -434,28 +455,28 @@ - + - + - + - + - +
在本地处理合并请求在本地处理合并请求的提示.在本地处理合并请求的提示
Cherry-pick对更改进行 Cherry Pick.对更改进行 Cherry Pick
Merge request thread resolution解析线程,将合并请求中的线程移至问题,并且仅在解决所有线程后才允许合并请求.解析线程,将合并请求中的线程移至问题,并且仅在解决所有线程后才允许合并请求。
合并请求合并请求管理.合并请求管理
草稿合并请求防止合并草稿合并请求.防止合并草稿合并请求

返回概览

-

刚开始使用Git/CODEChina/GitLab/Github?

+

刚开始使用Git/CODEChina/GitLab/Github?

使用新系统可能让您觉得难以入手,我们有以下文档可快速提升您的相关知识:

@@ -467,11 +488,11 @@ - + - + @@ -480,7 +501,7 @@
Basics guides开始在命令行和 CODEChina 上工作.开始在命令行和 CODEChina 上工作
Workflow overview利用最佳的工作流程增强您的工作流程.利用最佳的工作流程增强您的工作流程
Markdown

返回概览

-

账户管理

+

账户管理

了解有关帐户管理的更多信息:

@@ -492,20 +513,20 @@ - + - + - +
用户账号管理您的帐户.管理您的帐户
账号验证具有两因素身份验证的帐户安全性,设置您的 SSH 密钥,并部署密钥以安全地访问您的项目.具有两因素身份验证的帐户安全性,设置您的 SSH 密钥,并部署密钥以安全地访问您的项目。
用户权限了解项目中的每个角色可以做什么.了解项目中的每个角色可以做什么

返回概览

-

Git 和 CODEChina

+

Git 和 CODEChina

了解有关使用 Git 以及将 Git 与 CODEChina 结合使用的更多信息:

@@ -517,20 +538,20 @@ - + - + - +
GitGit 入门,分支策略,Git LFS 和高级用法.Git 入门,分支策略,Git LFS 和高级用法
Git cheat sheet下载描述最常用的 Git 操作的 PDF.下载描述最常用的 Git 操作的 PDF
Work Flow使用 Work Flow 策略探索 Git 的精华.使用 Work Flow 策略探索 Git 的精华

返回概览

-

从另一个平台进入 CODEChina?

+

从另一个平台进入到 CODEChina?

如果您是从另一个平台进入 CODEChina,您会发现以下有用信息:

@@ -542,16 +563,16 @@ - + - +
导入项目从 GitHub,Bitbucket,GitLab.com,FogBugz 和 SVN 导入项目.从 GitHub,Bitbucket,GitLab.com,FogBugz 和 SVN 导入项目
从SVN迁移将 SVN 存储库转换为 Git 和 CODEChina.将 SVN 存储库转换为 Git 和 CODEChina

返回概览

-

为CODEChina开源做贡献

+

为CODEChina开源做贡献

CODEChina 是开源的,您可以通过以下方式为我们的开源社区做出贡献:

@@ -563,20 +584,22 @@ - + - + - +
开发如何在开发上做贡献.如何在开发上做贡献
协议贡献者许可协议.贡献者许可协议
文档如何在文档上做贡献.如何在文档上做贡献
-

返回概览

- +

返回概览

+
@@ -604,18 +627,22 @@ - + + + + + @@ -629,6 +656,10 @@ + + + + @@ -649,10 +680,6 @@ - - - - diff --git a/_book/docs/003.md b/_book/docs/003.md deleted file mode 100644 index 1ff4afc6e9be8753b25555b544d10175642d4abd..0000000000000000000000000000000000000000 --- a/_book/docs/003.md +++ /dev/null @@ -1,76 +0,0 @@ -# Installation - -> 原文:[https://docs.gitlab.com/ee/install/README.html](https://docs.gitlab.com/ee/install/README.html) - -* [Requirements](#requirements) -* [Installing GitLab using the Omnibus GitLab package (recommended)](#installing-gitlab-using-the-omnibus-gitlab-package-recommended) -* [Installing GitLab on Kubernetes via the GitLab Helm charts](#installing-gitlab-on-kubernetes-via-the-gitlab-helm-charts) -* [Installing GitLab with Docker](#installing-gitlab-with-docker) -* [Installing GitLab from source](#installing-gitlab-from-source) -* [Installing GitLab on cloud providers](#installing-gitlab-on-cloud-providers) -* [Securing your GitLab installation](#securing-your-gitlab-installation) - -# Installation[](#installation-core-only "Permalink") - -GitLab 可以安装在大多数 GNU / Linux 发行版以及许多云提供商中. 为了从 GitLab 获得最佳体验,您需要在性能,可靠性,易于管理(备份,升级和故障排除)以及托管成本之间取得平衡. - -根据平台的不同,可以通过多种方式安装 GitLab: - -1. **Omnibus GitLab** :官方的 deb / rpm 软件包,包含捆绑的 GitLab 及其依赖的各种组件,例如 PostgreSQL,Redis,Sidekiq 等. -2. **GitLab Helm 图表** :用于在 Kubernetes 上安装 GitLab 及其所有组件的云原生 Helm 图表. -3. **码头**工人:Omnibus GitLab 软件包码头化. -4. **来源** :从头开始安装 GitLab 及其所有组件. - -**如有疑问,请选择 Omnibus:** Omnibus GitLab 软件包已经成熟, [可扩展,](../administration/reference_architectures/index.html)并且已在 GitLab.com 上使用. 建议向熟悉 Kubernetes 的人使用 Helm 图表. - -## Requirements[](#requirements "Permalink") - -在安装 GitLab 之前,查看系统[要求](requirements.html)至关重要. 系统要求包括有关最低硬件,软件,数据库以及支持 GitLab 的其他要求的详细信息. - -## Installing GitLab using the Omnibus GitLab package (recommended)[](#installing-gitlab-using-the-omnibus-gitlab-package-recommended "Permalink") - -Omnibus GitLab 软件包使用我们的官方 deb / rpm 存储库. 建议大多数用户使用. - -如果您需要更多的灵活性和弹性,我们建议按照[参考架构文档](../administration/reference_architectures/index.html)中的[说明](../administration/reference_architectures/index.html)部署 GitLab. - -[**> Install GitLab using the Omnibus GitLab package.**](https://about.gitlab.com/install/) - -## Installing GitLab on Kubernetes via the GitLab Helm charts[](#installing-gitlab-on-kubernetes-via-the-gitlab-helm-charts "Permalink") - -**需要 Kubernetes 经验:**我们建议您先熟悉 Kubernetes,然后再使用 Kubernetes 在生产中部署 GitLab. 管理,可观察性和某些概念的方法与传统部署不同. - -在 Kubernetes 上安装 GitLab 时,需要注意一些折衷: - -* 管理和故障排除需要 Kubernetes 知识. -* 对于较小的安装,它可能会更昂贵. 默认安装比单节点 Omnibus 部署需要更多的资源,因为大多数服务都是以冗余方式部署的. -* 有一些功能[限制需要注意](https://docs.gitlab.com/charts/) . - -[**> Install GitLab on Kubernetes using the GitLab Helm charts.**](https://docs.gitlab.com/charts/) - -## Installing GitLab with Docker[](#installing-gitlab-with-docker "Permalink") - -GitLab 基于 Omnibus GitLab 软件包维护一组正式的 Docker 映像. - -[**> Install GitLab using the official GitLab Docker images.**](docker.html) - -## Installing GitLab from source[](#installing-gitlab-from-source "Permalink") - -如果您的发行版中没有 Omnibus GitLab 软件包,则可以从源代码安装 GitLab:对于* BSD 等不受支持的系统很有用. 有关目录结构的概述,请阅读[结构文档](structure.html) . - -[**> Install GitLab from source.**](installation.html) - -## Installing GitLab on cloud providers[](#installing-gitlab-on-cloud-providers "Permalink") - -只要有云提供商支持,就可以使用上述任何一种方法将 GitLab 安装在各种云提供商上. - -* [在 AWS 上](aws/index.html)安装:使用 GitLab 提供的社区 AMI 在 AWS [上](aws/index.html)安装 Omnibus GitLab. -* [在 Google Cloud Platform 上安装 GitLab](google_cloud_platform/index.html) :在 GCP 中的 VM 上安装 Omnibus GitLab. -* [在 Azure 上](azure/index.html)安装 GitLab:从 Azure 市场安装 Omnibus GitLab. -* [在 OpenShift 上](https://docs.gitlab.com/charts/installation/cloud/openshift.html)安装 GitLab:通过使用 GitLab 的 Helm 图表在 OpenShift [上](https://docs.gitlab.com/charts/installation/cloud/openshift.html)安装 GitLab. -* [在 DC / OS 上](https://d2iq.com/blog/gitlab-dcos)安装 GitLab:通过[GitLab-Mesosphere 集成](https://about.gitlab.com/blog/2016/09/16/announcing-gitlab-and-mesosphere/)在 Mesosphere DC / OS 上安装 GitLab. -* [在 DigitalOcean 上安装 GitLab:在 DigitalOcean 上](https://about.gitlab.com/blog/2016/04/27/getting-started-with-gitlab-and-digitalocean/)安装 Omnibus GitLab. -* *仅测试!* [DigitalOcean 和 Docker Machine](digitaloceandocker.html) :使用 Docker Machine 在 DigitalOcean 上快速测试任何版本的 GitLab. - -## Securing your GitLab installation[](#securing-your-gitlab-installation "Permalink") - -完成安装后,请查看我们[建议的做法以保护您的 GitLab 实例](../security/README.html#securing-your-gitlab-installation) . \ No newline at end of file diff --git a/_book/docs/004.md b/_book/docs/004.md deleted file mode 100644 index 195670cc6a4867e74e3110db9019017296083cef..0000000000000000000000000000000000000000 --- a/_book/docs/004.md +++ /dev/null @@ -1,245 +0,0 @@ -# Requirements - -> 原文:[https://docs.gitlab.com/ee/install/requirements.html](https://docs.gitlab.com/ee/install/requirements.html) - -* [Operating Systems](#operating-systems) - * [Supported Linux distributions](#supported-linux-distributions) - * [Unsupported Linux distributions and Unix-like operating systems](#unsupported-linux-distributions-and-unix-like-operating-systems) - * [Microsoft Windows](#microsoft-windows) -* [Software requirements](#software-requirements) - * [Ruby versions](#ruby-versions) - * [Go versions](#go-versions) - * [Git versions](#git-versions) - * [Node.js versions](#nodejs-versions) -* [Redis versions](#redis-versions) -* [Hardware requirements](#hardware-requirements) - * [Storage](#storage) - * [CPU](#cpu) - * [Memory](#memory) -* [Database](#database) - * [PostgreSQL Requirements](#postgresql-requirements) - * [Additional requirements for GitLab Geo](#additional-requirements-for-gitlab-geo) -* [Puma settings](#puma-settings) - * [Puma workers](#puma-workers) - * [Puma threads](#puma-threads) -* [Unicorn Workers](#unicorn-workers) -* [Redis and Sidekiq](#redis-and-sidekiq) -* [Prometheus and its exporters](#prometheus-and-its-exporters) -* [GitLab Runner](#gitlab-runner) -* [Supported web browsers](#supported-web-browsers) - -# Requirements[](#requirements "Permalink") - -该页面包含有关受支持的操作系统以及安装和使用 GitLab 所需的硬件要求的有用信息. - -## Operating Systems[](#operating-systems "Permalink") - -### Supported Linux distributions[](#supported-linux-distributions "Permalink") - -* Ubuntu(16.04 / 18.04) -* Debian(8/9/10) -* CentOS 的(6/7/8) -* openSUSE(Leap 15.1 / Enterprise Server 12.2) -* 红帽企业版 Linux(请使用 CentOS 软件包和说明) -* 科学版 Linux(请使用 CentOS 软件包和说明) -* Oracle Linux(请使用 CentOS 软件包和说明) - -有关安装选项,请参见[主要安装页面](README.html) . - -### Unsupported Linux distributions and Unix-like operating systems[](#unsupported-linux-distributions-and-unix-like-operating-systems "Permalink") - -* Arch Linux -* Fedora -* FreeBSD -* Gentoo -* macOS - -可以在这些操作系统上安装 GitLab,但不支持. 请参阅[源安装指南](installation.html)和[安装指南](https://about.gitlab.com/install/)以获取更多信息. - -### Microsoft Windows[](#microsoft-windows "Permalink") - -GitLab 是针对基于 Linux 的操作系统开发的. 它**不能**在 Microsoft Windows 上运行,并且我们没有计划在不久的将来支持它. 有关最新的开发状态,请查看此[问题](https://gitlab.com/gitlab-org/gitlab/-/issues/22337) . 请考虑使用虚拟机运行 GitLab. - -## Software requirements[](#software-requirements "Permalink") - -### Ruby versions[](#ruby-versions "Permalink") - -GitLab 需要 Ruby(MRI)2.6\. 从 GitLab 12.2 开始,我们不再支持 Ruby 2.5 及更低版本. - -您必须使用 Ruby 的标准 MRI 实现. 我们喜欢[JRuby](https://www.jruby.org/)和[Rubinius](https://github.com/rubinius/rubinius#the-rubinius-language-platform) ,但是 GitLab 需要几个具有本机扩展的 Gems. - -### Go versions[](#go-versions "Permalink") - -所需的最低 Go 版本为 1.13. - -### Git versions[](#git-versions "Permalink") - -从 GitLab 13.1: - -* 需要 Git 2.25.x 及更高版本. -* [建议使用](https://gitlab.com/gitlab-org/gitaly/-/issues/2829) Git 2.27.x 及更高版本. - -### Node.js versions[](#nodejs-versions "Permalink") - -从 GitLab 12.9 开始,我们仅支持 node.js 10.13.0 或更高版本,并且我们放弃了对 node.js 8 的支持.(在 GitLab 11.8 中取消了对 node.js 6 的支持). - -我们建议使用 Node 12.x,因为它速度更快. - -GitLab 使用[Webpack](https://webpack.js.org/)编译前端资产,这需要最低版本的 Node.js 10.13.0. - -您可以使用`node -v`检查您正在运行哪个版本. 如果您运行的版本低于`v10.13.0` ,则需要将其更新为较新的版本. 您可以在[Node.js 网站上](https://s0nodejs0org.icopy.site/en/download/)找到从社区维护的软件包安装或从源代码进行编译的[说明](https://s0nodejs0org.icopy.site/en/download/) . - -## Redis versions[](#redis-versions "Permalink") - -GitLab 需要 Redis 5.0+. 从 GitLab 13.0 开始,不支持较低版本. - -## Hardware requirements[](#hardware-requirements "Permalink") - -### Storage[](#storage "Permalink") - -所需的硬盘空间在很大程度上取决于要存储在 GitLab 中的存储库的大小,但是根据*经验,*您应该至少具有与所有存储库加起来一样大的可用空间. - -如果您将来想灵活地增加硬盘驱动器空间,请考虑使用[逻辑卷管理(LVM)进行](https://en.wikipedia.org/wiki/Logical_volume_management)安装,以便在需要时可以添加更多硬盘驱动器. - -除本地硬盘驱动器外,您还可以安装支持网络文件系统(NFS)协议的卷. 该卷可能位于文件服务器,网络连接存储(NAS)设备,存储区域网络(SAN)或 Amazon Web Services(AWS)弹性块存储(EBS)卷上. - -如果您有足够的 RAM 和最新的 CPU,则 GitLab 的速度主要受硬盘搜索时间限制. 具有快速驱动器(7200 RPM 及更高版本)或固态驱动器(SSD)将提高 GitLab 的响应速度. - -**注意:**由于文件系统性能可能会影响 GitLab 的整体性能,因此[我们不建议使用 AWS EFS 进行存储](../administration/high_availability/nfs.html#avoid-using-awss-elastic-file-system-efs) . - -### CPU[](#cpu "Permalink") - -CPU 需求取决于用户数量和预期的工作量. 您的确切需求可能更多,具体取决于您的工作量. 您的工作负载受以下因素影响,这些因素包括但不限于:用户的活跃程度,使用的自动化程度,镜像和回购/更改大小. - -以下是一些示例 GitLab 用户库大小的建议最低 CPU 硬件指南. - -* **4 芯**是核心的**推荐**最小数目和多达 500 个用户支持 -* 8 个内核最多支持 1000 个用户 -* 更多用户? 查阅[参考架构页面](../administration/reference_architectures/index.html) - -### Memory[](#memory "Permalink") - -内存需求取决于用户数量和预期的工作量. 您的确切需求可能更多,具体取决于您的工作量. 您的工作负载受以下因素影响,这些因素包括但不限于:用户的活跃程度,使用的自动化程度,镜像和回购/更改大小. - -以下是一些示例 GitLab 用户库大小的建议最低内存硬件指南. - -* **4GB RAM**是**必需的**最小内存大小,最多可支持 500 个用户 - * 我们的[内存团队](https://about.gitlab.com/handbook/engineering/development/enablement/memory/)正在努力减少内存需求. -* 8GB RAM 最多支持 1000 个用户 -* 更多用户? 查阅[参考架构页面](../administration/reference_architectures/index.html) - -除上述之外,即使您当前有足够的可用 RAM,我们通常也建议在服务器上至少有 2GB 的交换空间. 如果您的可用内存发生更改,那么进行交换将有助于减少发生错误的机会. 我们还建议将内核的 swappiness 设置配置为较低的值(例如`10`以充分利用您的 RAM,同时在需要时仍可使用交换功能. - -## Database[](#database "Permalink") - -PostgreSQL 是唯一受支持的数据库,与 Omnibus GitLab 软件包捆绑在一起. 您也可以使用[外部 PostgreSQL 数据库](https://docs.gitlab.com/omnibus/settings/database.html) . 在 GitLab 12.1 中删除了对 MySQL 的支持. 建议在 MySQL / MariaDB 上使用 GitLab 的现有用户在升级之前[迁移到 PostgreSQL](../update/mysql_to_postgresql.html) . - -### PostgreSQL Requirements[](#postgresql-requirements "Permalink") - -运行 PostgreSQL 的服务器应*至少有* 5-10 GB 的可用存储空间,尽管确切的要求[取决于用户数量](../administration/reference_architectures/index.html) . - -我们强烈建议用户使用下面指定的最低 PostgreSQL 版本,因为这些是用于开发和测试的版本. - -| GitLab 版本 | 最低 PostgreSQL 版本 | -| --- | --- | -| 10.0 | 9.6 | -| 12.10 | 11 | -| 13.0 | 11 | - -您还必须确保将`pg_trgm`扩展加载到每个 GitLab 数据库中. [可以](https://s0www0postgresql0org.icopy.site/docs/11/sql-createextension.html)使用 PostgreSQL 超级用户[启用](https://s0www0postgresql0org.icopy.site/docs/11/sql-createextension.html)此扩展. - -在某些系统上,您可能需要安装一个附加软件包(例如`postgresql-contrib` ),此扩展才可以使用. - -**注意:** [在 GitLab 13.0 中已删除了](https://about.gitlab.com/releases/2020/05/22/gitlab-13-0-released/#postgresql-11-is-now-the-minimum-required-version-to-install-gitlab)对[PostgreSQL 9.6 和 10 的](https://about.gitlab.com/releases/2020/05/22/gitlab-13-0-released/#postgresql-11-is-now-the-minimum-required-version-to-install-gitlab)支持,因此 GitLab 可以从 PostgreSQL 11 的改进(例如分区)中受益. 有关过渡到 PostgreSQL 12 的时间表,请参阅[相关的 epic](https://gitlab.com/groups/gitlab-org/-/epics/2184) . - -#### Additional requirements for GitLab Geo[](#additional-requirements-for-gitlab-geo "Permalink") - -如果您使用的是[GitLab Geo](../administration/geo/replication/index.html) : - -* 我们强烈建议您在积极开发和测试的情况下运行由 Omnibus 管理的实例. 我们的目标是与大多数外部数据库(不由 Omnibus 管理)兼容(例如, [AWS Relational Database Service(RDS)](https://aws.amazon.com/rds/) ),但我们不保证兼容性. -* 您还必须确保将`postgres_fdw`扩展加载到每个 GitLab 数据库中. [可以](https://s0www0postgresql0org.icopy.site/docs/11/sql-createextension.html)使用 PostgreSQL 超级用户[启用](https://s0www0postgresql0org.icopy.site/docs/11/sql-createextension.html)此扩展. - -## Puma settings[](#puma-settings "Permalink") - -建议的 Puma 设置取决于运行它的基础结构. Omnibus GitLab 默认为建议的 Puma 设置. 无论安装方法如何,都可以调整 Puma 设置. - -如果您使用的是 Omnibus GitLab,请参阅[Puma 设置](https://docs.gitlab.com/omnibus/settings/puma.html)以获取有关更改 Puma 设置的说明. 如果您使用的是 GitLab Helm 图表,请参阅[Webservice 图表](https://docs.gitlab.com/charts/charts/gitlab/webservice/index.html) . - -### Puma workers[](#puma-workers "Permalink") - -推荐的工人人数是根据以下最高者计算得出的: - -* `2` -* CPU 核心数-1 - -例如,一个具有 4 个核心的节点应配置 3 个 Puma Worker. - -如果可以提供足够的 CPU 和内存容量,则可以增加 Puma worker 的数量. 数量更多的 Puma 工作人员通常将有助于减少应用程序的响应时间并提高处理并行请求的能力. 您必须执行测试以验证基础架构的最佳设置. - -### Puma threads[](#puma-threads "Permalink") - -推荐的线程数取决于几个因素,包括总内存和[传统 Rugged 代码的使用](../development/gitaly.html#legacy-rugged-code) . - -* 如果操作系统最多具有 2 GB 的内存,则建议的线程数为`1` . 较高的值将导致过多的交换,并降低性能. -* If legacy Rugged code is in use, the recommended number of threads is `1`. -* 在所有其他情况下,建议的线程数为`4` . 由于[Ruby MRI 多线程的](https://en.wikipedia.org/wiki/Global_interpreter_lock)工作方式,我们不建议设置更高的值. - -## Unicorn Workers[](#unicorn-workers "Permalink") - -对于大多数情况,我们建议使用:(CPU 内核* 1.5)+ 1 = Unicorn worker. 例如,一个具有 4 个核心的节点将有 7 个 Unicorn worker. - -对于所有 2GB 以上的计算机,我们建议至少三名 Unicorn 工人. 如果您有一台 1GB 的计算机,我们建议仅配置两个 Unicorn worker,以防止过度交换. - -只要您有足够的可用 CPU 和内存容量,就可以增加 Unicorn worker 的数量,这通常将有助于减少应用程序的响应时间并提高处理并行请求的能力. - -要在拥有 Omnibus 软件包(默认为上述建议)时更改 Unicorn worker,请参阅[Omnibus GitLab 文档中的 Unicorn 设置](https://docs.gitlab.com/omnibus/settings/unicorn.html) . - -## Redis and Sidekiq[](#redis-and-sidekiq "Permalink") - -Redis 存储所有用户会话和后台任务队列. Redis 的存储要求极低,每个用户大约 25kB. Sidekiq 使用多线程进程来处理后台作业. 此过程从整个 Rails 堆栈(200MB +)开始,但是由于内存泄漏,它可能随着时间的推移而增长. 在非常活跃的服务器(10,000 个活跃用户)上,Sidekiq 进程可以使用 1GB +的内存. - -## Prometheus and its exporters[](#prometheus-and-its-exporters "Permalink") - -从 Omnibus GitLab 9.0 起,默认启用[Prometheus](https://s0prometheus0io.icopy.site)及其相关出口商,以实现对 GitLab 的轻松和深度监控. 使用默认设置,这些进程将消耗大约 200MB 的内存. - -如果您想禁用 Prometheus 及其出口商或阅读有关它的更多信息,请查阅[Prometheus 文档](../administration/monitoring/prometheus/index.html) . - -## GitLab Runner[](#gitlab-runner "Permalink") - -强烈建议不要在打算安装 GitLab 的同一台计算机上安装 GitLab Runner. 根据您决定配置 GitLab Runner 的方式以及用于在 CI 环境中运行应用程序的工具的不同,GitLab Runner 会消耗大量可用内存. - -如果您决定在同一台计算机上运行 GitLab Runner 和 GitLab Rails 应用程序,则上面提供的内存消耗计算将无效. - -由于[安全原因](https://docs.gitlab.com/runner/security/) ,将所有内容都安装在一台机器上也不安全,尤其是当您计划将 Shell executor 与 GitLab Runner 一起使用时. - -如果您打算使用 CI 功能,我们建议为每个 GitLab Runner 使用单独的机器. GitLab Runner 服务器要求取决于: - -* 您在 GitLab Runner 上配置的[执行程序](https://docs.gitlab.com/runner/executors/)的类型. -* 运行构建作业所需的资源. -* 作业并发设置. - -由于作业的性质因每个用例而异,因此您将需要通过调整作业并发来进行实验以获得最佳设置. - -作为参考,对 GitLab.com 的[自动缩放共享](../user/gitlab_com/index.html#shared-runners)运行器进行了配置,以便**单个作业**将在**单个实例中**运行,并具有: - -* 1vCPU. -* 3.75GB 的 RAM. - -## Supported web browsers[](#supported-web-browsers "Permalink") - -**警告:**在 GitLab 13.0(2020 年 5 月)中,我们删除了对 Internet Explorer 11 的官方支持.在 GitLab 13.4 发行版(2020 年 9 月)中,我们将删除了所有支持 Internet Explorer 11 的代码.您可以提供[有关此问题的](https://gitlab.com/gitlab-org/gitlab/-/issues/197987)反馈[,](https://gitlab.com/gitlab-org/gitlab/-/issues/197987)也可以通过通常的支持渠道. - -GitLab supports the following web browsers: - -* [Mozilla Firefox](https://www.mozilla.org/en-US/firefox/new/) -* [Google Chrome](https://www.google.com/chrome/) -* [Chromium](https://www.chromium.org/getting-involved/dev-channel) -* [Apple Safari](https://www.apple.com/safari/) -* [Microsoft Edge](https://www.microsoft.com/en-us/edge) - -对于列出的 Web 浏览器,GitLab 支持: - -* 当前和以前的主要浏览器版本(Internet Explorer 除外). -* 受支持的主要版本的当前次要版本. - -**注意:**我们不支持在浏览器中禁用 JavaScript 的情况下运行 GitLab,并且将来也没有支持该计划的计划,因为我们具有诸如 Issue Boards 之类的功能,这些功能广泛需要 JavaScript. \ No newline at end of file diff --git a/_book/docs/005.md b/_book/docs/005.md deleted file mode 100644 index 0b8423e6516d336a1fee5bc0b1837fdb766a6dc5..0000000000000000000000000000000000000000 --- a/_book/docs/005.md +++ /dev/null @@ -1 +0,0 @@ -> 原文:[https://about.gitlab.com/install/](https://about.gitlab.com/install/) \ No newline at end of file diff --git a/_book/docs/006.md b/_book/docs/006.md deleted file mode 100644 index f9d6aa3fc2263d2d747eeecfbbe0b4d004d4ed61..0000000000000000000000000000000000000000 --- a/_book/docs/006.md +++ /dev/null @@ -1,181 +0,0 @@ -# GitLab cloud native Helm Chart - -> 原文:[https://docs.gitlab.com/charts/](https://docs.gitlab.com/charts/) - -* [Introduction](#introduction) -* [Limitations](#limitations) -* [GitLab Helm chart quick start guide](#gitlab-helm-chart-quick-start-guide) -* [Troubleshooting](#troubleshooting) -* [Installation](#installation) - * [Global settings](#global-settings) - * [Complete properties list](#complete-properties-list) -* [Upgrading](#upgrading) -* [Uninstall](#uninstall) -* [Advanced](#advanced) - * [Advanced Configuration](#advanced-configuration) - * [Migrate from Omnibus GitLab to Kubernetes](#migrate-from-omnibus-gitlab-to-kubernetes) -* [Architecture](#architecture) -* [Development](#development) - * [GitLab version mappings](#gitlab-version-mappings) - * [Contributing](#contributing) - -# GitLab cloud native Helm Chart[](#gitlab-cloud-native-helm-chart "Permalink") - -这是在云本机环境上安装 GitLab 的官方,推荐和受支持的方法. - -**注意:**不必在 Kubernetes 上安装 GitLab 即可使用[GitLab Kubernetes 集成](https://docs.gitlab.com/ee/user/project/clusters/) . - -## Introduction[](#introduction "Permalink") - -The `gitlab/gitlab` chart is the best way to operate GitLab on Kubernetes. This chart contains all the required components to get started, and can scale to large deployments. - -该图表包括完整的体验所需的所有组件,但是每个部分都可以单独安装. - -* GitLab 核心组件: - * [NGINX 入口](charts/nginx/index.html) - * [登记处](charts/registry/index.html) - * [亚搏体育 app](charts/gitlab/gitaly/index.html) / [Gitaly](charts/gitlab/gitaly/index.html) - * GitLab / [GitLab 出口商](charts/gitlab/gitlab-exporter/index.html) - * GitLab / [GitLab Grafana](charts/gitlab/gitlab-grafana/index.html) - * GitLab / [GitLab 外壳](charts/gitlab/gitlab-shell/index.html) - * GitLab / [迁移](charts/gitlab/migrations/index.html) - * [亚搏体育 app](charts/gitlab/sidekiq/index.html) / [Sidekiq](charts/gitlab/sidekiq/index.html) - * GitLab / [web 服务](charts/gitlab/webservice/index.html) -* 可选依赖项: - * [PostgreSQL 的](https://hub.helm.sh/charts/bitnami/postgresql) - * [雷迪斯](https://hub.helm.sh/charts/bitnami/redis) - * [MinIO](charts/minio/index.html) -* 可选的补充: - * [普罗米修斯](https://hub.helm.sh/charts/stable/prometheus) - * [格拉法纳](https://hub.helm.sh/charts/stable/grafana) - * 使用 Kubernetes 执行器的[*非特权*](https://docs.gitlab.com/runner/install/kubernetes.html) [GitLab Runner](https://docs.gitlab.com/runner/) - * 使用[Jetstack](https://www.jetstack.io/)的[cert-manager](https://cert-manager.io/docs/)通过[Let's Encrypt](https://letsencrypt.org/)自动提供 SSL - -## Limitations[](#limitations "Permalink") - -使用 Helm 图表当前无法使用 GitLab 的某些功能: - -* [GitLab Pages](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/37) -* [Smartcard authentication](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/988) - -数据库限制: - -* GitLab Geo 功能[需要使用外部数据库服务](installation/deployment.html#postgresql) . - -## GitLab Helm chart quick start guide[](#gitlab-helm-chart-quick-start-guide "Permalink") - -对于那些希望在*非生产*用例中尽快建立并运行这些图表的人,我们提供了概念验证(PoC)部署[快速入门指南](quickstart/index.html) . - -本指南将通过部署这些图表使用默认值和功能引导用户,但*不*符合生产做好准备的要求. 如果希望在持续负载下将这些图表部署到生产中,则应遵循以下完整的[安装指南](#installation) . - -## Troubleshooting[](#troubleshooting "Permalink") - -我们已尽力使这些图表尽可能地无缝,但偶尔也会出现无法控制的问题. 我们已收集了一些常见问题的疑难解答技巧. 在提出[问题](https://gitlab.com/gitlab-org/charts/gitlab/-/issues)之前,请先检查这些内容,并通过提出[合并请求](https://gitlab.com/gitlab-org/charts/gitlab/-/merge_requests)随意添加它们! - -See [Troubleshooting](troubleshooting/index.html). - -## Installation[](#installation "Permalink") - -`gitlab/gitlab`图表包含所有必需的依赖项. 在生产中,您可能需要启用可选功能或[高级配置](#advanced-configuration) . 本指南深入介绍了这些图表的所有选项和功能. - -如果您只是想部署概念验证进行测试,我们强烈建议您遵循我们的[快速入门](#gitlab-helm-chart-quick-start-guide)进行第一次迭代. - -1. [Preparation](installation/index.html) -2. [Deployment](installation/deployment.html) - -### Global settings[](#global-settings "Permalink") - -这些图表的复杂性使其可以使用全局属性. 有许多通用全局设置适用于多个图表. 有关不同的全局配置值及其应用程序的详细信息,请参见[Globals 文档](charts/globals.html) . - -### Complete properties list[](#complete-properties-list "Permalink") - -经常要求我们将所有可能的属性表直接放入此索引. 这些图表是规模*庞大* ,并作为属性的这种数量超过背景的量,我们在这里很舒服配售. 请参阅我们(几乎) [全面的属性和默认值列表](installation/command-line-options.html) . - -## Upgrading[](#upgrading "Permalink") - -安装了 GitLab 图表后,应使用`helm upgrade`完成配置更改和图表更新: - -``` -helm repo add gitlab https://charts.gitlab.io/ -helm repo update -helm get values gitlab > gitlab.yaml -helm upgrade gitlab gitlab/gitlab -f gitlab.yaml -``` - -有关更多详细信息,请参阅[升级](installation/upgrade.html) . - -## Uninstall[](#uninstall "Permalink") - -要卸载 GitLab Chart,请运行以下命令: - -``` -helm uninstall gitlab -``` - -**注意:**在 Helm v2 中,您需要使用`helm delete --purge gitlab`命令. - -为了连续起见,这些图表具有一些在执行`helm uninstall`时不会删除的 Kubernetes 对象. 这些是我们要求您有*意识地*删除的项目,因为它们会影响您应选择的重新部署. - -* 用于状态数据的 PVC,必须*自觉*删除 - * Gitaly:这是您的存储库数据. - * PostgreSQL(如果内部):这是您的元数据. - * Redis(如果内部):这是缓存和作业队列,可以安全地将其删除. -* 机密(如果由我们的共享机密工作生成). 这些图表旨在避免直接通过 Helm 生成 Kubernetes 秘密. 因此,Helm 无法删除它们. 它们包含密码,加密机密等.它们不应被恶意破坏. -* ConfigMaps - * `ingress-controller-leader-RELEASE-nginx` :这是由 NGINX Ingress 控制器本身生成的,不在我们图表的控制范围内. 可以安全地将其删除. - -PVC 和秘密将设置`release`标签,因此您可以通过以下方式找到它们: - -``` -kubectl get pvc,secret -lrelease=gitlab -``` - -## Advanced[](#advanced "Permalink") - -除了在云本机环境中进行 GitLab 的基本部署以外,还可以进行更复杂的配置. 本节为需要进一步计划的任务提供指导,例如大规模部署或从 Omnibus GitLab 迁移. - -### Advanced Configuration[](#advanced-configuration "Permalink") - -高级和大规模部署具有利用外部服务,扩展功能和备用提供程序的能力. - -高级配置示例: - -* 亚搏体育 app Geo -* 外部对象存储提供者 -* 外部 PostgreSQL,Redis,Gitaly -* 外部入口提供商 - -See [Advanced Configuration](advanced/index.html). - -### Migrate from Omnibus GitLab to Kubernetes[](#migrate-from-omnibus-gitlab-to-kubernetes "Permalink") - -可以从[Omnibus GitLab](https://docs.gitlab.com/omnibus/)迁移到这些图表. 这样做通常需要将现有数据迁移到对象存储,因此是[高级配置](advanced/index.html) . - -要将现有的 Omnibus GitLab 实例迁移到这些图表,请遵循[迁移文档](installation/migration/index.html) . - -## Architecture[](#architecture "Permalink") - -这些图表非常复杂,因为它们可以协调整个应用程序套件的部署. 我们提供有关目标,结构,设计决策和资源消耗的[文档](architecture/index.html) . - -## Development[](#development "Permalink") - -对于那些有兴趣为这些图表做出贡献的人,我们提供了涵盖该项目工作范围的开发指南. 它们可以在[开发中](development/index.html) . - -### GitLab version mappings[](#gitlab-version-mappings "Permalink") - -GitLab 图表与 GitLab 本身的版本号不同. 预计可能需要在图表中引入一些重大更改,这些更改可能会导致重大版本颠簸,而对这些更改的要求可能会完全阻止这些图表上的其他开发,直到完成为止. - -要快速查看它们映射到的`gitlab`图表版本和 GitLab 版本的完整列表,请对[Helm](installation/tools.html#helm)发出以下命令: - -``` -helm repo add gitlab https://charts.gitlab.io/ -helm search repo -l gitlab/gitlab -``` - -**注意**对于 Helm v2,搜索命令将为`helm search -l gitlab/gitlab` - -有关更多信息,请访问[版本映射 docs](installation/version_mappings.html) . - -### Contributing[](#contributing "Permalink") - -除了我们的[贡献准则](https://gitlab.com/gitlab-org/charts/gitlab/tree/master/CONTRIBUTING.md)之外,请参阅[开发者文档](development/index.html)以了解如何对 GitLab 图表[做出贡献](https://gitlab.com/gitlab-org/charts/gitlab/tree/master/CONTRIBUTING.md) . \ No newline at end of file diff --git a/_book/docs/007.md b/_book/docs/007.md deleted file mode 100644 index 1465da9585ee471ca3bd3eaed42a06e3ea53ff7d..0000000000000000000000000000000000000000 --- a/_book/docs/007.md +++ /dev/null @@ -1,26 +0,0 @@ -# Install GitLab with Docker - -> 原文:[https://docs.gitlab.com/ee/install/docker.html](https://docs.gitlab.com/ee/install/docker.html) - -* [Omnibus GitLab based images](#omnibus-gitlab-based-images) -* [Cloud native images](#cloud-native-images) - -# Install GitLab with Docker[](#install-gitlab-with-docker "Permalink") - -在过去的几年中, [Docker](https://www.docker.com)和容器技术一直在改变软件世界. 它们将本地执行的性能和效率与虚拟化的抽象性,安全性和不变性结合在一起. - -GitLab 提供了官方的 Docker 映像,使您可以在操作 GitLab 实例时轻松利用容器化的优势. - -## Omnibus GitLab based images[](#omnibus-gitlab-based-images "Permalink") - -GitLab 基于我们的[Omnibus GitLab 软件包](https://docs.gitlab.com/omnibus/README.html)维护了一组[正式的 Docker 映像](https://hub.docker.com/u/gitlab) . 这些图像包括: - -* [GitLab Community Edition](https://hub.docker.com/r/gitlab/gitlab-ce/) -* [GitLab Enterprise Edition](https://hub.docker.com/r/gitlab/gitlab-ee/) -* [GitLab Runner](https://hub.docker.com/r/gitlab/gitlab-runner/) - -提供了有关这些映像的[完整用法指南](https://docs.gitlab.com/omnibus/docker/) ,以及[用于构建映像](https://gitlab.com/gitlab-org/omnibus-gitlab/tree/master/docker)的[Dockerfile](https://gitlab.com/gitlab-org/omnibus-gitlab/tree/master/docker) . - -## Cloud native images[](#cloud-native-images "Permalink") - -manbetx 客户端打不开也正在努力向[容器](https://docs.gitlab.com/charts/)的[云本机集,](https://docs.gitlab.com/charts/)每个组件服务具有单个映像. 我们打算将这些图像最终替换为[基于 Omnibus GitLab 的图像](#omnibus-gitlab-based-images) . \ No newline at end of file diff --git a/_book/docs/008.md b/_book/docs/008.md deleted file mode 100644 index 6d91a29ea7ca76107f3c10e1534839edf4189a68..0000000000000000000000000000000000000000 --- a/_book/docs/008.md +++ /dev/null @@ -1,1010 +0,0 @@ -# Installation from source - -> 原文:[https://docs.gitlab.com/ee/install/installation.html](https://docs.gitlab.com/ee/install/installation.html) - -* [Consider the Omnibus package installation](#consider-the-omnibus-package-installation) -* [Select a version to install](#select-a-version-to-install) -* [GitLab directory structure](#gitlab-directory-structure) -* [Overview](#overview) -* [1\. Packages and dependencies](#1-packages-and-dependencies) -* [2\. Ruby](#2-ruby) -* [3\. Go](#3-go) -* [4\. Node](#4-node) -* [5\. System users](#5-system-users) -* [6\. Database](#6-database) -* [7\. Redis](#7-redis) -* [8\. GitLab](#8-gitlab) - * [Clone the Source](#clone-the-source) - * [Configure It](#configure-it) - * [Configure GitLab DB Settings](#configure-gitlab-db-settings) - * [Install Gems](#install-gems) - * [Install GitLab Shell](#install-gitlab-shell) - * [Install GitLab Workhorse](#install-gitlab-workhorse) - * [Install GitLab-Elasticsearch-indexer on Enterprise Edition](#install-gitlab-elasticsearch-indexer-on-enterprise-edition) - * [Install GitLab Pages](#install-gitlab-pages) - * [Install Gitaly](#install-gitaly) - * [Start Gitaly](#start-gitaly) - * [Initialize Database and Activate Advanced Features](#initialize-database-and-activate-advanced-features) - * [Secure secrets.yml](#secure-secretsyml) - * [Install Init Script](#install-init-script) - * [Set up Logrotate](#set-up-logrotate) - * [Check Application Status](#check-application-status) - * [Compile GetText PO files](#compile-gettext-po-files) - * [Compile Assets](#compile-assets) - * [Start Your GitLab Instance](#start-your-gitlab-instance) -* [9\. NGINX](#9-nginx) - * [Installation](#installation) - * [Site Configuration](#site-configuration) - * [Test Configuration](#test-configuration) - * [Restart](#restart) -* [Post-install](#post-install) - * [Double-check Application Status](#double-check-application-status) - * [Initial Login](#initial-login) -* [Advanced Setup Tips](#advanced-setup-tips) - * [Relative URL support](#relative-url-support) - * [Using HTTPS](#using-https) - * [Enable Reply by email](#enable-reply-by-email) - * [LDAP Authentication](#ldap-authentication) - * [Using Custom OmniAuth Providers](#using-custom-omniauth-providers) - * [Build your projects](#build-your-projects) - * [Adding your Trusted Proxies](#adding-your-trusted-proxies) - * [Custom Redis Connection](#custom-redis-connection) - * [Custom SSH Connection](#custom-ssh-connection) - * [Additional Markup Styles](#additional-markup-styles) - * [Using Unicorn](#using-unicorn) - * [Using Sidekiq instead of Sidekiq Cluster](#using-sidekiq-instead-of-sidekiq-cluster) -* [Troubleshooting](#troubleshooting) - * [“You appear to have cloned an empty repository.”](#you-appear-to-have-cloned-an-empty-repository) - * [`google-protobuf` “LoadError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14’ not found”](#google-protobuf-loaderror-libx86_64-linux-gnulibcso6-version-glibc_214-not-found) - -# Installation from source[](#installation-from-source "Permalink") - -这是使用源文件设置生产 GitLab 服务器的官方安装指南. 要设置**开发安装**或许多其他安装选项,请参见[主要安装页面](README.html) . 它是为**Debian / Ubuntu**操作系统创建并经过测试的. 有关硬件和操作系统[要求](requirements.html) ,请阅读 requirements.md. 如果要在 RHEL / CentOS 上安装,我们建议使用[Omnibus 软件包](https://about.gitlab.com/install/) . - -本指南之所以冗长,是因为它涵盖了许多情况,并且包括您需要的所有命令,这是[实际上可以立即使用的少数安装脚本之一](https://twitter.com/robinvdvleuten/status/424163226532986880) . 已知以下步骤有效. **偏离**本指南**时请多加注意** . 确保您没有违反任何有关 GitLab 对其环境的假设. 例如,许多人遇到权限问题,因为他们更改了目录的位置或以错误的用户身份运行服务. - -如果您在本指南中发现错误/错误, **请**按照[提供帮助的指南](https://gitlab.com/gitlab-org/gitlab/blob/master/CONTRIBUTING.md) **提交合并请求** . - -## Consider the Omnibus package installation[](#consider-the-omnibus-package-installation "Permalink") - -由于从源头进行安装需要大量工作并且容易出错,因此我们强烈建议您快速,可靠地[安装 Omnibus 软件包](https://about.gitlab.com/install/) (deb / rpm). - -Omnibus 软件包更可靠的原因之一是它使用 runit 来重新启动任何 GitLab 进程,以防万一崩溃. 在频繁使用的 GitLab 实例上,Sidekiq 后台工作程序的内存使用量会随着时间增长. - -Omnibus 软件包通过[使 Sidekiq](../administration/operations/sidekiq_memory_killer.html)在使用过多内存的情况下[正常终止来](../administration/operations/sidekiq_memory_killer.html)解决此问题. 在此终止后,runit 将检测到 Sidekiq 没有运行并启动它. 由于从源头进行的安装不使用 runit 进行过程监视,因此 Sidekiq 无法终止,并且其内存使用量会随着时间的推移而增长. - -## Select a version to install[](#select-a-version-to-install "Permalink") - -确保从您要安装的 GitLab 的分支(版本)中查看[此安装指南](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/install/installation.md) (例如`11-7-stable` ). 您可以在 GitLab 左上角的版本下拉菜单中选择分支(位于菜单栏下方). - -如果不清楚最高数目的稳定分支,请查看[GitLab 博客](https://about.gitlab.com/blog/)以获取版本信息. - -## GitLab directory structure[](#gitlab-directory-structure "Permalink") - -这是主要的目录结构,您将按照此页面的说明进行操作: - -``` -|-- home -| |-- git -| |-- .ssh -| |-- gitlab -| |-- gitlab-shell -| |-- repositories -``` - -* `/home/git/.ssh`包含 OpenSSH 设置. 具体来说,由 GitLab Shell 管理的`authorized_keys`文件. -* `/home/git/gitlab` -GitLab 核心软件. -* `/home/git/gitlab-shell` -GitLab 的核心附加组件. 维护 SSH 克隆和其他功能. -* `/home/git/repositories`按名称空间组织的所有项目的裸存储库. 这是为所有项目维护推/拉的 Git 存储库的地方. **该区域包含项目的关键数据.** **[保持备份](../raketasks/backup_restore.html) .** - -**注意:**可以在 GitLab 的`config/gitlab.yml`和 GitLab Shell 的`config.yml`中`config/gitlab.yml`存储库的默认位置. - -有关更深入的概述,请参阅[GitLab 体系结构文档](../development/architecture.html) . - -## Overview[](#overview "Permalink") - -GitLab 安装包括设置以下组件: - -1. [Packages and dependencies](#1-packages-and-dependencies). -2. [Ruby](#2-ruby). -3. [Go](#3-go). -4. [Node](#4-node). -5. [System users](#5-system-users). -6. [Database](#6-database). -7. [Redis](#7-redis). -8. [GitLab](#8-gitlab). -9. [NGINX](#9-nginx). - -## 1\. Packages and dependencies[](#1-packages-and-dependencies "Permalink") - -默认情况下,Debian 上未安装`sudo` . 确保您的系统是最新的并安装. - -``` -# run as root! -apt-get update -y -apt-get upgrade -y -apt-get install sudo -y -``` - -**注意:**在此安装过程中,将需要手动编辑某些文件. 如果您熟悉 vim,请使用以下命令将其设置为默认编辑器. 如果您不熟悉 vim,请跳过此步骤并继续使用默认编辑器. - -``` -# Install vim and set as default editor -sudo apt-get install -y vim -sudo update-alternatives --set editor /usr/bin/vim.basic -``` - -安装所需的软件包(需要编译 Ruby 和 Ruby gem 的本机扩展): - -``` -sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libre2-dev \ - libreadline-dev libncurses5-dev libffi-dev curl openssh-server checkinstall libxml2-dev \ - libxslt-dev libcurl4-openssl-dev libicu-dev logrotate rsync python-docutils pkg-config cmake \ - runit -``` - -Ubuntu 14.04(Trusty `libre2-dev` )没有可用的`libre2-dev`软件包,但您可以[手动安装 re2](https://github.com/google/re2/wiki/Install) . - -如果要使用 Kerberos 进行用户身份验证,请安装`libkrb5-dev` : - -``` -sudo apt-get install libkrb5-dev -``` - -**注意:**如果您不知道 Kerberos 是什么,则可以假定您不需要它. - -确保您安装了正确的 Git 版本: - -``` -# Install Git -sudo apt-get install -y git-core - -# Make sure Git is version 2.27.0 or higher (minimal supported version is 2.25.0) -git --version -``` - -从 GitLab 12.0 开始,需要使用`libpcre2`编译 Git. 找出是否是这种情况: - -``` -ldd $(command -v git) | grep pcre2 -``` - -输出应包含`libpcre2-8.so.0` . - -系统打包的 Git 是否过旧,或者未使用 pcre2 编译? 去掉它: - -``` -sudo apt-get remove git-core -``` - -在 Ubuntu 上, [从其官方 PPA](https://git-scm.com/download/linux)安装 Git: - -``` -# run as root! -add-apt-repository ppa:git-core/ppa -apt update -apt install git -# repeat libpcre2 check as above -``` - -在 Debian 上,使用以下编译说明: - -``` -# Install dependencies -sudo apt-get install -y libcurl4-openssl-dev libexpat1-dev gettext libz-dev libssl-dev build-essential - -# Download and compile pcre2 from source -curl --silent --show-error --location https://ftp.pcre.org/pub/pcre/pcre2-10.33.tar.gz --output pcre2.tar.gz -tar -xzf pcre2.tar.gz -cd pcre2-10.33 -chmod +x configure -./configure --prefix=/usr --enable-jit -make -sudo make install - -# Download and compile from source -cd /tmp -curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.27.0.tar.gz -echo '77ded85cbe42b1ffdc2578b460a1ef5d23bcbc6683eabcafbb0d394dffe2e787 git-2.27.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.27.0.tar.gz -cd git-2.27.0/ -./configure --with-libpcre -make prefix=/usr/local all - -# Install into /usr/local/bin -sudo make prefix=/usr/local install - -# When editing config/gitlab.yml later, change the git -> bin_path to /usr/local/bin/git -``` - -为了使[自定义图标](../user/admin_area/appearance.html#favicon)能够正常工作,需要安装 GraphicsMagick. - -``` -sudo apt-get install -y graphicsmagick -``` - -**注意:**为了接收邮件通知,请确保安装邮件服务器. 默认情况下,Debian 随 exim4 一起提供,但这[会带来问题,](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/12754)而 Ubuntu 则没有. 推荐的邮件服务器是 postfix,您可以使用以下命令进行安装: - -``` -sudo apt-get install -y postfix -``` - -然后选择" Internet Site",然后按 Enter 确认主机名. - -[GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse#dependencies)需要使用`exiftool`才能从上传的图像中删除 EXIF 数据. - -``` -sudo apt-get install -y libimage-exiftool-perl -``` - -## 2\. Ruby[](#2-ruby "Permalink") - -运行 GitLab 需要使用 Ruby 解释器. - -**注意:**当前支持的 Ruby(MRI)版本是 2.6.x. GitLab 12.2 放弃了对 Ruby 2.5.x 的支持. - -在生产环境[中将](https://github.com/rbenv/rbenv) Ruby 版本管理器(如[RVM](https://rvm.io/) , [rbenv](https://github.com/rbenv/rbenv)或[chruby)](https://github.com/postmodern/chruby)与 GitLab [一起](https://github.com/postmodern/chruby)使用通常会导致难以诊断问题. 不支持版本管理器,我们强烈建议所有人按照以下说明使用系统 Ruby. - -Linux 发行版通常提供较旧版本的 Ruby,因此这些说明旨在从官方源代码安装 Ruby. - -删除旧的 Ruby 1.8(如果存在): - -``` -sudo apt-get remove ruby1.8 -``` - -下载 Ruby 并进行编译: - -``` -mkdir /tmp/ruby && cd /tmp/ruby -curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.6.tar.gz -echo '2d78048e293817f38d4ede4ebc7873013e97bb0b ruby-2.6.6.tar.gz' | shasum -c - && tar xzf ruby-2.6.6.tar.gz -cd ruby-2.6.6 - -./configure --disable-install-rdoc -make -sudo make install -``` - -然后安装 Bundler gem(低于 2.x 的版本): - -``` -sudo gem install bundler --no-document --version '< 2' -``` - -## 3\. Go[](#3-go "Permalink") - -从 GitLab 8.0 开始,GitLab 有几个用 Go 编写的守护程序. 要安装 GitLab,我们需要一个 Go 编译器. 以下说明假定您使用 64 位 Linux. 您可以在[Go 下载页面上](https://s0golang0org.icopy.site/dl)找到其他平台的[下载](https://s0golang0org.icopy.site/dl) . - -``` -# Remove former Go installation folder -sudo rm -rf /usr/local/go - -curl --remote-name --progress https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz -echo '512103d7ad296467814a6e3f635631bd35574cab3369a97a323c9a585ccaa569 go1.13.5.linux-amd64.tar.gz' | shasum -a256 -c - && \ - sudo tar -C /usr/local -xzf go1.13.5.linux-amd64.tar.gz -sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/ -rm go1.13.5.linux-amd64.tar.gz -``` - -## 4\. Node[](#4-node "Permalink") - -从 GitLab 8.17 开始,GitLab 需要使用 Node 来编译 JavaScript 资产,并使用 Yarn 来管理 JavaScript 依赖项. 当前的最低要求是: - -* `node` > = v10.13.0\. (我们建议使用节点 12.x,因为它速度更快) -* `yarn` > = v1.10.0. - -在许多发行版中,官方软件包存储库提供的版本已经过时,因此我们需要通过以下命令进行安装: - -``` -# install node v12.x -curl --location https://deb.nodesource.com/setup_12.x | sudo bash - -sudo apt-get install -y nodejs - -curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - -echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list -sudo apt-get update -sudo apt-get install yarn -``` - -如果您对这些步骤有任何疑问,请访问[node](https://s0nodejs0org.icopy.site/en/download/package-manager/)和[yarn](https://classic.yarnpkg.com/en/docs/install/)的官方网站. - -## 5\. System users[](#5-system-users "Permalink") - -为 GitLab 创建一个`git`用户: - -``` -sudo adduser --disabled-login --gecos 'GitLab' git -``` - -## 6\. Database[](#6-database "Permalink") - -**注意:**从 GitLab 12.1 开始,仅支持 PostgreSQL. 从 GitLab 13.0 开始,我们需要 PostgreSQL 11+. - -1. 安装数据库软件包: - - ``` - sudo apt-get install -y postgresql postgresql-client libpq-dev postgresql-contrib - ``` - -2. 启动 PostgreSQL 服务并确认该服务正在运行: - - ``` - sudo service postgresql start - sudo service postgresql status - ``` - -3. 为 GitLab 创建数据库用户: - - ``` - sudo -u postgres psql -d template1 -c "CREATE USER git CREATEDB;" - ``` - -4. 创建`pg_trgm`扩展(GitLab 8.6+必需): - - ``` - sudo -u postgres psql -d template1 -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;" - ``` - -5. 创建 GitLab 生产数据库并授予该数据库的所有特权: - - ``` - sudo -u postgres psql -d template1 -c "CREATE DATABASE gitlabhq_production OWNER git;" - ``` - -6. 尝试使用新用户连接到新数据库: - - ``` - sudo -u git -H psql -d gitlabhq_production - ``` - -7. 检查是否启用了`pg_trgm`扩展名: - - ``` - SELECT true AS enabled - FROM pg_available_extensions - WHERE name = 'pg_trgm' - AND installed_version IS NOT NULL; - ``` - - 如果启用了扩展名,将产生以下输出: - - ``` - enabled - --------- - t - (1 row) - ``` - -8. 退出数据库会话: - - ``` - gitlabhq_production> \q - ``` - -## 7\. Redis[](#7-redis "Permalink") - -GitLab 至少需要 Redis 5.0. - -如果您使用的是 Debian 10 或 Ubuntu 20.04 及更高版本,则可以使用以下命令安装 Redis 5.0: - -``` -sudo apt-get install redis-server -``` - -完成后,您可以配置 Redis: - -``` -# Configure redis to use sockets -sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.orig - -# Disable Redis listening on TCP by setting 'port' to 0 -sudo sed 's/^port .*/port 0/' /etc/redis/redis.conf.orig | sudo tee /etc/redis/redis.conf - -# Enable Redis socket for default Debian / Ubuntu path -echo 'unixsocket /var/run/redis/redis.sock' | sudo tee -a /etc/redis/redis.conf - -# Grant permission to the socket to all members of the redis group -echo 'unixsocketperm 770' | sudo tee -a /etc/redis/redis.conf - -# Create the directory which contains the socket -sudo mkdir -p /var/run/redis -sudo chown redis:redis /var/run/redis -sudo chmod 755 /var/run/redis - -# Persist the directory which contains the socket, if applicable -if [ -d /etc/tmpfiles.d ]; then echo 'd /var/run/redis 0755 redis redis 10d -' | sudo tee -a /etc/tmpfiles.d/redis.conf -fi - -# Activate the changes to redis.conf -sudo service redis-server restart - -# Add git to the redis group -sudo usermod -aG redis git -``` - -## 8\. GitLab[](#8-gitlab "Permalink") - -``` -# We'll install GitLab into the home directory of the user "git" -cd /home/git -``` - -### Clone the Source[](#clone-the-source "Permalink") - -克隆社区版: - -``` -# Clone GitLab repository -sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-foss.git -b X-Y-stable gitlab -``` - -克隆企业版: - -``` -# Clone GitLab repository -sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ee.git -b X-Y-stable gitlab -``` - -确保用与要安装的版本匹配的稳定分支替换`XY-stable` . 例如,如果要安装 11.8,则可以使用分支名称`11-8-stable` . - -**注意:**您可以更改`XY-stable` ,以`master` ,如果你想最*前沿*的版本,但从来没有安装`master`在生产服务器上! - -### Configure It[](#configure-it "Permalink") - -``` -# Go to GitLab installation folder -cd /home/git/gitlab - -# Copy the example GitLab config -sudo -u git -H cp config/gitlab.yml.example config/gitlab.yml - -# Update GitLab config file, follow the directions at top of the file -sudo -u git -H editor config/gitlab.yml - -# Copy the example secrets file -sudo -u git -H cp config/secrets.yml.example config/secrets.yml -sudo -u git -H chmod 0600 config/secrets.yml - -# Make sure GitLab can write to the log/ and tmp/ directories -sudo chown -R git log/ -sudo chown -R git tmp/ -sudo chmod -R u+rwX,go-w log/ -sudo chmod -R u+rwX tmp/ - -# Make sure GitLab can write to the tmp/pids/ and tmp/sockets/ directories -sudo chmod -R u+rwX tmp/pids/ -sudo chmod -R u+rwX tmp/sockets/ - -# Create the public/uploads/ directory -sudo -u git -H mkdir -p public/uploads/ - -# Make sure only the GitLab user has access to the public/uploads/ directory -# now that files in public/uploads are served by gitlab-workhorse -sudo chmod 0700 public/uploads - -# Change the permissions of the directory where CI job logs are stored -sudo chmod -R u+rwX builds/ - -# Change the permissions of the directory where CI artifacts are stored -sudo chmod -R u+rwX shared/artifacts/ - -# Change the permissions of the directory where GitLab Pages are stored -sudo chmod -R ug+rwX shared/pages/ - -# Copy the example Puma config -sudo -u git -H cp config/puma.rb.example config/puma.rb - -# Refer to https://github.com/puma/puma#configuration for more information. -# You should scale Puma workers and threads based on the number of CPU -# cores you have available. You can get that number via the `nproc` command. -sudo -u git -H editor config/puma.rb - -# Copy the example Rack attack config -sudo -u git -H cp config/initializers/rack_attack.rb.example config/initializers/rack_attack.rb - -# Configure Git global settings for git user -# 'autocrlf' is needed for the web editor -sudo -u git -H git config --global core.autocrlf input - -# Disable 'git gc --auto' because GitLab already runs 'git gc' when needed -sudo -u git -H git config --global gc.auto 0 - -# Enable packfile bitmaps -sudo -u git -H git config --global repack.writeBitmaps true - -# Enable push options -sudo -u git -H git config --global receive.advertisePushOptions true - -# Enable fsyncObjectFiles to reduce risk of repository corruption if the server crashes -sudo -u git -H git config --global core.fsyncObjectFiles true - -# Configure Redis connection settings -sudo -u git -H cp config/resque.yml.example config/resque.yml - -# Change the Redis socket path if you are not using the default Debian / Ubuntu configuration -sudo -u git -H editor config/resque.yml -``` - -**注意:**请确保同时编辑`gitlab.yml`和`puma.rb`以匹配您的设置. 如果要使用 Unicorn Web 服务器,请参阅" [使用 Unicorn"](#using-unicorn)以了解其他步骤.**注意:**如果要使用 HTTPS,请参阅" [使用 HTTPS"](#using-https)以了解其他步骤. - -### Configure GitLab DB Settings[](#configure-gitlab-db-settings "Permalink") - -``` -sudo -u git cp config/database.yml.postgresql config/database.yml - -# Remove host, username, and password lines from config/database.yml. -# Once modified, the `production` settings will be as follows: -# -# production: -# adapter: postgresql -# encoding: unicode -# database: gitlabhq_production -# pool: 10 -# -sudo -u git -H editor config/database.yml - -# Remote PostgreSQL only: -# Update username/password in config/database.yml. -# You only need to adapt the production settings (first part). -# If you followed the database guide then please do as follows: -# Change 'secure password' with the value you have given to $password -# You can keep the double quotes around the password -sudo -u git -H editor config/database.yml - -# Make config/database.yml readable to git only -sudo -u git -H chmod o-rwx config/database.yml -``` - -### Install Gems[](#install-gems "Permalink") - -**注意:**从 Bundler 1.5.2 开始,您可以调用`bundle install -jN` (其中`N`是您的处理器内核数)并享受并行 gem 的安装,其完成时间有可衡量的差异(快 60%). 使用`nproc`检查您的内核数. 有关更多信息,请参见这篇[文章](https://thoughtbot.com/blog/parallel-gem-installing-using-bundler) . - -确保您有`bundle` (运行`bundle -v` ): - -* `>= 1.5.2` ,因为某些[问题](https://devcenter.heroku.com/changelog-items/411)已在 1.5.2 中[修复](https://github.com/rubygems/bundler/pull/2817) . -* `< 2.x`. - -``` -sudo -u git -H bundle install --deployment --without development test mysql aws kerberos -``` - -**注意:**如果要使用 Kerberos 进行用户身份验证,请在上面的`--without`选项中省略`kerberos` . - -### Install GitLab Shell[](#install-gitlab-shell "Permalink") - -GitLab Shell 是专门为 GitLab 开发的 SSH 访问和存储库管理软件. - -``` -# Run the installation task for gitlab-shell: -sudo -u git -H bundle exec rake gitlab:shell:install RAILS_ENV=production - -# By default, the gitlab-shell config is generated from your main GitLab config. -# You can review (and modify) the gitlab-shell config as follows: -sudo -u git -H editor /home/git/gitlab-shell/config.yml -``` - -**注意:**如果要使用 HTTPS,请参阅" [使用 HTTPS"](#using-https)以了解其他步骤.**注意:**确保您的主机名可以通过正确的 DNS 记录或`/etc/hosts`的其他行(" 127.0.0.1 主机名")在计算机上解析. 例如,如果您在反向代理后面设置了 GitLab,则可能有必要. 如果无法解析主机名,则最终安装检查将失败,并具有`Check GitLab API access: FAILED. code: 401` `Check GitLab API access: FAILED. code: 401`和推送提交将通过`[remote rejected] master -> master (hook declined)` . - -### Install GitLab Workhorse[](#install-gitlab-workhorse "Permalink") - -GitLab-Workhorse 使用[GNU Make](https://www.gnu.org/software/make/) . 以下命令行将在建议的位置`/home/git/gitlab-workhorse`安装 GitLab-Workhorse. - -``` -sudo -u git -H bundle exec rake "gitlab:workhorse:install[/home/git/gitlab-workhorse]" RAILS_ENV=production -``` - -您可以通过提供其他参数来指定其他 Git 存储库: - -``` -sudo -u git -H bundle exec rake "gitlab:workhorse:install[/home/git/gitlab-workhorse,https://example.com/gitlab-workhorse.git]" RAILS_ENV=production -``` - -### Install GitLab-Elasticsearch-indexer on Enterprise Edition[](#install-gitlab-elasticsearch-indexer-on-enterprise-edition "Permalink") - -GitLab-Elasticsearch-Indexer 使用[GNU Make](https://www.gnu.org/software/make/) . 以下命令行将在推荐位置`/home/git/gitlab-elasticsearch-indexer`中安装 GitLab-Elasticsearch-Indexer. - -``` -sudo -u git -H bundle exec rake "gitlab:indexer:install[/home/git/gitlab-elasticsearch-indexer]" RAILS_ENV=production -``` - -您可以通过提供其他参数来指定其他 Git 存储库: - -``` -sudo -u git -H bundle exec rake "gitlab:indexer:install[/home/git/gitlab-elasticsearch-indexer,https://example.com/gitlab-elasticsearch-indexer.git]" RAILS_ENV=production -``` - -首先将源代码提取到第一个参数指定的路径. 然后,将在其`bin`目录下构建一个二进制文件. 然后,您将需要更新`gitlab.yml`的`production -> elasticsearch -> indexer_path`设置以指向该二进制文件. - -**注意:** Elasticsearch 是 GitLab 企业版的一项功能,不包含在 GitLab 社区版中. - -### Install GitLab Pages[](#install-gitlab-pages "Permalink") - -GitLab Pages 使用[GNU Make](https://www.gnu.org/software/make/) . 此步骤是可选的,仅当您希望在 GitLab 中托管静态站点时才需要. 以下命令将在`/home/git/gitlab-pages`安装 GitLab `/home/git/gitlab-pages` . 有关其他设置步骤,请查阅适用于您的 GitLab 版本的[管理指南](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/administration/pages/source.md) ,因为 GitLab Pages 守护程序可以通过几种不同的方式运行. - -``` -cd /home/git -sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-pages.git -cd gitlab-pages -sudo -u git -H git checkout v$(> $gitlab_path/log/gitaly.log 2>&1 &" -``` - -### Initialize Database and Activate Advanced Features[](#initialize-database-and-activate-advanced-features "Permalink") - -``` -cd /home/git/gitlab -sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production -# Type 'yes' to create the database tables. - -# or you can skip the question by adding force=yes -sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production force=yes - -# When done, you see 'Administrator account created:' -``` - -**注意:**您可以通过分别在环境变量`GITLAB_ROOT_PASSWORD`和`GITLAB_ROOT_EMAIL`提供管理员/ root 密码和电子邮件来设置它们,如下所示. 如果您未设置密码(并且密码已设置为默认密码),请等待 GitLab 暴露在公共互联网上,直到安装完成并且您已首次登录服务器. 首次登录时,将被迫更改默认密码. 通过在`GITLAB_LICENSE_FILE`环境变量中提供完整路径,此时也可以安装 Enterprise Edition 许可证. - -``` -sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production GITLAB_ROOT_PASSWORD=yourpassword GITLAB_ROOT_EMAIL=youremail GITLAB_LICENSE_FILE="/path/to/license" -``` - -### Secure secrets.yml[](#secure-secretsyml "Permalink") - -`secrets.yml`文件存储会话和安全变量的加密密钥. 备份`secrets.yml`安全保存,但是请不要将其与数据库备份存储在同一位置. 否则,如果其中一个备份遭到破坏,您的秘密就会暴露出来. - -### Install Init Script[](#install-init-script "Permalink") - -下载初始化脚本(将为`/etc/init.d/gitlab` ): - -``` -sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab -``` - -而且,如果要使用非默认文件夹或用户安装,请复制并编辑默认文件: - -``` -sudo cp lib/support/init.d/gitlab.default.example /etc/default/gitlab -``` - -如果将 GitLab 安装在其他目录中或以默认用户以外的用户身份安装,则应在`/etc/default/gitlab`更改这些设置. 不要编辑`/etc/init.d/gitlab`因为它将在升级时更改. - -使 GitLab 在启动时启动: - -``` -sudo update-rc.d gitlab defaults 21 -``` - -### Set up Logrotate[](#set-up-logrotate "Permalink") - -``` -sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab -``` - -### Check Application Status[](#check-application-status "Permalink") - -检查 GitLab 及其环境是否配置正确: - -``` -sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production -``` - -### Compile GetText PO files[](#compile-gettext-po-files "Permalink") - -``` -sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production -``` - -### Compile Assets[](#compile-assets "Permalink") - -``` -sudo -u git -H yarn install --production --pure-lockfile -sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production NODE_ENV=production -``` - -如果`rake`因`JavaScript heap out of memory`不足错误而失败,请尝试按如下所示设置`NODE_OPTIONS`来运行它. - -``` -sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production NODE_ENV=production NODE_OPTIONS="--max_old_space_size=4096" -``` - -### Start Your GitLab Instance[](#start-your-gitlab-instance "Permalink") - -``` -sudo service gitlab start -# or -sudo /etc/init.d/gitlab restart -``` - -## 9\. NGINX[](#9-nginx "Permalink") - -**注意:** NGINX 是 GitLab 官方支持的 Web 服务器. 如果您不能或不想将 NGINX 用作 Web 服务器,请参阅[GitLab 配方](https://gitlab.com/gitlab-org/gitlab-recipes/) . - -### Installation[](#installation "Permalink") - -``` -sudo apt-get install -y nginx -``` - -### Site Configuration[](#site-configuration "Permalink") - -复制示例站点配置: - -``` -sudo cp lib/support/nginx/gitlab /etc/nginx/sites-available/gitlab -sudo ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab -``` - -确保编辑配置文件以匹配您的设置. 另外,请确保您与 GitLab 的路径匹配,尤其是在为`git`用户以外的用户安装时: - -``` -# Change YOUR_SERVER_FQDN to the fully-qualified -# domain name of your host serving GitLab. -# -# Remember to match your paths to GitLab, especially -# if installing for a user other than 'git'. -# -# If using Ubuntu default nginx install: -# either remove the default_server from the listen line -# or else sudo rm -f /etc/nginx/sites-enabled/default -sudo editor /etc/nginx/sites-available/gitlab -``` - -如果您打算启用 GitLab 页面,则需要使用一个单独的 NGINX 配置. 在[GitLab 页面管理指南中](../administration/pages/index.html)阅读有关所需配置的所有信息. - -**注意:**如果要使用 HTTPS,请将`gitlab` NGINX 配置替换为`gitlab-ssl` . 有关 HTTPS 配置的详细信息,请参见[使用 HTTPS](#using-https) . - -### Test Configuration[](#test-configuration "Permalink") - -使用以下命令验证`gitlab`或`gitlab-ssl` NGINX 配置文件: - -``` -sudo nginx -t -``` - -您应该会收到`syntax is okay`并且`test is successful`消息. 如果收到错误,请按照给出的错误消息中的说明检查`gitlab`或`gitlab-ssl` NGINX 配置文件是否有错别字等. - -**注意:**通过运行`nginx -v`验证安装的版本是否大于 1.12.1\. 如果它较低,您可能会收到以下错误: `nginx: [emerg] unknown "start$temp=[filtered]$rest" variable nginx: configuration file /etc/nginx/nginx.conf test failed` - -### Restart[](#restart "Permalink") - -``` -sudo service nginx restart -``` - -## Post-install[](#post-install "Permalink") - -### Double-check Application Status[](#double-check-application-status "Permalink") - -为了确保您不会错过任何东西,请使用以下命令进行更彻底的检查: - -``` -sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production -``` - -如果所有项目均为绿色,则恭喜您成功安装了 GitLab! - -向`gitlab:check`提供`SANITIZE=true`环境变量,以从 check 命令的输出中省略项目名称. - -### Initial Login[](#initial-login "Permalink") - -在您的 Web 浏览器中访问 YOUR_SERVER 进行首次 GitLab 登录. - -如果[在设置过程中](#initialize-database-and-activate-advanced-features)未[提供 root 密码,](#initialize-database-and-activate-advanced-features)则将重定向到密码重置屏幕,以提供初始管理员帐户的密码. 输入所需的密码,您将被重定向回登录屏幕. - -默认帐户的用户名是**root** . 提供您先前创建的密码并登录. 登录后,您可以根据需要更改用户名. - -**Enjoy!** - -You can use `sudo service gitlab start` and `sudo service gitlab stop` to start and stop GitLab. - -## Advanced Setup Tips[](#advanced-setup-tips "Permalink") - -### Relative URL support[](#relative-url-support "Permalink") - -有关如何使用相对 URL 配置 GitLab 的更多信息,请参见[相对 URL 文档](relative_url.html) . - -### Using HTTPS[](#using-https "Permalink") - -要将 GitLab 与 HTTPS 一起使用: - -1. In `gitlab.yml`: - 1. 将第 1 节中的`port`选项设置为`443` . - 2. 将第 1 节中的`https`选项设置为`true` . -2. 在 GitLab Shell 的`config.yml`中: - 1. 将`gitlab_url`选项设置为 GitLab 的 HTTPS 端点(例如`https://git.example.com` ). - 2. 使用`ca_file`或`ca_path`选项设置证书. -3. 使用`gitlab-ssl` NGINX 示例配置,而不是`gitlab`配置. - 1. 更新`YOUR_SERVER_FQDN` . - 2. 更新`ssl_certificate`和`ssl_certificate_key` . - 3. 查看配置文件,并考虑应用其他安全性和性能增强功能. - -不鼓励使用自签名证书,但如果必须使用它,请遵循正常说明. 然后: - -1. 生成自签名 SSL 证书: - - ``` - mkdir -p /etc/nginx/ssl/ - cd /etc/nginx/ssl/ - sudo openssl req -newkey rsa:2048 -x509 -nodes -days 3560 -out gitlab.crt -keyout gitlab.key - sudo chmod o-r gitlab.key - ``` - -2. 在 GitLab Shell 的`config.yml` ,将`self_signed_cert`设置为`true` . - -### Enable Reply by email[](#enable-reply-by-email "Permalink") - -有关如何进行此设置的更多信息,请参见["通过电子邮件答复"文档](../administration/reply_by_email.html) . - -### LDAP Authentication[](#ldap-authentication "Permalink") - -您可以在`config/gitlab.yml`配置 LDAP 身份验证. 编辑此文件后,重新启动 GitLab. - -### Using Custom OmniAuth Providers[](#using-custom-omniauth-providers "Permalink") - -请参阅[OmniAuth 集成文档](../integration/omniauth.html) . - -### Build your projects[](#build-your-projects "Permalink") - -GitLab 可以构建您的项目. 要启用该功能,您需要 GitLab Runners 为您执行此操作. 请参阅[GitLab Runner 部分](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/#gitlab-runner)进行安装. - -### Adding your Trusted Proxies[](#adding-your-trusted-proxies "Permalink") - -如果要在单独的计算机上使用反向代理,则可能要将代理添加到"受信任的代理"列表中. 否则,用户将显示为从代理的 IP 地址登录. - -您可以通过自定义第 1 节中的`trusted_proxies`选项在`config/gitlab.yml`添加受信任的代理.保存文件并[重新配置 GitLab,](../administration/restart_gitlab.html)以使更改生效. - -### Custom Redis Connection[](#custom-redis-connection "Permalink") - -如果您想通过非标准端口或其他主机连接到 Redis 服务器,则可以通过`config/resque.yml`文件配置其连接字符串. - -``` -# example -production: - url: redis://redis.example.tld:6379 -``` - -如果要通过套接字连接 Redis 服务器,请使用" unix:" URL 方案以及`config/resque.yml`文件中 Redis 套接字文件的路径. - -``` -# example -production: - url: unix:/path/to/redis/socket -``` - -另外,您可以在`config/resque.yml`文件中使用环境变量: - -``` -# example -production: - url: <%= ENV.fetch('GITLAB_REDIS_URL') %> -``` - -### Custom SSH Connection[](#custom-ssh-connection "Permalink") - -如果您在非标准端口上运行 SSH,则必须更改 GitLab 用户的 SSH 配置. - -``` -# Add to /home/git/.ssh/config -host localhost # Give your setup a name (here: override localhost) - user git # Your remote git user - port 2222 # Your port number - hostname 127.0.0.1; # Your server name or IP -``` - -您还需要在`config\gitlab.yml`文件中更改相应的选项(例如`ssh_user` , `ssh_host` , `admin_uri` ). - -### Additional Markup Styles[](#additional-markup-styles "Permalink") - -除了始终支持的 Markdown 样式外,GitLab 还可以显示其他富文本文件. 但是您可能必须安装依赖项才能这样做. 有关更多信息,请参见[`github-markup` gem 自述文件](https://github.com/gitlabhq/markup#markups) . - -### Using Unicorn[](#using-unicorn "Permalink") - -从 GitLab 12.9 开始, [Puma](https://github.com/puma/puma)已取代 Unicorn 成为默认源安装 Web 服务器. 如果要切换回独角兽,请按照下列步骤操作: - -1. 完成 GitLab 设置,以使其启动并运行. -2. 将提供的示例 Unicorn 配置文件复制到位: - - ``` - cd /home/git/gitlab - - # Copy config file for the web server - sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb - ``` - -3. 编辑系统`init.d`脚本并设置`USE_WEB_SERVER="unicorn"` . 如果您有`/etc/default/gitlab` ,那么您应该对其进行编辑. -4. Restart GitLab. - -### Using Sidekiq instead of Sidekiq Cluster[](#using-sidekiq-instead-of-sidekiq-cluster "Permalink") - -从 GitLab 12.10 开始,Source 安装使用`bin/sidekiq-cluster`来管理 Sidekiq 进程. 在 14.0 之前,仍支持直接使用 Sidekiq. 因此,如果您遇到问题,请: - -1. 编辑系统`init.d`脚本以删除`SIDEKIQ_WORKERS`标志. 如果您有`/etc/default/gitlab` ,那么您应该对其进行编辑. -2. 重新启动 GitLab. -3. [创建一个](https://gitlab.com/gitlab-org/gitlab/-/issues/-/new)描述问题的问题. - -## Troubleshooting[](#troubleshooting "Permalink") - -### “You appear to have cloned an empty repository.”[](#you-appear-to-have-cloned-an-empty-repository "Permalink") - -如果在尝试克隆由 GitLab 托管的存储库时看到此消息,则可能是由于 NGINX 或 Apache 配置过时,或者缺少或配置了错误的 GitLab Workhorse 实例. 仔细检查您是否已[安装 Go](#3-go) , [已安装 GitLab Workhorse](#install-gitlab-workhorse)并已正确[配置 NGINX](#site-configuration) . - -### `google-protobuf` “LoadError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14’ not found”[](#google-protobuf-loaderror-libx86_64-linux-gnulibcso6-version-glibc_214-not-found "Permalink") - -对于某些版本的`google-protobuf` gem,这可能会在某些平台上发生. 解决方法是安装此 gem 的仅源版本. - -首先,您必须找到 GitLab 安装所需的`google-protobuf`确切版本: - -``` -cd /home/git/gitlab - -# Only one of the following two commands will print something. It -# will look like: * google-protobuf (3.2.0) -bundle list | grep google-protobuf -bundle check | grep google-protobuf -``` - -下面以`3.2.0`为例. 将其替换为您在上面找到的版本号: - -``` -cd /home/git/gitlab -sudo -u git -H gem install google-protobuf --version 3.2.0 --platform ruby -``` - -最后,您可以测试`google-protobuf`是否正确加载. 以下应打印"确定". - -``` -sudo -u git -H bundle exec ruby -rgoogle/protobuf -e 'puts :OK' -``` - -如果`gem install`命令失败,则可能需要安装操作系统的开发人员工具. - -在 Debian / Ubuntu 上: - -``` -sudo apt-get install build-essential libgmp-dev -``` - -在 RedHat / CentOS 上: - -``` -sudo yum groupinstall 'Development Tools' -``` \ No newline at end of file diff --git a/_book/docs/009.md b/_book/docs/009.md deleted file mode 100644 index 9d598f33ac273490e9dbaa468678d3d7e6b46394..0000000000000000000000000000000000000000 --- a/_book/docs/009.md +++ /dev/null @@ -1,345 +0,0 @@ -# Install GitLab on Microsoft Azure - -> 原文:[https://docs.gitlab.com/ee/install/azure/](https://docs.gitlab.com/ee/install/azure/) - -* [Getting started](#getting-started) -* [Working with Azure](#working-with-azure) -* [Create New VM](#create-new-vm) -* [Basics](#basics) -* [Size](#size) -* [Settings](#settings) -* [Purchase](#purchase) -* [Deployment](#deployment) -* [Set up a domain name](#set-up-a-domain-name) -* [Let’s open some ports](#lets-open-some-ports) - * [Which ports to open?](#which-ports-to-open) - * [Open HTTP on Port 80](#open-http-on-port-80) - * [Open SSH on Port 22](#open-ssh-on-port-22) -* [Connecting to GitLab](#connecting-to-gitlab) - * [Success?](#success) -* [Creating your first GitLab project](#creating-your-first-gitlab-project) -* [Maintaining your GitLab instance](#maintaining-your-gitlab-instance) - * [Checking our current version](#checking-our-current-version) - * [Connect via SSH](#connect-via-ssh) - * [SSH from the command-line](#ssh-from-the-command-line) - * [SSH from Windows (PuTTY)](#ssh-from-windows-putty) - * [Updating GitLab](#updating-gitlab) - * [Check out your updated GitLab](#check-out-your-updated-gitlab) -* [Conclusion](#conclusion) -* [Where to next?](#where-to-next) - * [Useful links](#useful-links) - -# Install GitLab on Microsoft Azure[](#install-gitlab-on-microsoft-azure "Permalink") - -Azure 是 Microsoft 的业务云,GitLab 是 Azure 市场上的预配置产品. 希望您不会惊讶地听到 Microsoft 和 Azure 接受了开源软件,例如 Ubuntu,Red Hat Enterprise Linux,当然还有 GitLab! 这意味着您可以启动预配置的 GitLab VM,并在 30 分钟左右启动并运行自己的私有 GitLab. 让我们开始吧. - -## Getting started[](#getting-started "Permalink") - -首先,您需要在 Azure 上拥有一个帐户. 有三种方法可以做到这一点: - -* 如果您的公司(或您)已经有一个帐户,那么您就可以开始了! -* 您还可以免费打开自己的 Azure 帐户. *在撰写本文时* ,您将获得 200 美元的信用额度,可用于 30 天的 Azure 服务支出. 您可以使用此信用额度试用付费的 Azure 服务,免费浏览 Microsoft 的云. 即使在开始的 30 天之后,您也无需支付任何费用,除非您决定转换为使用"按需付费" Azure 订阅的付费服务. 这是试用 Azure 和云计算的好方法,您可以[在其全面的 FAQ 中阅读更多内容](https://azure.microsoft.com/en-us/free/free-account-faq/) . -* 如果您具有 MSDN 订阅,则可以激活 Azure 订阅者权益. 您的 MSDN 订阅每月为您提供经常性的 Azure 信用,那么为什么不立即使用这些信用并尝试 GitLab 呢? - -## Working with Azure[](#working-with-azure "Permalink") - -Once you have an Azure account, you can get started. [Log in to Azure](https://portal.azure.com) and the first thing you will see is the Dashboard: - -[![Azure Dashboard](img/27f5db1ffe5c715ccd311bccf93665f2.png)](img/azure-dashboard.png) - -仪表板为您提供了 Azure 资源的快速概述,从这里您可以构建 VM,创建 SQL 数据库,创建网站以及执行许多其他云任务. - -## Create New VM[](#create-new-vm "Permalink") - -[Azure 市场](https://azuremarketplace.microsoft.com/en-us/marketplace/)是一个在线商店,用于存储预配置的应用程序和服务,这些软件和服务已由 GitLab 等软件供应商针对云进行了优化,可以在 Azure 市场上作为预配置的解决方案使用. 在本教程中,我们将安装 GitLab 社区版,但是对于 GitLab 企业版,您可以遵循相同的过程. - -要开始创建新的 GitLab VM,请单击**+新建**图标,在搜索框中键入" GitLab",然后单击**" GitLab Community Edition"**搜索结果: - -[![Azure - New - Search for 'GitLab'](img/3e0f74f35030a15b593a12090d5c0daf.png)](img/azure-new-search-gitlab.png) - -将会弹出一个新的"刀片"窗口,您可以在其中阅读有关 MIT Expat 许可免费提供的**" GitLab 社区版"**产品的更多信息: - -[![Azure - New - Select 'GitLab Community Edition'](img/0290c1013dba1b07f226f1548c8b6fd2.png)](img/azure-new-gitlab-ce.png) - -单击**"创建"** ,将显示"创建虚拟机"刀片: - -[![Azure - Create Virtual Machine - Basics](img/e4581843d51522e972a6bb6716aa4b05.png)](img/azure-create-virtual-machine-basics.png) - -## Basics[](#basics "Permalink") - -我们需要配置的第一项是基础虚拟机的基本设置: - -1. 输入虚拟机的`Name` -例如**" GitLab-CE"** -2. 选择一个`VM disk type` -无论是***HDD(**慢,成本更低)*或***SSD(**更快,更高成本)* -3. 输入`User name` -例如`gitlab-admin` -4. 选择一种`Authentication type` , **SSH 公钥**或**密码** : - - > **注意:**如果不确定要使用哪种身份验证类型,请选择**密码** - - 1. 如果您选择**SSH 公钥** -在提供的字段中输入`SSH public key` *(请阅读[SSH 文档,](../../ssh/README.html)以了解有关如何设置 SSH 公钥的更多信息)* - 2. 如果选择了**密码** -输入要使用*的密码(这是本教程后面将用于[SSH](https://en.wikipedia.org/wiki/Secure_Shell)到 VM 的密码,因此请确保它是一个强密码/密码)* -5. 为您的 Azure 帐户选择适当的`Subscription`层 -6. 选择一个现有的`Resource Group`或创建一个新的`Resource Group` -例如**" GitLab-CE-Azure"** - - > **注意:** "资源组"是一种将相关资源分组在一起以简化管理的方法. 我们选择了" GitLab-CE-Azure",但是您的资源组可以与 VM 具有相同的名称. - -7. 选择一个`Location` -如果不确定,请选择默认位置 - -这是我们使用的设置: - -[![Azure - Create Virtual Machine - Basics Completed](img/defc257dc0219b95ed3f3065afcaff94.png)](img/azure-create-virtual-machine-basics-password.png) - -检查您输入的设置,然后在准备好继续时单击**"确定"** . - -## Size[](#size "Permalink") - -接下来,您需要选择 VM 的大小-选择功能,例如 CPU 内核数,RAM 数量,存储大小(及其速度)等. - -> **注意:**与其他云供应商一样,Azure 运行资源/使用定价模型,即,VM 消耗的资源越多,运行成本就越高,因此请谨慎选择. 您会看到,Azure 提供了每个 VM 大小以下的*估计*每月费用,以帮助指导选择. - -默认大小-成本最低的**" DS1_V2 标准" VM-**满足运行测试和评估目的小型 GitLab 环境的最低系统要求,因此我们将继续选择该大小,但请选择大小最能满足您的要求: - -[![Azure - Create Virtual Machine - Size](img/f7bf9b7c134eb4ee2629082be8992d5a.png)](img/azure-create-virtual-machine-size.png) - -> **注意:请**注意,当您的 VM 处于活动状态(称为"已分配")时,将产生"计算费用",最终将向您收费. 因此,即使您使用的是免费试用版信用,您也可能想学习[如何正确关闭 Azure VM 以节省资金](https://build5nines.com/properly-shutdown-azure-vm-to-save-money/) . - -继续并单击您选择的大小,然后在准备进行下一步时单击**"选择"** . - -## Settings[](#settings "Permalink") - -在下一个刀片服务器上,要求您配置存储,网络和扩展设置. 我们保留了默认设置,因为它们足以进行 GitLab 的测试驾驶,但是请选择最能满足您自己要求的设置: - -[![Azure - Create Virtual Machine - Settings](img/e470cb0eb6198f35d2db011704471fce.png)](img/azure-create-virtual-machine-settings.png) - -检查设置,然后在准备好进行最后一步时单击**"确定"** . - -## Purchase[](#purchase "Permalink") - -"购买"页面是最后一步,在这里将为您显示新 VM 的每小时价格. 您只需要为 VM 本身付费(例如" Standard DS1 v2"),因为**" GitLab 社区版"**市场解决方案可以以 0 美元/小时的价格免费使用: - -[![Azure - Create Virtual Machine - Purchase](img/ed70f998a438f30a2762829a3cc5b5b6.png)](img/azure-create-virtual-machine-purchase.png) - -> **注意:**在此阶段,您可以查看和修改在之前所有步骤中所做的任何设置,只需单击四个步骤中的任何一个即可重新打开它们. - -阅读并同意使用条款并准备进行时,请单击**"购买"** . - -## Deployment[](#deployment "Permalink") - -此时,Azure 将开始部署您的新 VM. 部署过程将需要几分钟才能完成,进度显示在**"部署"**刀片上: - -[![Azure - Create Virtual Machine - Deployment](img/c9fb44f57074dc166ca07353bd7d31c7.png)](img/azure-create-virtual-machine-deployment.png) - -部署过程完成后,新的 VM 及其相关资源将显示在 Azure 仪表板上(您可能需要刷新页面): - -[![Azure - Dashboard - All resources](img/12208c7d040cd738d51605b7fcb55237.png)](img/azure-dashboard-running-resources.png) - -也可以通过单击 Azure Portal 侧栏导航菜单中的" `All resources`或" `Virtual machines`图标来访问新 VM. - -## Set up a domain name[](#set-up-a-domain-name "Permalink") - -该虚拟机将具有一个公共 IP 地址(默认情况下为静态),但是 Azure 允许我们为该虚拟机分配一个友好的 DNS 名称,所以让我们继续吧. - -在控制面板中,单击**" GitLab-CE"**图块以打开新 VM 的管理刀片. VM 使用的公共 IP 地址在"基本"部分中显示: - -[![Azure - VM - Management - Public IP Address](img/f08e838598cbf1f61321a510bb24c6a1.png)](img/azure-vm-management-public-ip.png) - -单击公共 IP 地址-这将打开**"公共 IP 地址-配置"**刀片,然后单击**"配置"** (在"设置"下). 现在,在" `DNS name label`字段中为您的实例输入一个友好的 DNS 名称: - -[![Azure - VM - Domain Name](img/bccfe6e36a18f67a038a8d90f2a6499f.png)](img/azure-vm-domain-name.png) - -In the screenshot above, you’ll see that we’ve set the `DNS name label` to `gitlab-ce-test`. This will make our VM accessible at `gitlab-ce-test.centralus.cloudapp.azure.com` *(当然,您自己的 VM 的完整域名将有所不同)*. - -单击**"保存"**以使更改生效. - -> **注意:**如果要使用自己的域名,则需要在域注册商处添加 DNS `A`记录, `A`记录指向 Azure VM 的公共 IP 地址. 如果这样做,则需要确保将 VM 配置为使用*静态的*公共 IP 地址(即不是*动态的* IP 地址),否则每次 Azure 重新为 VM 分配新的公共 IP 时,都必须重新配置 DNS `A`记录.地址. 阅读[公共 IP 地址](https://docs.microsoft.com/en-us/azure/virtual-network/public-ip-addresses)以了解更多信息. - -## Let’s open some ports[](#lets-open-some-ports "Permalink") - -在此阶段,您应该拥有一个正在运行且完全可运行的 VM. 但是,在您打开必要的端口以启用对这些服务的访问之前,将无法通过 Internet 公开访问 VM 上的任何服务(例如 GitLab). - -通过将*安全规则*添加到已分配了我们的 VM 的**"网络安全组"** (NSG),可以打开端口. 如果按照上述过程进行操作,则 Azure 将自动创建一个名为`GitLab-CE-nsg`的 NSG 并将`GitLab-CE` VM 分配给它. - -> **注意:**如果给虚拟机命名不同,则 Azure 自动创建的 NSG 也将具有不同的名称-您拥有虚拟机的名称,并附加`-nsg` . - -您可以通过 Azure 门户中的许多不同路径导航到 NSG 设置,但是最简单的方法之一是转到 Azure 仪表板,然后单击**"所有资源"**图块中列出的 Network Security 组: - -[![Azure - Dashboard - All resources - Network security group](img/c380b8ddd78f1d3281d0eeea7f19971c.png)](img/azure-dashboard-highlight-nsg.png) - -在打开**"网络安全组"**刀片的情况下,单击**"设置"**下的**"** **入站安全规则** **"** : - -[![Azure - Network security group - Inbound security rules](img/3b13f587681dd3391c82eb9b650ff6cf.png)](img/azure-nsg-inbound-sec-rules-highlight.png) - -接下来,点击**"添加"** : - -[![Azure - Network security group - Inbound security rules - Add](img/f6e26efd0e5206a2e9d1bf43865b9f4a.png)](img/azure-nsg-inbound-sec-rules-add-highlight.png) - -### Which ports to open?[](#which-ports-to-open "Permalink") - -像所有服务器一样,我们的 VM 将运行许多服务. 但是,我们要打开正确的端口,以使公共互联网特别能够访问两种服务: - -1. **HTTP** (端口 80)-打开端口 80 将使我们的 VM 能够响应 HTTP 请求,从而允许公众访问在我们的 VM 上运行的 GitLab 实例. -2. **SSH** (端口 22)-打开端口 22 将使我们的 VM 能够响应 SSH 连接请求,允许对远程终端会话进行公共访问(带有身份验证) *(您将[在本教程的后面部分](#maintaining-your-gitlab-instance)看到为什么我们需要对 VM 进行[SSH](https://en.wikipedia.org/wiki/Secure_Shell)访问)* - -### Open HTTP on Port 80[](#open-http-on-port-80 "Permalink") - -在**"添加入站安全规则"**刀片中,让我们打开端口 80,以便我们的 VM 可以接受 HTTP 连接: - -[![Azure - Add inbound security rules - HTTP](img/7d05273dffbd24f67285426b02a19ddc.png)](img/azure-add-inbound-sec-rule-http.png) - -1. 在`Name`字段中输入**" HTTP"** -2. 从`Service`下拉列表中的选项中选择**HTTP** -3. 确保将`Action`设置为**允许** -4. Click **“OK”** - -### Open SSH on Port 22[](#open-ssh-on-port-22 "Permalink") - -重复上述过程,添加第二个入站安全规则以打开端口 22,使我们的 VM 能够接受[SSH](https://en.wikipedia.org/wiki/Secure_Shell)连接: - -[![Azure - Add inbound security rules - SSH](img/fb8ded1bb07112b49dc42dff02fe01f7.png)](img/azure-add-inbound-sec-rule-ssh.png) - -1. 在" `Name`字段中输入**" SSH"** -2. 从`Service`下拉列表中的选项中选择**SSH** -3. 确保将`Action`设置为**允许** -4. Click **“OK”** - -Azure 将花一点时间来添加每个新的入站安全规则(您可能需要单击**"入站安全规则"**以刷新列表),但是一旦完成,您应该在列表中看到两个新规则: - -[![Azure - Inbound security rules - List](img/72431eb6b6fe2dd27e2f6f9be7d91672.png)](img/azure-inbound-sec-rules-list.png) - -## Connecting to GitLab[](#connecting-to-gitlab "Permalink") - -使用您先前设置的域名(或公共 IP 地址)在浏览器中访问新的 GitLab 实例. 如果一切都按计划进行,则应显示以下页面,要求您为 GitLab 自动创建的管理员帐户设置*新*密码: - -[![GitLab - Change Password](img/b786322ea49fe7840203db128b72a5e0.png)](img/gitlab-change-password.png) - -在两个表单字段中输入您的*新*密码,然后单击**"更改密码"** . - -更改密码后,您将被重定向到 GitLab 登录页面. 使用`root`作为用户名,输入在上一步中设置的新密码,然后单击**"登录"** : - -[![GitLab - Login](img/56b25600afa13ee05e76062ab09ee470.png)](img/gitlab-login.png) - -### Success?[](#success "Permalink") - -成功登录后,您应该看到 GitLab 项目页面显示**"欢迎使用 GitLab!".** 信息: - -[![GitLab - Projects Page](img/96c6ce839dca0e2ef2d69b8fbc0cff56.png)](img/gitlab-home.png) - -如果是这样,您现在可以在自己的私有 Azure VM 上拥有一个正常的 GitLab 实例. **恭喜你!** - -## Creating your first GitLab project[](#creating-your-first-gitlab-project "Permalink") - -如果您熟悉 Git 和 GitLab,则可以跳过本节. 否则,让我们创建第一个项目. 在"欢迎"页面上,单击**"新建项目"** . - -让我们给项目命名和描述,然后接受其他所有内容的默认值: - -1. 在`Project path`项目名称字段中输入**" demo"** -2. 输入`description` ,例如**"我的真棒演示项目!"** -3. Click **"创建项目"** - -[![GitLab - New Project](img/c7562ae46b8ec150661af0c88f1a5aad.png)](img/gitlab-new-project.png) - -一旦创建了新项目(只需要一点时间),您将被重定向到该项目的主页: - -[![GitLab - Empty Project](img/669c2de32e70a30ad93c28d4afd41491.png)](img/gitlab-project-home-empty.png) - -If you scroll further down the project’s home page, you’ll see some basic instructions on how to set up a local clone of your new repository and push and pull from it: - -[![GitLab - Empty Project - Basic Instructions](img/3281ef5fea53e2f0a57bb3c648aa7fa4.png)](img/gitlab-project-home-instructions.png) - -**而已! 现在,您已经在云中安装并运行了自己的私有 GitLab 环境!** - -## Maintaining your GitLab instance[](#maintaining-your-gitlab-instance "Permalink") - -保持最新的 GitLab 环境非常重要. GitLab 团队会不断进行增强,出于安全原因,有时您可能需要进行更新. 因此,让我们回顾一下如何更新 GitLab. - -### Checking our current version[](#checking-our-current-version "Permalink") - -要检查我们当前正在运行的 GitLab 版本,请单击"管理区域"链接-它是显示在搜索框旁边的右上角的扳手图标. - -在以下屏幕截图中,您可以在右上角看到**"尽快更新"**通知消息. 此特定消息表明存在可用的较新版本的 GitLab,其中包含一个或多个安全修复程序: - -[![GitLab - update asap](img/8465cc4b8bf68fad2a64c9fc838c7939.png)](img/gitlab-admin-area.png) - -在**"组件"**部分下,我们可以看到我们的 VM 当前正在运行 GitLab 的`8.6.5`版本. 这是 GitLab 的版本,包含在 Azure 市场**" GitLab 社区版"中,该**产品在编写本教程时曾用来构建 VM. - -> **注意:**您自己的 VM 实例中的 GitLab 版本可能会有所不同,但是更新过程仍然相同. - -### Connect via SSH[](#connect-via-ssh "Permalink") - -要执行更新,我们需要直接连接到我们的 Azure VM 实例并从终端运行一些命令. 我们的 Azure VM 实际上是运行 Linux(Ubuntu)的服务器,因此我们需要使用 SSH( [Secure Shell](https://en.wikipedia.org/wiki/Secure_Shell) )连接到它. - -如果您正在运行 Windows,则需要使用[PuTTY](https://www.putty.org)或等效的 Windows SSH 客户端进行连接. 如果您正在运行 Linux 或 macOS,则说明您已经安装了 SSH 客户端. - -> **Note:** -> -> * 请记住,您将需要使用[创建](#basics) Azure VM [时](#basics)指定的用户名和密码登录 -> * 如果需要重置虚拟机密码,请阅读[如何为 Azure VM 上的用户重置 SSH 凭据](https://docs.microsoft.com/en-us/azure/virtual-machines/troubleshooting/troubleshoot-ssh-connection) . - -#### SSH from the command-line[](#ssh-from-the-command-line "Permalink") - -如果您从命令行(终端)运行[SSH](https://en.wikipedia.org/wiki/Secure_Shell) ,则键入以下命令以连接到您的 VM,用`username`和`your-azure-domain-name.com`替换正确的值. - -再次提醒您,您的 Azure VM 域名将是您[先前在本教程中设置的](#set-up-a-domain-name)域名. 如果未为 VM 设置域名,则可以在以下命令中使用其 IP 地址: - -``` -ssh username@your-azure-domain-name.com -``` - -在提示时提供密码以进行身份​​验证. - -#### SSH from Windows (PuTTY)[](#ssh-from-windows-putty "Permalink") - -如果您将 Windows 中的[PuTTY](https://www.putty.org)用作[SSH](https://en.wikipedia.org/wiki/Secure_Shell)客户端,那么您可能想快速阅读[Windows 中的 PuTTY](https://mediatemple.net/community/products/dv/204404604/using-ssh-in-putty-) . - -### Updating GitLab[](#updating-gitlab "Permalink") - -通过 SSH 登录后,输入以下命令将 GitLab 更新到最新版本: - -``` -sudo apt-get update && sudo apt-get install gitlab-ce -``` - -此命令会将 GitLab 及其关联的组件更新为最新版本,因此需要一些时间才能完成. 您将在 SSH 终端窗口中看到各种更新任务正在完成: - -[![GitLab updating](img/dbae11f07630ae759b8156031d0c496d.png)](img/gitlab-ssh-update-in-progress.png) - -更新过程完成后,您将看到以下消息: - -``` -Upgrade complete! If your GitLab server is misbehaving try running - - sudo gitlab-ctl restart - -before anything else. -``` - -#### Check out your updated GitLab[](#check-out-your-updated-gitlab "Permalink") - -在浏览器中刷新您的 GitLab 实例,然后导航到"管理区域". 您现在应该具有最新的 GitLab 实例. - -在编写本教程时,我们的 Azure VM GitLab 实例在撰写本文时已更新为最新版本( `9.4.0` ). 您可以看到以前显示**" update asap"**的消息现在显示为**"最新"** : - -[![GitLab up to date](img/80a9fe0374f84134fa2b40172431604d.png)](img/gitlab-admin-area-9.4.0.png) - -## Conclusion[](#conclusion "Permalink") - -自然地,我们认为 GitLab 是一个很棒的 Git 存储库工具. 但是,GitLab 的功能远不止于此. GitLab 将问题,代码审查,CI 和 CD 统一到一个 UI 中,可帮助您从构思到生产更快地迁移,并且在本教程中,我们向您展示了在 Azure 上设置和运行自己的 GitLab 实例是多么快速和容易. ,微软的云服务. - -Azure 是尝试 GitLab 的好方法,如果您决定(如我们所愿)GitLab 适合您,则可以继续使用 Azure 作为您的安全,可扩展的云提供商,当然也可以在您选择的任何云服务上运行 GitLab. - -## Where to next?[](#where-to-next "Permalink") - -查看其他[技术文章](../../articles/index.html)或浏览[GitLab 文档](../../README.html)以了解有关 GitLab 的更多信息. - -### Useful links[](#useful-links "Permalink") - -* [GitLab Community Edition](https://about.gitlab.com/features/) -* [GitLab Enterprise Edition](https://about.gitlab.com/features/#ee-starter) -* [Microsoft Azure](https://azure.microsoft.com/en-us/) - * [Azure - Free Account FAQ](https://azure.microsoft.com/en-us/free/free-account-faq/) - * [Azure - Marketplace](https://azuremarketplace.microsoft.com/en-us/marketplace/) - * [Azure Portal](https://portal.azure.com) - * [Azure - Pricing Calculator](https://azure.microsoft.com/en-us/pricing/calculator/) - * [Azure - Troubleshoot SSH Connections to an Azure Linux VM](https://docs.microsoft.com/en-us/azure/virtual-machines/troubleshooting/troubleshoot-ssh-connection) - * [Azure - Properly Shutdown an Azure VM](https://build5nines.com/properly-shutdown-azure-vm-to-save-money/) -* [SSH](https://en.wikipedia.org/wiki/Secure_Shell), [PuTTY](https://www.putty.org) and [Using SSH in PuTTY](https://mediatemple.net/community/products/dv/204404604/using-ssh-in-putty-) \ No newline at end of file diff --git a/_book/docs/010.md b/_book/docs/010.md deleted file mode 100644 index f3fad8a66bd72e139804011598deb4618d1a8a71..0000000000000000000000000000000000000000 --- a/_book/docs/010.md +++ /dev/null @@ -1,122 +0,0 @@ -# Installing GitLab on Google Cloud Platform - -> 原文:[https://docs.gitlab.com/ee/install/google_cloud_platform/](https://docs.gitlab.com/ee/install/google_cloud_platform/) - -* [Prerequisites](#prerequisites) -* [Creating the VM](#creating-the-vm) -* [Installing GitLab](#installing-gitlab) -* [Next steps](#next-steps) - * [Assigning a static IP](#assigning-a-static-ip) - * [Using a domain name](#using-a-domain-name) - * [Configuring HTTPS with the domain name](#configuring-https-with-the-domain-name) - * [Configuring the email SMTP settings](#configuring-the-email-smtp-settings) -* [Further reading](#further-reading) - -# Installing GitLab on Google Cloud Platform[](#installing-gitlab-on-google-cloud-platform "Permalink") - -本指南将帮助您在[Google Cloud Platform(GCP)](https://cloud.google.com/)实例上安装 GitLab. - -**替代安装方法:** Google 提供了一份白皮书,用于[在 Google Kubernetes Engine 上部署可投入生产的 GitLab](https://cloud.google.com/solutions/deploying-production-ready-gitlab-on-gke) ,包括所有步骤和外部资源配置. 这些是使用 GCP VM 的替代方法,并使用[Cloud native GitLab Helm chart](https://docs.gitlab.com/charts/) . - -## Prerequisites[](#prerequisites "Permalink") - -在 GCP 上安装 GitLab 的前提条件只有两个: - -1. 您需要有一个 Google 帐户. -2. 您需要注册 GCP 计划. 如果您是第一次,Google 会为您提供[$ 300 的信用额,](https://console.cloud.google.com/freetrial)可在 60 天内[免费](https://console.cloud.google.com/freetrial)使用. - -完成这两个步骤后,就可以[创建 VM 了](#creating-the-vm) . - -## Creating the VM[](#creating-the-vm "Permalink") - -要在 GCP 上部署 GitLab,您首先需要创建一个虚拟机: - -1. 转到[https://console.cloud.google.com/compute/instances](https://console.cloud.google.com/compute/instances)并使用您的 Google 凭据登录. -2. 点击**创建** - - [![Search for GitLab](img/9f6f0b27f8e7df6c95a3262de502b39f.png)](img/launch_vm.png) - -3. On the next page, you can select the type of VM as well as the estimated costs. Provide the name of the instance, desired datacenter, and machine type. Note our [hardware requirements for different user base sizes](../requirements.html#hardware-requirements). - - [![Launch on Compute Engine](img/d345ea7938f401127d9471442b27eb27.png)](img/vm_details.png) - -4. 要选择大小,类型和所需的[操作系统](../requirements.html#supported-linux-distributions) ,请在" `Boot disk` **"**下单击" **更改** ". 完成后单击" **选择"** . - -5. 最后,允许 HTTP 和 HTTPS 通信,然后点击**创建** . 该过程将在几秒钟内完成. - -## Installing GitLab[](#installing-gitlab "Permalink") - -几秒钟后,实例将被创建并可以登录.下一步是将 GitLab 安装到实例上. - -[![Deploy settings](img/ad33446e7ba7897d31835424ce5e1feb.png)](img/vm_created.png) - -1. 记下实例的 IP 地址,因为在后续步骤中将需要使用该 IP 地址. -2. 单击 SSH 按钮以连接到实例. -3. 登录到实例后,将出现一个新窗口. - - [![GitLab first sign in](img/e2a52ca7a089fcbd9b17f94875cba0ca.png)](img/ssh_terminal.png) - -4. 接下来,在[https://about.gitlab.com/install/上](https://about.gitlab.com/install/)按照说明为您选择的操作系统安装 GitLab. 您可以将上述步骤中的 IP 地址用作主机名. - -5. 恭喜你! GitLab 现在已安装,您可以通过浏览器访问它. 要完成安装,请在浏览器中打开 URL 并提供初始管理员密码. 该帐户的用户名是`root` . - - [![GitLab first sign in](img/279650b9e9c3ec26a7d6f0493bd5af7c.png)](img/first_signin.png) - -## Next steps[](#next-steps "Permalink") - -这些是首次安装 GitLab 之后要执行的最重要的后续步骤. - -### Assigning a static IP[](#assigning-a-static-ip "Permalink") - -默认情况下,Google 会为您的实例分配一个临时 IP. 如果您要在生产中使用 GitLab 并使用域名,则强烈建议分配一个静态 IP,如下所示. - -阅读 Google 有关如何[提升临时 IP 地址](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip)的文档. - -### Using a domain name[](#using-a-domain-name "Permalink") - -假设您拥有一个域名,并且已正确设置 DNS 以指向在上一步中配置的静态 IP,则可以通过以下方法配置 GitLab 以了解更改: - -1. SSH 进入虚拟机. 您可以轻松使用 Google 控制台中的**SSH**按钮,然后会弹出一个新窗口. - - [![SSH button](img/ad33446e7ba7897d31835424ce5e1feb.png)](img/vm_created.png) - - 将来,您可能想设置[使用 SSH 密钥的连接](https://cloud.google.com/compute/docs/instances/connecting-to-instance) . - -2. 使用您喜欢的文本编辑器编辑 Omnibus GitLab 的配置文件: - - ``` - sudo vim /etc/gitlab/gitlab.rb - ``` - -3. 将`external_url`值设置为您希望 GitLab 在**不使用** `https` **情况下**拥有的域名: - - ``` - external_url 'http://gitlab.example.com' - ``` - - 我们将在下一步中设置 HTTPS,而现在无需这样做. - -4. 重新配置 GitLab,以使更改生效: - - ``` - sudo gitlab-ctl reconfigure - ``` - -5. 您现在可以使用域名访问 GitLab. - -### Configuring HTTPS with the domain name[](#configuring-https-with-the-domain-name "Permalink") - -尽管不需要,但强烈建议使用 TLS 证书保护 GitLab. 请遵循[Omnibus 文档中](https://docs.gitlab.com/omnibus/settings/nginx.html)的步骤. - -### Configuring the email SMTP settings[](#configuring-the-email-smtp-settings "Permalink") - -您需要正确配置电子邮件 SMTP 设置,否则 GitLab 将无法发送通知电子邮件,例如注释和密码更改. 检查[Omnibus 文档的](https://docs.gitlab.com/omnibus/settings/smtp.html)操作方法. - -## Further reading[](#further-reading "Permalink") - -可以将 GitLab 配置为与其他 OAuth 提供程序,LDAP,SAML,Kerberos 等进行身份验证.以下是您可能感兴趣阅读的一些文档: - -* [Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/) -* [Integration documentation](../../integration/README.html) -* [GitLab Pages configuration](../../administration/pages/index.html) -* [GitLab Container Registry configuration](../../administration/packages/container_registry.html) \ No newline at end of file diff --git a/_book/docs/011.md b/_book/docs/011.md deleted file mode 100644 index 97920a2c475f285239d9eb4f496cf2ab0b5256cc..0000000000000000000000000000000000000000 --- a/_book/docs/011.md +++ /dev/null @@ -1,754 +0,0 @@ -# Installing GitLab on Amazon Web Services (AWS) - -> 原文:[https://docs.gitlab.com/ee/install/aws/](https://docs.gitlab.com/ee/install/aws/) - -* [Introduction](#introduction) -* [Requirements](#requirements) -* [Architecture](#architecture) -* [AWS costs](#aws-costs) -* [Create an IAM EC2 instance role and profile](#create-an-iam-ec2-instance-role-and-profile) - * [Create an IAM Policy](#create-an-iam-policy) - * [Create an IAM Role](#create-an-iam-role) -* [Configuring the network](#configuring-the-network) - * [Creating the Virtual Private Cloud (VPC)](#creating-the-virtual-private-cloud-vpc) - * [Subnets](#subnets) - * [Internet Gateway](#internet-gateway) - * [Create NAT Gateways](#create-nat-gateways) - * [Route Tables](#route-tables) - * [Public Route Table](#public-route-table) - * [Private Route Tables](#private-route-tables) -* [Load Balancer](#load-balancer) - * [Configure DNS for Load Balancer](#configure-dns-for-load-balancer) -* [PostgreSQL with RDS](#postgresql-with-rds) - * [RDS Security Group](#rds-security-group) - * [RDS Subnet Group](#rds-subnet-group) - * [Create the database](#create-the-database) -* [Redis with ElastiCache](#redis-with-elasticache) - * [Create a Redis Security Group](#create-a-redis-security-group) - * [Redis Subnet Group](#redis-subnet-group) - * [Create the Redis Cluster](#create-the-redis-cluster) -* [Setting up Bastion Hosts](#setting-up-bastion-hosts) - * [Create Bastion Host A](#create-bastion-host-a) - * [Create Bastion Host B](#create-bastion-host-b) - * [Use SSH Agent Forwarding](#use-ssh-agent-forwarding) -* [Install GitLab and create custom AMI](#install-gitlab-and-create-custom-ami) - * [Install GitLab](#install-gitlab) - * [Add custom configuration](#add-custom-configuration) - * [Disable Let’s Encrypt](#disable-lets-encrypt) - * [Install the `pg_trgm` extension for PostgreSQL](#install-the-pg_trgm-extension-for-postgresql) - * [Configure GitLab to connect to PostgreSQL and Redis](#configure-gitlab-to-connect-to-postgresql-and-redis) - * [Set up Gitaly](#set-up-gitaly) - * [Add Support for Proxied SSL](#add-support-for-proxied-ssl) - * [Fast lookup of authorized SSH keys](#fast-lookup-of-authorized-ssh-keys) - * [Configure host keys](#configure-host-keys) - * [Amazon S3 object storage](#amazon-s3-object-storage) - * [Create custom AMI](#create-custom-ami) -* [Deploy GitLab inside an auto scaling group](#deploy-gitlab-inside-an-auto-scaling-group) - * [Create a launch configuration](#create-a-launch-configuration) - * [Create an auto scaling group](#create-an-auto-scaling-group) - * [Log in for the first time](#log-in-for-the-first-time) -* [Health check and monitoring with Prometheus](#health-check-and-monitoring-with-prometheus) -* [GitLab Runners](#gitlab-runners) -* [Backup and restore](#backup-and-restore) - * [Backing up GitLab](#backing-up-gitlab) - * [Restoring GitLab from a backup](#restoring-gitlab-from-a-backup) -* [Updating GitLab](#updating-gitlab) -* [Conclusion](#conclusion) -* [Troubleshooting](#troubleshooting) - * [Instances are failing health checks](#instances-are-failing-health-checks) - * [“The change you requested was rejected (422)”](#the-change-you-requested-was-rejected-422) - -# Installing GitLab on Amazon Web Services (AWS)[](#installing-gitlab-on-amazon-web-services-aws "Permalink") - -该页面提供了 AWS 上 GitLab 通用配置的演练. 您应该对其进行自定义以满足您的需求. - -**注意:**对于拥有 1,000 个或更少用户的组织,建议的 AWS 安装方法是启动 EC2 单框[Omnibus 安装](https://about.gitlab.com/install/)并实施快照策略以备份数据. 有关更多信息,请参见[1,000 个用户参考体系结构](../../administration/reference_architectures/1k_users.html) . - -## Introduction[](#introduction "Permalink") - -在大多数情况下,我们将在我们的设置中使用 Omnibus GitLab,但我们还将利用本机 AWS 服务. 代替使用 Omnibus 捆绑的 PostgreSQL 和 Redis,我们将使用 AWS RDS 和 ElastiCache. - -在本指南中,我们将进行多节点设置,首先将配置虚拟私有云和子网,以稍后集成服务(例如用于数据库服务器的 RDS 和作为 Redis 集群的 ElastiCache)以最终在一个具有自定义缩放策略的自动缩放组. - -## Requirements[](#requirements "Permalink") - -除了基本了解[AWS](https://docs.aws.amazon.com/)和[Amazon EC2 之外](https://docs.aws.amazon.com/ec2/) ,您还需要: - -* [An AWS account](https://console.aws.amazon.com/console/home) -* [To create or upload an SSH key](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html) to connect to the instance via SSH -* GitLab 实例的域名 -* SSL / TLS 证书以保护您的域. 如果您还不拥有该证书,则可以通过[AWS Certificate Manager](https://aws.amazon.com/certificate-manager/) (ACM)设置免费的公共 SSL / TLS 证书,以与我们将创建的[Elastic Load Balancer](#load-balancer)一起使用. - -**注意:**验证通过 ACM 设置的证书可能需要几个小时. 为避免以后出现延迟,请尽快申请您的证书. - -## Architecture[](#architecture "Permalink") - -下面是推荐架构的示意图. - -[![AWS architecture diagram](img/20bba5f798131b98df30aaa9202ccfd5.png)](img/aws_ha_architecture_diagram.png) - -## AWS costs[](#aws-costs "Permalink") - -以下是我们将使用的 AWS 服务的列表,以及指向定价信息的链接: - -* **EC2** :GitLab 将部署在共享硬件上,这意味着将[按需定价](https://aws.amazon.com/ec2/pricing/on-demand/) . 如果要在专用或保留实例上运行它,请参阅[EC2 定价页面](https://aws.amazon.com/ec2/pricing/)以获取有关费用的更多信息. -* **S3** :我们将使用 S3 来存储备份,工件,LFS 对象等.请参阅[Amazon S3 定价](https://aws.amazon.com/s3/pricing/) . -* **ELB** :经典负载均衡器将用于将请求路由到 GitLab 实例. 请参阅[Amazon ELB 定价](https://aws.amazon.com/elasticloadbalancing/pricing/) . -* **RDS** :将使用使用 PostgreSQL 的 Amazon Relational Database Service. 请参阅[Amazon RDS 定价](https://aws.amazon.com/rds/postgresql/pricing/) . -* **ElastiCache** :内存缓存环境将用于提供 Redis 配置. 请参阅[Amazon ElastiCache 定价](https://aws.amazon.com/elasticache/pricing/) . - -## Create an IAM EC2 instance role and profile[](#create-an-iam-ec2-instance-role-and-profile "Permalink") - -由于我们将使用[Amazon S3 对象存储](#amazon-s3-object-storage) ,因此我们的 EC2 实例需要具有对 S3 存储桶的读取,写入和列出权限. 为了避免将 AWS Key 嵌入我们的 GitLab 配置中,我们将利用[IAM 角色](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)允许 GitLab 实例具有此访问权限. 我们需要创建一个 IAM 策略以附加到我们的 IAM 角色: - -### Create an IAM Policy[](#create-an-iam-policy "Permalink") - -1. 导航到 IAM 仪表板,然后单击左侧菜单中的" **策略** ". -2. 单击**创建策略** ,选择`JSON`选项卡,然后添加策略. 我们希望[遵循安全最佳实践并授予*最少的特权*](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) ,仅向我们的角色授予执行所需操作所需的权限. - 1. 假设如图所示,在 S3 存储桶名称前添加`gl-`作为前缀,请添加以下策略: - -``` -{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:AbortMultipartUpload", "s3:CompleteMultipartUpload", "s3:ListBucket", "s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:PutObjectAcl" ], "Resource": [ "arn:aws:s3:::gl-*/*" ] } ] } -``` - -1. 点击**审核政策** ,为您的政策命名(我们将使用`gl-s3-policy` ),然后点击**创建政策** . - -### Create an IAM Role[](#create-an-iam-role "Permalink") - -1. 仍在 IAM 仪表板上,单击左侧菜单中的**角色** ,然后单击**创建角色** . -2. 通过选择**AWS 服务> EC2**来创建新角色,然后单击**下一步:权限** . -3. 在策略过滤器中,搜索我们在上面创建的`gl-s3-policy` ,选择它,然后点击**标签** . -4. 根据需要添加标签,然后单击" **查看"** . -5. 为角色命名(我们将使用`GitLabS3Access` ),然后点击**创建角色** . - -稍后[创建启动配置](#create-a-launch-configuration)时,将使用此角色. - -## Configuring the network[](#configuring-the-network "Permalink") - -我们将从为 GitLab 云基础架构创建 VPC 开始,然后我们可以创建子网以在至少两个[可用区(AZ)中](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html)具有公共实例和私有实例. 公共子网将需要保留路由表和关联的 Internet 网关. - -### Creating the Virtual Private Cloud (VPC)[](#creating-the-virtual-private-cloud-vpc "Permalink") - -现在,我们将创建一个 VPC,一个您可以控制的虚拟网络环境: - -1. 导航至[https://console.aws.amazon.com/vpc/home](https://console.aws.amazon.com/vpc/home) . -2. 从左侧菜单中选择**您的 VPC** ,然后单击**创建 VPC** . 在"名称标签"中输入`gitlab-vpc` ,在" IPv4 CIDR 块"中输入`10.0.0.0/16` . 如果不需要专用硬件,则可以将" Tenancy"保留为默认设置. 单击**是,**准备好后**创建** . - - [![Create VPC](img/7cfe14b5f606095866af7260c844d4e2.png)](img/create_vpc.png) - -3. 选择 VPC,单击" **操作"** ,单击" **编辑 DNS 解析"** ,然后启用 DNS 解析. 完成后点击**保存** . - -### Subnets[](#subnets "Permalink") - -现在,让我们在不同的可用区中创建一些子网. 确保每个子网都与我们刚刚创建的 VPC 相关联,并且 CIDR 块不会重叠. 这也将使我们能够启用多可用区以实现冗余. - -我们还将创建专用和公用子网以匹配负载均衡器和 RDS 实例: - -1. 从左侧菜单中选择**子网** . -2. 单击**创建子网** . 给它一个基于 IP 的描述性名称标签,例如`gitlab-public-10.0.0.0` ,选择我们之前创建的 VPC,选择一个可用区(我们将使用`us-west-2a` ),并在 IPv4 CIDR 块上让我们给它一个 24 个子网`10.0.0.0/24` : - - [![Create subnet](img/48482b1410caf250f0257d772e55c544.png)](img/create_subnet.png) - -3. 请按照相同的步骤创建所有子网: - - | 名称标签 | Type | 可用区 | CIDR 块 | - | --- | --- | --- | --- | - | `gitlab-public-10.0.0.0` | public | `us-west-2a` | `10.0.0.0/24` | - | `gitlab-private-10.0.1.0` | private | `us-west-2a` | `10.0.1.0/24` | - | `gitlab-public-10.0.2.0` | public | `us-west-2b` | `10.0.2.0/24` | - | `gitlab-private-10.0.3.0` | private | `us-west-2b` | `10.0.3.0/24` | - -4. 创建所有子网后,请为两个公共子网启用**自动分配 IPv4** : - 1. 依次选择每个公共子网,单击" **操作"** ,然后单击" **修改自动分配 IP 设置"** . 启用该选项并保存. - -### Internet Gateway[](#internet-gateway "Permalink") - -现在,仍然在同一仪表板上,转到 Internet 网关并创建一个新的网关: - -1. 从左侧菜单中选择" **Internet 网关** ". -2. 单击**创建互联网网关** ,为其命名为`gitlab-gateway` ,然后单击**创建** . -3. 从表中选择它,然后在" **操作"**下拉菜单下选择"附加到 VPC". - - [![Create gateway](img/104374dd85800b346ef75734f6fd0b38.png)](img/create_gateway.png) - -4. 从列表中选择`gitlab-vpc` ,然后点击**Attach** . - -### Create NAT Gateways[](#create-nat-gateways "Permalink") - -部署在我们专用子网中的实例需要连接到 Internet 进行更新,但不能从公共 Internet 到达. 为此,我们将利用部署在每个公共子网中的[NAT 网关](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html) : - -1. 导航到 VPC 仪表板,然后单击左侧菜单栏中的**NAT 网关** . -2. 单击**创建 NAT 网关,**然后完成以下操作: - 1. **子网** :从下拉列表中选择`gitlab-public-10.0.0.0` . - 2. **弹性 IP 分配 ID** :输入现有的弹性 IP 或单击**分配弹性 IP 地址,**以将新 IP 分配给您的 NAT 网关. - 3. 如果需要,添加标签. - 4. 单击**创建 NAT 网关** . - -创建第二个 NAT 网关,但这一次将其放置在第二个公共子网`gitlab-public-10.0.2.0` . - -### Route Tables[](#route-tables "Permalink") - -#### Public Route Table[](#public-route-table "Permalink") - -我们需要为公共子网创建路由表,以通过上一步中创建的 Internet 网关访问 Internet. - -在 VPC 仪表板上: - -1. 从左侧菜单中选择**路由表** . -2. Click **创建路由表**. -3. 在"名称标签"中,输入`gitlab-public` , `gitlab-vpc`在" VPC"下选择`gitlab-vpc` . -4. Click **Create**. - -现在,我们需要将我们的 Internet 网关添加为新目标,并使其接收来自任何目的地的流量. - -1. 从左侧菜单中选择" **路由表"** ,然后选择`gitlab-public`路由以在底部显示选项. -2. 选择" **路线"**选项卡,单击" **编辑路线">"添加路线",**然后将`0.0.0.0/0`设置为目的地. 在目标列中,选择我们之前创建的`gitlab-gateway` . 完成后,点击**保存路线** . - -接下来,我们必须将**公共**子网关联到路由表: - -1. Select the **子网关联** tab and click **编辑子网关联**. -2. 仅检查公共子网,然后单击" **保存"** . - -#### Private Route Tables[](#private-route-tables "Permalink") - -我们还需要创建两个私有路由表,以便每个私有子网中的实例都可以通过同一可用性区域中相应公共子网中的 NAT 网关到达 Internet. - -1. 请按照与上述相同的步骤创建两个专用路由表. 将它们`gitlab-private-a`命名为`gitlab-private-a`和`gitlab-private-b` . -2. Next, add a new route to each of the private route tables where the destination is `0.0.0.0/0` and the target is one of the NAT gateways we created earlier. - 1. 将我们在`gitlab-public-10.0.0.0`创建的 NAT 网关添加为`gitlab-private-a`路由表中新路由的目标. - 2. 同样,在`gitlab-public-10.0.2.0`添加 NAT 网关作为`gitlab-private-b`新路由的目标. -3. 最后,将每个专用子网与专用路由表相关联. - 1. 将`gitlab-private-10.0.1.0` `gitlab-private-a`与`gitlab-private-a` . - 2. 将`gitlab-private-10.0.3.0`与`gitlab-private-b` . - -## Load Balancer[](#load-balancer "Permalink") - -我们将创建一个负载平衡器,以在我们的 GitLab 应用程序服务器之间平均分配端口`80`和`443`上的入站流量. 根据我们稍后将创建的[扩展策略](#create-an-auto-scaling-group) ,实例将根据需要添加到负载均衡器中或从负载均衡器中删除. 此外,负载平衡将对我们的实例执行运行状况检查. - -在 EC2 仪表板上,在左侧导航栏中查找 Load Balancer: - -1. 单击**创建负载均衡器**按钮. - 1. 选择**经典负载均衡器** . - 2. 给它`gitlab-loadbalancer` (我们将使用`gitlab-loadbalancer` ),并在**Create LB Inside**选项中,从下拉菜单中选择`gitlab-vpc` . - 3. 在" **侦听器"**部分中,设置以下侦听器: - * 负载均衡器和实例协议以及端口的 HTTP 端口 80 - * 负载均衡器和实例协议以及端口的 TCP 端口 22 - * HTTPS 端口 443(用于负载均衡器协议和端口),转发到实例上的 HTTP 端口 80(我们将[在指南](#add-support-for-proxied-ssl)中将 GitLab 配置为侦听端口 80) - 4. 在" **选择子网"**部分中,从列表中选择两个公共子网,以便负载均衡器可以将流量路由到两个可用区域. -2. 我们将为负载均衡器添加一个安全组,以充当防火墙来控制允许通过的流量. 单击**分配安全组,**然后选择**创建新的安全组** ,为其命名(我们将使用`gitlab-loadbalancer-sec-group` )和说明,并允许来自任何地方的 HTTP 和 HTTPS 通信( `0.0.0.0/0, ::/0` ). 还允许 SSH 流量,选择自定义来源,并以 CIDR 表示法添加单个受信任的 IP 地址或 IP 地址范围. 这将允许用户通过 SSH 执行 Git 操作. -3. 单击**配置安全设置,**然后进行以下设置: - 1. 从 ACM 中选择一个 SSL / TLS 证书或将一个证书上传到 IAM. - 2. 在" **选择密码"下** ,从下拉列表中选择预定义的安全策略. 您可以在 AWS 文档中[查看 Classic Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html)的[预定义 SSL 安全策略](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html)明细. 检查 GitLab 代码库以获取[受支持的 SSL 密码和协议](https://gitlab.com/gitlab-org/gitlab/-/blob/9ee7ad433269b37251e0dd5b5e00a0f00d8126b4/lib/support/nginx/gitlab-ssl#L97-99)的列表. -4. 单击" **配置**运行状况检查",然后为您的 EC2 实例设置运行状况检查. - 1. 对于" **Ping 协议"** ,选择" HTTP". - 2. 对于**Ping 端口** ,输入 80\. - 3. 对于**Ping Path** ,输入`/users/sign_in` . (我们使用`/users/sign_in`因为它是不需要授权的公共端点.) - 4. 保留默认的" **高级详细信息"**或根据需要进行调整. -5. 单击**添加 EC2 实例** -不要添加任何内容,因为稍后我们将创建一个 Auto Scaling 组来为我们管理实例. -6. 单击**添加标签,**然后添加您需要的任何标签. -7. 单击" **查看并创建"** ,查看所有设置,如果满意,请单击" **创建"** . - -在负载均衡器启动并运行后,您可以重新访问安全组以仅通过 ELB 和您可能具有的任何其他要求来完善访问. - -### Configure DNS for Load Balancer[](#configure-dns-for-load-balancer "Permalink") - -在 Route 53 仪表板上,单击左侧导航栏中的" **托管区域** ": - -1. 选择一个现有的托管区域,或者,如果您的域还没有一个,请单击**创建托管区域** ,输入您的域名,然后单击**创建** . -2. 单击**创建记录集,**并提供以下值: - 1. **名称:**使用域名(默认值)或输入一个子域. - 2. **类型:**选择**A-IPv4 地址** . - 3. **别名:**默认为**No.** 选择**是** . - 4. **别名目标:**找到" **ELB 经典负载均衡器"**部分,然后选择我们之前创建的经典负载均衡器. - 5. **路由策略:**我们将使用" **简单",**但您可以根据用例选择其他策略. - 6. **评估目标健康状况:**我们将其设置为" **否",**但是您可以选择让负载均衡器根据目标健康状况来路由流量. - 7. 点击**创建** . -3. 如果您通过 Route 53 注册了域,那么您就完成了. 如果您使用了其他域名注册商,则需要使用域名注册商更新 DNS 记录. 您需要: - 1. 单击**托管区域,**然后选择您在上面添加的域. - 2. 您将看到`NS`记录列表. 在您的域名注册商的管理面板中,将每一个作为`NS`记录添加到您域的 DNS 记录中. 这些步骤在域注册商之间可能会有所不同. 如果您陷入困境,则 Google **"您的注册商名称"会添加 dns 记录** ,您应该会找到针对您的域名注册商的帮助文章. - -根据您使用的注册商的不同,执行此操作的步骤也有所不同,这超出了本指南的范围. - -## PostgreSQL with RDS[](#postgresql-with-rds "Permalink") - -对于我们的数据库服务器,我们将使用提供多可用区以实现冗余的 Amazon RDS. 首先,我们将创建一个安全组和子网组,然后将创建实际的 RDS 实例. - -### RDS Security Group[](#rds-security-group "Permalink") - -我们需要一个用于数据库的安全组,该安全组将允许稍后将在`gitlab-loadbalancer-sec-group`部署的实例的入站流量: - -1. 在 EC2 仪表板中,从左侧菜单栏中选择" **安全组** ". -2. Click **创建安全组**. -3. 给它起一个名字(我们将使用`gitlab-rds-sec-group` ),一个描述,并从**VPC**下拉列表中选择`gitlab-vpc` . -4. 在" **入站规则"**部分中,单击" **添加规则"**并进行以下设置: - 1. **键入:**搜索并选择**PostgreSQL**规则. - 2. **来源类型:**设置为"自定义". - 3. **来源:**选择我们之前创建的`gitlab-loadbalancer-sec-group` . -5. 完成后,点击**创建安全组** . - -### RDS Subnet Group[](#rds-subnet-group "Permalink") - -1. 导航到 RDS 仪表板,然后从左侧菜单中选择" **子网组** ". -2. 单击**创建数据库子网组** . -3. 在" **子网组详细信息"下** ,输入名称(我们将使用`gitlab-rds-group` ),描述,然后从 VPC 下拉列表中选择`gitlab-vpc` . -4. 从" **可用区"**下拉列表中,选择包括您已配置的子网的可用区. 在本例中,我们将添加`eu-west-2a`和`eu-west-2b` . -5. 从**子网**下拉列表中,选择两个专用子网( `10.0.1.0/24`和`10.0.3.0/24` ,因为我们在定义它们) [的子网部分](#subnets) . -6. 准备好后,单击**创建** . - -### Create the database[](#create-the-database "Permalink") - -**危险:**避免对数据库使用易爆实例(t 类实例),因为由于 CPU 信用在持续的高负载期间用尽而可能导致性能问题. - -现在,该创建数据库了: - -1. 导航到 RDS 仪表板,从左侧菜单中选择" **数据库** ",然后单击" **创建数据库"** . -2. 选择**标准创建**作为数据库创建方法. -3. 选择**PostgreSQL**作为数据库引擎,然后选择在[数据库要求中](../../install/requirements.html#postgresql-requirements)为您的 GitLab 版本定义的最低 PostgreSQL 版本. -4. 由于这是生产服务器,因此我们从" **模板"**部分中选择" **生产** ". -5. 在**"设置"下** ,设置数据库实例标识符,主用户名和主密码. 我们将分别使用`gitlab-db-ha` , `gitlab`和一个非常安全的密码. 记下这些内容,稍后我们将需要它们. -6. 对于数据库实例大小,请选择" **标准类",**然后从下拉菜单中选择一个满足您要求的实例大小. 我们将使用`db.m4.large`实例. -7. 在" **存储"下** ,配置以下内容: - 1. 从存储类型下拉菜单中选择" **Provisioned IOPS(SSD)** ". 预置 IOPS(SSD)存储最适合此用途(尽管您可以选择 General Purpose(SSD)来降低成本). 在[Amazon RDS 的存储中](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Storage.html)阅读有关它的更多信息. - 2. 分配存储并设置预配置的 IOPS. 我们将分别使用最小值`100`和`1000` . - 3. 启用存储自动缩放(可选)并设置最大存储阈值. -8. 在" **可用性和持久性"下** ,选择" **创建备用实例"**以在另一个可用[区中](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.MultiAZ.html)配置备用 RDS 实例. -9. 在" **连接性"下** ,配置以下内容: - 1. 从**虚拟私有云(VPC)**下拉菜单中选择我们之前创建的 VPC( `gitlab-vpc` ). - 2. 展开**其他连接配置**部分,然后选择我们之前创建的子网组( `gitlab-rds-group` ). - 3. 设置公众了解**没有** . - 4. 在**VPC 安全组下** ,选择**选择现有,**然后从下拉列表中选择我们在上面创建的`gitlab-rds-sec-group` . - 5. 将数据库端口保留为默认值`5432` . -10. 对于**数据库身份验证** ,选择**密码身份验证** . -11. 展开**其他配置**部分,并完成以下操作: - 1. 初始数据库名称. 我们将使用`gitlabhq_production` . - 2. 配置您的首选备份设置. - 3. 我们将在此处进行的唯一其他更改是禁用" **维护"**下的自动次要版本更新. - 4. 保留所有其他设置不变或根据需要进行调整. - 5. 满意后,点击**创建数据库** . - -现在已经创建了数据库,让我们继续使用 ElastiCache 设置 Redis. - -## Redis with ElastiCache[](#redis-with-elasticache "Permalink") - -ElastiCache 是​​一个内存托管的缓存解决方案. Redis 保持其自身的持久性,并用于为 GitLab 应用程序存储会话数据,临时缓存信息和后台作业队列. - -### Create a Redis Security Group[](#create-a-redis-security-group "Permalink") - -1. 导航到 EC2 仪表板. -2. 从左侧菜单中选择" **安全组** ". -3. 单击**创建安全组,**然后填写详细信息. 给它`gitlab-redis-sec-group` (我们将使用`gitlab-redis-sec-group` ),添加描述,然后选择我们之前创建的 VPC -4. 在" **入站规则"**部分中,单击" **添加规则"**并添加一个" **自定义 TCP"**规则,设置端口`6379` ,并将"自定义"源设置为我们之前创建的`gitlab-loadbalancer-sec-group` . -5. 完成后,点击**创建安全组** . - -### Redis Subnet Group[](#redis-subnet-group "Permalink") - -1. 从您的 AWS 控制台导航到 ElastiCache 仪表板. -2. 转到左侧菜单中的" **子网组** ",然后创建一个新的子网组(我们将其命名为`gitlab-redis-group` ). 确保选择我们的 VPC 及其[专用子网](#subnets) . 准备好后,单击**创建** . - - [![ElastiCache subnet](img/98f7e80b6f738f9886082aeec3955fd5.png)](img/ec_subnet.png) - -### Create the Redis Cluster[](#create-the-redis-cluster "Permalink") - -1. 导航回到 ElastiCache 仪表板. -2. 在左侧菜单上选择**Redis** ,然后单击**创建**以创建新的 Redis 集群. 不要启用**集群模式,**因为它[不受支持](../../administration/redis/replication_and_failover_external.html#requirements) . 即使没有启用群集模式,您仍然有机会在多个可用性区域中部署 Redis. -3. 在设置部分: - 1. 为集群命名( `gitlab-redis` )和描述. - 2. 对于版本,选择最新的`5.0`系列(例如`5.0.6` ). - 3. 将端口保留为`6379`因为这是我们在上面的 Redis 安全组中使用的端口. - 4. 选择节点类型(至少为`cache.t3.medium` ,但根据需要进行调整)和副本数. -4. 在高级设置部分: - 1. 选择多可用区自动故障转移选项. - 2. 选择我们之前创建的子网组. - 3. 手动选择首选的可用区域,然后在"副本 2"下选择与其他两个区域不同的区域. - - [![Redis 可用区](img/38ef5bf427869fe9b1050db6eacd2972.png)](img/ec_az.png) - -5. 在安全设置中,编辑安全组,然后选择我们之前创建的`gitlab-redis-sec-group` . -6. 将其余设置保留为默认值,或根据自己的喜好进行编辑. -7. 完成后,点击**创建** . - -## Setting up Bastion Hosts[](#setting-up-bastion-hosts "Permalink") - -由于我们的 GitLab 实例将位于专用子网中,因此我们需要一种通过 SSH 连接到这些实例以进行配置更改,执行升级等的方法.一种方法是通过[堡垒主机](https://en.wikipedia.org/wiki/Bastion_host) ,有时也称为跳转框. - -**提示:**如果您不想维护堡垒主机,则可以设置[AWS Systems Manager Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html)来访问实例. 这超出了本文档的范围. - -### Create Bastion Host A[](#create-bastion-host-a "Permalink") - -1. 导航到 EC2 仪表板,然后单击**Launch instance** . -2. 选择**Ubuntu Server 18.04 LTS(HVM)** AMI. -3. 选择一个实例类型. 我们将使用`t2.micro`因为我们仅使用堡垒主机将 SSH SSH 到我们的其他实例中. -4. Click **配置实例详细信息**. - 1. 在" **网络"下** ,从下拉菜单中选择`gitlab-vpc` . - 2. 在" **子网"下** ,选择我们之前创建的公共子网( `gitlab-public-10.0.0.0` ). - 3. 仔细检查是否在" **自动分配公用 IP"下**选择了" **使用子网设置"("启用")** . - 4. 将其他所有内容保留为默认值,然后单击" **添加存储"** . -5. 对于存储,我们将所有内容保留为默认设置,仅添加 8GB 根卷. 我们不会在此实例上存储任何内容. -6. 单击**添加标签** ,然后在下一个屏幕上单击**添加标签** . - 1. 我们只设置`Key: Name`和`Value: Bastion Host A` -7. Click **配置安全组**. - 1. 选择**创建新的安全组** ,输入**安全组名称** (我们将使用`bastion-sec-group` ),然后添加描述. - 2. 我们将从任何地方( `0.0.0.0/0` )启用 SSH 访问. 如果需要更严格的安全性,请以 CIDR 表示法指定单个 IP 地址或 IP 地址范围. - 3. Click **审查并启动** -8. Review all your settings and, if you’re happy, click **Launch**. -9. 确认您有权访问现有的密钥对或创建一个新的密钥对. 单击**启动实例** . - -确认您可以通过 SSH 进入实例: - -1. 在 EC2 仪表板上,单击左侧菜单中的**Instances** . -2. 从实例列表中选择**Bastion HostA** . -3. 单击**连接,**然后按照连接说明进行操作. -4. 如果能够成功连接,让我们继续设置第二个堡垒主机以实现冗余. - -### Create Bastion Host B[](#create-bastion-host-b "Permalink") - -1. 按照与上述相同的步骤创建 EC2 实例,并进行以下更改: - 1. 对于**Subnet** ,选择我们之前创建的第二个公共子网( `gitlab-public-10.0.2.0` ). - 2. 在" **添加标签"**部分下,我们将设置" `Key: Name`和`Value: Bastion Host B`以便我们可以轻松识别两个实例. - 3. 对于安全组,选择我们上面创建的现有`bastion-sec-group` . - -### Use SSH Agent Forwarding[](#use-ssh-agent-forwarding "Permalink") - -运行 Linux 的 EC2 实例使用私钥文件进行 SSH 身份验证. 您将使用 SSH 客户端和存储在客户端上的私钥文件连接到堡垒主机. 由于私有密钥文件不存在于堡垒主机上,因此您将无法连接到私有子网中的实例. - -在堡垒主机上存储私钥文件是一个坏主意. 要解决此问题,请在客户端上使用 SSH 代理转发. 有关如何使用 SSH 代理转发的分步指南,请参阅[安全连接到在私有 Amazon VPC 中运行的 Linux 实例](https://aws.amazon.com/blogs/security/securely-connect-to-linux-instances-running-in-a-private-amazon-vpc/) . - -## Install GitLab and create custom AMI[](#install-gitlab-and-create-custom-ami "Permalink") - -我们将需要预先配置的自定义 GitLab AMI,以便稍后在我们的启动配置中使用. 首先,我们将使用官方的 GitLab AMI 创建 GitLab 实例. 然后,我们将为 PostgreSQL,Redis 和 Gitaly 添加自定义配置. 如果愿意,您也可以使用自己选择的 EC2 实例启动并[手动安装 GitLab](https://about.gitlab.com/install/) ,而不是使用官方的 GitLab AMI. - -### Install GitLab[](#install-gitlab "Permalink") - -从 EC2 仪表板: - -1. 单击**启动实例,**然后从左侧菜单中选择**社区 AMI** . -2. 在搜索栏中,搜索`GitLab EE ` ,其中``是[发行页面](https://about.gitlab.com/releases/)上显示的最新版本. 选择最新的补丁程序版本,例如`GitLab EE 12.9.2` . -3. 根据您的工作量选择一个实例类型. 请查阅[硬件要求,](../../install/requirements.html#hardware-requirements)以选择适合您需求的[硬件](../../install/requirements.html#hardware-requirements) (至少`c5.xlarge` ,足以容纳 100 位用户). -4. Click **配置实例详细信息**: - 1. 在" **网络"**下拉列表中,选择`gitlab-vpc` ,这是我们之前创建的 VPC. - 2. 在" **子网"**下拉列表中,从我们先前创建的**子网**列表中选择`gitlab-private-10.0.1.0` . - 3. 仔细检查是否将" **自动分配公用 IP"**设置为" `Use subnet setting (Disable)` . - 4. Click **添加存储**. - 5. 默认情况下,根卷为 8GiB,并且在我们不会在其中存储任何数据的情况下,根卷应该足够. -5. 单击**添加标签,**然后添加您可能需要的任何标签. 在本例中,我们将仅设置`Key: Name`和`Value: GitLab` . -6. 单击**配置安全组** . 选中**选择现有安全组,**然后选择我们之前创建的`gitlab-loadbalancer-sec-group` . -7. 如果对设置满意,请单击**查看并启动,**然后单击**启动** . -8. 最后,确认您有权访问所选的私钥文件或创建一个新的私钥文件. 单击**启动实例** . - -### Add custom configuration[](#add-custom-configuration "Permalink") - -使用[SSH 代理转发](#use-ssh-agent-forwarding)通过**Bastion Host A**连接到您的 GitLab 实例. 连接后,添加以下自定义配置: - -#### Disable Let’s Encrypt[](#disable-lets-encrypt "Permalink") - -由于我们要在负载均衡器中添加 SSL 证书,因此我们不需要 GitLab 对 Let's Encrypt 的内置支持. 自 GitLab 10.7 起,使用`https`域时[,默认情况下启用](https://docs.gitlab.com/omnibus/settings/ssl.html)加密[功能](https://docs.gitlab.com/omnibus/settings/ssl.html) ,因此我们需要显式禁用它: - -1. 打开`/etc/gitlab/gitlab.rb`并禁用它: - - ``` - letsencrypt['enable'] = false - ``` - -2. 保存文件并重新配置以使更改生效: - - ``` - sudo gitlab-ctl reconfigure - ``` - -#### Install the `pg_trgm` extension for PostgreSQL[](#install-the-pg_trgm-extension-for-postgresql "Permalink") - -在您的 GitLab 实例中,连接到 RDS 实例以验证访问权限并安装所需的`pg_trgm`扩展. - -要查找主机或终端节点,请导航至**Amazon RDS>数据库** ,然后单击您之前创建的数据库. 在" **连接性和安全性"**选项卡下查找端点. - -不要包括冒号和端口号: - -``` -sudo /opt/gitlab/embedded/bin/psql -U gitlab -h -d gitlabhq_production -``` - -在`psql`提示符下,创建扩展,然后退出会话: - -``` -psql (10.9) -Type "help" for help. - -gitlab=# CREATE EXTENSION pg_trgm; -gitlab=# \q -``` - -#### Configure GitLab to connect to PostgreSQL and Redis[](#configure-gitlab-to-connect-to-postgresql-and-redis "Permalink") - -1. 编辑`/etc/gitlab/gitlab.rb` ,找到`external_url 'http://'`选项并将其更改为您将使用的`https`域. - -2. 查找 GitLab 数据库设置,并根据需要取消注释. 在当前情况下,我们将指定数据库适配器,编码,主机,名称,用户名和密码: - - ``` - # Disable the built-in Postgres - postgresql['enable'] = false - - # Fill in the connection details - gitlab_rails['db_adapter'] = "postgresql" - gitlab_rails['db_encoding'] = "unicode" - gitlab_rails['db_database'] = "gitlabhq_production" - gitlab_rails['db_username'] = "gitlab" - gitlab_rails['db_password'] = "mypassword" - gitlab_rails['db_host'] = "" - ``` - -3. 接下来,我们需要通过添加主机并取消注释端口来配置 Redis 部分: - - ``` - # Disable the built-in Redis - redis['enable'] = false - - # Fill in the connection details - gitlab_rails['redis_host'] = "" - gitlab_rails['redis_port'] = 6379 - ``` - -4. 最后,重新配置 GitLab 以使更改生效: - - ``` - sudo gitlab-ctl reconfigure - ``` - -5. 您可能还会发现运行检查和服务状态以确保一切均已正确设置很有用: - - ``` - sudo gitlab-rake gitlab:check - sudo gitlab-ctl status - ``` - -#### Set up Gitaly[](#set-up-gitaly "Permalink") - -**注意:**在这种体系结构中,只有一台 Gitaly 服务器会造成单点故障. 使用[Gitaly Cluster](../../administration/gitaly/praefect.html)可以消除此限制. - -Gitaly 是一项服务,它提供对 Git 存储库的高级 RPC 访问. 应该在我们之前配置的[专用子网](#subnets)之一中的单独 EC2 实例上启用和配置它. - -让我们创建一个安装 Gitaly 的 EC2 实例: - -1. 在 EC2 仪表板中,单击**启动实例** . -2. 选择一个 AMI. 在此示例中,我们将选择**Ubuntu Server 18.04 LTS(HVM),SSD Volume Type** . -3. Choose an instance type. We’ll pick a **c5.xlarge**. -4. Click **配置实例详细信息**. - 1. 在" **网络"**下拉列表中,选择`gitlab-vpc` ,这是我们之前创建的 VPC. - 2. 在" **子网"**下拉列表中,从我们先前创建的**子网**列表中选择`gitlab-private-10.0.1.0` . - 3. 仔细检查是否将" **自动分配公用 IP"**设置为" `Use subnet setting (Disable)` . - 4. Click **添加存储**. -5. 将根卷大小增加到`20 GiB` ,并将**卷类型**更改为`Provisoned IOPS SSD (io1)` . (这是一个任意大小.创建一个足以满足您的存储库存储需求的卷.) - 1. 对于**IOPS**设置`1000` (20 GiB x 50 IOPS). 每个 GiB 最多可以配置 50 IOPS. 如果选择更大的音量,请相应地增加 IOPS. 以串行方式写入许多小文件的工作负载(如`git` )需要高性能的存储,因此选择`Provisoned IOPS SSD (io1)` . -6. 单击**添加标签**并添加您的标签. 在本例中,我们将仅设置`Key: Name`和`Value: Gitaly` . -7. 单击" **配置安全组",**然后**创建一个新的安全组** . - 1. 给您的安全组一个名称和描述. 我们将同时使用`gitlab-gitaly-sec-group` . - 2. 创建一个**自定义 TCP**规则,并将端口`8075`添加到" **端口范围"中** . 对于**Source** ,选择`gitlab-loadbalancer-sec-group` . - 3. 还要从`bastion-sec-group`添加 SSH 的入站规则,以便我们可以使用来自堡垒主机的[SSH 代理转发](#use-ssh-agent-forwarding)进行连接. -8. 如果对设置满意,请单击**查看并启动,**然后单击**启动** . -9. 最后,确认您有权访问所选的私钥文件或创建一个新的私钥文件. 单击**启动实例** . - -**注意:**除了将配置*和*存储库数据存储在根卷上之外,您还可以选择添加其他 EBS 卷用于存储库存储. 请遵循上述相同的指导. 请参阅[Amazon EBS 定价](https://aws.amazon.com/ebs/pricing/) . 我们不建议使用 EFS,因为它可能会对 GitLab 的性能产生负面影响. 您可以查看[相关文档](../../administration/high_availability/nfs.html#avoid-using-awss-elastic-file-system-efs)以了解更多详细信息. - -现在我们已经准备好我们的 EC2 实例,请按照[文档安装 GitLab 并在其自己的服务器上设置 Gitaly](../../administration/gitaly/index.html#run-gitaly-on-its-own-server) . 在[我们](#install-gitlab)上面[创建](#install-gitlab)的[GitLab 实例](#install-gitlab)上,从该文档执行客户端设置步骤. - -#### Add Support for Proxied SSL[](#add-support-for-proxied-ssl "Permalink") - -当我们在[负载均衡器](#load-balancer)处终止 SSL 时,请按照[支持代理的 SSL 中](https://docs.gitlab.com/omnibus/settings/nginx.html)的步骤在`/etc/gitlab/gitlab.rb`进行配置. - -将更改保存到`gitlab.rb`文件后,切记要运行`sudo gitlab-ctl reconfigure` . - -#### Fast lookup of authorized SSH keys[](#fast-lookup-of-authorized-ssh-keys "Permalink") - -允许访问 GitLab 的用户的公共 SSH 密钥存储在`/var/opt/gitlab/.ssh/authorized_keys` . 通常,我们会使用共享存储,以便当用户通过 SSH 执行 Git 操作时,所有实例都能够访问该文件. 由于我们的设置中没有共享存储,因此我们将更新配置,以通过 GitLab 数据库中的索引查找来授权 SSH 用户. - -按照[通过 GitLab Shell 设置快速查找中](../../administration/operations/fast_ssh_key_lookup.html#setting-up-fast-lookup-via-gitlab-shell)的说明,从使用`authorized_keys`文件切换到数据库. - -如果不配置快速查找,则通过 SSH 进行的 Git 操作将导致以下错误: - -``` -Permission denied (publickey). -fatal: Could not read from remote repository. - -Please make sure you have the correct access rights -and the repository exists. -``` - -#### Configure host keys[](#configure-host-keys "Permalink") - -通常,我们将手动将主应用程序服务器上`/etc/ssh/`的内容(主密钥和公共密钥)复制到所有辅助服务器上的`/etc/ssh` . 这样可以防止在访问负载均衡器后面的群集中的服务器时出现虚假的中间人攻击警报. - -我们将通过创建静态主机密钥作为自定义 AMI 的一部分来自动执行此操作. 由于每次 EC2 实例启动时也会旋转这些主机密钥,因此将它们"硬编码"到我们的自定义 AMI 中是一种方便的解决方法. - -在您的 GitLab 实例上运行以下命令: - -``` -sudo mkdir /etc/ssh_static -sudo cp -R /etc/ssh/* /etc/ssh_static -``` - -在`/etc/ssh/sshd_config`更新以下内容: - -``` -# HostKeys for protocol version 2 -HostKey /etc/ssh_static/ssh_host_rsa_key -HostKey /etc/ssh_static/ssh_host_dsa_key -HostKey /etc/ssh_static/ssh_host_ecdsa_key -HostKey /etc/ssh_static/ssh_host_ed25519_key -``` - -#### Amazon S3 object storage[](#amazon-s3-object-storage "Permalink") - -由于我们不使用 NFS 进行共享存储,因此我们将使用[Amazon S3](https://aws.amazon.com/s3/)存储桶来存储备份,工件,LFS 对象,上传,合并请求差异,容器注册表映像等等. 我们的文档包括[有关如何](../../administration/object_storage.html)为每种数据类型[配置对象存储的说明](../../administration/object_storage.html) ,以及有关在 GitLab 中使用对象存储的其他信息. - -**注意:**由于我们使用的是之前创建的[AWS IAM 配置文件](#create-an-iam-role) ,因此在配置对象存储时,请确保省略 AWS 访问密钥和秘密访问密钥/值对. 而是在您的配置中使用`'use_iam_profile' => true` ,如上面链接的对象存储文档中所示. - -将更改保存到`gitlab.rb`文件后,切记要运行`sudo gitlab-ctl reconfigure` . - -**注意:** GitLab 的当前一项功能仍需要共享目录(NFS),即[GitLab Pages](../../user/project/pages/index.html) . 目前[正在进行的工作](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/196) ,以消除支持 GitLab 页面需要 NFS. - -* * * - -到此,我们的 GitLab 实例的配置更改结束了. 接下来,我们将基于该实例创建自定义 AMI,以用于我们的启动配置和自动缩放组. - -### Create custom AMI[](#create-custom-ami "Permalink") - -在 EC2 仪表板上: - -1. 选择我们[之前创建](#install-gitlab)的`GitLab`实例. -2. 单击" **操作"** ,向下滚动到" **图像"** ,然后单击" **创建图像"** . -3. 给您的图像起一个名称和描述(我们将同时使用`GitLab-Source` ). -4. 将其他所有内容保留为默认值,然后单击**创建图像** - -现在,我们有了一个定制的 AMI,将用于下一步创建启动配置. - -## Deploy GitLab inside an auto scaling group[](#deploy-gitlab-inside-an-auto-scaling-group "Permalink") - -### Create a launch configuration[](#create-a-launch-configuration "Permalink") - -从 EC2 仪表板: - -1. 从左侧菜单中选择**启动配置** ,然后单击**创建启动配置** . -2. 从左侧菜单中选择**我的 AMI** ,然后选择我们在上面创建的`GitLab`自定义 AMI. -3. 选择最适合您需求的实例类型(至少为`c5.xlarge` ),然后单击**配置详细信息** . -4. 输入启动配置的名称(我们将使用`gitlab-ha-launch-config` ). -5. **不要** check **请求竞价型实例**. -6. 从**IAM 角色**下拉列表中,选择我们[之前创建](#create-an-iam-ec2-instance-role-and-profile)的`GitLabAdmin`实例角色. -7. 将其余的保留为默认值,然后单击" **添加存储"** . -8. 默认情况下,根卷为 8GiB,并且在我们不会在其中存储任何数据的情况下,根卷应该足够. 单击**配置安全组** . -9. 选中**选择和现有安全组,**然后选择我们之前创建的`gitlab-loadbalancer-sec-group` . -10. 点击**查看** ,查看您的更改,然后点击**创建启动配置** . -11. 确认您有权访问私钥或创建一个新私钥. 单击**创建启动配置** . - -### Create an auto scaling group[](#create-an-auto-scaling-group "Permalink") - -1. 创建启动配置后,您将看到一个**使用此启动配置创建 Auto Scaling 组**的选项. 单击以开始创建自动缩放组. -2. 输入一个**组名** (我们将使用`gitlab-auto-scaling-group` ). -3. 对于**Group size** ,输入您要开始的实例数(我们将输入`2` ). -4. 从" **网络"**下拉列表中选择`gitlab-vpc` . -5. 添加[我们先前创建的](#subnets)两个专用[子网](#subnets) . -6. 展开" **高级详细信息"**部分,然后选中" **从一个或多个负载平衡器接收流量"**选项. -7. 从**经典负载均衡器**下拉列表中,选择我们之前创建的负载均衡器. -8. For **健康检查类型**, select **ELB**. -9. 我们将" **健康检查宽限期"**保留为默认的`300`秒. 单击" **配置扩展策略"** . -10. Check **使用扩展策略来调整该组的容量**. -11. 对于该组,我们将在 2 到 4 个实例之间扩展,如果 CPU 利用率大于 60%将添加一个实例,如果 CPU 利用率小于 45%则删除一个实例. - -[![Auto scaling group policies](img/36aa502eb297ed552d82e3b015053e9e.png)](img/policies.png) - -1. 最后,根据需要配置通知和标签,查看更改并创建自动缩放组. - -创建自动伸缩组后,您将在 EC2 仪表板中看到新实例. 您还将看到新实例添加到您的负载均衡器. 一旦实例通过健康检查,它们就准备开始从负载平衡器接收流量. - -由于我们的实例是由自动缩放组创建的,因此请返回您的实例并终止[我们在上面手动创建](#install-gitlab)的[实例](#install-gitlab) . 我们只需要该实例即可创建我们的自定义 AMI. - -### Log in for the first time[](#log-in-for-the-first-time "Permalink") - -现在,使用[为负载均衡器](#configure-dns-for-load-balancer)设置[DNS](#configure-dns-for-load-balancer)时使用的域名,您现在应该能够在浏览器中访问 GitLab. 首次要求您为在 GitLab 实例上具有管理员权限的`root`用户设置密码. - -设置后,使用用户名`root`和新创建的密码登录. - -## Health check and monitoring with Prometheus[](#health-check-and-monitoring-with-prometheus "Permalink") - -除了可以在各种服务上启用的 Amazon Cloudwatch 之外,GitLab 还提供了自己的基于 Prometheus 的集成监控解决方案. 有关如何设置的更多信息,请访问[GitLab Prometheus 文档.](../../administration/monitoring/prometheus/index.html) - -GitLab 还具有各种[运行状况检查端点](../../user/admin_area/monitoring/health_check.html) ,您可以对其进行 ping 操作并获取报告. - -## GitLab Runners[](#gitlab-runners "Permalink") - -如果要利用[GitLab CI / CD](../../ci/README.html) ,则必须至少设置一个[GitLab Runner](https://docs.gitlab.com/runner/) . - -阅读有关[在 AWS](https://docs.gitlab.com/runner/configuration/runner_autoscale_aws/)上配置[自动缩放 GitLab Runner 的](https://docs.gitlab.com/runner/configuration/runner_autoscale_aws/)更多信息. - -## Backup and restore[](#backup-and-restore "Permalink") - -GitLab 提供[了一个备份](../../raketasks/backup_restore.html#back-up-gitlab)和还原其 Git 数据,数据库,附件,LFS 对象等的工具. - -一些重要的事情要知道: - -* 备份/还原工具**不**存储某些配置文件,例如机密. 您需要[自己配置](../../raketasks/backup_restore.html#storing-configuration-files) . -* 默认情况下,备份文件存储在本地,但是您可以[使用 S3 备份 GitLab](../../raketasks/backup_restore.html#using-amazon-s3) . -* 您可以[从备份中排除特定目录](../../raketasks/backup_restore.html#excluding-specific-directories-from-the-backup) . - -### Backing up GitLab[](#backing-up-gitlab "Permalink") - -备份 GitLab: - -1. SSH 进入您的实例. -2. 备份: - - ``` - sudo gitlab-backup create - ``` - -**注意:**对于 GitLab 12.1 和更早版本,请使用`gitlab-rake gitlab:backup:create` . - -### Restoring GitLab from a backup[](#restoring-gitlab-from-a-backup "Permalink") - -To restore GitLab, first review the [restore documentation](../../raketasks/backup_restore.html#restore-gitlab), and primarily the restore prerequisites. Then, follow the steps under the [Omnibus installations section](../../raketasks/backup_restore.html#restore-for-omnibus-gitlab-installations). - -## Updating GitLab[](#updating-gitlab "Permalink") - -GitLab 于 22 日每月发布一个新版本. 每当发布新版本时,您都可以更新您的 GitLab 实例: - -1. SSH 进入您的实例 -2. 备份: - - ``` - sudo gitlab-backup create - ``` - -**注意:**对于 GitLab 12.1 和更早版本,请使用`gitlab-rake gitlab:backup:create` . - -1. 更新存储库并安装 GitLab: - - ``` - sudo apt update - sudo apt install gitlab-ee - ``` - -几分钟后,新版本应已启动并正在运行. - -## Conclusion[](#conclusion "Permalink") - -在本指南中,我们主要进行了缩放和一些冗余选项,您的里程可能会有所不同. - -请记住,所有解决方案都需要在成本/复杂性和正常运行时间之间进行权衡. 您想要的正常运行时间越长,解决方案就越复杂. 解决方案越复杂,设置和维护该解决方案所涉及的工作就越多. - -通读以下其他资源,并随时[提出问题](https://gitlab.com/gitlab-org/gitlab/-/issues/new)以请求其他材料: - -* [扩展 GitLab](../../administration/reference_architectures/index.html) :GitLab 支持几种不同类型的集群. -* [Geo 复制](../../administration/geo/replication/index.html) :Geo 是面向广泛分布的开发团队的解决方案. -* [Omnibus GitLab-](https://docs.gitlab.com/omnibus/)您需要了解的有关管理 GitLab 实例的所有信息. -* [上载许可证](../../user/admin_area/license.html) : [使用许可证](../../user/admin_area/license.html)激活所有的 GitLab Enterprise Edition 功能. -* [定价](https://about.gitlab.com/pricing/) :不同层级的定价. - -## Troubleshooting[](#troubleshooting "Permalink") - -### Instances are failing health checks[](#instances-are-failing-health-checks "Permalink") - -如果您的实例未通过负载均衡器的运行状况检查,请验证它们是否从我们之前配置的运行状况检查终结点返回状态`200` . 任何其他状态,包括重定向(例如状态`302` ),都会导致运行状况检查失败. - -您可能必须在`root`用户上设置密码,以防止在运行状况检查通过之前在登录端点上进行自动重定向. - -### “The change you requested was rejected (422)”[](#the-change-you-requested-was-rejected-422 "Permalink") - -如果你看到这个页面,试图设置通过网络界面输入密码时,请确保`external_url`在`gitlab.rb`你正在从一个请求域,并运行匹配`sudo gitlab-ctl reconfigure`进行任何更改之后. \ No newline at end of file diff --git a/_book/docs/012.md b/_book/docs/012.md deleted file mode 100644 index a2446ee93c4059a4196535aa608014b207485b1b..0000000000000000000000000000000000000000 --- a/_book/docs/012.md +++ /dev/null @@ -1,40 +0,0 @@ -# Analytics - -> 原文:[https://docs.gitlab.com/ee/user/analytics/](https://docs.gitlab.com/ee/user/analytics/) - -* [Analytics workspace](#analytics-workspace) -* [Group-level analytics](#group-level-analytics) -* [Project-level analytics](#project-level-analytics) - -# Analytics[](#analytics "Permalink") - -## Analytics workspace[](#analytics-workspace "Permalink") - -在 GitLab 12.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/12077) . - -通过 Analytics(分析)工作区,可以跨 GitLab 汇总分析,以便用户可以在一个地方查看多个项目和组中的信息. - -要访问 Google Analytics(分析)工作区,请单击顶部导航栏中的**更多>分析** . - -## Group-level analytics[](#group-level-analytics "Permalink") - -在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/195979) . - -在组级别可以使用以下分析功能: - -* [Contribution](../group/contribution_analytics/index.html). -* [Insights](../group/insights/index.html). -* [Issues](../group/issues_analytics/index.html). -* [生产力](productivity_analytics.html) (通过`productivity_analytics` [功能标记](../../development/feature_flags/development.html#enabling-a-feature-flag-in-development)启用). -* [值流](value_stream_analytics.html) ,通过`cycle_analytics` [功能标记](../../development/feature_flags/development.html#enabling-a-feature-flag-in-development)启用. - -## Project-level analytics[](#project-level-analytics "Permalink") - -在项目级别可以使用以下分析功能: - -* [CI/CD](../../ci/pipelines/index.html#pipeline-success-and-duration-charts). -* [Code Review](code_review_analytics.html). -* [Insights](../group/insights/index.html). -* [Issues](../group/issues_analytics/index.html). -* [Repository](repository_analytics.html). -* [值流](value_stream_analytics.html) ,通过`cycle_analytics` [功能标记](../../development/feature_flags/development.html#enabling-a-feature-flag-in-development)启用. \ No newline at end of file diff --git a/_book/docs/013.md b/_book/docs/013.md deleted file mode 100644 index 8743ce152e598a049b28436eb559af5e5cd70437..0000000000000000000000000000000000000000 --- a/_book/docs/013.md +++ /dev/null @@ -1,49 +0,0 @@ -# Code Review Analytics - -> 原文:[https://docs.gitlab.com/ee/user/analytics/code_review_analytics.html](https://docs.gitlab.com/ee/user/analytics/code_review_analytics.html) - -* [Overview](#overview) -* [Use cases](#use-cases) -* [Permissions](#permissions) - -# Code Review Analytics[](#code-review-analytics-starter "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/38062) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.7. - -通过 Code Review Analytics,可以轻松地查看打开的合并请求中运行时间最长的审查,从而使您可以对单个合并请求采取措施,并缩短总体周期. - -**注意:**最初,不会显示任何数据. 用户在打开的合并请求中发表评论时,将填充数据. - -## Overview[](#overview "Permalink") - -Code Review Analytics 显示一个打开的合并请求表,该请求至少具有一个非作者注释. 审阅时间从提交第一个非作者评论的时间开始计算. 合并请求的代码审阅时间自动标识为自第一个非作者评论以来的时间. - -要访问 Code Review Analytics,请从您项目的菜单中转到 **项目分析>代码审查** . - -[![Code Review Analytics](img/0124687ca256ab68d34dd0918f1e1a8d.png "List of code reviews; oldest review first.")](img/code_review_analytics_v12_8.png) - -* 该表格按评论时长排序,可帮助您快速找到运行时间最长的评论,这可能需要干预或分解成较小的部分. -* 您可以按里程碑和标签过滤 MR 列表. -* 用于显示作者,批准者,评论数和行更改(-/ +)数的列. - -## Use cases[](#use-cases "Permalink") - -此功能专为[开发团队负责](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#delaney-development-team-lead)人和其他想了解广泛的代码审查动态并确定模式以对其进行解释的人员而设计. - -您可以使用 Code Review Analytics 通过代码审查来揭露团队的独特挑战,并确定可能会大大加快开发周期的改进. - -在以下情况下可以使用代码审查分析: - -* 您的团队同意代码审查进度太慢. -* [价值流分析功能](value_stream_analytics.html)表明,审核是您团队最耗时的步骤. - -您可以使用 Code Review Analytics 查看当前运行最慢的工作类型,并分析它们之间的模式和趋势. 例如: - -* 很多评论或承诺? 也许代码太复杂了. -* 涉及特定作者吗? 也许需要更多的培训. -* 评论和批准者很少? 也许您的团队人手不足. - -## Permissions[](#permissions "Permalink") - -* 在[简化版或青铜级](https://about.gitlab.com/pricing/)上. -* 由具有 Reporter 访问权限及以上权限的用户组成. \ No newline at end of file diff --git a/_book/docs/014.md b/_book/docs/014.md deleted file mode 100644 index 1c80f2ec3f6019d2b886758914547fdc914c5fbd..0000000000000000000000000000000000000000 --- a/_book/docs/014.md +++ /dev/null @@ -1,91 +0,0 @@ -# Productivity Analytics - -> 原文:[https://docs.gitlab.com/ee/user/analytics/productivity_analytics.html](https://docs.gitlab.com/ee/user/analytics/productivity_analytics.html) - -* [Supported features](#supported-features) -* [Accessing metrics and visualizations](#accessing-metrics-and-visualizations) -* [Date ranges](#date-ranges) -* [Permissions](#permissions) -* [Enabling and disabling using feature flags](#enabling-and-disabling-using-feature-flags) - -# Productivity Analytics[](#productivity-analytics-premium "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12079) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.3. - -使用 Productivity Analytics 追踪发展速度. - -For many companies, the development cycle is a black box and getting an estimate of how long, on average, it takes to deliver features is an enormous endeavor. - -虽然[价值流分析](../project/cycle_analytics.html)专注于整个软件开发生命周期(SDLC)流程,但生产力分析为工程管理提供了一种以系统的方式向下钻取的方法,以揭示在个人,项目或团队级别上的模式以及成败的原因. - -生产力降低的原因很多,从降低代码库到快速成长的团队. 为了进行调查,部门或团队负责人可以从可视化合并请求所花费的时间开始. - -## Supported features[](#supported-features "Permalink") - -生产力分析允许 GitLab 用户执行以下操作: - -* 可视化典型的合并请求(MR)生存期和统计信息. 使用直方图显示创建和合并合并请求之间经过的时间分布. -* 深入研究最耗时的合并请求,选择一些异常值,然后筛选所有后续图表以调查潜在原因. -* 按组,项目,作者,标签,里程碑或特定日期范围过滤. 例如,在里程碑或特定日期范围内,筛选出组或项目中特定作者的合并请求. -* 测量随时间变化的速度. 随时间推移可视化以上图表中每个指标的趋势,以观察进度. 如果发现异常值,请放大特定的日期范围. - -## Accessing metrics and visualizations[](#accessing-metrics-and-visualizations "Permalink") - -要访问该图表,请导航至组的侧边栏,然后选择**Analytics(分析)> Productivity Analytics(生产力分析)** . - -以下度量标准和可视化在项目或组级别可用-当前仅涵盖**合并的**合并请求: - -* 直方图,显示创建后经过指定天数进行合并的合并请求数. 选择一个特定的列以筛选后续的图表. -* 直方图显示了合并合并请求所花费的时间(以小时为单位)的细目. 可以使用以下间隔: - * 从第一次提交到第一次评论的时间. - * 从第一次评论到最后一次提交的时间. - * 从上次提交到合并的时间. -* 使用以下内容显示合并请求的大小或复杂度的直方图: - * 每个合并请求的提交数. - * 每次提交的代码行数. - * 触摸的文件数. -* 散点图显示所有 MR 在特定日期合并,以及完成操作所需的天数和 30 天的滚动中位数. -* 该表显示了合并请求的列表及其各自的持续时间指标. - * 用户可以按上述任何指标进行排序. - -## Date ranges[](#date-ranges "Permalink") - -在 GitLab 12.4 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/13188) . - -GitLab 能够根据日期范围过滤分析. 要过滤结果: - -1. 选择一个组. -2. (可选)选择一个项目. -3. 使用可用的日期选择器选择日期范围. - -## Permissions[](#permissions "Permalink") - -只能访问**Productivity Analytics**仪表板: - -* 在[高级或银级](https://about.gitlab.com/pricing/)以上. -* 由具有[Reporter 访问权限](../permissions.html)及以上[权限的](../permissions.html)用户组成. - -## Enabling and disabling using feature flags[](#enabling-and-disabling-using-feature-flags "Permalink") - -生产力分析是: - -* [默认情况下](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18754)从 GitLab 12.4 [启用](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18754) ,但可以使用以下功能标志禁用: - * `productivity_analytics` . - * `productivity_analytics_scatterplot_enabled` . -* 在 GitLab 12.3 中默认为禁用,但可以使用以下功能标志启用: - * `productivity_analytics` . - -GitLab 管理员可以: - -* 通过在 Rails 控制台中运行以下命令,从 GitLab 12.4 禁用此功能: - - ``` - Feature.disable(:productivity_analytics) - Feature.disable(:productivity_analytics_scatterplot_enabled) - ``` - -* 通过在 Rails 控制台中运行以下命令,在 GitLab 12.3 中启用此功能: - - ``` - Feature.enable(:productivity_analytics) - ``` \ No newline at end of file diff --git a/_book/docs/015.md b/_book/docs/015.md deleted file mode 100644 index 571c1984e5848d74a125a4302a5f3284f97814bd..0000000000000000000000000000000000000000 --- a/_book/docs/015.md +++ /dev/null @@ -1,298 +0,0 @@ -# Value Stream Analytics - -> 原文:[https://docs.gitlab.com/ee/user/analytics/value_stream_analytics.html](https://docs.gitlab.com/ee/user/analytics/value_stream_analytics.html) - -* [Overview](#overview) -* [Date ranges](#date-ranges) -* [How Time metrics are measured](#how-time-metrics-are-measured) -* [How the stages are measured](#how-the-stages-are-measured) -* [Example workflow](#example-workflow) -* [Customizable Value Stream Analytics](#customizable-value-stream-analytics) - * [Stage path](#stage-path) - * [Adding a stage](#adding-a-stage) - * [Re-ordering stages](#re-ordering-stages) - * [Label based stages](#label-based-stages) - * [Hiding unused stages](#hiding-unused-stages) -* [Days to completion chart](#days-to-completion-chart) - * [Chart median line](#chart-median-line) - * [Disabling chart](#disabling-chart) - * [Disabling chart median line](#disabling-chart-median-line) -* [Type of work - Tasks by type chart](#type-of-work---tasks-by-type-chart) -* [Permissions](#permissions) -* [More resources](#more-resources) - -# Value Stream Analytics[](#value-stream-analytics "Permalink") - -版本历史 - -* 在项目级别在 GitLab 12.3 之前作为 Cycle Analytics 引入. -* 在小组级别的[GitLab Premium](https://about.gitlab.com/pricing/) 12.3 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/12077) . -* 在 GitLab 12.8 中从 Cycle Analytics [重命名](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23427)为 Value Stream Analytics. - -Value Stream Analytics measures the time spent to go from an [idea to production](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#from-idea-to-production-with-gitlab) (also known as cycle time) for each of your projects. Value Stream Analytics displays the median time spent in each stage defined in the process. - -有关如何为 Value Stream Analytics 的发展做出贡献的信息,请参阅我们的[贡献者文档](../../development/value_stream_analytics.html) . - -值流分析有助于快速确定给定项目的速度. 它指出了开发过程中的瓶颈,从而使管理层能够发现,分类和识别软件开发生命周期中速度下降的根本原因. - -Value Stream Analytics 与[GitLab 流程](../../topics/gitlab_flow.html)紧密结合,并为每个阶段计算单独的中位数. - -## Overview[](#overview "Permalink") - -价值流分析可用: - -* 在 GitLab 12.9 中,通过**组>分析>值流**在组级别. -* 在项目级别,通过" **项目">"分析">"价值流"** . - -作为"价值流分析"计算的一部分,将跟踪七个阶段. - -* **Issue** (Tracker) - * 安排问题的时间(按里程碑或通过将其添加到问题板) -* **Plan** (Board) - * 第一次提交的时间 -* **Code** (IDE) - * 是时候创建合并请求了 -* **Test** (CI) - * GitLab CI / CD 测试代码所需的时间 -* **审核** (合并请求/ MR) - * 花在代码审查上的时间 -* **暂存** (连续部署) - * 合并和部署到生产之间的时间 -* **Total** (Total) - * 总生命周期时间. 也就是说,项目或团队的速度. [以前称为](https://gitlab.com/gitlab-org/gitlab/-/issues/38317) **Production** . - -## Date ranges[](#date-ranges "Permalink") - -在 GitLab 12.4 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/13216) . - -GitLab 提供了根据日期范围过滤分析的功能. 要过滤结果: - -1. 选择一个组. -2. (可选)选择一个项目. -3. 使用可用的日期选择器选择日期范围. - -## How Time metrics are measured[](#how-time-metrics-are-measured "Permalink") - -页面顶部附近的"时间"指标的测量方法如下: - -* **提前期** :从创建问题到关闭问题的平均时间. -* **周期时间** :从第一次提交到发布完成的中值时间. - -注意:通过在提交消息中进行[交联](../project/issues/crosslinking_issues.html)或通过手动链接包含提交的合并请求,将提交与问题相关[联](../project/issues/crosslinking_issues.html) . - -[![Value stream analytics time metrics](img/f7050ce0aa3559c639befc2fe3d7aacb.png "Time metrics for value stream analytics")](img/vsa_time_metrics_v13_0.png) - -## How the stages are measured[](#how-the-stages-are-measured "Permalink") - -Value Stream Analytics 根据项目问题记录阶段时间和数据,但阶段和总阶段除外,在阶段和总阶段中,仅测量部署到生产中的数据. - -具体而言,如果未设置 CI 且尚未定义`production`或`production/*` [环境](../../ci/yaml/README.html#environment) ,则此阶段将没有任何数据. - -下表进一步描述了价值流分析的每个阶段. - -| **Stage** | **Description** | -| --- | --- | -| Issue | 通过标记问题或将其添加到里程碑中,以先发生的为准,来衡量从创建问题到采取行动解决问题之间的平均时间. 仅在标签已经为其创建了[发行委员会列表的](../project/issue_board.html)情况下,才会跟踪该标签. | -| Plan | 测量您在上一阶段采取的操作与将第一次提交推入分支之间的平均时间. 分支的第一个提交是触发**计划**和**代码**之间分离的提交,并且分支中的至少一个提交需要包含相关的发行编号(例如`#42` ). 如果分支中的所有提交都未提及相关的发行号,则不会考虑该阶段的度量时间. | -| Code | 测量推入第一个提交(上一阶段)与创建与该提交相关的合并请求(MR)之间的平均时间. 保持流程跟踪的关键是在合并请求的描述中包括[问题关闭模式](../project/issues/managing_issues.html#closing-issues-automatically) (例如, `Closes #xxx` ,其中`xxx`是与此合并请求相关的问题编号). 如果合并请求描述中不存在问题结束模式,则不会将 MR 视为平台的测量时间. | -| Test | 测量运行该项目的整个管道的中值时间. 这与 GitLab CI / CD 为推送到上一阶段中定义的合并请求的提交运行每个作业所花费的时间有关. 基本上,这是所有管道的开始->完成时间. | -| Review | 测量从创建到合并之间,审核具有结束问题模式的合并请求所需的平均时间. | -| Staging | 测量从合并合并请求到结束发布模式到首次部署到生产之间的平均时间. 在您的 GitLab CI / CD 配置中,通过设置为`production`或匹配`production/*` (区分大小写, `Production`将不起作用)的环境进行跟踪. 如果没有生产环境,则不会进行跟踪. | -| Total | 从问题创建到将代码部署到生产中,运行整个过程所需的所有时间(中位数)之和. [以前称为](https://gitlab.com/gitlab-org/gitlab/-/issues/38317) **Production** . | - -幕后工作原理: - -1. 问题和合并请求成对地分组在一起,这样对于每个``对,合并请求都具有对应问题的[问题关闭模式](../project/issues/managing_issues.html#closing-issues-automatically) . **不**考虑所有其他问题和合并请求. -2. 然后,在最近的 XX 天(由 UI 指定-默认为 90 天)中过滤出``对. 因此,它禁止考虑这些对. -3. 对于其余的``对,我们检查阶段所需的信息,例如发行日期,合并请求合并时间等. - -综上所述,不会跟踪任何未遵循[GitLab 流程的](../../workflow/gitlab_flow.html)内容,并且 Value Stream Analytics 仪表板将不会显示以下任何数据: - -* 合并不会解决问题的请求. -* 未在发行委员会中贴有标签的问题或未分配里程碑的问题. -* 如果项目没有`production`或`production/*`环境,则为阶段和生产阶段. - -## Example workflow[](#example-workflow "Permalink") - -以下是一个简单的虚拟周期工作流,它在一天中经历了所有七个阶段后,才发生. 请注意,如果一个阶段没有开始和结束标记,则不会对其进行测量,因此不会在中位时间中进行计算. 假定已创建里程碑并配置了用于测试和设置环境的 CI. - -1. 在 09:00( **发行**阶段开始)创建**发行** . -2. 在 11:00( **发行**阶段停止/ **计划**阶段开始)将发行添加到里程碑. -3. 开始解决此问题,在本地创建一个分支,并在 12:00 提交一次. -4. 对分支进行第二次提交,该分支在 12.30( **计划**阶段的停止/ **代码**阶段的开始)中提及发行号. -5. 推送分支并创建一个合并请求,该请求的描述在 14:00( **代码**阶段停止/ **测试**和**复审**阶段开始)中包含[问题关闭模式](../project/issues/managing_issues.html#closing-issues-automatically) . -6. CI 将开始运行您在[`.gitlab-ci.yml`](../../ci/yaml/README.html)定义的脚本,并需要 5 分钟( **测试**阶段停止). -7. 查看合并请求,确保一切正常,然后在 19:00 合并合并请求. ( **复习**阶段的停止/启动**分期**阶段). -8. 现在,合并请求合并,部署到`production`环境中开始和结束日 19:30( **分期**阶段停止). -9. 循环完成,并且先前阶段的中位数时间总和记录到" **总计"**阶段. 这是从创建问题到将其相关合并请求部署到生产之间的时间. - -从上面的示例中,您可以得出每个阶段完成所需的时间,只要达到其总时间即可: - -* **问题** :2 小时(11:00-09:00) -* **计划** :1 小时(12:00-11:00) -* **编码** :2h(14:00-12:00) -* **测试时间** :5 分钟 -* **评论** :5 小时(19:00-14:00) -* **演出时间** :30 分钟(19:30-19:00) -* **总计** :由于此阶段测量的是之前所有阶段的中位时间之和,因此如果我们不知道之前各阶段的状态,则无法计算. 如果这是项目中运行的第一个周期,则**总**时间为 10h 30min(19:30-09:00) - -一些注意事项: - -* 在上面的示例中,我们演示了您的第一次提交没有提到发行号也没关系,您可以稍后在正在处理的分支的任何提交中进行此操作. -* 您可以看到,由于未将" **测试"**阶段计算为整个周期的时间,因此" **检查"**阶段已包含在" **审查"**过程中(应测试每个 MR). -* 上面的示例只是七个阶段中的**一个循环** . 添加多个周期,计算它们的中值时间,结果就是 Value Stream Analytics 仪表板显示的内容. - -## Customizable Value Stream Analytics[](#customizable-value-stream-analytics "Permalink") - -在 GitLab 12.9 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/12196) . - -默认阶段旨在直接使用,但是可能并不适合所有团队. 不同的团队使用不同的方法来构建软件,因此一些团队可能想要自定义其 Value Stream Analytics. - -GitLab 允许用户隐藏默认阶段并创建自定义阶段,使其更适合其开发工作流程. - -**注意:**自定义性[仅适用于组级别的](https://gitlab.com/gitlab-org/gitlab/-/issues/35823#note_272558950)价值流分析. - -### Stage path[](#stage-path "Permalink") - -在 GitLab 13.0 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/210315) . - -从视觉上将阶段描绘为水平过程流. 选择一个阶段将更新值流下方的内容. - -默认情况下禁用. 如果您具有自我管理的实例,则管理员可以[打开 Rails 控制台](../../administration/troubleshooting/navigating_gitlab_via_rails_console.html)并使用以下命令启用它: - -``` -Feature.enable(:value_stream_analytics_path_navigation) -``` - -### Adding a stage[](#adding-a-stage "Permalink") - -在下面的示例中,我们将创建一个新阶段,该阶段可以衡量和跟踪从创建到关闭的所有问题. - -1. 导航到您组的" **分析">"价值流"** . -2. 单击**添加阶段**按钮. -3. 填写新的舞台表格: - * 名称:问题开始完成. - * 开始事件:已创建问题. - * 结束事件:问题已关闭. -4. 单击**添加阶段**按钮. - -[![New Value Stream Analytics Stage](img/d1c47110b6092ce9cec04ff22addfaa4.png "Form for creating a new stage")](img/new_vsm_stage_v12_9.png) - -新阶段将保持不变,并将始终显示在您组的"价值流分析"页面上. - -如果要更改或删除阶段,可以通过以下方法轻松地针对自定义阶段进行操作: - -1. Hovering over the stage. -2. 单击垂直省略号( )出现的按钮. - -[![Value Stream Analytics Stages](img/d277485e75207494ed3529dfcc7a6395.png)](img/vsm_stage_list_v12_9.png) - -创建自定义阶段需要指定两个事件: - -* 开始. -* 结束. - -请小心选择*在*结束事件*之前*发生的开始事件. 例如,考虑一个阶段: - -* 在将问题添加到板上时开始. -* 创建问题时结束. - -此阶段将不起作用,因为开始事件发生时,结束事件已经发生. 为防止此类无效阶段,UI 禁止出现不兼容的开始和结束事件. 选择开始事件后,停止事件下拉列表将仅列出兼容事件. - -### Re-ordering stages[](#re-ordering-stages "Permalink") - -在 GitLab 12.10 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/196698) . - -添加自定义阶段后,您可以"拖放"阶段以重新排列其顺序. 这些更改将自动保存到系统中. - -### Label based stages[](#label-based-stages "Permalink") - -预定义的开始和结束事件可以涵盖涉及问题和合并请求的许多用例. - -为了支持更复杂的工作流程,请使用基于组标签的阶段. 这些事件基于添加或删除的标签. 特别是, [范围标签](../project/labels.html#scoped-labels-premium)对于复杂的工作流程很有用. - -在此示例中,我们希望测量更准确的代码检查时间. 工作流程如下: - -* 代码审阅开始时,审阅者将`workflow::code_review_start`标签添加到合并请求中. -* 代码检查完成后,检查者将`workflow::code_review_complete`标签添加到合并请求中. - -创建一个称为"代码审查"的新阶段: - -[![New Label Based Value Stream Analytics Stage](img/ea01744c06eb8853392bfd840dc1517d.png "Creating a label based Value Stream Analytics Stage")](img/label_based_stage_vsm_v12_9.png) - -### Hiding unused stages[](#hiding-unused-stages "Permalink") - -有时某些默认阶段与团队无关. 在这种情况下,您可以轻松隐藏阶段,使它们不再出现在列表中. 隐藏阶段: - -1. 添加定制阶段以激活可定制性. -2. 将鼠标悬停在要隐藏的默认阶段上. -3. 单击垂直省略号( )按钮出现,然后选择" **隐藏舞台"** . - -要恢复以前隐藏的默认阶段: - -1. Click **添加一个阶段** button. -2. 在右上角打开" **恢复隐藏的阶段"**下拉列表. -3. 选择一个阶段. - -## Days to completion chart[](#days-to-completion-chart "Permalink") - -在 GitLab 12.6 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21631) . - -该图表直观地描述了完成周期所需的总天数. - -该图表使用全局页面过滤器来基于选定的组,项目和时间范围显示数据. 此外,可以从图表本身内选择特定阶段. - -### Chart median line[](#chart-median-line "Permalink") - -在 GitLab 12.7 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/36675) . - -图表上的中间线显示的数据偏移了所选的天数. 例如,如果选择了 30 天的数据(例如 2019-12-16 至 2020-01-15),则中线将代表前 30 天的数据(2019-11-16 至 2019-12 -16)作为要比较的指标. - -### Disabling chart[](#disabling-chart "Permalink") - -This chart is enabled by default. If you have a self-managed instance, an administrator can open a Rails console and disable it with the following command: - -``` -Feature.disable(:cycle_analytics_scatterplot_enabled) -``` - -### Disabling chart median line[](#disabling-chart-median-line "Permalink") - -默认情况下,此图表的中线是启用的. 如果您具有自我管理的实例,则管理员可以打开 Rails 控制台并使用以下命令将其禁用: - -``` -Feature.disable(:cycle_analytics_scatterplot_median_enabled) -``` - -## Type of work - Tasks by type chart[](#type-of-work---tasks-by-type-chart "Permalink") - -在 GitLab 12.10 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/32421) . - -此图表显示每天的问题和合并请求的累积计数. - -该图表使用全局页面过滤器来基于选定的组,项目和时间范围显示数据. 该图表默认为显示问题计数,但可以切换为显示合并请求数据,并进一步细化为特定的组级标签. - -默认情况下,预先选择了最高的组级别标签(最多 10 个),最多可以选择 15 个标签. - -## Permissions[](#permissions "Permalink") - -Project Value Stream Analytics 仪表板上的当前权限为: - -* 公共项目-任何人都可以访问. -* 内部项目-任何经过身份验证的用户都可以访问. -* 私人项目-访客及以上的任何成员都可以访问. - -您通常可以[阅读有关权限的更多信息](../../ci/yaml/README.html) . - -对于 GitLab 12.3 和更高版本中引入的 Value Stream Analytics 功能: - -* 用户必须具有 Reporter 或更高权限. -* 仅在[Premium 或 Silver 等级](https://about.gitlab.com/pricing/)及更高[级别](https://about.gitlab.com/pricing/)上可用. - -## More resources[](#more-resources "Permalink") - -Learn more about Value Stream Analytics in the following resources: - -* [Value Stream Analytics feature page](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/). -* [Value Stream Analytics feature preview](https://about.gitlab.com/blog/2016/09/16/feature-preview-introducing-cycle-analytics/). -* [Value Stream Analytics feature highlight](https://about.gitlab.com/blog/2016/09/21/cycle-analytics-feature-highlight/). \ No newline at end of file diff --git a/_book/docs/016.md b/_book/docs/016.md deleted file mode 100644 index 4ce588b0d0e27519d83261314aa935773d7e0fea..0000000000000000000000000000000000000000 --- a/_book/docs/016.md +++ /dev/null @@ -1,309 +0,0 @@ -# Kubernetes clusters - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/](https://docs.gitlab.com/ee/user/project/clusters/) - -* [Overview](#overview) -* [Setting up](#setting-up) - * [Supported cluster versions](#supported-cluster-versions) - * [Adding and removing clusters](#adding-and-removing-clusters) - * [Multiple Kubernetes clusters](#multiple-kubernetes-clusters) - * [Setting the environment scope](#setting-the-environment-scope-premium) -* [Configuring your Kubernetes cluster](#configuring-your-kubernetes-cluster) - * [Security implications](#security-implications) - * [GitLab-managed clusters](#gitlab-managed-clusters) - * [Important notes](#important-notes) - * [Clearing the cluster cache](#clearing-the-cluster-cache) - * [Base domain](#base-domain) -* [Installing applications](#installing-applications) -* [Auto DevOps](#auto-devops) -* [Deploying to a Kubernetes cluster](#deploying-to-a-kubernetes-cluster) - * [Deployment variables](#deployment-variables) - * [Custom namespace](#custom-namespace) - * [Integrations](#integrations) - * [Canary Deployments](#canary-deployments-premium) - * [Deploy Boards](#deploy-boards-premium) - * [Viewing pod logs](#viewing-pod-logs) - * [Web terminals](#web-terminals) - * [Troubleshooting](#troubleshooting) -* [Monitoring your Kubernetes cluster](#monitoring-your-kubernetes-cluster) - * [Visualizing cluster health](#visualizing-cluster-health) - -# Kubernetes clusters[](#kubernetes-clusters "Permalink") - -版本历史 - -* 在项目的 GitLab 10.1 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/35954) . -* 在 GitLab 11.6 中针对[组](../../group/clusters/index.html) [引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/34758) . -* 在 GitLab 11.11 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/39840)了[实例](../../instance/clusters/index.html) . - -## Overview[](#overview "Permalink") - -使用 GitLab 项目 Kubernetes 集成,您可以: - -* Use [Review Apps](../../../ci/review_apps/index.html). -* Run [pipelines](../../../ci/pipelines/index.html). -* [部署](#deploying-to-a-kubernetes-cluster)您的应用程序. -* 检测和[监控 Kubernetes](#monitoring-your-kubernetes-cluster) . -* 与[Auto DevOps](#auto-devops)一起使用. -* Use [Web terminals](#web-terminals). -* Use [Deploy Boards](#deploy-boards-premium). -* Use [Canary Deployments](#canary-deployments-premium). -* View [Logs](#viewing-pod-logs). -* [使用 Knative](serverless/index.html)在[Kubernetes 上](serverless/index.html)运行无服务器工作负载. - -除了在项目级别进行集成之外,Kubernetes 集群还可以在[组级别](../../group/clusters/index.html)或[GitLab 实例级别](../../instance/clusters/index.html)进行集成. - -## Setting up[](#setting-up "Permalink") - -### Supported cluster versions[](#supported-cluster-versions "Permalink") - -GitLab 承诺在任何给定时间至少支持两个生产就绪的 Kubernetes 次要版本. 我们会定期审查我们支持的版本,并提供四个月的弃用期,然后再删除特定版本的支持. 支持的版本范围基于以下方面的评估: - -* 我们自己的需求. -* 主要托管 Kubernetes 提供商支持的版本. -* [Kubernetes 社区支持](https://kubernetes.io/docs/setup/release/version-skew-policy/#supported-versions)的版本. - -当前,GitLab 支持以下 Kubernetes 版本: - -* 1.16 -* 1.15 -* 1.14 -* 1.13(不建议使用,支持终止于 2020 年 11 月 22 日) -* 1.12(不建议使用,支持终止于 2020 年 9 月 22 日) - -**注意:**某些 GitLab 功能可能支持此处提供的范围之外的版本. - -### Adding and removing clusters[](#adding-and-removing-clusters "Permalink") - -有关如何执行以下操作的详细信息,请参见[添加和删​​除 Kubernetes 集群](add_remove_clusters.html) : - -* 使用 GitLab 的 UI 在 Google Cloud Platform(GCP)或 Amazon Elastic Kubernetes Service(EKS)中创建集群. -* 从任何 Kubernetes 平台向现有集群添加集成. - -### Multiple Kubernetes clusters[](#multiple-kubernetes-clusters "Permalink") - -版本历史 - -* 在[GitLab Premium](https://about.gitlab.com/pricing/) 10.3 中引入 -* 在 13.2 中[移至](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35094) GitLab 核心. - -您可以将多个 Kubernetes 集群关联到您的项目. 这样,您可以为不同的环境(例如开发,登台,生产等)使用不同的集群. - -就像您第一次一样,只需添加另一个集群,并确保[设置一个环境范围即可](#setting-the-environment-scope-premium)将新集群与其他集群区分开. - -#### Setting the environment scope[](#setting-the-environment-scope-premium "Permalink") - -将多个 Kubernetes 集群添加到您的项目时,您需要通过环境范围来区分它们. 环境范围将群集与[环境](../../../ci/environments/index.html)相关联,类似于[特定](../../../ci/variables/README.html#limit-the-environment-scopes-of-environment-variables)于[环境的变量的](../../../ci/variables/README.html#limit-the-environment-scopes-of-environment-variables)工作方式. - -默认环境范围是`*` ,这意味着所有作业,无论其环境如何,都将使用该群集. 每个作用域只能由项目中的单个群集使用,否则将发生验证错误. 另外,没有设置环境关键字的作业将无法访问任何群集. - -例如,假设项目中存在以下 Kubernetes 集群: - -| Cluster | 环境范围 | -| --- | --- | -| Development | `*` | -| Production | `production` | - -[`.gitlab-ci.yml`](../../../ci/yaml/README.html)中设置了以下环境: - -``` -stages: - - test - - deploy - -test: - stage: test - script: sh test - -deploy to staging: - stage: deploy - script: make deploy - environment: - name: staging - url: https://staging.example.com/ - -deploy to production: - stage: deploy - script: make deploy - environment: - name: production - url: https://example.com/ -``` - -结果将是: - -* The Development cluster details will be available in the `deploy to staging` job. -* 生产集群详细信息将在`deploy to production`作业中提供. -* `test`作业中没有可用的群集详细信息,因为它没有定义任何环境. - -## Configuring your Kubernetes cluster[](#configuring-your-kubernetes-cluster "Permalink") - -[将 Kubernetes 群集添加](add_remove_clusters.html)到 GitLab 之后,请阅读本节,其中涵盖了使用 GitLab 配置 Kubernetes 群集的重要注意事项. - -### Security implications[](#security-implications "Permalink") - -**Important:** The whole cluster security is based on a model where [developers](../../permissions.html) are trusted, so **仅允许受信任的用户控制您的集群**. - -默认的群集配置授予对成功构建和部署容器化应用程序所需的广泛功能的访问权限. 请记住,群集上运行的所有应用程序都使用相同的凭据. - -### GitLab-managed clusters[](#gitlab-managed-clusters "Permalink") - -版本历史 - -* 在 GitLab 11.5 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22011) . -* 在 GitLab 11.11 中成为[可选](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/26565) . - -您可以选择允许 GitLab 为您管理集群. 如果您的集群由 GitLab 管理,则将自动创建项目资源. 有关创建哪些资源的详细信息,请参见" [访问控制"](add_remove_clusters.html#access-controls)部分. - -如果选择管理自己的群集,则不会自动创建特定于项目的资源. 如果使用的是[Auto DevOps](../../../topics/autodevops/index.html) ,则需要显式提供部署作业将使用的`KUBE_NAMESPACE` [部署变量](#deployment-variables) ,否则将为您创建一个名称空间. - -#### Important notes[](#important-notes "Permalink") - -在 GitLab 和集群上注意以下几点: - -* 如果您在群集上[安装应用程序](#installing-applications) ,即使您选择管理自己的群集,GitLab 也会创建运行这些资源所需的资源. -* 请注意,手动管理由 GitLab 创建的资源(例如名称空间和服务帐户)可能会导致意外错误. 如果发生这种情况,请尝试[清除集群缓存](#clearing-the-cluster-cache) . - -#### Clearing the cluster cache[](#clearing-the-cluster-cache "Permalink") - -在 GitLab 12.6 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/31759) . - -如果您选择允许 GitLab 为您管理集群,则 GitLab 将存储它为项目创建的名称空间和服务帐户的缓存版本. 如果在群集中手动修改这些资源,则此缓存可能与群集不同步,这可能导致部署作业失败. - -清除缓存: - -1. 导航到项目的" **操作">" Kubernetes"**页面,然后选择您的集群. -2. 展开**高级设置**部分. -3. Click **Clear cluster cache**. - -### Base domain[](#base-domain "Permalink") - -在 GitLab 11.8 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24580) . - -**注意:**使用 GitLab Serverless 时,无需在群集设置上指定基本域. 在这种情况下,域将被指定为 Knative 安装的一部分. 请参阅[安装应用程序](#installing-applications) . - -指定基本域将自动将`KUBE_INGRESS_BASE_DOMAIN`设置为环境变量. 如果您使用的是[Auto DevOps](../../../topics/autodevops/index.html) ,则此域将用于不同的阶段. 例如,"自动查看应用程序"和"自动部署". - -该域应将通配符 DNS 配置为入口 IP 地址. 安装 Ingress 之后(请参阅[安装应用程序](#installing-applications) ),您可以: - -* 创建一个指向您的域提供商指向入口 IP 地址的`A`记录. -* 使用 nip.io 或 xip.io 之类的服务输入通配符 DNS 地址. 例如, `192.168.1.1.xip.io` . - -## Installing applications[](#installing-applications "Permalink") - -GitLab 可以在项目级集群中安装和管理一些应用程序,例如 Helm,GitLab Runner,Ingress,Prometheus 等. 有关为项目集群安装,升级,卸载和故障排除应用程序的更多信息,请参阅[GitLab 托管应用程序](../../clusters/applications.html) . - -## Auto DevOps[](#auto-devops "Permalink") - -Auto DevOps 自动检测,构建,测试,部署和监视您的应用程序. - -要充分利用 Auto DevOps(自动部署,自动查看应用程序和自动监控),您需要启用 Kubernetes 项目集成. - -[Read more about Auto DevOps](../../../topics/autodevops/index.html) - -**注意** Kubernetes 群集可以在没有 Auto DevOps 的情况下使用. - -## Deploying to a Kubernetes cluster[](#deploying-to-a-kubernetes-cluster "Permalink") - -Kubernetes 集群可以作为部署作业的目标. 如果 - -* 该集群与 GitLab 集成在一起,特殊的[部署变量](#deployment-variables)可用于您的工作,并且不需要配置. 您可以使用诸如`kubectl`或`helm`工具立即开始从作业中与集群进行交互. -* 您无需使用 GitLab 的集群集成,仍然可以将其部署到集群中. 但是,您需要自己使用[环境变量](../../../ci/variables/README.html#custom-environment-variables)配置 Kubernetes 工具,然后才能通过作业与集群进行交互. - -### Deployment variables[](#deployment-variables "Permalink") - -Kubernetes 集群集成在 GitLab CI / CD 构建环境中公开了以下[部署变量](../../../ci/variables/README.html#deployment-environment-variables) . - -| Variable | Description | -| --- | --- | -| `KUBE_URL` | 等于 API URL. | -| `KUBE_TOKEN` | [环境服务帐户](add_remove_clusters.html#access-controls)的 Kubernetes 令牌. | -| `KUBE_NAMESPACE` | 与项目的部署服务帐户关联的名称空间. 格式为`--` . 对于由 GitLab 管理的集群,GitLab 会在集群中自动创建一个匹配的名称空间. | -| `KUBE_CA_PEM_FILE` | 包含 PEM 数据的文件的路径. 仅当指定了自定义 CA 捆绑包时才存在. | -| `KUBE_CA_PEM` | ( **已弃用** )原始 PEM 数据. 仅当指定了自定义 CA 捆绑包时. | -| `KUBECONFIG` | 包含用于此部署的`kubeconfig`的文件的路径. 如果指定,则将嵌入 CA 捆绑软件. 此配置还嵌入了在`KUBE_TOKEN`定义的相同令牌,因此您可能只需要此变量. 该变量名也会由`kubectl`自动选择,因此,如果使用`kubectl`则实际上不需要显式引用它. | -| `KUBE_INGRESS_BASE_DOMAIN` | 从 GitLab 11.8 开始,此变量可用于为每个群集设置一个域. 有关更多信息,请参见[群集域](#base-domain) . | - -**注意:**在 GitLab 11.5 之前, `KUBE_TOKEN`是集群集成的主要服务帐户的 Kubernetes 令牌.**注意:**如果您的集群是在 GitLab 12.2 之前创建的,则默认`KUBE_NAMESPACE`将设置为`-` . - -### Custom namespace[](#custom-namespace "Permalink") - -在 GitLab 12.6 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/27630) . - -Kubernetes 集成默认为格式为`--`的特定于项目环境的名称空间(请参阅[部署变量](#deployment-variables) ). - -对于**非** GitLab 管理的集群,可以使用`.gitlab-ci.yml` [`environment:kubernetes:namespace`](../../../ci/environments/index.html#configuring-kubernetes-deployments)来定制[`environment:kubernetes:namespace`](../../../ci/environments/index.html#configuring-kubernetes-deployments) . - -**注意:**使用[GitLab 管理的集群时](#gitlab-managed-clusters) ,名称空间是在部署之前自动创建的, [无法自定义](https://gitlab.com/gitlab-org/gitlab/-/issues/38054) . - -### Integrations[](#integrations "Permalink") - -#### Canary Deployments[](#canary-deployments-premium "Permalink") - -利用[Kubernetes 的 Canary 部署,](https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments)并在部署板内部可视化您的 Canary 部署,而无需离开 GitLab. - -[Read more about Canary Deployments](../canary_deployments.html) - -#### Deploy Boards[](#deploy-boards-premium "Permalink") - -GitLab 的部署板提供了 Kubernetes 上运行的每个 CI [环境](../../../ci/environments/index.html)的当前运行状况和状态的合并视图,显示了部署中 Pod 的状态. 开发人员和其他团队成员可以在已经使用的工作流程中逐个窗格地查看发布的进度和状态,而无需访问 Kubernetes. - -[Read more about Deploy Boards](../deploy_boards.html) - -#### Viewing pod logs[](#viewing-pod-logs "Permalink") - -使用 GitLab 可以轻松查看连接的 Kubernetes 集群中正在运行的 Pod 的日志. 通过直接在 GitLab 中显示日志,开发人员可以避免管理控制台工具或跳转到其他界面. - -[Read more about Kubernetes logs](kubernetes_pod_logs.html) - -#### Web terminals[](#web-terminals "Permalink") - -在 GitLab 8.15 中引入. - -启用后,Kubernetes 集成将为您的[环境](../../../ci/environments/index.html)添加[Web 终端](../../../ci/environments/index.html#web-terminals)支持. 这基于 Docker 和 Kubernetes 中的`exec`功能,因此您可以在现有容器中获得一个新的 Shell 会话. 要使用此集成,您应该使用上面的部署变量将其部署到 Kubernetes,并确保对所有部署,副本集和 Pod 进行注释: - -* `app.gitlab.com/env: $CI_ENVIRONMENT_SLUG` -* `app.gitlab.com/app: $CI_PROJECT_PATH_SLUG` - -`$CI_ENVIRONMENT_SLUG`和`$CI_PROJECT_PATH_SLUG`是 CI 变量的值. - -您必须是项目所有者或拥有`maintainer`权限才能使用终端. 支持仅限于环境中第一个容器中的第一个容器. - -### Troubleshooting[](#troubleshooting "Permalink") - -在开始部署作业之前,GitLab 将为部署作业专门创建以下内容: - -* 命名空间. -* A service account. - -但是,有时 GitLab 无法创建它们. 在这种情况下,您的工作将失败,并显示以下消息: - -``` -This job failed because the necessary resources were not successfully created. -``` - -要在创建名称空间和服务帐户时查找导致此错误的原因,请检查[日志](../../../administration/logs.html#kuberneteslog) . - -失败的原因包括: - -* 您为 GitLab 提供的令牌没有 GitLab 所需的[`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)特权. -* 缺少`KUBECONFIG`或`KUBE_TOKEN`变量. 要传递给您的工作,他们必须具有匹配的[`environment:name`](../../../ci/environments/index.html#defining-environments) . 如果您的作业没有设置`environment:name` ,则不会通过 Kubernetes 凭据. - -**注意:**从 GitLab 12.0 或更早版本升级的项目级群集可能以导致此错误的方式进行配置. 如果要自己管理名称空间和服务帐户,请确保取消选择由[GitLab 管理的群集](#gitlab-managed-clusters)选项. - -## Monitoring your Kubernetes cluster[](#monitoring-your-kubernetes-cluster "Permalink") - -自动检测和监控 Kubernetes 指标. 还支持[NGINX Ingress 的](../integrations/prometheus_library/nginx.html)自动监视. - -[Read more about Kubernetes monitoring](../integrations/prometheus_library/kubernetes.html) - -### Visualizing cluster health[](#visualizing-cluster-health "Permalink") - -版本历史 - -* 在[GitLab Ultimate](https://about.gitlab.com/pricing/) 10.6 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4701) . -* 在 13.2 中[移至](https://gitlab.com/gitlab-org/gitlab/-/issues/208224) GitLab 核心. - -[部署 Prometheus 后](#installing-applications) ,GitLab 将自动监视群集的运行状况. 在群集设置页面的顶部,显示 CPU 和内存利用率以及可用总量. 如果群集的内存不足,则监视群集资源可能很重要,可能会关闭或无法启动. - -[![Cluster Monitoring](img/0e27f7f7b1dd7b6748365d5ea985238a.png)](img/k8s_cluster_monitoring.png) \ No newline at end of file diff --git a/_book/docs/017.md b/_book/docs/017.md deleted file mode 100644 index 44149203201a8e84ffd6b29e0d80e99ab486a7da..0000000000000000000000000000000000000000 --- a/_book/docs/017.md +++ /dev/null @@ -1,256 +0,0 @@ -# Adding and removing Kubernetes clusters - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/add_remove_clusters.html](https://docs.gitlab.com/ee/user/project/clusters/add_remove_clusters.html) - -* [Before you begin](#before-you-begin) -* [Access controls](#access-controls) - * [Important notes](#important-notes) - * [RBAC cluster resources](#rbac-cluster-resources) - * [ABAC cluster resources](#abac-cluster-resources) - * [Security of GitLab Runners](#security-of-gitlab-runners) -* [Create new cluster](#create-new-cluster) -* [Add existing cluster](#add-existing-cluster) - * [Existing Kubernetes cluster](#existing-kubernetes-cluster) - * [Disable Role-Based Access Control (RBAC) (optional)](#disable-role-based-access-control-rbac-optional) -* [Enabling or disabling integration](#enabling-or-disabling-integration) -* [Removing integration](#removing-integration) -* [Learn more](#learn-more) - -# Adding and removing Kubernetes clusters[](#adding-and-removing-kubernetes-clusters "Permalink") - -GitLab 为以下 Kubernetes 提供者提供了集成的集群创建功能: - -* Google Kubernetes 引擎(GKE). -* Amazon Elastic Kubernetes 服务(EKS). - -GitLab 还可以与本地或托管的任何标准 Kubernetes 提供程序集成. - -**注意:**观看[使用 GitLab 和 Google Cloud Platform 进行](https://about.gitlab.com/webcast/scalable-app-deploy/)的网络广播[可扩展应用程序部署,](https://about.gitlab.com/webcast/scalable-app-deploy/)并了解如何通过单击几下加速由 Google Cloud Platform(GCP)管理的 Kubernetes 集群.**提示:**每个新的 Google Cloud Platform(GCP)帐户[在注册后](https://console.cloud.google.com/freetrial)都会获得[$ 300 的信用额](https://console.cloud.google.com/freetrial) ,并且与 Google 合作,GitLab 能够为新的 GCP 帐户提供额外的$ 200,以开始使用 GitLab 的 Google Kubernetes Engine Integration. 您所要做的就是[点击此链接](https://cloud.google.com/partners/partnercredit/?pcn_code=0014M00001h35gDQAQ#contact-form)并申请信贷. - -## Before you begin[](#before-you-begin "Permalink") - -在使用 GitLab [添加 Kubernetes 集群](#create-new-cluster)之前,您需要: - -* GitLab 本身. 要么: - * 一个[GitLab.com 帐户](https://about.gitlab.com/pricing/#gitlab-com) . - * 使用 GitLab 12.5 或更高版本的[自我管理安装](https://about.gitlab.com/pricing/#self-managed) . 这将确保 GitLab UI 可用于创建集群. -* 以下 GitLab 访问: - * [维护者](../../permissions.html#project-members-permissions)对项目级集群的项目[访问](../../permissions.html#project-members-permissions) . - * [维护者](../../permissions.html#group-members-permissions)对组级别集群的[访问权限](../../permissions.html#group-members-permissions) . - * 自我管理的实例级别群集的管理[区域访问](../../admin_area/index.html) . - -## Access controls[](#access-controls "Permalink") - -在 GitLab 中创建集群时,系统会询问您是否要创建以下任一集群: - -* A [Role-based access control (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) cluster. -* An [Attribute-based access control (ABAC)](https://kubernetes.io/docs/reference/access-authn-authz/abac/) cluster. - -**注意:**建议使用[RBAC](#rbac-cluster-resources) ,GitLab 为默认值. - -GitLab 创建必要的服务帐户和特权,以安装和运行[GitLab 托管的应用程序](index.html#installing-applications) . 当 GitLab 创建集群时,将在`default`名称空间中创建具有`cluster-admin`特权的`gitlab`服务帐户,以管理新创建的集群. - -**注意:**用于部署的受限服务帐户是在 GitLab 11.5 中[引入的](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/51716) . - -The first time you install an application into your cluster, the `tiller` service account is created with `cluster-admin` privileges in the `gitlab-managed-apps` namespace. This service account will be used by Helm to install and run [GitLab managed applications](index.html#installing-applications). - -Helm 还将为每个已安装的应用程序创建其他服务帐户和其他资源. 有关每个应用程序,请查阅 Helm 图表的文档. - -如果要[添加现有的 Kubernetes 集群](add_remove_clusters.html#add-existing-cluster) ,请确保该帐户的令牌具有该集群的管理员特权. - -GitLab 创建的资源取决于集群的类型. - -### Important notes[](#important-notes "Permalink") - -请注意以下有关访问控制的内容: - -* 仅当集群[由 GitLab 管理时,](index.html#gitlab-managed-clusters)才会创建特定于环境的资源. -* 如果您的集群是在 GitLab 12.2 之前创建的,它将为所有项目环境使用单个名称空间. - -### RBAC cluster resources[](#rbac-cluster-resources "Permalink") - -GitLab 为 RBAC 集群创建以下资源. - -| Name | Type | Details | 创建时间 | -| --- | --- | --- | --- | -| `gitlab` | `ServiceAccount` | `default` namespace | 创建一个新集群 | -| `gitlab-admin` | `ClusterRoleBinding` | [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | 创建一个新集群 | -| `gitlab-token` | `Secret` | `gitlab` ServiceAccount 的令牌 | 创建一个新集群 | -| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | 安装舵图 | -| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | 安装舵图 | -| 环境名称空间 | `Namespace` | 包含所有特定于环境的资源 | 部署到集群 | -| 环境名称空间 | `ServiceAccount` | 使用环境的名称空间 | 部署到集群 | -| 环境名称空间 | `Secret` | 环境 ServiceAccount 的令牌 | 部署到集群 | -| 环境名称空间 | `RoleBinding` | [`edit`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | 部署到集群 | - -### ABAC cluster resources[](#abac-cluster-resources "Permalink") - -GitLab 为 ABAC 群集创建以下资源. - -| Name | Type | Details | 创建时间 | -| --- | --- | --- | --- | -| `gitlab` | `ServiceAccount` | `default` namespace | 创建一个新集群 | -| `gitlab-token` | `Secret` | `gitlab` ServiceAccount 的令牌 | 创建一个新集群 | -| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | 安装舵图 | -| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | 安装舵图 | -| 环境名称空间 | `Namespace` | 包含所有特定于环境的资源 | 部署到集群 | -| 环境名称空间 | `ServiceAccount` | 使用环境的名称空间 | 部署到集群 | -| 环境名称空间 | `Secret` | 环境 ServiceAccount 的令牌 | 部署到集群 | - -### Security of GitLab Runners[](#security-of-gitlab-runners "Permalink") - -GitLab Runners 默认情况[下](https://docs.gitlab.com/runner/executors/docker.html)启用了[特权模式](https://docs.gitlab.com/runner/executors/docker.html) ,这使他们可以执行特殊命令并在 Docker 中运行 Docker. 运行某些[Auto DevOps](../../../topics/autodevops/index.html)作业需要此功能. 这意味着容器正在特权模式下运行,因此,您应该注意一些重要的细节. - -特权标志为正在运行的容器提供了所有功能,而容器又可以执行主机可以执行的几乎所有操作. 请注意与对任意映像执行`docker run`操作相关的固有安全风险,因为它们有效地具有 root 用户访问权限. - -如果您不想在特权模式下使用 GitLab Runner,请执行以下任一操作: - -* 在 GitLab.com 上使用共享的跑步者. 他们没有这个安全问题. -* 使用[Shared Runners 中](../../gitlab_com/index.html#shared-runners)描述的配置来设置自己的[Runners](../../gitlab_com/index.html#shared-runners) . 这涉及: - 1. 确保您没有通过[应用程序](index.html#installing-applications)安装它. - 2. [使用`docker+machine`](https://docs.gitlab.com/runner/executors/docker_machine.html)安装 Runner. - -## Create new cluster[](#create-new-cluster "Permalink") - -可以使用 Google Kubernetes Engine(GKE)上的 GitLab 或 Amazon Elastic Kubernetes Service(EKS)在项目,组或实例级别上创建新集群: - -1. 导航到您的: - * 项目的 **操作> Kubernetes**页面,用于项目级集群. - * 组的 **Kubernetes**页面,用于组级别集群. - * **管理区>** **Kubernetes**页面,用于实例级集群. -2. Click **添加 Kubernetes 集群**. -3. 单击**创建新集群**选项卡. -4. 单击**Amazon EKS**或**Google GKE** ,然后按照说明提供所需的服务: - * [亚马逊 EKS](add_eks_clusters.html#new-eks-cluster) . - * [Google GKE](add_gke_clusters.html#creating-the-cluster-on-gke) . - -## Add existing cluster[](#add-existing-cluster "Permalink") - -如果您已有 Kubernetes 集群,则可以将其添加到项目,组或实例中. - -**注意:** arm64 集群不支持 Kubernetes 集成. 有关详细信息,请参阅问题[Helm Tiller 无法在 arm64 群集上安装](https://gitlab.com/gitlab-org/gitlab/-/issues/29838) . - -### Existing Kubernetes cluster[](#existing-kubernetes-cluster "Permalink") - -要将 Kubernetes 集群添加到您的项目,组或实例: - -1. 导航到您的: - 1. 项目的 **操作> Kubernetes**页面,用于项目级集群. - 2. 组的 **Kubernetes**页面,用于组级别集群. - 3. **管理区>** **Kubernetes**页面,用于实例级集群. -2. Click **添加 Kubernetes 集群**. -3. 单击**添加现有集群**选项卡,然后填写详细信息: - 1. **Kubernetes 集群名称** (必填)-您希望为**集群指定**的名称. - 2. **环境范围** (必需)- [与](index.html#setting-the-environment-scope-premium)此集群[相关的环境](index.html#setting-the-environment-scope-premium) . - 3. **API URL** (必填)-这是 GitLab 用于访问 Kubernetes API 的 URL. Kubernetes 公开了几个 API,我们想要所有这些 API 通用的"基本" URL. 例如, `https://kubernetes.example.com`而不是`https://kubernetes.example.com/api/v1` . - - 通过运行以下命令获取 API URL: - - ``` - kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}' - ``` - - 4. **CA 证书** (必需)-需要有效的 Kubernetes 证书才能对集群进行身份验证. 我们将使用默认创建的证书. - 1. 列出带有`kubectl get secrets` ,并且应将其命名类似于`default-token-xxxxx` . 复制该令牌名称以在下面使用. - 2. 通过运行以下命令获取证书: - - ``` - kubectl get secret -o jsonpath = "{['data']['ca \. crt']}" | base64 --decode - ``` - - **注意:**如果命令返回整个证书链,则需要在证书链的底部复制*根 ca*证书. - 5. **令牌** -GitLab 使用服务令牌对 Kubernetes 进行身份验证,服务令牌的作用域是特定的`namespace` . **使用的令牌应属于具有[`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)特权的服务帐户.** 要创建此服务帐户: - 1. 创建一个名为`gitlab-admin-service-account.yaml` ,其内容为: - - ``` - apiVersion : v1 kind : ServiceAccount metadata : name : gitlab-admin namespace : kube-system --- apiVersion : rbac.authorization.k8s.io/v1beta1 kind : ClusterRoleBinding metadata : name : gitlab-admin roleRef : apiGroup : rbac.authorization.k8s.io kind : ClusterRole name : cluster-admin subjects : - kind : ServiceAccount name : gitlab-admin namespace : kube-system - ``` - - 2. 将服务帐户和群集角色绑定应用于您的群集: - - ``` - kubectl apply -f gitlab-admin-service-account.yaml - ``` - - 您将需要`container.clusterRoleBindings.create`权限来创建集群级角色. 如果您没有此权限,则可以选择启用基本身份验证,然后以管理员身份运行`kubectl apply`命令: - - ``` - kubectl apply -f gitlab-admin-service-account.yaml --username = admin --password = - ``` - - **注意:**可以打开基本身份验证,并可以使用 Google Cloud Console 获取密码凭据. - - 输出: - - ``` - serviceaccount "gitlab-admin" created clusterrolebinding "gitlab-admin" created - ``` - - 3. 检索`gitlab-admin`服务帐户的令牌: - - ``` - kubectl -n kube-system describe secret $( kubectl -n kube-system get secret | grep gitlab-admin | awk '{print $1}' ) - ``` - - 从输出中复制``值: - - ``` - Name : gitlab-admin-token-b5zv4 Namespace : kube-system Labels : Annotations : kubernetes.io/service-account.name=gitlab-admin kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8 Type : kubernetes.io/service-account-token Data ==== ca.crt : 1025 bytes namespace : 11 bytes token : - ``` - - **注意:**对于 GKE 群集,您将需要`container.clusterRoleBindings.create`权限来创建群集角色绑定. 您可以按照[Google Cloud 文档](https://cloud.google.com/iam/docs/granting-changing-revoking-access)授予访问权限. - 6. **由 GitLab 管理的群集** -如果要让 GitLab 管理该群集的名称空间和服务帐户,请选中此复选框. 有关更多信息,请参见[托管集群部分](index.html#gitlab-managed-clusters) . - 7. **项目名称空间** (可选)-您不必填写它; 将其保留为空白,GitLab 将为您创建一个. 也: - * 每个项目应具有唯一的名称空间. - * 如果您正在使用具有更广泛权限的机密(例如`default`的机密),则项目名称空间不一定是机密的名称空间. - * 你**不**应该使用`default`为项目命名空间. - * 如果您或某人为项目专门创建了一个秘密(通常具有有限的权限),则该秘密的名称空间和项目名称空间可能是相同的. -4. 最后,单击**创建 Kubernetes 集群**按钮. - -几分钟后,您的集群将准备就绪. 现在,您可以继续安装一些[预定义的应用程序](index.html#installing-applications) . - -#### Disable Role-Based Access Control (RBAC) (optional)[](#disable-role-based-access-control-rbac-optional "Permalink") - -通过 GitLab 集成连接集群时,您可以指定集群是否支持 RBAC. 这将影响 GitLab 如何与集群进行某些操作的交互. 如果您在创建时*未*选中**启用 RBAC 的群集**复选框,则 GitLab 将假定与群集进行交互时禁用了 RBAC. 如果是这样,则必须在群集上禁用 RBAC 才能使集成正常工作. - -[![rbac](img/9d9a196fe723b5afc79e2d7b29fd0f4d.png)](img/rbac_v13_1.png) - -**注意:**禁用 RBAC 意味着群集中运行的任何应用程序或可以向群集进行身份验证的用户都具有完全的 API 访问权限. 这是一个[安全问题](index.html#security-implications) ,可能不是所希望的. - -为了有效地禁用 RBAC,可以应用全局权限来授予完全访问权限: - -``` -kubectl create clusterrolebinding permissive-binding \ - --clusterrole=cluster-admin \ - --user=admin \ - --user=kubelet \ - --group=system:serviceaccounts -``` - -## Enabling or disabling integration[](#enabling-or-disabling-integration "Permalink") - -成功创建新集群或添加现有集群后,即可启用 Kubernetes 集群集成. 要禁用 Kubernetes 集群集成: - -1. 导航到您的: - * 项目的 **操作> Kubernetes**页面,用于项目级集群. - * 组的 **Kubernetes**页面,用于组级别集群. - * **管理区>** **Kubernetes**页面,用于实例级集群. -2. 单击群集的名称. -3. 单击**GitLab 集成**切换. -4. Click **保存更改**. - -## Removing integration[](#removing-integration "Permalink") - -要从您的项目中删除 Kubernetes 集群集成,请首先导航到集群详细信息页面的**Advanced Settings**选项卡,然后执行以下任一操作: - -* 选择**删除集成** ,仅删除 Kubernetes 集成. -* [从 GitLab 12.6 中](https://gitlab.com/gitlab-org/gitlab/-/issues/26815) ,选择**删除集成和资源** ,以在**删除集成时**也删除所有相关的 GitLab 集群资源(例如,名称空间,角色和绑定). - -删除集群集成时,请注意: - -* 您需要具有维护人员及以上[权限](../../permissions.html)才能删除 Kubernetes 集群集成. -* 删除集群时,只删除其与 GitLab 的关系,而不删除集群本身. 要删除集群,可以通过访问 GKE 或 EKS 仪表板或使用`kubectl`来`kubectl` . - -## Learn more[](#learn-more "Permalink") - -要了解有关自动部署应用程序的更多信息,请阅读有关[Auto DevOps](../../../topics/autodevops/index.html) . \ No newline at end of file diff --git a/_book/docs/018.md b/_book/docs/018.md deleted file mode 100644 index ed361cb7d4b5f8794d573c41a2c6ff1ffa94548e..0000000000000000000000000000000000000000 --- a/_book/docs/018.md +++ /dev/null @@ -1,190 +0,0 @@ -# Adding EKS clusters - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/add_eks_clusters.html](https://docs.gitlab.com/ee/user/project/clusters/add_eks_clusters.html) - -* [EKS requirements](#eks-requirements) - * [Additional requirements for self-managed instances](#additional-requirements-for-self-managed-instances-core-only) -* [New EKS cluster](#new-eks-cluster) - * [Troubleshooting creating a new cluster](#troubleshooting-creating-a-new-cluster) - * [Error: Request failed with status code 422](#error-request-failed-with-status-code-422) - * [Could not load Security Groups for this VPC](#could-not-load-security-groups-for-this-vpc) - * [`ROLLBACK_FAILED` during cluster creation](#rollback_failed-during-cluster-creation) -* [Existing EKS cluster](#existing-eks-cluster) - * [Create a default Storage Class](#create-a-default-storage-class) - * [Deploy the app to EKS](#deploy-the-app-to-eks) - -# Adding EKS clusters[](#adding-eks-clusters "Permalink") - -GitLab 支持添加新的和现有的 EKS 集群. - -## EKS requirements[](#eks-requirements "Permalink") - -在通过 GitLab 集成在 Amazon EKS 上创建第一个集群之前,请确保满足以下要求: - -* 设置了[Amazon Web Services](https://aws.amazon.com/)帐户,您就可以登录. -* 您有权管理 IAM 资源. -* 如果要使用[现有的 EKS 集群](#existing-eks-cluster) : - * 已正确配置工作节点的 Amazon EKS 集群. - * [安装并配置](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html#get-started-kubectl)了`kubectl`以访问 EKS 集群. - -### Additional requirements for self-managed instances[](#additional-requirements-for-self-managed-instances-core-only "Permalink") - -如果您使用自我管理的 GitLab 实例,则必须首先使用一组 Amazon 凭证配置 GitLab. 这些凭证将用于承担创建集群的用户提供的 Amazon IAM 角色. 创建一个 IAM 用户,并确保其有权承担您的用户将用来创建 EKS 群集的角色. - -例如,以下策略文档允许在帐户`123456789012`假设一个角色的名称以`gitlab-eks-` : - -``` -{ "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::123456789012:role/gitlab-eks-*" } } -``` - -为 IAM 用户生成访问密钥,并使用凭据配置 GitLab: - -1. 导航至**管理区域>设置>集成,**然后展开**Amazon EKS**部分. -2. Check **启用 Amazon EKS 集成**. -3. 在相应的`Account ID` , `Access key ID`和`Secret access key`字段中输入帐户 ID 和访问密钥凭据. -4. Click **保存更改**. - -## New EKS cluster[](#new-eks-cluster "Permalink") - -在 GitLab 12.5 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/22392) . - -要创建新的 Kubernetes 集群并将其添加到您的项目,组或实例: - -1. 导航到您的: - * 项目的 **操作> Kubernetes**页面,用于项目级集群. - * 组的 **Kubernetes**页面,用于组级别集群. - * **管理区>** **Kubernetes** ,用于实例级集群. -2. Click **添加 Kubernetes 集群**. -3. 在" **创建新集群"**选项卡下,单击**Amazon EKS** . 将为您提供一个`Account ID`和`External ID` ,供下一步使用. -4. 在[IAM 管理控制台中](https://console.aws.amazon.com/iam/home) ,创建一个 IAM 角色: - 1. 在左侧面板中,选择**角色** . - 2. 单击**创建角色** . - 3. 在`Select type of trusted entity` ,选择**另一个 AWS 账户** . - 4. 在 GitLab 中的`Account ID`字段中输入`Account ID` . - 5. 选中**需要外部 ID** . - 6. 在 GitLab 中将`External ID`输入到`External ID`字段中. - 7. 单击**下一步:权限** . - 8. 点击**创建策略** ,这将打开一个新窗口. - 9. 选择**JSON**标签,然后粘贴以下代码段代替现有内容: - - ``` - { - "Version" : "2012-10-17" , - "Statement" : [ - { - "Effect" : "Allow" , - "Action" : [ - "autoscaling:CreateAutoScalingGroup" , - "autoscaling:DescribeAutoScalingGroups" , - "autoscaling:DescribeScalingActivities" , - "autoscaling:UpdateAutoScalingGroup" , - "autoscaling:CreateLaunchConfiguration" , - "autoscaling:DescribeLaunchConfigurations" , - "cloudformation:CreateStack" , - "cloudformation:DescribeStacks" , - "ec2:AuthorizeSecurityGroupEgress" , - "ec2:AuthorizeSecurityGroupIngress" , - "ec2:RevokeSecurityGroupEgress" , - "ec2:RevokeSecurityGroupIngress" , - "ec2:CreateSecurityGroup" , - "ec2:createTags" , - "ec2:DescribeImages" , - "ec2:DescribeKeyPairs" , - "ec2:DescribeRegions" , - "ec2:DescribeSecurityGroups" , - "ec2:DescribeSubnets" , - "ec2:DescribeVpcs" , - "eks:CreateCluster" , - "eks:DescribeCluster" , - "iam:AddRoleToInstanceProfile" , - "iam:AttachRolePolicy" , - "iam:CreateRole" , - "iam:CreateInstanceProfile" , - "iam:CreateServiceLinkedRole" , - "iam:GetRole" , - "iam:ListRoles" , - "iam:PassRole" , - "ssm:GetParameters" - ], - "Resource" : "*" - } - ] - } - ``` - - **注意:**这些权限使 GitLab 能够创建资源,但不能删除它们. 这意味着,如果在创建过程中遇到错误,更改将不会回滚,您必须手动删除资源. 您可以通过删除相关的[CloudFormation 堆栈](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-delete-stack.html)来做到这一点 - 10. 点击**审核政策** . - 11. 为此策略输入合适的名称,然后点击**创建策略** . 您现在可以关闭此窗口. - 12. 切换回"创建角色"窗口,然后选择刚创建的策略. - 13. 单击**下一步:标签** ,并选择输入您希望与此角色关联的任何标签. - 14. 单击**下一步:查看** . - 15. 在提供的字段中输入角色名称和可选描述. - 16. 点击**创建角色** ,新角色名称将显示在顶部. 单击其名称,然后从新创建的角色复制`Role ARN` . -5. 在 GitLab 中,将复制的角色 ARN 输入到`Role ARN`字段中. -6. Click **使用 AWS 进行身份验证**. -7. 选择集群的设置: - * **Kubernetes 集群名称** -您希望赋予集群的名称. - * **环境范围** -该集群的[关联环境](index.html#setting-the-environment-scope-premium) . - * **Kubernetes 版本** -要使用的 Kubernetes 版本. 当前唯一支持的版本是 1.14\. - * **角色名称** -选择[IAM 角色](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html)以允许 Amazon EKS 和 Kubernetes 控制平面代表您管理 AWS 资源. 此 IAM 角色与上面创建的 IAM 角色是分开的,如果尚不存在,则需要创建它. - * **区域** -将在其中创建群集的[区域](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html) . - * **密钥对名称** -如果需要,选择可用于连接到工作节点的[密钥对](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html) . - * **VPC-**选择要用于 EKS 群集资源的[VPC](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html) . - * **子网** -在您的 VPC 中选择运行工作节点的[子网](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html) . 您必须至少选择两个. - * **安全组** -选择[安全组](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html)以应用到在工作节点子网中创建的 EKS 管理的弹性网络接口. - * **实例类型** -工作节点的[实例类型](https://aws.amazon.com/ec2/instance-types/) . - * **节点数** -工作节点数. - * **由 GitLab 管理的群集** -如果要让 GitLab 管理该群集的名称空间和服务帐户,请选中此复选框. 有关更多信息,请参见[托管集群部分](index.html#gitlab-managed-clusters) . -8. 最后,单击**创建 Kubernetes 集群**按钮. - -大约 10 分钟后,您的集群便可以使用了. 现在,您可以继续安装一些[预定义的应用程序](index.html#installing-applications) . - -**注意:**您需要将 AWS 外部 ID 添加到[AWS CLI 中](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html#cli-configure-role-xaccount)的[IAM 角色,](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html#cli-configure-role-xaccount)才能使用`kubectl`管理集群. - -### Troubleshooting creating a new cluster[](#troubleshooting-creating-a-new-cluster "Permalink") - -创建新集群时,通常会遇到以下错误. - -#### Error: Request failed with status code 422[](#error-request-failed-with-status-code-422 "Permalink") - -提交初始身份验证表单时,如果无法确定您提供的角色,则 GitLab 会返回状态码 422 错误. 确保已使用 GitLab 提供的**帐户 ID**和**外部 ID**正确配置了角色. 在 GitLab 中,确保输入正确的**Role ARN** . - -#### Could not load Security Groups for this VPC[](#could-not-load-security-groups-for-this-vpc "Permalink") - -当在配置表单中填充选项时,GitLab 将返回此错误,因为 GitLab 已成功承担了您提供的角色,但是该角色没有足够的权限来检索表单所需的资源. 确保已为角色分配了正确的权限. - -#### `ROLLBACK_FAILED` during cluster creation[](#rollback_failed-during-cluster-creation "Permalink") - -由于 GitLab 在创建一个或多个资源时遇到错误,因此创建过程停止. 您可以检查关联的[CloudFormation 堆栈](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-view-stack-data-resources.html)以查找创建失败的特定资源. - -如果`Cluster`资源因错误`The provided role doesn't have the Amazon EKS Managed Policies associated with it.`失败,则`The provided role doesn't have the Amazon EKS Managed Policies associated with it.` , **角色名称**中指定的**角色**配置不正确. - -**注意:**此角色不应与上面创建的角色相同. 如果您没有现有的[EKS 群集 IAM 角色](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html) ,则必须创建一个. - -## Existing EKS cluster[](#existing-eks-cluster "Permalink") - -有关添加现有 EKS 群集的信息,请参阅" [现有 Kubernetes 群集"](add_remove_clusters.html#existing-kubernetes-cluster) . - -### Create a default Storage Class[](#create-a-default-storage-class "Permalink") - -Amazon EKS 没有开箱即用的默认存储类,这意味着对持久卷的请求将不会自动满足. 作为 Auto DevOps 的一部分,已部署的 PostgreSQL 实例将请求持久存储,并且如果没有默认存储类,它将无法启动. - -如果默认的存储类尚不存在并且需要使用,请按照 Amazon 的[存储类指南](https://docs.aws.amazon.com/eks/latest/userguide/storage-classes.html)创建一个. - -或者,通过将项目变量[`POSTGRES_ENABLED`](../../../topics/autodevops/customize.html#environment-variables)设置为`false`来禁用 PostgreSQL. - -### Deploy the app to EKS[](#deploy-the-app-to-eks "Permalink") - -在禁用 RBAC 和部署服务的情况下,现在可以利用[Auto DevOps](../../../topics/autodevops/index.html)构建,测试和部署应用程序. - -如果尚未启用,则[启用 Auto DevOps](../../../topics/autodevops/index.html#at-the-project-level) . 如果创建了通配符 DNS 条目以解析到负载均衡器,请在"自动 DevOps"设置下的" `domain`字段中输入它. 否则,已部署的应用程序将无法在群集外部从外部获得. - -[![Deploy Pipeline](img/de608fa9aefa963f38d0d95043413679.png)](img/pipeline.png) - -将自动创建一个新管道,该管道将开始构建,测试和部署该应用程序. - -管道完成后,您的应用将在 EKS 中运行,并可供用户使用. 单击**CI / CD>环境** . - -[![Deployed Environment](img/dc47374cec4da1de3e6476346ecf738e.png)](img/environment.png) - -您将看到环境及其部署状态的列表,以及浏览到应用程序,查看监视指标甚至访问正在运行的 Pod 上的 Shell 的选项. \ No newline at end of file diff --git a/_book/docs/019.md b/_book/docs/019.md deleted file mode 100644 index fa763920987d9effd3c7fdadfe55e25f7149dc67..0000000000000000000000000000000000000000 --- a/_book/docs/019.md +++ /dev/null @@ -1,65 +0,0 @@ -# Adding GKE clusters - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/add_gke_clusters.html](https://docs.gitlab.com/ee/user/project/clusters/add_gke_clusters.html) - -* [GKE requirements](#gke-requirements) -* [New GKE cluster](#new-gke-cluster) - * [Creating the cluster on GKE](#creating-the-cluster-on-gke) - * [Cloud Run for Anthos](#cloud-run-for-anthos) -* [Existing GKE cluster](#existing-gke-cluster) - -# Adding GKE clusters[](#adding-gke-clusters "Permalink") - -GitLab 支持添加新的和现有的 GKE 集群. - -## GKE requirements[](#gke-requirements "Permalink") - -在通过 GitLab 集成在 Google GKE 上创建第一个集群之前,请确保满足以下要求: - -* 设置了具有访问权限的[结算帐户](https://cloud.google.com/billing/docs/how-to/manage-billing-account) . -* 启用了 Kubernetes Engine API 和相关服务. 它应该可以立即工作,但是创建项目后最多可能需要 10 分钟. 有关更多信息,请参见[Kubernetes Engine 文档](https://cloud.google.com/kubernetes-engine/docs/quickstart#before-you-begin)的["开始之前"部分](https://cloud.google.com/kubernetes-engine/docs/quickstart#before-you-begin) . - -## New GKE cluster[](#new-gke-cluster "Permalink") - -从[GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/issues/25925)开始, [GitLab](https://gitlab.com/gitlab-org/gitlab/-/issues/25925)提供的所有 GKE 群集均为[VPC 本地的](https://cloud.google.com/kubernetes-engine/docs/how-to/alias-ips) . - -请注意以下几点: - -* 必须在实例级别的 GitLab 中启用[Google 身份验证集成](../../../integration/google.html) . 如果不是这种情况,请要求您的 GitLab 管理员启用它. 在 GitLab.com 上启用了此功能. -* 从[GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/55902)开始,由[GitLab](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/55902)创建的所有 GKE 集群都启用了 RBAC. 请参阅[RBAC 部分](add_remove_clusters.html#rbac-cluster-resources)以获取更多信息. -* 从[GitLab 12.5](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18341)开始,群集的 Pod 地址 IP 范围将设置为/ 16,而不是常规的/ 14\. / 16 是 CIDR 表示法. -* GitLab 要求启用基本身份验证并为集群颁发客户端证书,以设置[初始服务帐户](add_remove_clusters.html#access-controls) . 在[GitLab 11.10 及更高版本中](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/58208) ,集群创建过程明确要求 GKE 创建启用了基本身份验证和客户端证书的集群. - -### Creating the cluster on GKE[](#creating-the-cluster-on-gke "Permalink") - -要创建新的 Kubernetes 集群并将其添加到您的项目,组或实例: - -1. 导航到您的: - * 项目的 **操作> Kubernetes**页面,用于项目级集群. - * 组的 **Kubernetes**页面,用于组级别集群. - * **管理区>** **Kubernetes**页面,用于实例级集群. -2. Click **添加 Kubernetes 集群**. -3. 在[ **建立新丛集]**标签下,按一下[ **Google GKE]** . -4. 如果尚未连接 Google 帐户,请单击" **使用 Google 登录"**按钮. -5. 选择集群的设置: - * **Kubernetes 集群名称** -您希望赋予集群的名称. - * **环境范围** -该集群的[关联环境](index.html#setting-the-environment-scope-premium) . - * **Google Cloud Platform 项目** -选择您在 GCP 控制台中创建的将托管 Kubernetes 集群的项目. 了解有关[Google Cloud Platform 项目的](https://cloud.google.com/resource-manager/docs/creating-managing-projects)更多信息. - * **区域** -选择将在其下创建群集的[区域区域](https://cloud.google.com/compute/docs/regions-zones/) . - * **节点数** -输入希望群集具有的节点数. - * **计算机类型** -群集将基于的虚拟机实例的[计算机类型](https://cloud.google.com/compute/docs/machine-types) . - * **为 Anthos 启用 Cloud Run-**如果要对此集群使用 Cloud Run for Anthos,请选中此复选框. 有关更多信息,请参见[Anthos](#cloud-run-for-anthos)的[Cloud Run 部分](#cloud-run-for-anthos) . - * **由 GitLab 管理的群集** -如果要让 GitLab 管理该群集的名称空间和服务帐户,请选中此复选框. 有关更多信息,请参见[托管集群部分](index.html#gitlab-managed-clusters) . -6. 最后,单击**创建 Kubernetes 集群**按钮. - -几分钟后,您的集群将准备就绪. 现在,您可以继续安装一些[预定义的应用程序](index.html#installing-applications) . - -### Cloud Run for Anthos[](#cloud-run-for-anthos "Permalink") - -在 GitLab 12.4 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/16566) . - -创建群集后,可以选择使用 Cloud Run for Anthos 代替分别安装 Knative 和 Istio. 这意味着将在创建时在集群上启用 Cloud Run(Knative),Istio 和 HTTP Load Balancing,并且不能单独[安装或卸载](../../clusters/applications.html) . - -## Existing GKE cluster[](#existing-gke-cluster "Permalink") - -有关添加现有 GKE 群集的信息,请参阅" [现有 Kubernetes 群集"](add_remove_clusters.html#existing-kubernetes-cluster) . \ No newline at end of file diff --git a/_book/docs/020.md b/_book/docs/020.md deleted file mode 100644 index e00a05647fd42a90e2515b47ea7136bf641168d0..0000000000000000000000000000000000000000 --- a/_book/docs/020.md +++ /dev/null @@ -1,144 +0,0 @@ -# Group-level Kubernetes clusters - -> 原文:[https://docs.gitlab.com/ee/user/group/clusters/](https://docs.gitlab.com/ee/user/group/clusters/) - -* [Installing applications](#installing-applications) -* [RBAC compatibility](#rbac-compatibility) -* [Cluster precedence](#cluster-precedence) -* [Multiple Kubernetes clusters](#multiple-kubernetes-clusters) -* [GitLab-managed clusters](#gitlab-managed-clusters) - * [Clearing the cluster cache](#clearing-the-cluster-cache) -* [Base domain](#base-domain) -* [Environment scopes](#environment-scopes-premium) -* [Cluster environments](#cluster-environments-premium) -* [Security of Runners](#security-of-runners) -* [More information](#more-information) - -# Group-level Kubernetes clusters[](#group-level-kubernetes-clusters "Permalink") - -在 GitLab 11.6 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/34758) . - -与[项目级](../../project/clusters/index.html)和[实例级](../../instance/clusters/index.html) Kubernetes 集群类似,组级 Kubernetes 集群允许您将 Kubernetes 集群连接到您的组,从而使您可以在多个项目中使用同一集群. - -## Installing applications[](#installing-applications "Permalink") - -GitLab 可以在您的组级别集群中安装和管理某些应用程序. 有关为您的组集群安装,升级,卸载和故障排除应用程序的更多信息,请参阅[GitLab 托管应用程序](../../clusters/applications.html) . - -## RBAC compatibility[](#rbac-compatibility "Permalink") - -版本历史 - -* 在 GitLab 11.4 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/29398) . -* [项目名称空间限制](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/51716)是在 GitLab 11.5 中引入的. - -对于具有 Kubernetes 集群的组中的每个项目,GitLab 都会在项目名称空间中创建具有[`edit`权限](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)的受限服务帐户. - -## Cluster precedence[](#cluster-precedence "Permalink") - -如果项目的群集可用且未禁用,则 GitLab 在使用属于包含该项目的组的任何群集之前,先使用项目的群集. 对于子组,如果未禁用该组,则 GitLab 将使用与项目最接近的祖先组的集群. - -## Multiple Kubernetes clusters[](#multiple-kubernetes-clusters "Permalink") - -版本历史 - -* 在 13.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35094)了 GitLab Core. - -您可以将多个 Kubernetes 集群关联到您的组,并为不同的环境(例如开发,登台和生产)维护不同的集群. - -添加另一个群集时,请[设置环境范围](#environment-scopes-premium)以帮助区分新群集和其他群集. - -## GitLab-managed clusters[](#gitlab-managed-clusters "Permalink") - -版本历史 - -* 在 GitLab 11.5 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22011) . -* 在 GitLab 11.11 中成为[可选](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/26565) . - -You can choose to allow GitLab to manage your cluster for you. If GitLab manages your cluster, resources for your projects will be automatically created. See the [Access controls](../../project/clusters/add_remove_clusters.html#access-controls) section for details on which resources GitLab creates for you. - -对于不受 GitLab 管理的集群,将不会自动创建特定于项目的资源. 如果将[Auto DevOps](../../../topics/autodevops/index.html)用于具有不受 GitLab 管理的群集的部署,则必须确保: - -* 项目的部署服务帐户有权部署到[`KUBE_NAMESPACE`](../../project/clusters/index.html#deployment-variables) . -* `KUBECONFIG`正确反映了对`KUBE_NAMESPACE`任何更改(这[不是自动的](https://gitlab.com/gitlab-org/gitlab/-/issues/31519) ). 不建议直接编辑`KUBE_NAMESPACE` . - -**注意:**如果您在群集上[安装应用程序](#installing-applications) ,即使您选择管理自己的群集,GitLab 也会创建运行它们所需的资源. - -### Clearing the cluster cache[](#clearing-the-cluster-cache "Permalink") - -在 GitLab 12.6 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/31759) . - -如果您选择允许 GitLab 为您管理集群,则 GitLab 将存储它为项目创建的名称空间和服务帐户的缓存版本. 如果在群集中手动修改这些资源,则此缓存可能与群集不同步,这可能导致部署作业失败. - -清除缓存: - -1. 导航到您小组的 **Kubernetes**页面,然后选择您的集群. -2. 展开**高级设置**部分. -3. Click **清除集群缓存**. - -## Base domain[](#base-domain "Permalink") - -在 GitLab 11.8 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24580) . - -集群级别的域允许每个[多个 Kubernetes 集群](#multiple-kubernetes-clusters)支持多个域.指定域时,这将在[Auto DevOps](../../../topics/autodevops/index.html)阶段自动设置为环境变量( `KUBE_INGRESS_BASE_DOMAIN` ). - -该域应将通配符 DNS 配置为入口 IP 地址. - -## Environment scopes[](#environment-scopes-premium "Permalink") - -将多个 Kubernetes 集群添加到您的项目时,您需要通过环境范围来区分它们. 环境范围将群集与[环境](../../../ci/environments/index.html)相关联,类似于[特定](../../../ci/variables/README.html#limit-the-environment-scopes-of-environment-variables)于[环境的变量的](../../../ci/variables/README.html#limit-the-environment-scopes-of-environment-variables)工作方式. - -在评估哪个环境与群集的环境范围匹配时, [群集优先级](#cluster-precedence)将生效. 项目级别的集群优先,其次是最接近的祖先组,然后是该组的父级,依此类推. - -例如,如果您的项目具有以下 Kubernetes 集群: - -| Cluster | 环境范围 | Where | -| --- | --- | --- | -| Project | `*` | Project | -| Staging | `staging/*` | Project | -| Production | `production/*` | Project | -| Test | `test` | Group | -| Development | `*` | Group | - -[`.gitlab-ci.yml`](../../../ci/yaml/README.html)中设置了以下环境: - -``` -stages: - - test - - deploy - -test: - stage: test - script: sh test - -deploy to staging: - stage: deploy - script: make deploy - environment: - name: staging/$CI_COMMIT_REF_NAME - url: https://staging.example.com/ - -deploy to production: - stage: deploy - script: make deploy - environment: - name: production/$CI_COMMIT_REF_NAME - url: https://example.com/ -``` - -结果是: - -* 项目集群用于`test`作业. -* 分段群集用于`deploy to staging`作业. -* 生产集群用于`deploy to production`作业. - -## Cluster environments[](#cluster-environments-premium "Permalink") - -有关将哪种 CI [环境](../../../ci/environments/index.html)部署到 Kubernetes 集群的统一视图,请参阅[集群环境](../../clusters/environments.html)文档. - -## Security of Runners[](#security-of-runners "Permalink") - -有关安全配置 GitLab Runners 的重要信息,请参阅项目级集群[的 Runners 安全性](../../project/clusters/add_remove_clusters.html#security-of-gitlab-runners)文档. - -## More information[](#more-information "Permalink") - -For information on integrating GitLab and Kubernetes, see [Kubernetes clusters](../../project/clusters/index.html). \ No newline at end of file diff --git a/_book/docs/021.md b/_book/docs/021.md deleted file mode 100644 index a9f066f1278ddb6dc5e8a5cb06ccf07cf17d1858..0000000000000000000000000000000000000000 --- a/_book/docs/021.md +++ /dev/null @@ -1,34 +0,0 @@ -# Instance-level Kubernetes clusters - -> 原文:[https://docs.gitlab.com/ee/user/instance/clusters/](https://docs.gitlab.com/ee/user/instance/clusters/) - -* [Overview](#overview) -* [Cluster precedence](#cluster-precedence) -* [Cluster environments](#cluster-environments-premium) -* [More information](#more-information) - -# Instance-level Kubernetes clusters[](#instance-level-kubernetes-clusters "Permalink") - -在 GitLab 11.11 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/39840) . - -## Overview[](#overview "Permalink") - -与[项目级](../../project/clusters/index.html)和[组级](../../group/clusters/index.html) Kubernetes 集群类似,实例级 Kubernetes 集群允许您将 Kubernetes 集群连接到 GitLab 实例,这使您可以在多个项目中使用同一集群. - -## Cluster precedence[](#cluster-precedence "Permalink") - -GitLab 将尝试按以下顺序匹配集群: - -* 项目级集群. -* 组级别群集. -* 实例级集群. - -要选择集群,必须启用集群并使其与[环境选择器](../../../ci/environments/index.html#scoping-environments-with-specs)匹配. - -## Cluster environments[](#cluster-environments-premium "Permalink") - -有关将哪种 CI [环境](../../../ci/environments/index.html)部署到 Kubernetes 集群的统一视图,请参阅[集群环境](../../clusters/environments.html)文档. - -## More information[](#more-information "Permalink") - -有关集成 GitLab 和 Kubernetes 的信息,此[Kubernetes 集群](../../project/clusters/index.html) . \ No newline at end of file diff --git a/_book/docs/022.md b/_book/docs/022.md deleted file mode 100644 index 5a0961c34fd6d09c041f896aa2b37619333e2e79..0000000000000000000000000000000000000000 --- a/_book/docs/022.md +++ /dev/null @@ -1,42 +0,0 @@ -# Canary Deployments - -> 原文:[https://docs.gitlab.com/ee/user/project/canary_deployments.html](https://docs.gitlab.com/ee/user/project/canary_deployments.html) - -* [Overview](#overview) -* [Use cases](#use-cases) -* [Enabling Canary Deployments](#enabling-canary-deployments) - -# Canary Deployments[](#canary-deployments-premium "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1659) in [GitLab Premium](https://about.gitlab.com/pricing/) 9.1. - -一种流行的[持续部署](https://en.wikipedia.org/wiki/Continuous_deployment)策略,其中将一小部分机队更新为应用程序的新版本. - -## Overview[](#overview "Permalink") - -在采用[持续交付时](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) ,公司需要决定要使用哪种部署策略. 最受欢迎的策略之一是金丝雀部署,首先将一小部分机队更新为新版本. 金丝雀的这个子集,然后在煤矿中成为众所周知的[金丝雀](https://en.wiktionary.org/wiki/canary_in_a_coal_mine) . - -如果应用程序的新版本存在问题,则仅会影响一小部分用户,并且可以固定更改或快速还原更改. - -利用[Kubernetes 的 Canary 部署](https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments) ,无需离开 GitLab,即可在[Deploy Board](deploy_boards.html)内部可视化您的 Canary 部署. - -## Use cases[](#use-cases "Permalink") - -当您只想向部分 Pod 舰队提供功能并观看其行为时,可以使用 Canary 部署. 如果一切正常,您可以将该功能部署到生产中,因为它不会造成任何问题. - -Canary 部署对于后端重构,性能改进或用户界面不变的其他更改也特别有用,但是您要确保性能保持不变或有所提高. 开发人员在使用面向用户的更改的 Canary 时需要谨慎,因为默认情况下,来自同一用户的请求将随机分布在 Canary 和非 Canary Pod 之间,这可能导致混乱甚至错误. 如果需要,您可能需要考虑[在 Kubernetes 服务定义中将`service.spec.sessionAffinity`设置为`ClientIP`](https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies) ,但这超出了本文档的范围. - -## Enabling Canary Deployments[](#enabling-canary-deployments "Permalink") - -Canary 部署要求您正确配置 Deploy Boards: - -1. 请按照以下步骤[启用 Deploy Boards](deploy_boards.html#enabling-deploy-boards) . -2. 要跟踪 canary 部署,您需要使用`track: canary`标记 Kubernetes 部署和 Pod. 为了快速入门,您可以将[自动部署](../../topics/autodevops/stages.html#auto-deploy)模板用于 GitLab 提供的金丝雀部署. - -根据部署情况,标签应该是`stable`或`canary` . 通常, `stable`且空白或丢失的标签表示同一件事,而`canary`或任何其他轨道表示金丝雀/临时. 这使 GitLab 能够发现部署是稳定的还是金丝雀(临时)的. - -完成以上所有设置并且管道至少运行了一次之后,导航至" **管道">"环境"**下的环境页面. 随着管道的执行,部署委员会将清楚地标记金丝雀荚,从而可以快速,轻松地洞察每种环境和部署的状态. - -Canary deployments are marked with a yellow dot in the Deploy Board so that you can easily notice them. - -[![Canary deployments on Deploy Board](img/9a002df90c6ed1d01c8ae3a9817242df.png)](img/deploy_boards_canary_deployments.png) \ No newline at end of file diff --git a/_book/docs/023.md b/_book/docs/023.md deleted file mode 100644 index 9a11616616052d0777d2aa9e4218d2ab88ef726d..0000000000000000000000000000000000000000 --- a/_book/docs/023.md +++ /dev/null @@ -1,42 +0,0 @@ -# Cluster Environments - -> 原文:[https://docs.gitlab.com/ee/user/clusters/environments.html](https://docs.gitlab.com/ee/user/clusters/environments.html) - -* [Overview](#overview) -* [Usage](#usage) - -# Cluster Environments[](#cluster-environments-premium "Permalink") - -> * 在[GitLab Premium](https://about.gitlab.com/pricing/) 12.3 中针对组级集群[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/13392) . -> * 在[GitLab Premium](https://about.gitlab.com/pricing/) 12.4 中针对实例级集群进行了[介绍](https://gitlab.com/gitlab-org/gitlab/-/issues/14809) . - -群集环境提供了一个统一的视图,用于说明将哪些 CI [环境](../../ci/environments/index.html)部署到 Kubernetes 群集及其: - -* 显示项目和与部署相关的相关环境. -* 显示该环境的窗格的状态. - -## Overview[](#overview "Permalink") - -使用集群环境,您可以深入了解: - -* 哪些项目已部署到集群. -* 每个项目的环境使用了多少个 Pod. -* 用于部署到该环境的 CI 作业. - -[![Cluster environments page](img/662e9b0c090a4f28c82eb779aabdc9c8.png)](img/cluster_environments_table_v12_3.png) - -仅限集群[维护者和所有者](../permissions.html#group-members-permissions)访问集群环境 - -## Usage[](#usage "Permalink") - -为了: - -* 跟踪集群的环境,您必须成功[部署到 Kubernetes 集群](../project/clusters/index.html#deploying-to-a-kubernetes-cluster) . -* 正确显示容器使用情况,必须[启用 Deploy Boards](../project/deploy_boards.html#enabling-deploy-boards) . - -成功部署到组级或实例级集群后: - -1. 导航到您组的**Kubernetes**页面. -2. 单击**环境**选项卡. - -**注意:**此页面仅包含成功部署到群集的信息. 非群集环境将不包括在内. \ No newline at end of file diff --git a/_book/docs/024.md b/_book/docs/024.md deleted file mode 100644 index 0fc69a277907a6d55e4970d65c873902713cfdb5..0000000000000000000000000000000000000000 --- a/_book/docs/024.md +++ /dev/null @@ -1,113 +0,0 @@ -# Deploy Boards - -> 原文:[https://docs.gitlab.com/ee/user/project/deploy_boards.html](https://docs.gitlab.com/ee/user/project/deploy_boards.html) - -* [Overview](#overview) -* [Use cases](#use-cases) -* [Enabling Deploy Boards](#enabling-deploy-boards) - * [Example manifest file](#example-manifest-file) -* [Canary Deployments](#canary-deployments) -* [Further reading](#further-reading) - -# Deploy Boards[](#deploy-boards-premium "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1589) in [GitLab Premium](https://about.gitlab.com/pricing/) 9.0. - -GitLab 的部署板提供了[Kubernetes](https://kubernetes.io)上运行的每个 CI [环境](../../ci/environments/index.html)的当前运行状况和状态的综合视图,显示了部署中 Pod 的状态. 开发人员和其他团队成员可以在已经使用的工作流程中逐个窗格地查看发布的进度和状态,而无需访问 Kubernetes. - -## Overview[](#overview "Permalink") - -使用部署板,您可以通过以下优势对部署进行更多了解: - -* 从头开始进行部署,而不仅仅是完成之后 -* 监视跨多个服务器的构建的推出 -* 更详细的状态详细信息(成功,正在运行,失败,待处理,未知) -* See [Canary Deployments](canary_deployments.html) - -这是生产环境的部署板的示例. - -[![Deploy Boards landing page](img/4ceccc7ae590a56e8b135fa8baaafabe.png)](img/deploy_boards_landing_page.png) - -正方形表示与给定环境关联的 Kubernetes 集群中的 Pod. 将鼠标悬停在每个方块上方,可以看到部署的状态. 百分比是已更新到最新版本的 Pod 的百分比. - -由于部署板与 Kubernetes 紧密结合,因此需要一些知识. 特别是,您应该熟悉: - -* [Kubernetes pods](https://kubernetes.io/docs/concepts/workloads/pods/pod/) -* [Kubernetes labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) -* [Kubernetes namespaces](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/) -* [Kubernetes canary deployments](https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments) - -**注意:**包含多个部署的应用程序在部署板上显示为重复项. 有关详细信息,请关注[此问题](https://gitlab.com/gitlab-org/gitlab/-/issues/8463) . - -## Use cases[](#use-cases "Permalink") - -由于部署板是针对特定环境的 Kubernetes 吊舱的直观表示,因此存在许多用例. 仅举几例: - -* 您想将分阶段运行的产品推广到生产环境. 您转到环境列表,验证阶段运行的是您认为正在运行的,然后单击[手动操作](../../ci/yaml/README.html#whenmanual)以部署到生产环境. -* 您触发了部署,并且有很多容器需要升级,因此您将花费一段时间(您也限制了部署,一次只能删除 X 个容器). 但是您需要告诉某人何时部署,因此您可以转到环境列表,查看生产环境,以了解每个 Pod 滚动时的实时进度. -* 您会得到一份报告,说明生产中有些异常,因此您可以查看生产环境以查看正在运行什么,以及部署是否正在进行,是否停止或失败. -* 您的 MR 看起来不错,但是您希望在登台上运行它,因为登台是在某种程度上更接近生产环境进行设置的. 您转到环境列表,找到您感兴趣的[Review App](../../ci/review_apps/index.html) ,然后单击手动操作将其部署到登台. - -## Enabling Deploy Boards[](#enabling-deploy-boards "Permalink") - -要显示特定[环境](../../ci/environments/index.html)的部署板,您应该: - -1. 用部署阶段[定义了一个环境](../../ci/environments/index.html#defining-environments) . - -2. 使 Kubernetes 集群启动并运行. - - **在 OpenShift 上运行:**如果使用的是 OpenShift,请确保使用的是`Deployment`资源而不是`DeploymentConfiguration` . 否则,部署板将无法正确渲染. 有关更多信息,请阅读[OpenShift docs](https://docs.openshift.com/container-platform/3.7/dev_guide/deployments/kubernetes_deployments.html#kubernetes-deployments-vs-deployment-configurations)和[GitLab 问题#4584](https://gitlab.com/gitlab-org/gitlab/-/issues/4584) . -3. 使用[Docker](https://docs.gitlab.com/runner/executors/docker.html)或[Kubernetes](https://docs.gitlab.com/runner/executors/kubernetes.html)执行器[配置 GitLab Runner](../../ci/runners/README.html) . -4. 在您的项目中为集群配置[Kubernetes 集成](clusters/index.html) . 特别注意 Kubernetes 命名空间,因为部署脚本(由`KUBE_NAMESPACE` env 变量公开)将需要它. -5. 确保将 app.gitlab.com/env:$ `app.gitlab.com/env: $CI_ENVIRONMENT_SLUG`和`app.gitlab.com/app: $CI_PROJECT_PATH_SLUG` CI_PROJECT_PATH_SLUG 的 Kubernetes 注释应用于部署,副本集和 Pod,其中`$CI_ENVIRONMENT_SLUG`和`$CI_PROJECT_PATH_SLUG`是 CI 变量的值. 这样一来,我们便可以在可能有多个的群集/命名空间中查找适当的环境. 这些资源应包含在 Kubernetes 服务设置中定义的名称空间中. 您可以使用[Autodeploy](../../topics/autodevops/stages.html#auto-deploy) `.gitlab-ci.yml`模板,该模板具有要使用的预定义阶段和命令,并自动应用注释. 每个项目还需要在 Kubernetes 中具有唯一的名称空间. 下图演示了如何在 Kubernetes 中显示此内容. - - **注意:**在[GitLab 12.1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/14020)中删除了基于 Kubernetes `app`标签的匹配. 要迁移,请应用所需的注释(请参见上文),然后重新部署您的应用程序. 如果您使用的是 Auto DevOps,这将自动完成,无需采取任何措施. - - [![Deploy Boards Kubernetes Label](img/f5739c1b278ddd91c915c534514b4235.png)](img/deploy_boards_kubernetes_label.png) - -完成以上所有设置并且管道至少运行了一次之后,导航至**Operations> Environments**下的 environment 页面. - -默认情况下,部署板是可见的. 您可以显式单击相应环境名称旁边的三角形以隐藏它们. - -### Example manifest file[](#example-manifest-file "Permalink") - -以下示例是使用两个注释`app.gitlab.com/env`和`app.gitlab.com/app`启用 Kubernetes 清单部署文件的`app.gitlab.com/env` ,以启用**Deploy Boards** : - -``` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: "APPLICATION_NAME" - annotations: - app.gitlab.com/app: ${CI_PROJECT_PATH_SLUG} - app.gitlab.com/env: ${CI_ENVIRONMENT_SLUG} -spec: - replicas: 1 - selector: - matchLabels: - app: "APPLICATION_NAME" - template: - metadata: - labels: - app: "APPLICATION_NAME" - annotations: - app.gitlab.com/app: ${CI_PROJECT_PATH_SLUG} - app.gitlab.com/env: ${CI_ENVIRONMENT_SLUG} -``` - -注释将应用于部署,副本集和 Pod. 通过更改副本数量,例如`kubectl scale --replicas=3 deploy APPLICATION_NAME -n ${KUBE_NAMESPACE}` ,您可以从开发板上跟踪实例的 pod. - -**注意:** YAML 文件是静态的. 如果使用`kubectl apply` ,则必须在`kubectl apply`之前手动提供项目和环境段,或者创建脚本来替换 YAML 中的变量. - -## Canary Deployments[](#canary-deployments "Permalink") - -一种流行的 CI 策略,其中将一小部分车队更新为应用程序的新版本. - -[Read more about Canary Deployments.](canary_deployments.html) - -## Further reading[](#further-reading "Permalink") - -* [GitLab Autodeploy](../../topics/autodevops/stages.html#auto-deploy) -* [GitLab CI/CD environment variables](../../ci/variables/README.html) -* [Environments and deployments](../../ci/environments/index.html) -* [Kubernetes deploy example](https://gitlab.com/gitlab-examples/kubernetes-deploy) \ No newline at end of file diff --git a/_book/docs/025.md b/_book/docs/025.md deleted file mode 100644 index ba3543f75b3deba1b090b905b7b9ef53348754cb..0000000000000000000000000000000000000000 --- a/_book/docs/025.md +++ /dev/null @@ -1,1220 +0,0 @@ -# GitLab Managed Apps - -> 原文:[https://docs.gitlab.com/ee/user/clusters/applications.html](https://docs.gitlab.com/ee/user/clusters/applications.html) - -* [Installing applications](#installing-applications) - * [Helm](#helm) - * [Enable or disable local Tiller](#enable-or-disable-local-tiller-core-only) - * [cert-manager](#cert-manager) - * [GitLab Runner](#gitlab-runner) - * [Ingress](#ingress) - * [Determining the external endpoint automatically](#determining-the-external-endpoint-automatically) - * [Determining the external endpoint manually](#determining-the-external-endpoint-manually) - * [Using a static IP](#using-a-static-ip) - * [Pointing your DNS at the external endpoint](#pointing-your-dns-at-the-external-endpoint) - * [Web Application Firewall (ModSecurity)](#web-application-firewall-modsecurity) - * [Logging and blocking modes](#logging-and-blocking-modes) - * [WAF version updates](#waf-version-updates) - * [Viewing Web Application Firewall traffic](#viewing-web-application-firewall-traffic) - * [JupyterHub](#jupyterhub) - * [Jupyter Git Integration](#jupyter-git-integration) - * [Knative](#knative) - * [Prometheus](#prometheus) - * [Crossplane](#crossplane) - * [Elastic Stack](#elastic-stack) - * [Optional: deploy Kibana to perform advanced queries](#optional-deploy-kibana-to-perform-advanced-queries) - * [Fluentd](#fluentd) - * [Future apps](#future-apps) -* [Install using GitLab CI/CD (alpha)](#install-using-gitlab-cicd-alpha) - * [Usage](#usage) - * [Important notes](#important-notes) - * [Install Ingress using GitLab CI/CD](#install-ingress-using-gitlab-cicd) - * [Install cert-manager using GitLab CI/CD](#install-cert-manager-using-gitlab-cicd) - * [Install Sentry using GitLab CI/CD](#install-sentry-using-gitlab-cicd) - * [Install PostHog using GitLab CI/CD](#install-posthog-using-gitlab-cicd) - * [Install Prometheus using GitLab CI/CD](#install-prometheus-using-gitlab-cicd) - * [Install GitLab Runner using GitLab CI/CD](#install-gitlab-runner-using-gitlab-cicd) - * [Install Cilium using GitLab CI/CD](#install-cilium-using-gitlab-cicd) - * [Install Falco using GitLab CI/CD](#install-falco-using-gitlab-cicd) - * [Install Vault using GitLab CI/CD](#install-vault-using-gitlab-cicd) - * [Install JupyterHub using GitLab CI/CD](#install-jupyterhub-using-gitlab-cicd) - * [Install Elastic Stack using GitLab CI/CD](#install-elastic-stack-using-gitlab-cicd) - * [Install Crossplane using GitLab CI/CD](#install-crossplane-using-gitlab-cicd) - * [Install Fluentd using GitLab CI/CD](#install-fluentd-using-gitlab-cicd) - * [Install Knative using GitLab CI/CD](#install-knative-using-gitlab-cicd) - * [Knative Metrics](#knative-metrics) - * [Uninstall Knative](#uninstall-knative) - * [Install AppArmor using GitLab CI/CD](#install-apparmor-using-gitlab-cicd) - * [Using AppArmor profiles in your deployments](#using-apparmor-profiles-in-your-deployments) -* [Upgrading applications](#upgrading-applications) -* [Uninstalling applications](#uninstalling-applications) -* [Troubleshooting applications](#troubleshooting-applications) - * [Error installing managed apps on EKS cluster](#error-installing-managed-apps-on-eks-cluster) - * [Unable to install Prometheus](#unable-to-install-prometheus) - -# GitLab Managed Apps[](#gitlab-managed-apps "Permalink") - -GitLab 提供**GitLab 托管应用程序** ,一键安装各种应用程序,可以直接将其添加到配置的集群中. - -使用[Auto DevOps](../../topics/autodevops/index.html)时, [Review Apps](../../ci/review_apps/index.html)和[部署](../../ci/environments/index.html)需要这些应用程序. - -您可以在[创建集群](../project/clusters/add_remove_clusters.html)后安装它们. - -## Installing applications[](#installing-applications "Permalink") - -由 GitLab `gitlab-managed-apps`将安装到`gitlab-managed-apps`命名空间中. - -该名称空间: - -* 与用于项目部署的名称空间不同. -* 创建一次. -* 具有不可配置的名称. - -查看可用安装的应用程序列表. 为一个: - -* [项目级集群](../project/clusters/index.html) ,导航到项目的 **运营> Kubernetes** . -* [小组级别的集群](../group/clusters/index.html) ,导航到您小组的 **Kubernetes**页面. - -**注意:**从 GitLab 11.6 开始,Helm 将在安装任何应用程序之前升级到 GitLab 支持的最新版本. - -可以安装以下应用程序: - -* [Helm](#helm) -* [Ingress](#ingress) -* [cert-manager](#cert-manager) -* [Prometheus](#prometheus) -* [GitLab Runner](#gitlab-runner) -* [JupyterHub](#jupyterhub) -* [Knative](#knative) -* [Crossplane](#crossplane) -* [Elastic Stack](#elastic-stack) -* [Fluentd](#fluentd) - -除 Knative 外,这些应用程序将安装在名为`gitlab-managed-apps`的专用命名空间中. - -**注意:**某些应用程序仅可用于项目级集群安装. 计划在将来的发行版中支持在组级群集中安装这些应用程序. 有关更新,请参阅[问题跟踪进度](https://gitlab.com/gitlab-org/gitlab/-/issues/24411) .**注意:**如果您现有的 Kubernetes 集群已安装 Helm,则应谨慎使用,因为 GitLab 无法检测到它. 在这种情况下,通过应用程序安装 Helm 将导致集群对其进行两次配置,这可能导致部署期间的混乱. - -### Helm[](#helm "Permalink") - -版本历史 - -* 在 GitLab 10.2 中针对项目级集群引入. -* 在 GitLab 11.6 中针对组级集群引入. -* 在 GitLab 13.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/209736)了本地 Tiller 选项,该选项在功能标记后(默认情况下启用). -* 在 GitLab.com 上启用了本地 Tiller 的功能标志. - -[Helm](https://helm.sh/docs/)是 Kubernetes 的软件包管理器,用于安装 GitLab 管理的应用程序. GitLab 在集群内`gitlab-managed-apps`命名空间内的 pod 中运行每个`helm`命令. - -从 GitLab 13.2 开始,集成默认使用本地[Tiller](https://v2.helm.sh/docs/glossary/#tiller) . 使用本地 Tiller 时,不需要安装 Helm 应用程序,也不会显示在应用程序列表中. - -**注意:** GitLab 的 Helm 集成不支持在代理后面安装应用程序,但是可以使用一种[解决方法](../../topics/autodevops/index.html#install-applications-behind-a-proxy) . - -### Enable or disable local Tiller[](#enable-or-disable-local-tiller-core-only "Permalink") - -版本历史 - -* 在 GitLab 13.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/209736) -* [计划](https://gitlab.com/gitlab-org/gitlab/-/issues/209736)在 GitLab 13.3 中[删除](https://gitlab.com/gitlab-org/gitlab/-/issues/209736)禁用本地 Tiller 的选项 - -本地分 iller 正在开发中,但已准备好用于生产. 它部署在**默认情况下启用**的功能标志的后面. [有权访问 GitLab Rails 控制台的 GitLab 管理员](../../administration/feature_flags.html)可以为您的实例启用它. - -要启用它: - -``` -# Instance-wide -Feature.enable(:managed_apps_local_tiller) -``` - -禁用它: - -``` -# Instance-wide -Feature.disable(:managed_apps_local_tiller) -``` - -### cert-manager[](#cert-manager "Permalink") - -在 GitLab 11.6 中针对项目级和组级集群引入. - -[cert-manager](https://cert-manager.io/docs/)是本地 Kubernetes 证书管理控制器,可帮助颁发证书. 在群集上安装 cert-manager 将通过[Let's Encrypt](https://letsencrypt.org/)颁发证书,并确保证书有效和最新. - -用于安装此应用程序的图表取决于所使用的 GitLab 版本. 在: - -* 在 GitLab 12.3 及更高版本中, [jetstack / cert-manager](https://github.com/jetstack/cert-manager)图表与[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/cert_manager/values.yaml)文件一起使用. -* 在 GitLab 12.2 和更早版本中,使用了[稳定/证书管理器](https://github.com/helm/charts/tree/master/stable/cert-manager)图表. - -如果您在 GitLab 12.3 之前安装了 cert-manager,那么我们加密将[阻止来自较早版本 cert-manager 的请求](https://community.letsencrypt.org/t/blocking-old-cert-manager-versions/98753) . - -要解决此问题: - -1. 卸载 cert-manager(考虑[备份任何其他配置](https://cert-manager.io/docs/tutorials/backup/) ). -2. 再次安装 cert-manager. - -### GitLab Runner[](#gitlab-runner "Permalink") - -版本历史 - -* 在 GitLab 10.6 中针对项目级集群引入. -* 在 GitLab 11.10 中针对组级集群引入. - -[GitLab Runner](https://docs.gitlab.com/runner/)是一个开源项目,用于运行您的作业并将结果发送回 GitLab. 它与[GitLab CI / CD](../../ci/README.html)结合使用, [GitLab CI / CD](../../ci/README.html)是 GitLab 随附的用于协调作业的开源持续集成服务. - -如果该项目在 GitLab.com 上,则可以使用共享的 Runners(前 2000 分钟是免费的,以后您可以[购买更多](../../subscriptions/index.html#purchasing-additional-ci-minutes) ),并且如果它们足以满足您的需求,则不必部署它. 如果需要特定于项目的运行器,或者没有共享的运行器,则部署它很容易. - -请注意,已部署的 Runner 将设置为**privileged** ,这意味着它实际上将具有对基础计算机的 root 访问权限. 这是构建 Docker 映像所必需的,因此它是默认设置. 在部署前,请确保已阅读[安全隐患](../project/clusters/index.html#security-implications) . - -**注意:** [`runner/gitlab-runner`](https://gitlab.com/gitlab-org/charts/gitlab-runner)图表用于使用[预先配置的`values.yaml`](https://gitlab.com/gitlab-org/charts/gitlab-runner/-/blob/master/values.yaml)文件安装此应用程序. 不支持通过修改此文件来自定义安装. - -### Ingress[](#ingress "Permalink") - -版本历史 - -* 在 GitLab 10.2 中针对项目级集群引入. -* 在 GitLab 11.6 中针对组级集群引入. - -[Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/)提供开箱即用的负载平衡,SSL 终止和基于名称的虚拟主机. 它充当应用程序的 Web 代理,如果要使用[Auto DevOps](../../topics/autodevops/index.html)或部署自己的 Web 应用程序,则很有用. - -安装的 Ingress Controller 是[Ingress-NGINX](https://kubernetes.io/docs/concepts/services-networking/ingress/) ,由 Kubernetes 社区支持. - -**注意:**通过以下过程,必须在群集中安装负载均衡器才能获取端点. 如果使用 Knative,则可以使用 Ingress 或 Knative 自己的负载平衡器( [Istio](https://istio.io) ). - -In order to publish your web application, you first need to find the endpoint which will be either an IP address or a hostname associated with your load balancer. - -要安装它,请点击 Ingress 的**安装**按钮. GitLab 将尝试确定外部端点,并且它应在几分钟之内可用. - -#### Determining the external endpoint automatically[](#determining-the-external-endpoint-automatically "Permalink") - -在 GitLab 10.6 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17052) . - -安装 Ingress 之后,外部端点应在几分钟之内可用. - -**提示:**可以使用`KUBE_INGRESS_BASE_DOMAIN`环境变量将此端点用于[Auto DevOps 基础域](../../topics/autodevops/index.html#auto-devops-base-domain) . - -如果没有出现端点,并且您的集群在 Google Kubernetes Engine 上运行: - -1. [在 Google Kubernetes Engine 上](https://console.cloud.google.com/kubernetes)检查您的[Kubernetes 集群,](https://console.cloud.google.com/kubernetes)以确保其节点上没有错误. -2. 确保您在 Google Kubernetes Engine 上有足够的[配额](https://console.cloud.google.com/iam-admin/quotas) . 有关更多信息,请参见[资源配额](https://cloud.google.com/compute/quotas) . -3. 检查[Google Cloud 的状态,](https://status.cloud.google.com/)以确保它们没有任何中断. - -安装后,您可能会看到一个`?` 取决于云提供商的"入口 IP 地址". 特别是对于 EKS,这是因为 ELB 是使用 DNS 名称而不是 IP 地址创建的. 如果 GitLab 仍然无法确定您的 Ingress 或 Knative 应用程序的端点,则可以[手动确定它](#determining-the-external-endpoint-manually) . - -**注意:** [`stable/nginx-ingress`](https://github.com/helm/charts/tree/master/stable/nginx-ingress)图表用于通过[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/ingress/values.yaml)文件安装此应用程序. - -#### Determining the external endpoint manually[](#determining-the-external-endpoint-manually "Permalink") - -如果群集位于 GKE 上,请单击" **高级设置"中**的**Google Kubernetes Engine**链接,或直接转到[Google Kubernetes Engine 仪表板,](https://console.cloud.google.com/kubernetes/)然后选择适当的项目和群集. 然后单击" **连接"** ,然后在本地终端或使用**Cloud Shell**执行`gcloud`命令. - -如果集群不在 GKE 上,请按照 Kubernetes 提供程序的特定说明使用正确的凭据配置`kubectl` . 以下示例的输出将显示集群的外部端点. 然后,可以使用此信息来设置 DNS 条目和转发规则,以允许外部访问已部署的应用程序. - -If you installed Ingress via the **Applications**, run the following command: - -``` -kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}' -``` - -有些 Kubernetes 集群会返回主机名,例如[Amazon EKS](https://aws.amazon.com/eks/) . 对于这些平台,运行: - -``` -kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' -``` - -对于 Istio / Knative,命令将有所不同: - -``` -kubectl get svc --namespace=istio-system istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip} ' -``` - -否则,您可以列出所有负载均衡器的 IP 地址: - -``` -kubectl get svc --all-namespaces -o jsonpath='{range.items[?(@.status.loadBalancer.ingress)]}{.status.loadBalancer.ingress[*].ip} ' -``` - -**注意:**如果使用 EKS,还将创建一个[Elastic Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/) ,这将产生额外的 AWS 成本.**注意:**在某些 Kubernetes 版本上,您可能会看到尾随`%` , **但不要包括它** . - -入口现在在此地址可用,并将基于请求中的 DNS 名称将传入请求路由到适当的服务. 为此,应为所需的域名创建通配符 DNS CNAME 记录. 例如, `*.myekscluster.com`将指向之前获得的 Ingress 主机名. - -#### Using a static IP[](#using-a-static-ip "Permalink") - -默认情况下,临时外部 IP 地址与群集的负载平衡器关联. 如果您将临时 IP 与 DNS 关联,并且 IP 更改,则将无法访问您的应用程序,因此您必须再次更改 DNS 记录. 为了避免这种情况,您应该将其更改为静态保留的 IP. - -阅读如何[在 GKE 中提升临时外部 IP 地址](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip) . - -#### Pointing your DNS at the external endpoint[](#pointing-your-dns-at-the-external-endpoint "Permalink") - -设置外部终结点后,应将其与[通配符 DNS 记录(](https://en.wikipedia.org/wiki/Wildcard_DNS_record)例如`*.example.com.`相关联`*.example.com.` 为了能够访问您的应用. 如果您的外部端点是 IP 地址,请使用 A 记录. 如果您的外部端点是主机名,请使用 CNAME 记录. - -#### Web Application Firewall (ModSecurity)[](#web-application-firewall-modsecurity "Permalink") - -在 GitLab 12.7 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21966) . - -Web 应用程序防火墙(WAF)可以检查正在发送或接收的流量,并可以在恶意流量到达您的应用程序之前对其进行阻止. WAF 的好处是: - -* 实时监控您的应用程序 -* 将所有 HTTP 通信记录到应用程序 -* 您的应用程序的访问控制 -* 高度可配置的日志记录和阻止规则 - -开箱即用,GitLab 为您提供了一个称为[`ModSecurity`](https://www.modsecurity.org/)的 WAF. - -ModSecurity 是用于实时 Web 应用程序监视,日志记录和访问控制的工具包. 借助 GitLab 的产品,将自动应用[OWASP 的 Core Rule Set](https://www.modsecurity.org/CRS/Documentation/) (提供通用的攻击检测功能). - -此功能: - -* 除非另有配置,否则以"仅检测模式"运行. -* 通过检查您的 Ingress 控制器的`modsec`日志中是否有违反规则可以查看. 例如: - - ``` - kubectl logs -n gitlab-managed-apps $(kubectl get pod -n gitlab-managed-apps -l app=nginx-ingress,component=controller --no-headers=true -o custom-columns=:metadata.name) modsecurity-log -f - ``` - -要启用 WAF,请在安装或更新[Ingress 应用程序](#ingress)时将其相应的切换开关切换到启用位置. - -如果这是您首次使用 GitLab 的 WAF,我们建议您遵循[快速入门指南](../../topics/web_application_firewall/quick_start_guide.html) . - -通过启用 ModSecurity,性能开销很小. 如果这对于您的应用程序而言很重要,则可以通过以下任何一种方式为已部署的应用程序禁用 ModSecurity 的规则引擎: - -1. Setting [the deployment variable](../../topics/autodevops/index.html) `AUTO_DEVOPS_MODSECURITY_SEC_RULE_ENGINE` to `Off`. This will prevent ModSecurity from processing any requests for the given application or environment. - -2. 将其各自的切换开关切换到禁用位置,然后通过" **保存更改"**按钮应用更改. 这将使用最新更改重新安装 Ingress. - -[![Disabling WAF](img/74f87e79779a102e82a644227e50a2e4.png)](../../topics/web_application_firewall/img/guide_waf_ingress_save_changes_v12_10.png) - -##### Logging and blocking modes[](#logging-and-blocking-modes "Permalink") - -为了帮助您调整 WAF 规则,可以将 WAF 全局设置为" **日志记录"**或" **阻止"**模式: - -* **日志记录模式** -允许符合规则的流量通过并记录事件. -* **阻止模式** -阻止符合规则的流量通过,并记录事件. - -更改 WAF 的模式: - -1. 如果尚未[安装 ModSecurity](../../topics/web_application_firewall/quick_start_guide.html) ,请[安装它](../../topics/web_application_firewall/quick_start_guide.html) . -2. 导航 **运营>州长** . -3. In **Applications**, scroll to **Ingress**. -4. 在" **全局默认值"下** ,选择所需的模式. -5. Click **保存更改**. - -##### WAF version updates[](#waf-version-updates "Permalink") - -由于[Helm 的](https://helm.sh/)限制,在以后的发行版中可能会克服这些问题,因此仅在同一版本的[Ingress 中](#ingress)才允许启用,禁用或更改**ModSecurity**的日志记录模式. - -如果所部署的版本与 GitLab 中可用的版本不同,则将禁用**ModSecurity** UI 控件,而仍可以执行[Ingress](#ingress)级别的操作,例如卸载: - -[![WAF settings disabled](img/27858125d0f3461e373b06413f40e616.png)](../../topics/web_application_firewall/img/guide_waf_ingress_disabled_settings_v12_10.png) - -将[Ingress](#ingress)更新到最新版本使您能够利用错误修复,安全修复和性能改进. 要更新[Ingress 应用程序](#ingress) ,您必须首先将其卸载,然后按照[Install ModSecurity 中的说明](../../topics/web_application_firewall/quick_start_guide.html)进行重新[安装](../../topics/web_application_firewall/quick_start_guide.html) . - -##### Viewing Web Application Firewall traffic[](#viewing-web-application-firewall-traffic "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14707) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.9. - -您可以通过导航到项目的" **安全性和合规性">"威胁监视"**页面来查看 Web 应用程序防火墙的流量. - -从那里,您可以看到随着时间的推移进行跟踪: - -* 您的应用程序的总流量. -* Web 应用程序防火墙的默认[OWASP 规则集](https://www.modsecurity.org/CRS/Documentation/)认为异常的流量比例. - -如果很大一部分流量是异常的,则应[检查](#web-application-firewall-modsecurity)潜在的威胁,这可以通过[检查 Web 应用程序防火墙日志](#web-application-firewall-modsecurity)来完成. - -[![Threat Monitoring](img/a3964b6d91003c90a72b5ca689b9e0c5.png)](img/threat_monitoring_v12_9.png) - -### JupyterHub[](#jupyterhub "Permalink") - -版本历史 - -* 在 GitLab 11.0 中针对项目级集群引入. -* 在 GitLab 12.3 中针对组和实例级集群引入. - -[JupyterHub](https://jupyterhub.readthedocs.io/en/stable/)是用于在团队中管理笔记本的多用户服务. [Jupyter Notebook](https://jupyter-notebook.readthedocs.io/en/latest/)提供了一个基于 Web 的交互式编程环境,用于数据分析,可视化和机器学习. - -Authentication will be enabled only for [project members](../project/members/index.html) for project-level clusters and group members for group-level clusters with [Developer or higher](../permissions.html) access to the associated project or group. - -我们使用一个[自定义的 Jupyter 映像](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) ,该[映像](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile)将在基础 Jupyter 之上安装其他有用的软件包. 您还将看到使用 Nurtch 的[Rubix 库](https://github.com/Nurtch/rubix)构建的即用型 DevOps Runbook. - -有关创建可执行运行本的更多信息,请参见[我们的运行本文档](../project/clusters/runbooks/index.html#configure-an-executable-runbook-with-gitlab) . 请注意,必须先安装 Ingress 并分配 IP 地址,然后才能安装 JupyterHub. - -**注意:** [`jupyter/jupyterhub`](https://jupyterhub.github.io/helm-chart/)图表用于通过[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/jupyter/values.yaml)文件安装此应用程序. - -#### Jupyter Git Integration[](#jupyter-git-integration "Permalink") - -版本历史 - -* 在 GitLab 12.0 中针对项目级集群[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/28783) . -* 在 GitLab 12.3 中针对组和实例级集群[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/32512) . - -将 JupyterHub 安装到 Kubernetes 集群上时,将使用已验证用户的身份自动配置和配置[JupyterLab 的 Git 扩展](https://github.com/jupyterlab/jupyterlab-git) : - -* Name. -* Email. -* 新创建的访问令牌. - -JupyterLab 的 Git 扩展使您能够对笔记本进行完整版本控制,并在 Jupyter 中发布 Git 命令. Git 命令可以通过左侧面板上的**Git**选项卡或 Jupyter 的命令行提示符发出. - -**注意:** JupyterLab 的 Git 扩展将用户令牌以加密格式存储在 JupyterHub DB 中,并以纯文本形式存储在单个用户 Jupyter 实例中. 这是因为[Git 要求将凭据存储为纯文本](https://git-scm.com/docs/git-credential-store) . 潜在地,如果一个邪恶的用户在单用户 Jupyter 实例中找到一种从文件系统读取的方法,则他们可以检索令牌. - -[![Jupyter's Git Extension](img/993315f2d7b2aa15b2f3faa03d14705c.png)](img/jupyter-git-extension.gif) - -您可以从 Jupyter 的"文件"选项卡中克隆存储库: - -[![Jupyter clone repository](img/bed33522d3ca08c8f5c920ba11fa05d4.png)](img/jupyter-gitclone.png) - -### Knative[](#knative "Permalink") - -版本历史 - -* 在 GitLab 11.5 中针对项目级集群引入. -* 在 GitLab 12.3 中针对组和实例级集群引入. - -[Knative](https://cloud.google.com/knative/)提供了一个平台,用于从 Kubernetes 集群创建,部署和管理无服务器工作负载. 它与[Istio](https://istio.io)结合使用并包括在内, [以为 Knative](https://istio.io)托管的所有程序提供外部 IP 地址. - -系统将提示您输入一个通配符域,您的应用程序将在该域中公开. 配置您的 DNS 服务器以使用该域的外部 IP 地址. 对于创建和安装的任何应用程序,可以通过`..` . 这将要求您的 Kubernetes 群集[启用 RBAC](../project/clusters/add_remove_clusters.html#rbac-cluster-resources) . - -**Note:** The [`knative/knative`](https://storage.googleapis.com/triggermesh-charts) chart is used to install this application. - -### Prometheus[](#prometheus "Permalink") - -版本历史 - -* 在 GitLab 10.4 中针对项目级集群引入. -* 在 GitLab 11.11 中针对组级集群引入. - -[Prometheus](https://s0prometheus0io.icopy.site/docs/introduction/overview/)是一个开源监视和警报系统,可用于监督已部署的应用程序. - -GitLab 能够使用[Prometheus 集成](../project/integrations/prometheus.html)自动监视应用程序. Kubernetes 容器的 CPU 和内存指标将自动收集,响应指标也将从 NGINX Ingress 检索. - -要启用监视,只需使用" **安装"**按钮将 Prometheus 安装到群集中. - -**注意:** [`stable/prometheus`](https://github.com/helm/charts/tree/master/stable/prometheus)图表用于通过[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/prometheus/values.yaml)文件安装此应用程序. - -### Crossplane[](#crossplane "Permalink") - -版本历史 - -* 在 GitLab 12.5 中针对项目级集群[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/34702) . - -[Crossplane](https://crossplane.github.io/docs/v0.9/)是一种多云控制平面,可用于跨多个云管理应用程序和基础架构. 它使用以下方法扩展了 Kubernetes API: - -* 自定义资源. -* 监视那些自定义资源的控制器. - -Crossplane 通过抽象特定于云提供商的配置,以统一的方式允许跨云提供商进行基础架构组件的供应和生命周期管理. - -Crossplane GitLab 管理的应用程序: - -* 在连接到项目存储库的 Kubernetes 集群上使用选择的提供程序安装 Crossplane. -* 然后可以用于通过 Auto DevOps 管道来配置基础结构或托管应用程序,例如 PostgreSQL(例如,来自 GCP 的 CloudSQL 或来自 AWS 的 RDS)以及该应用程序所需的其他服务. - -有关配置群集上安装的 Crossplane 的信息,请参阅[Crossplane 配置](crossplane.html) . - -**注意:** [`alpha/crossplane`](https://github.com/crossplane/crossplane/tree/v0.4.1/cluster/charts/crossplane) crossplane 图表 v0.4.1 用于通过[`values.yaml`](https://github.com/crossplane/crossplane/blob/master/cluster/charts/crossplane/values.yaml.tmpl)文件安装 Crossplane. - -### Elastic Stack[](#elastic-stack "Permalink") - -在 GitLab 12.7 中针对项目级和组级集群引入. - -[Elastic Stack](https://www.elastic.co/elastic-stack)是一个完整的端到端日志分析解决方案,可帮助深入搜索,分析和可视化从不同计算机生成的日志. - -GitLab 能够自动从集群中的 Pod 收集日志. Filebeat 将在集群中的每个节点上作为 DaemonSet 运行,并将容器日志发送到 Elasticsearch 进行查询. 然后,GitLab 将连接到 Elasticsearch 以获取日志而不是 Kubernetes API,您将可以使用更高级的查询功能. - -使用[Curator](https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/about.html)在 30 天后会自动删除日志数据. - -要启用日志传送: - -1. 确保您的集群至少包含 3 个实例类型大于`f1-micro` , `g1-small`或`n1-standard-1`节点. -2. 导航 **运营>州长** . -3. 在**Kubernetes Cluster 中** ,选择一个集群. -4. 在" **应用程序"**部分中,找到" **Elastic Stack"** ,然后单击" **安装"** . - -**注意:** [`gitlab/elastic-stack`](https://gitlab.com/gitlab-org/charts/elastic-stack)图用于通过[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/elastic_stack/values.yaml)文件安装此应用程序.**注意:**该图表部署了 3 个相同的 Elasticsearch Pod,这些 Pod 无法共置,每个 Pod 需要 1 个 CPU 和 2 GB RAM,从而使其与包含少于 3 个节点或由`f1-micro` , `g1-small` , `n1-standard-1`组成的集群不兼容`n1-standard-1`或`*-highcpu-2`实例类型.**注意:** Elastic Stack 群集应用程序旨在用作日志聚合解决方案,并且与我们的[Advanced Global Search](../search/advanced_global_search.html)功能无关,后者使用单独的 Elasticsearch 群集. - -#### Optional: deploy Kibana to perform advanced queries[](#optional-deploy-kibana-to-perform-advanced-queries "Permalink") - -如果您是高级用户,并且可以使用`kubectl`和`helm`直接访问 Kubernetes 集群,则可以手动部署 Kibana. - -下面假设`helm`已经[初始化](https://v2.helm.sh/docs/helm/)与`helm init` . - -将以下内容保存到`kibana.yml` : - -``` -elasticsearch: - enabled: false - -filebeat: - enabled: false - -kibana: - enabled: true - elasticsearchHosts: http://elastic-stack-elasticsearch-master.gitlab-managed-apps.svc.cluster.local:9200 -``` - -然后将其安装在您的集群上: - -``` -helm repo add gitlab https://charts.gitlab.io -helm install --name kibana gitlab/elastic-stack --values kibana.yml -``` - -要访问 Kibana,请将端口转发到本地计算机: - -``` -kubectl port-forward svc/kibana-kibana 5601:5601 -``` - -然后,您可以通过`http://localhost:5601`访问 Kibana. - -### Fluentd[](#fluentd "Permalink") - -在 GitLab 12.10 中针对项目级和组级集群引入. - -[Fluentd](https://www.fluentd.org/)是一个开源数据收集器,它使您能够统一数据收集和使用以更好地使用和理解数据. Fluentd 以 syslog 格式发送日志. - -To enable Fluentd: - -1. 导航 **操作> Kubernetes** ,然后单击**应用程序** . 系统将提示您输入主机,端口和协议,WAF 日志将通过 syslog 发送到该主机,端口和协议. -2. 在**SIEM Hostname 中**提供主机域名或 URL. -3. 在**SIEM Port 中**提供主机端口号. -4. 选择一个**SIEM 协议** . -5. 选择至少一个可用日志(例如 WAF 或 Cilium). -6. Click **保存更改**. - -[![Fluentd input fields](img/f52fe1b4788045a510a1783bfb546b6f.png)](img/fluentd_v13_0.png) - -### Future apps[](#future-apps "Permalink") - -有兴趣贡献一个新的 GitLab 托管应用程序吗? 访问[开发指南页面](../../development/kubernetes.html#gitlab-managed-apps)以开始使用. - -## Install using GitLab CI/CD (alpha)[](#install-using-gitlab-cicd-alpha "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20822) in GitLab 12.6. - -**警告:**这是*Alpha 版*功能,如有更改,恕不另行通知. - -这种替代方法允许用户使用 GitLab CI / CD 安装由 GitLab 管理的应用程序. 它还允许使用 Helm `values.yaml`文件来自定义安装. - -支持的应用程序: - -* [Ingress](#install-ingress-using-gitlab-cicd) -* [cert-manager](#install-cert-manager-using-gitlab-cicd) -* [Sentry](#install-sentry-using-gitlab-cicd) -* [GitLab Runner](#install-gitlab-runner-using-gitlab-cicd) -* [Cilium](#install-cilium-using-gitlab-cicd) -* [Falco](#install-falco-using-gitlab-cicd) -* [Vault](#install-vault-using-gitlab-cicd) -* [JupyterHub](#install-jupyterhub-using-gitlab-cicd) -* [Elastic Stack](#install-elastic-stack-using-gitlab-cicd) -* [Crossplane](#install-crossplane-using-gitlab-cicd) -* [Fluentd](#install-fluentd-using-gitlab-cicd) -* [Knative](#install-knative-using-gitlab-cicd) -* [PostHog](#install-posthog-using-gitlab-cicd) -* [Prometheus](#install-prometheus-using-gitlab-cicd) - -### Usage[](#usage "Permalink") - -您可以在[示例集群应用程序项目中](https://gitlab.com/gitlab-org/cluster-integration/example-cluster-applications/)找到并导入下面引用的所有文件. - -要使用 GitLab CI / CD 安装应用程序: - -1. 将集群连接到[集群管理项目](management_project.html) . -2. 在该项目中,添加具有以下内容的`.gitlab-ci.yml`文件: - - ``` - include: - - template: Managed-Cluster-Applications.gitlab-ci.yml - ``` - - **注意:**此模板提供的作业使用自定义 Docker 映像中提供的工具连接到集群. 它要求您具有在 Docker,Kubernetes 或 Docker Machine 执行器上注册的运行程序. -3. 添加`.gitlab/managed-apps/config.yaml`文件,以定义要安装的应用程序. 将已`installed`密钥定义为`true`以安装应用程序,将`false`为卸载应用程序. 例如,要安装 Ingress: - - ``` - ingress: - installed: true - ``` - -4. (可选)定义`.gitlab/managed-apps//values.yaml`文件,以自定义已安装应用程序的值. - -然后,一个 GitLab CI / CD 管道将在`master`分支上运行,以安装您配置的应用程序. 万一管道发生故障, [Helm Tiller](https://v2.helm.sh/docs/install/#running-tiller-locally)二进制文件的输出将另存为[CI 作业工件](../../ci/pipelines/job_artifacts.html) . - -### Important notes[](#important-notes "Permalink") - -请注意以下几点: - -* 我们建议仅使用集群管理项目来管理集群的部署. 不要将应用程序的源代码添加到此类项目中. -* 当您将`installed`密钥的值`installed`回`false` ,将从群集中取消配置该应用程序. -* 如果使用新值更新`.gitlab/managed-apps//values.yaml` ,则将重新部署该应用程序. - -### Install Ingress using GitLab CI/CD[](#install-ingress-using-gitlab-cicd "Permalink") - -要安装 Ingress,请使用以下命令定义`.gitlab/managed-apps/config.yaml`文件: - -``` -ingress: - installed: true -``` - -然后,Ingress 将安装到集群的`gitlab-managed-apps`命名空间中. - -You can customize the installation of Ingress by defining a `.gitlab/managed-apps/ingress/values.yaml` file in your cluster management project. Refer to the [chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress) for the available configuration options. - -**注意:** GitLab 配置组提供了对安装 Ingress 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从[Configure 组中](https://about.gitlab.com/handbook/product/categories/#configure-group) ping 通至少 2 个人. - -### Install cert-manager using GitLab CI/CD[](#install-cert-manager-using-gitlab-cicd "Permalink") - -通过在`.gitlab/managed-apps/config.yaml`定义配置,使用 GitLab CI / CD 安装了 cert-manager. - -cert-manager: - -* 已安装到集群的`gitlab-managed-apps`命名空间中. -* Can be installed with or without a default [Let’s Encrypt `ClusterIssuer`](https://cert-manager.io/docs/configuration/acme/), which requires an email address to be specified. The email address is used by Let’s Encrypt to contact you about expiring certificates and issues related to your account. - -使用 GitLab CI / CD 安装证书管理器需要以下配置: - -``` -certManager: - installed: true - letsEncryptClusterIssuer: - installed: true - email: "user@example.com" -``` - -以下使用 GitLab CI / CD 安装 cert-manager,而没有默认的`ClusterIssuer` : - -``` -certManager: - installed: true - letsEncryptClusterIssuer: - installed: false -``` - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/cert-manager/values.yaml`文件来自定义 cert-manager 的安装. 请参阅[图表](https://hub.helm.sh/charts/jetstack/cert-manager)以获取可用的配置选项. - -**注意:** GitLab 配置组提供了对安装 Cert Manager 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从[Configure 组中](https://about.gitlab.com/handbook/product/categories/#configure-group) ping 通至少 2 个人. - -### Install Sentry using GitLab CI/CD[](#install-sentry-using-gitlab-cicd "Permalink") - -**注意:** Sentry Helm 图表[建议](https://github.com/helm/charts/blob/f6e5784f265dd459c5a77430185d0302ed372665/stable/sentry/values.yaml#L284-L285)至少 3GB 的可用 RAM 用于数据库迁移. - -To install Sentry, define the `.gitlab/managed-apps/config.yaml` file with: - -``` -sentry: - installed: true -``` - -然后,将 Sentry 安装到集群的`gitlab-managed-apps`命名空间中. - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/sentry/values.yaml`文件来自定义 Sentry 的安装. 请参阅[图表](https://github.com/helm/charts/tree/master/stable/sentry)以获取可用的配置选项. - -我们建议您密切注意以下配置选项: - -* `email` . 需要邀请用户加入您的 Sentry 实例并发送错误电子邮件. -* `user` . 您可以在其中设置默认管理员用户的登录凭据. -* `postgresql` . 有关在将来运行更新时可以使用的 PostgreSQL 密码. - -**注意:**升级时,重要的是提供现有的 PostgreSQL 密码(使用`postgresql.postgresqlPassword`密钥提供),否则您将收到认证错误. 有关更多信息,请参见[PostgreSQL 图表文档](https://github.com/helm/charts/tree/master/stable/postgresql#upgrade) . - -这是 Sentry 的示例配置: - -``` -# Admin user to create -user: - # Indicated to create the admin user or not, - # Default is true as the initial installation. - create: true - email: "" - password: "" - -email: - from_address: "" - host: smtp - port: 25 - use_tls: false - user: "" - password: "" - enable_replies: false - -ingress: - enabled: true - hostname: "" - -# Needs to be here between runs. -# See https://github.com/helm/charts/tree/master/stable/postgresql#upgrade for more info -postgresql: - postgresqlPassword: example-postgresql-password -``` - -**注意:** GitLab Health 组为安装 Sentry 托管应用程序提供支持. 如果您遇到未知问题,请[打开一个新的问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从[健康小组](https://about.gitlab.com/handbook/product/product-categories/#health-group) ping 至少 2 个人. - -### Install PostHog using GitLab CI/CD[](#install-posthog-using-gitlab-cicd "Permalink") - -[PostHog](https://www.posthog.com)是开发人员友好的开源产品分析平台. - -要将 PostHog 安装到群集的`gitlab-managed-apps`命名空间中,请使用以下`.gitlab/managed-apps/config.yaml`定义`.gitlab/managed-apps/config.yaml`文件: - -``` -posthog: - installed: true -``` - -您可以通过在群集管理项目中定义`.gitlab/managed-apps/posthog/values.yaml`来自定义`.gitlab/managed-apps/posthog/values.yaml`的安装. 有关可用的配置选项,请参阅[PostHog 图表的自述文件](https://github.com/PostHog/charts/tree/master/charts/posthog)的" [配置"部分](https://github.com/PostHog/charts/tree/master/charts/posthog) . - -**注意:**您必须在`postgresql.postgresqlPassword`提供 PostgreSQL 密码,否则将收到身份验证错误. 有关更多信息,请参见[PostgreSQL 图表文档](https://github.com/helm/charts/tree/master/stable/postgresql#upgrade) . - -Redis Pod 在升级之间重新启动. 为防止停机,请使用`redis.password`键提供 Redis 密码. 这样可以防止在每次重新启动时生成新密码. - -这是 PostHog 的示例配置: - -``` -ingress: - enabled: true - hostname: "" - -# This will be autogenerated if you skip it. Include if you have 2 or more web replicas -posthogSecret: 'long-secret-key-used-to-sign-cookies' - -# Needs to be here between runs. -# See https://github.com/helm/charts/tree/master/stable/postgresql#upgrade for more info -postgresql: - postgresqlPassword: example-postgresql-password - -# Recommended to set this to a value to redis prevent downtime between upgrades -redis: - password: example-redis-password -``` - -**注意:** PostHog 团队对 PostHog 托管应用程序提供支持. 如果遇到问题,请直接[打开支持凭单](https://github.com/PostHog/posthog/issues/new/choose) . - -### Install Prometheus using GitLab CI/CD[](#install-prometheus-using-gitlab-cicd "Permalink") - -在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25138) . - -[Prometheus](https://s0prometheus0io.icopy.site/docs/introduction/overview/)是用于监视已部署应用程序的开源监视和警报系统. - -要将 Prometheus 安装到群集的`gitlab-managed-apps`命名空间中,请使用以下`.gitlab/managed-apps/config.yaml`定义`.gitlab/managed-apps/config.yaml`文件: - -``` -prometheus: - installed: true -``` - -您可以通过在群集管理项目中定义`.gitlab/managed-apps/prometheus/values.yaml`来定制 Prometheus 的安装. 有关可用的配置选项,请参阅[Prometheus 图的 README](https://github.com/helm/charts/tree/master/stable/prometheus#configuration)的[Configuration(配置)部分](https://github.com/helm/charts/tree/master/stable/prometheus#configuration) . - -**注意:** GitLab APM 组提供了对安装 Prometheus 托管应用程序的支持. 如果遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping [APM 组中的](https://about.gitlab.com/handbook/product/product-categories/#apm-group)至少 2 个人. - -### Install GitLab Runner using GitLab CI/CD[](#install-gitlab-runner-using-gitlab-cicd "Permalink") - -通过在`.gitlab/managed-apps/config.yaml`定义配置,使用 GitLab CI / CD 安装了 GitLab Runner. - -使用 GitLab CI / CD 安装 GitLab Runner 需要以下配置: - -``` -gitlabRunner: - installed: true -``` - -GitLab Runner 已安装到集群的`gitlab-managed-apps`命名空间中. - -为了使 GitLab Runner 运行, **必须**指定以下内容: - -* `gitlabUrl`用于注册 Runner 的 GitLab 服务器完整 URL(例如, `https://example.gitlab.com` `gitlabUrl` ). -* `runnerRegistrationToken`用于将新的`runnerRegistrationToken`添加到 GitLab 的注册令牌. 这必须[从您的 GitLab 实例中检索](../../ci/runners/README.html) . - -这些值可以使用[CI 变量](../../ci/variables/README.html)指定: - -* `GITLAB_RUNNER_GITLAB_URL`将用于`gitlabUrl` . -* `GITLAB_RUNNER_REGISTRATION_TOKEN`将用于`runnerRegistrationToken` - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/gitlab-runner/values.yaml`文件来自定义 GitLab Runner 的安装. 请参阅[图表](https://gitlab.com/gitlab-org/charts/gitlab-runner)以获取可用的配置选项. - -**注意:** GitLab Runner 组提供了对安装 Runner 管理的应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping [Runner 组中的](https://about.gitlab.com/handbook/product/product-categories/#runner-group)至少 2 个人. - -### Install Cilium using GitLab CI/CD[](#install-cilium-using-gitlab-cicd "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/22) in GitLab 12.8. - -[Cilium](https://cilium.io/)是[Kubernetes](https://cilium.io/)的网络插件,可用于实现对[NetworkPolicy](https://kubernetes.io/docs/concepts/services-networking/network-policies/)资源的支持. 有关更多信息,请参阅[网络策略](../../topics/autodevops/stages.html#network-policy) . - -有关概述,请参见[GitLab 12.8](https://www.youtube.com/watch?v=pgUEdhdhoUI)的[容器网络安全演示](https://www.youtube.com/watch?v=pgUEdhdhoUI) . - -在`.gitlab/managed-apps/config.yaml`文件中启用 Cilium 进行安装: - -``` -# possible values are gke, eks or you can leave it blank -clusterType: gke - -cilium: - installed: true -``` - -`clusterType`变量为相应的群集类型启用建议的 Helm 变量. 默认值为空白. 您可以在官方文档中检查每种群集类型的建议变量: - -* [Google GKE](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-gke/#deploy-cilium) -* [AWS EKS](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-eks/#deploy-cilium) - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/cilium/values.yaml`文件来自定义 Cilium 的 Helm 变量. 有关可用的配置选项,请参阅[Cilium 图表](https://github.com/cilium/cilium/tree/master/install/kubernetes/cilium) . - -**注意:**安装和拆卸纤毛的需要**手动** [重新启动](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-gke/#restart-unmanaged-pods)在所有命名空间所有受影响的吊舱,以确保它们[管理](https://docs.cilium.io/en/stable/troubleshooting/#ensure-pod-is-managed-by-cilium)由正确的网络插件.**注意:**主要升级可能需要其他设置步骤,请查阅官方[升级指南](https://docs.cilium.io/en/stable/install/upgrade/)以获取更多信息. - -默认情况下,Cilium 会在策略部署时丢弃所有不允许的数据包. 但是,在[auditmode](https://docs.cilium.io/en/v1.8/gettingstarted/policy-creation/?highlight=policy-audit#enable-policy-audit-mode)中,Cilium 不会丢弃不允许的数据包. 您可以使用`policy-verdict`日志来观察与策略相关的决策. 您可以通过将以下内容添加到`.gitlab/managed-apps/cilium/values.yaml`来启用审核模式: - -``` -config: - policyAuditMode: true - -agent: - monitor: - eventTypes: ["drop", "policy-verdict"] -``` - -用于流量的 Cilium 监视器日志由`cilium-monitor`边车容器注销. 您可以使用以下命令检查这些日志: - -``` -kubectl -n gitlab-managed-apps logs cilium-XXXX cilium-monitor -``` - -您可以在`.gitlab/managed-apps/cilium/values.yaml`禁用监视器日志: - -``` -agent: - monitor: - enabled: false -``` - -默认情况下,启用了[Hubble](https://github.com/cilium/hubble)监视守护程序,并将其设置为收集每个命名空间流指标. 可在" [威胁监控"](../application_security/threat_monitoring/index.html)仪表板上访问此指标. 您可以通过将以下内容添加到`.gitlab/managed-apps/cilium/values.yaml`来禁用 Hubble: - -``` -global: - hubble: - enabled: false -``` - -您还可以通过`.gitlab/managed-apps/cilium/values.yaml`来为哈勃调整 Helm 值: - -``` -global: - hubble: - enabled: true - metrics: - enabled: - - 'flow:sourceContext=namespace;destinationContext=namespace' -``` - -**注意:** GitLab Container Security 组提供了对安装 Cilium 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping 通至少来自[Container Security 组的](https://about.gitlab.com/handbook/product/product-categories/#container-security-group) 2 个人. - -### Install Falco using GitLab CI/CD[](#install-falco-using-gitlab-cicd "Permalink") - -在 GitLab 13.1 中[引入](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/91) . - -GitLab 容器主机安全监视使用[Falco](https://falco.org/)作为运行时安全工具,该工具使用 eBPF 侦听 Linux 内核. Falco 实时解析系统调用并针对可配置的规则引擎声明流. 有关更多信息,请参见[Falco 的文档](https://falco.org/docs/) . - -您可以在`.gitlab/managed-apps/config.yaml`文件中启用 Falco: - -``` -falco: - installed: true -``` - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/falco/values.yaml`文件来自定义 Falco 的 Helm 变量. 有关可用的配置选项,请参考[Falco 图表](https://github.com/falcosecurity/charts/tree/master/falco) . - -**警告:**默认情况下,eBPF 支持已启用,Falco 将使用[eBPF 探针](https://falco.org/docs/event-sources/drivers/#using-the-ebpf-probe)将系统调用传递到用户空间. 如果您的群集不支持此功能,则可以通过将以下内容添加到`.gitlab/managed-apps/falco/values.yaml` ,将其配置为使用 Falco 内核模块: - -``` -ebpf: - enabled: false -``` - -在极少数情况下,无法在群集上自动安装探针并且未预编译内核/探针,您可能需要手动准备带有[driverkit](https://github.com/falcosecurity/driverkit#against-a-kubernetes-cluster)的内核模块或 eBPF 探针,并将其安装在每个群集节点上. - -默认情况下,Falco 部署的规则有限. 要添加更多规则,请将以下内容添加到`.gitlab/managed-apps/falco/values.yaml` (您可以从[Cloud Native Security Hub 中](https://securityhub.dev/)获取示例): - -``` -customRules: - file-integrity.yaml: |- - - rule: Detect New File - desc: detect new file created - condition: > - evt.type = chmod or evt.type = fchmod - output: > - File below a known directory opened for writing (user=%user.name - command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2]) - priority: ERROR - tags: [filesystem] - - rule: Detect New Directory - desc: detect new directory created - condition: > - mkdir - output: > - File below a known directory opened for writing (user=%user.name - command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2]) - priority: ERROR - tags: [filesystem] -``` - -默认情况下,Falco 仅将安全事件作为 JSON 对象输出到日志. 要将其设置为输出到[外部 API](https://falco.org/docs/alerts/#https-output-send-alerts-to-an-https-end-point)或[应用程序](https://falco.org/docs/alerts/#program-output) ,请将以下内容添加到`.gitlab/managed-apps/falco/values.yaml` : - -``` -falco: - programOutput: - enabled: true - keepAlive: false - program: mail -s "Falco Notification" someone@example.com - - httpOutput: - enabled: true - url: http://some.url -``` - -您可以使用以下命令检查这些日志: - -``` -kubectl logs -l app=falco -n gitlab-managed-apps -``` - -**注意:** GitLab Container Security 组提供了对安装 Falco 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping 通至少来自[Container Security 组的](https://about.gitlab.com/handbook/product/product-categories/#container-security-group) 2 个人. - -### Install Vault using GitLab CI/CD[](#install-vault-using-gitlab-cicd "Permalink") - -在 GitLab 12.9 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/9982) . - -[Hashicorp Vault](https://www.vaultproject.io/)是一个秘密管理解决方案,可用于安全地管理和存储密码,凭据,证书等. 可以利用 Vault 安装为应用程序,GitLab CI / CD 作业等中使用的凭据提供一个安全的数据存储. 它还可以用作向基础结构中的系统和部署提供 SSL / TLS 证书的方式. 通过将 Vault 作为所有这些凭据的单一来源,可以通过对所有敏感凭据和证书具有单一的访问,控制和可审核性来源,从而提高安全性. - -To install Vault, enable it in the `.gitlab/managed-apps/config.yaml` file: - -``` -vault: - installed: true -``` - -默认情况下,您将获得基本的保险柜设置,没有可扩展的存储后端. 这对于简单的测试和小规模部署就足够了,尽管限制了它可以扩展的规模,并且由于它是单实例部署,因此在升级 Vault 应用程序时会遇到停机时间. - -为了在生产环境中最佳地使用 Vault,理想的是充分了解 Vault 的内部结构以及如何配置它. 这可以通过阅读[Vault 文档](https://www.vaultproject.io/docs/internals)以及 Vault Helm 图表[`values.yaml`文件来完成](https://github.com/hashicorp/vault-helm/blob/v0.3.3/values.yaml) . - -至少您可能会设置: - -* 用于对主密钥进行额外加密的[印章](https://www.vaultproject.io/docs/configuration/seal) . -* 适合于环境和存储安全性要求的[存储后端](https://www.vaultproject.io/docs/configuration/storage) . -* [HA Mode](https://www.vaultproject.io/docs/concepts/ha). -* [The Vault UI](https://www.vaultproject.io/docs/configuration/ui). - -以下是一个示例值文件( `.gitlab/managed-apps/vault/values.yaml` ),该文件使用 Google Cloud Storage 后端,启用 Vault UI 并启用具有 3 个 pod 的 HA,将 Google 密钥管理服务配置为自动`.gitlab/managed-apps/vault/values.yaml`副本. 下面的`storage`和`seal`节是示例,应替换为特定于您的环境的设置. - -``` -# Enable the Vault WebUI -ui: - enabled: true -server: - # Disable the built in data storage volume as it's not safe for Hight Availability mode - dataStorage: - enabled: false - # Enable High Availability Mode - ha: - enabled: true - # Configure Vault to listen on port 8200 for normal traffic and port 8201 for inter-cluster traffic - config: | - listener "tcp" { - tls_disable = 1 - address = "[::]:8200" - cluster_address = "[::]:8201" - } - # Configure Vault to store its data in a GCS Bucket backend - storage "gcs" { - path = "gcs://my-vault-storage/vault-bucket" - ha_enabled = "true" - } - # Configure Vault to automatically unseal storage using a GKMS key - seal "gcpckms" { - project = "vault-helm-dev-246514" - region = "global" - key_ring = "vault-helm-unseal-kr" - crypto_key = "vault-helm-unseal-key" - } -``` - -成功安装保险柜后,您将需要[初始化保险柜](https://learn.hashicorp.com/vault/getting-started/deploy#initializing-the-vault)并获取初始根令牌. 为此,您将需要访问已将 Vault 部署到的 Kubernetes 群集. 要初始化 Vault,请在 Kubernetes 内部运行的一个 Vault 容器中安装一个外壳(通常是通过使用`kubectl`命令行工具来完成). 将外壳放入吊舱后,运行`vault operator init`命令: - -``` -kubectl -n gitlab-managed-apps exec -it vault-0 sh -/ $ vault operator init -``` - -这应该为您提供解封密钥和初始根令牌. 确保记下这些内容并保持安全,因为您将需要它们在保险柜的整个生命周期内将其解封. - -**注意:** GitLab 版本管理组提供了对安装 Vault 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从" [发行管理"组](https://about.gitlab.com/handbook/product/product-categories/#release-management-group) ping 至少 2 个人. - -### Install JupyterHub using GitLab CI/CD[](#install-jupyterhub-using-gitlab-cicd "Permalink") - -在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/40) . - -通过在`.gitlab/managed-apps/config.yaml`定义配置,使用 GitLab CI / CD 安装`.gitlab/managed-apps/config.yaml` ,如下所示: - -``` -jupyterhub: - installed: true - gitlabProjectIdWhitelist: [] - gitlabGroupWhitelist: [] -``` - -在配置中: - -* `gitlabProjectIdWhitelist`将 GitLab 身份验证限制为仅指定项目的成员. -* `gitlabGroupWhitelist`将 GitLab 身份验证限制为仅指定组的成员. -* 为两者指定一个空数组将允许 GitLab 实例上的任何用户登录. - -JupyterHub 已安装到集群的`gitlab-managed-apps`命名空间中. - -为了使 JupyterHub 正常运行,您必须设置一个[OAuth 应用程序](../../integration/oauth_provider.html) . 组: - -* “Redirect URI” to `http:///hub/oauth_callback`. -* `api read_repository write_repository` "范围". - -此外,必须使用[CI 变量](../../ci/variables/README.html)指定以下[变量](../../ci/variables/README.html) : - -| 可变 CI | Description | -| --- | --- | -| `JUPYTERHUB_PROXY_SECRET_TOKEN` | 用于签名来自集线器的通信的安全字符串. 请参阅[`proxy.secretToken`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#proxy-secrettoken) . | -| `JUPYTERHUB_COOKIE_SECRET` | 用于签署安全 cookie 的安全字符串. 参见[`hub.cookieSecret`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#hub-cookiesecret) . | -| `JUPYTERHUB_HOST` | 用于安装的主机名. 例如, `jupyter.gitlab.example.com` . | -| `JUPYTERHUB_GITLAB_HOST` | 用于身份验证的 GitLab 实例的主机名. 例如, `gitlab.example.com` . | -| `JUPYTERHUB_AUTH_CRYPTO_KEY` | 一个 32 字节的加密密钥,用于设置[`auth.state.cryptoKey`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#auth-state-cryptokey) . | -| `JUPYTERHUB_AUTH_GITLAB_CLIENT_ID` | OAuth 应用程序的"应用程序 ID". | -| `JUPYTERHUB_AUTH_GITLAB_CLIENT_SECRET` | OAuth 应用程序的"秘密". | - -默认情况下,将使用[默认值文件](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/blob/master/src/default-data/jupyterhub/values.yaml.gotmpl)安装 JupyterHub. 您可以通过在群集管理项目中定义`.gitlab/managed-apps/jupyterhub/values.yaml`文件来自定义`.gitlab/managed-apps/jupyterhub/values.yaml`的安装. - -有关可用的配置选项,请参考[图表参考](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html) . - -**注意:** GitLab 配置组提供了对安装 JupyterHub 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从[Configure 组中](https://about.gitlab.com/handbook/product/categories/#configure-group) ping 通至少 2 个人. - -### Install Elastic Stack using GitLab CI/CD[](#install-elastic-stack-using-gitlab-cicd "Permalink") - -在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25138) . - -通过在`.gitlab/managed-apps/config.yaml`定义配置,使用 GitLab CI / CD 安装 Elastic Stack. - -使用 GitLab CI / CD 安装 Elastic Stack 需要以下配置: - -``` -elasticStack: - installed: true -``` - -Elastic Stack 已安装到集群的`gitlab-managed-apps`命名空间中. - -您可以检查默认[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/vendor/elastic_stack/values.yaml)我们此图表设置. - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/elastic-stack/values.yaml`文件来自定义 Elastic Stack 的安装. 请参阅[图表](https://gitlab.com/gitlab-org/charts/elastic-stack)以获取可用的配置选项. - -**注意:**在通过 CI 安装 Elastic Stack 的 alpha 实现中,不支持通过 Elasticsearch 读取环境日志. 如果[通过 UI 安装,](#elastic-stack)则支持此功能.**注意:** GitLab APM 组提供了对安装 Elastic Stack 托管应用程序的支持. 如果遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping [APM 组中的](https://about.gitlab.com/handbook/product/product-categories/#apm-group)至少 2 个人. - -### Install Crossplane using GitLab CI/CD[](#install-crossplane-using-gitlab-cicd "Permalink") - -在 GitLab 12.9 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/35675) . - -通过在`.gitlab/managed-apps/config.yaml`定义配置,使用 GitLab CI / CD 安装 Crossplane. - -使用 GitLab CI / CD 安装 Crossplane 需要以下配置: - -``` -Crossplane: - installed: true -``` - -Crossplane 已安装到集群的`gitlab-managed-apps`命名空间中. - -您可以检查默认[`values.yaml`](https://github.com/crossplane/crossplane/blob/master/cluster/charts/crossplane/values.yaml.tmpl)我们此图表设置. - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/crossplane/values.yaml`文件来自定义 Crossplane 的安装. 请参阅[图表](https://github.com/crossplane/crossplane/tree/master/cluster/charts/crossplane#configuration)以获取可用的配置选项. 请注意,此链接指向当前开发版本的文档,该文档可能与您安装的版本不同. - -**注意:** Crossplane 团队提供对 Crossplane 托管应用程序的支持. 如果遇到问题,请直接[打开支持凭单](https://github.com/crossplane/crossplane/issues/new/choose) . - -### Install Fluentd using GitLab CI/CD[](#install-fluentd-using-gitlab-cicd "Permalink") - -在 GitLab 12.10 中[引入](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/76) . - -要使用 GitLab CI / CD 将`gitlab-managed-apps`安装到群集的`gitlab-managed-apps`命名空间中,请在`.gitlab/managed-apps/config.yaml`定义以下配置: - -``` -Fluentd: - installed: true -``` - -您也可以在[`values.yaml`](https://github.com/helm/charts/blob/master/stable/fluentd/values.yaml)文件中查看为此图表设置的默认值. - -您可以通过在群集管理项目中定义`.gitlab/managed-apps/fluentd/values.yaml`文件来自定义`.gitlab/managed-apps/fluentd/values.yaml`的安装. 有关可用的配置选项,请参阅[Fluentd 当前开发版本](https://github.com/helm/charts/tree/master/stable/fluentd#configuration)的[配置表](https://github.com/helm/charts/tree/master/stable/fluentd#configuration) . - -**注意:**配置图表链接指向当前的开发版本,该版本可能与您安装的版本不同. 为了确保兼容性,请切换到您正在使用的特定分支或标签.**注意:** GitLab Container Security 组提供了对安装 Fluentd 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping 通至少来自[Container Security 组的](https://about.gitlab.com/handbook/product/product-categories/#container-security-group) 2 个人. - -### Install Knative using GitLab CI/CD[](#install-knative-using-gitlab-cicd "Permalink") - -要安装 Knative,请使用以下命令定义`.gitlab/managed-apps/config.yaml`文件: - -``` -knative: - installed: true -``` - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/knative/values.yaml`文件来自定义`.gitlab/managed-apps/knative/values.yaml`的安装. 请参阅[图表](https://gitlab.com/gitlab-org/charts/knative)以获取可用的配置选项. - -这是 Knative 的示例配置: - -``` -domain: 'my.wildcard.A.record.dns' -``` - -如果计划使用 GitLab 无服务器功能,请确保在自定义配置上设置 A 记录通配符域. - -**注意:** GitLab 配置组提供了对安装 Knative 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从[Configure 组中](https://about.gitlab.com/handbook/product/categories/#configure-group) ping 通至少 2 个人. - -#### Knative Metrics[](#knative-metrics "Permalink") - -GitLab 为您的函数提供了[调用指标](../project/clusters/serverless/index.html#invocation-metrics) . 要收集这些指标,您必须具有: - -1. 在群集上安装了 Knative 和 Prometheus 托管的应用程序. -2. 通过运行以下命令在群集上手动应用自定义指标: - - ``` - kubectl apply -f https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/raw/02c8231e30ef5b6725e6ba368bc63863ceb3c07d/src/default-data/knative/istio-metrics.yaml - ``` - -#### Uninstall Knative[](#uninstall-knative "Permalink") - -要卸载 Knative,必须首先通过运行以下命令手动删除已添加的所有自定义指标: - -``` -kubectl delete -f https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/raw/02c8231e30ef5b6725e6ba368bc63863ceb3c07d/src/default-data/knative/istio-metrics.yaml -``` - -### Install AppArmor using GitLab CI/CD[](#install-apparmor-using-gitlab-cicd "Permalink") - -在 GitLab 13.1 中[引入](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/100) . - -要使用 GitLab CI / CD 将 AppArmor 安装到群集的`gitlab-managed-apps`命名空间中,请在`.gitlab/managed-apps/config.yaml`定义以下配置: - -``` -apparmor: - installed: true -``` - -您可以通过将它们添加到`.gitlab/managed-apps/apparmor/values.yaml`来定义一个或多个 AppArmor 配置文件,如下所示: - -``` -profiles: - profile-one: |- - profile profile-one { - file, - } -``` - -有关此图表的更多信息,请参考[AppArmor](https://gitlab.com/gitlab-org/charts/apparmor)图表. - -#### Using AppArmor profiles in your deployments[](#using-apparmor-profiles-in-your-deployments "Permalink") - -安装 AppAmor 之后,您可以通过添加 Pod 注释来使用配置文件. 如果您使用的是 Auto DevOps,则可以[自定义`auto-deploy-values.yaml`](../../topics/autodevops/customize.html#customize-values-for-helm-chart)来注释您的 Pod. 尽管了解[自定义属性列表](https://gitlab.com/gitlab-org/charts/auto-deploy-app#gitlabs-auto-deploy-helm-chart)会有所帮助,但只需`podAnnotations`如下所示设置`podAnnotations` : - -``` -podAnnotations: - container.apparmor.security.beta.kubernetes.io/auto-deploy-app: localhost/profile-one -``` - -此处唯一要更改的信息是配置文件名称,在本示例中为`profile-one` . 有关如何在 Kubernetes 中集成[AppArmor](https://kubernetes.io/docs/tutorials/clusters/apparmor/#securing-a-pod)的更多信息,请参考[AppArmor 教程](https://kubernetes.io/docs/tutorials/clusters/apparmor/#securing-a-pod) . - -**注意:** GitLab Container Security 组提供了对安装 AppArmor 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping 通至少来自[Container Security 组的](https://about.gitlab.com/handbook/product/product-categories/#container-security-group) 2 个人. - -## Upgrading applications[](#upgrading-applications "Permalink") - -在 GitLab 11.8 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24789) . - -以下应用程序可以升级. - -| Application | GitLab 版本 | -| --- | --- | -| Runner | 11.8+ | - -升级应用程序: - -1. 为一个: - * [在项目级别的集群中](../project/clusters/index.html) ,导航到项目的**Operations> Kubernetes** . - * [组级别集群](../group/clusters/index.html) ,导航到您组的**Kubernetes**页面. -2. 选择您的集群. -3. 如果有升级,将显示" **升级"**按钮. 单击按钮进行升级. - -**注意:**升级会将值重置为`runner`图表中内置的值, [`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/runner/values.yaml)设置的值. - -## Uninstalling applications[](#uninstalling-applications "Permalink") - -在 GitLab 11.11 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/60665) . - -可以卸载以下应用程序. - -| Application | GitLab 版本 | Notes | -| --- | --- | --- | -| cert-manager | 12.2+ | 关联的私钥将被删除,并且无法还原. 部署的应用程序将继续使用 HTTPS,但是不会续订证书. 卸载之前,您可能希望[备份配置](https://cert-manager.io/docs/tutorials/backup/)或[吊销证书](https://letsencrypt.org/docs/revoking/) . | -| 亚搏体育 app Runner | 12.2+ | 任何正在运行的管道将被取消. | -| Helm | 12.2+ | 关联的 Tiller 容器, `gitlab-managed-apps`命名空间及其所有资源将被删除,并且无法还原. | -| Ingress | 12.1+ | 关联的负载均衡器和 IP 将被删除,并且无法还原. 此外,仅当未安装 JupyterHub 时才能将其卸载. | -| JupyterHub | 12.1+ | 所有未提交到 GitLab 的数据将被删除,并且无法还原. | -| Knative | 12.1+ | 关联的 IP 将被删除,无法恢复. | -| Prometheus | 11.11+ | 所有数据将被删除,无法还原. | -| Crossplane | 12.5+ | 所有数据将被删除,无法还原. | -| 弹性堆叠 | 12.7+ | 所有数据将被删除,无法还原. | -| Sentry | 12.6+ | PostgreSQL 永久卷将保留,应手动删除以完全卸载. | - -卸载应用程序: - -1. 为一个: - * [在项目级别的集群中](../project/clusters/index.html) ,导航到项目的**Operations> Kubernetes** . - * [组级别集群](../group/clusters/index.html) ,导航到您组的**Kubernetes**页面. -2. 选择您的集群. -3. 单击该应用程序的" **卸载"**按钮. - -支持逐步卸载所有支持的应用程序. 要了解进度,请参阅[相关的史诗](https://gitlab.com/groups/gitlab-org/-/epics/1201) . - -## Troubleshooting applications[](#troubleshooting-applications "Permalink") - -应用程序可能因以下错误而失败: - -``` -Error: remote error: tls: bad certificate -``` - -为避免安装错误: - -* 在开始安装应用程序之前,请确保您的 GitLab 服务器和 Kubernetes 集群之间的时间已同步. -* 确保证书不同步. 在安装应用程序时,GitLab 需要一个没有先前安装的 Helm 的新集群. - - 您可以通过`kubectl`确认证书匹配: - - ``` - kubectl get configmaps/values-content-configuration-ingress -n gitlab-managed-apps -o \ - "jsonpath={.data['cert\.pem']}" | base64 -d > a.pem - kubectl get secrets/tiller-secret -n gitlab-managed-apps -o "jsonpath={.data['ca\.crt']}" | base64 -d > b.pem - diff a.pem b.pem - ``` - -### Error installing managed apps on EKS cluster[](#error-installing-managed-apps-on-eks-cluster "Permalink") - -如果您在 AWS EKS 上使用托管集群,但无法安装某些托管应用程序,请考虑检查日志. - -您可以通过运行以下命令来检查日志: - -``` -kubectl get pods --all-namespaces -kubectl get services --all-namespaces -``` - -如果遇到`Failed to assign an IP address to container`错误,则可能是由于您在 AWS 配置中指定的实例类型. 节点的数量和大小可能没有足够的 IP 地址来运行或安装这些 Pod. - -作为参考,可以[在 GitHub 上的此 AWS 存储库](https://github.com/aws/amazon-vpc-cni-k8s/blob/master/pkg/awsutils/vpc_ip_resource_limit.go)中找到所有 AWS 实例 IP 限制(搜索`InstanceENIsAvailable` ). - -### Unable to install Prometheus[](#unable-to-install-prometheus "Permalink") - -Prometheus 安装失败,出现以下错误: - -``` -# kubectl -n gitlab-managed-apps logs install-prometheus -... -Error: Could not get apiVersions from Kubernetes: unable to retrieve the complete list of server APIs: admission.certmanager.k8s.io/v1beta1: the server is currently unable to handle the request -``` - -这是在 Helm `2.15`中引入并在`3.0.2`修复的错误. 解决方法是,在安装 Prometheus 之前,需要确保已成功安装[`cert-manager`](#cert-manager) . \ No newline at end of file diff --git a/_book/docs/026.md b/_book/docs/026.md deleted file mode 100644 index 7adc85bef91ade83593af0abc823335be5b3c842..0000000000000000000000000000000000000000 --- a/_book/docs/026.md +++ /dev/null @@ -1,264 +0,0 @@ -# Crossplane configuration - -> 原文:[https://docs.gitlab.com/ee/user/clusters/crossplane.html](https://docs.gitlab.com/ee/user/clusters/crossplane.html) - -* [Configure RBAC permissions](#configure-rbac-permissions) -* [Configure Crossplane with a cloud provider](#configure-crossplane-with-a-cloud-provider) -* [Configure Managed Service Access](#configure-managed-service-access) -* [Setting up Resource classes](#setting-up-resource-classes) -* [Auto DevOps Configuration Options](#auto-devops-configuration-options) -* [Connect to the PostgreSQL instance](#connect-to-the-postgresql-instance) - -# Crossplane configuration[](#crossplane-configuration "Permalink") - -[安装](applications.html#crossplane) Crossplane 后,必须对其进行配置以供使用. 配置 Crossplane 的过程包括: - -1. [Configure RBAC permissions](#configure-rbac-permissions). -2. [Configure Crossplane with a cloud provider](#configure-crossplane-with-a-cloud-provider). -3. [Configure managed service access](#configure-managed-service-access). -4. [Set up Resource classes](#setting-up-resource-classes). -5. Use [Auto DevOps configuration options](#auto-devops-configuration-options). -6. [Connect to the PostgreSQL instance](#connect-to-the-postgresql-instance). - -为了允许 Crossplane 设置诸如 PostgreSQL 之类的云服务,必须使用用户帐户配置云提供商堆栈. 例如: - -* GCP 的服务帐户. -* AWS 的 IAM 用户. - -一些重要的注意事项: - -* 本指南以 GCP 为例,但 AWS 和 Azure 的过程相似. -* Crossplane 要求 Kubernetes 集群是启用了 Alias IP 的 VPC 本机,因此可以在 GCP 网络内路由 Pod 的 IP 地址. - -首先,使用配置声明一些环境变量以供本指南使用: - -``` -export PROJECT_ID=crossplane-playground # the GCP project where all resources reside. -export NETWORK_NAME=default # the GCP network where your GKE is provisioned. -export REGION=us-central1 # the GCP region where the GKE cluster is provisioned. -``` - -## Configure RBAC permissions[](#configure-rbac-permissions "Permalink") - -对于由 GitLab 管理的群集,将自动配置基于角色的访问控制(RBAC). - -对于非 GitLab 管理的群集,请确保提供的令牌的服务帐户可以管理`database.crossplane.io` API 组中的资源: - -1. 将以下 YAML 保存为`crossplane-database-role.yaml` : - - ``` - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole - metadata: - name: crossplane-database-role - labels: - rbac.authorization.k8s.io/aggregate-to-edit: "true" - rules: - - apiGroups: - - database.crossplane.io - resources: - - postgresqlinstances - verbs: - - get - - list - - create - - update - - delete - - patch - - watch - ``` - -2. 将集群角色应用于集群: - - ``` - kubectl apply -f crossplane-database-role.yaml - ``` - -## Configure Crossplane with a cloud provider[](#configure-crossplane-with-a-cloud-provider "Permalink") - -请参阅[配置您的云提供商帐户](https://crossplane.github.io/docs/v0.4/cloud-providers.html)以使用用户帐户配置已安装的云提供商堆栈. - -**注意:必须**将 Secret 和引用该 Secret 的 Provider 资源应用于指南中的`gitlab-managed-apps`命名空间. 请确保在执行该过程时进行更改. - -## Configure Managed Service Access[](#configure-managed-service-access "Permalink") - -接下来,通过以下任一方法配置 PostgreSQL 数据库和 GKE 集群之间的连接: - -* 如下所示使用 Crossplane. -* Directly in the GCP console by [configuring private services access](https://cloud.google.com/vpc/docs/configure-private-services-access). - -1. 运行以下命令,这将创建一个`network.yaml`文件,并配置`GlobalAddress`和连接资源: - - ``` - cat > network.yaml < gcp-postgres-standard.yaml < -Annotations: crossplane.io/propagate-from-name: 108e460e-06c7-11ea-b907-42010a8000bd - crossplane.io/propagate-from-namespace: gitlab-managed-apps - crossplane.io/propagate-from-uid: 10c79605-06c7-11ea-b907-42010a8000bd - -Type: Opaque - -Data -==== -privateIP: 8 bytes -publicIP: 13 bytes -serverCACertificateCert: 1272 bytes -serverCACertificateCertSerialNumber: 1 bytes -serverCACertificateCreateTime: 24 bytes -serverCACertificateExpirationTime: 24 bytes -username: 8 bytes -endpoint: 8 bytes -password: 27 bytes -serverCACertificateCommonName: 98 bytes -serverCACertificateInstance: 41 bytes -serverCACertificateSha1Fingerprint: 40 bytes -``` - -## Connect to the PostgreSQL instance[](#connect-to-the-postgresql-instance "Permalink") - -如果您想连接到 CloudSQL 上新配置的 PostgreSQL 数据库实例,请遵循此[GCP 指南](https://cloud.google.com/sql/docs/postgres/connect-kubernetes-engine) . \ No newline at end of file diff --git a/_book/docs/027.md b/_book/docs/027.md deleted file mode 100644 index 267cdcd9578a0721596624b7b57e6a1cbe5ca77c..0000000000000000000000000000000000000000 --- a/_book/docs/027.md +++ /dev/null @@ -1,103 +0,0 @@ -# Cluster management project (alpha) - -> 原文:[https://docs.gitlab.com/ee/user/clusters/management_project.html](https://docs.gitlab.com/ee/user/clusters/management_project.html) - -* [Permissions](#permissions) -* [Usage](#usage) - * [Selecting a cluster management project](#selecting-a-cluster-management-project) - * [Configuring your pipeline](#configuring-your-pipeline) - * [Setting the environment scope](#setting-the-environment-scope-premium) - -# Cluster management project (alpha)[](#cluster-management-project-alpha "Permalink") - -**警告:**这是*Alpha 版*功能,如有更改,恕不另行通知. - -在 GitLab 12.5 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/32810) - -可以将一个项目指定为集群的管理项目. 管理项目可用于以 Kubernetes [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)权限运行部署作业. - -这对以下情况很有用: - -* 创建管道以将群集范围的应用程序安装到群集中,有关详细信息,请参见[使用 GitLab CI / CD(alpha)](applications.html#install-using-gitlab-cicd-alpha)安装. -* 需要`cluster-admin`权限的所有作业. - -## Permissions[](#permissions "Permalink") - -仅管理项目将获得`cluster-admin`权限. 所有其他项目将继续获得[命名空间范围的`edit`级别特权](../project/clusters/add_remove_clusters.html#rbac-cluster-resources) . - -管理项目仅限于以下内容: - -* 对于项目级集群,管理项目必须与集群项目位于相同的名称空间(或子代)中. -* 对于组级集群,管理项目必须与集群的组位于同一组(或子孙)中. -* 对于实例级群集,没有此类限制. - -## Usage[](#usage "Permalink") - -要将群集管理项目用于群集: - -1. 选择项目. -2. 配置管道. -3. 设置环境范围. - -### Selecting a cluster management project[](#selecting-a-cluster-management-project "Permalink") - -选择要使用的集群管理项目: - -1. 导航到适当的配置页面. 为一个: - * [项目级集群](../project/clusters/index.html) ,导航到项目的**Operations> Kubernetes**页面. - * [组级别集群](../group/clusters/index.html) ,导航到您组的**Kubernetes**页面. - * [实例级集群](../instance/clusters/index.html) ,导航到管理区域的**Kubernetes**页面. -2. 在" **高级设置"**部分中的"使用**集群管理项目"字段**中选择项目. - -[![Selecting a cluster management project under Advanced settings](img/838245c530d1afaf54929d9edd3f6a24.png)](img/advanced-settings-cluster-management-project-v12_5.png) - -### Configuring your pipeline[](#configuring-your-pipeline "Permalink") - -将项目指定为集群的管理项目后,在该项目中编写[`.gitlab-ci.yml`](../../ci/yaml/README.html) . 例如: - -``` -configure cluster: - stage: deploy - script: kubectl get namespaces - environment: - name: production -``` - -### Setting the environment scope[](#setting-the-environment-scope-premium "Permalink") - -将多个群集与同一管理项目关联时,可以使用[环境范围](../project/clusters/index.html#setting-the-environment-scope-premium) . - -每个作用域只能由单个群集用于管理项目. - -例如,假设以下 Kubernetes 集群与管理项目相关联: - -| Cluster | 环境范围 | -| --- | --- | -| Development | `*` | -| Staging | `staging` | -| Production | `production` | - -[`.gitlab-ci.yml`](../../ci/yaml/README.html)设置的以下环境将分别部署到 Development,Staging 和 Production 集群. - -``` -stages: - - deploy - -configure development cluster: - stage: deploy - script: kubectl get namespaces - environment: - name: development - -configure staging cluster: - stage: deploy - script: kubectl get namespaces - environment: - name: staging - -configure production cluster: - stage: deploy - script: kubectl get namespaces - environment: - name: production -``` \ No newline at end of file diff --git a/_book/docs/028.md b/_book/docs/028.md deleted file mode 100644 index 72b89b4e4b654a3acd84f965ee24cc57fbcf96d3..0000000000000000000000000000000000000000 --- a/_book/docs/028.md +++ /dev/null @@ -1,100 +0,0 @@ -# Kubernetes Logs - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/kubernetes_pod_logs.html](https://docs.gitlab.com/ee/user/project/clusters/kubernetes_pod_logs.html) - -* [Overview](#overview) -* [Requirements](#requirements) -* [Usage](#usage) - * [From the project sidebar](#from-the-project-sidebar) - * [From Deploy Boards](#from-deploy-boards) - * [Logs view](#logs-view) - * [Filter by date](#filter-by-date) - * [Full text search](#full-text-search) - -# Kubernetes Logs[](#kubernetes-logs "Permalink") - -版本历史 - -* 在[GitLab Ultimate](https://about.gitlab.com/pricing/) 11.0 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/4752) . -* [移至](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26383) [GitLab Core](https://about.gitlab.com/pricing/) 12.9\. - -使用 GitLab 可以轻松查看[连接的 Kubernetes 集群](index.html)中正在运行的 Pod 的日志. 通过直接在**Log Explorer 的** GitLab 中显示**日志** ,开发人员可以避免管理控制台工具或跳转到其他界面. - -**注意:** [了解有关 Kubernetes + GitLab 的更多信息](https://about.gitlab.com/solutions/kubernetes/) . 大规模构建,测试,部署和运行应用程序所需的一切. - -## Overview[](#overview "Permalink") - -[Kubernetes](https://kubernetes.io)日志可以使用**Log Explorer**在 GitLab 中直接查看. - -[![Pod logs](img/0370f6d6a289b9e8237fcad4c7672e78.png)](img/kubernetes_pod_logs_v12_10.png) - -要了解更多信息,请参阅[APM-Log Explorer](https://www.youtube.com/watch?v=hWclZHA7Dgw) . - -## Requirements[](#requirements "Permalink") - -要使用日志,需要[部署到 Kubernetes 环境](../deploy_boards.html#enabling-deploy-boards) . - -## Usage[](#usage "Permalink") - -要访问日志,您必须具有正确的[权限](../../permissions.html#project-members-permissions) . - -您可以通过两种方式访问​​它们. - -### From the project sidebar[](#from-the-project-sidebar "Permalink") - -在 GitLab 12.5 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22011) . - -去 侧栏菜单上的" **操作">"舱位日志** "以显示" **日志资源管理器"** . - -[![Sidebar menu](img/0050abd936ad2e13e4ad057a58611cc9.png)](img/sidebar_menu_pod_logs_v12_10.png) - -### From Deploy Boards[](#from-deploy-boards "Permalink") - -可以通过单击[Deploy Boards 中](../deploy_boards.html)的特定窗格来显示日志: - -1. 去 **操作>环境,**然后找到包含所需 pod 的环境,例如`production` . -2. 在" **环境"**页面上,您应该通过[Deploy Boards](../deploy_boards.html)看到环境容器的状态. -3. 将鼠标悬停在窗格列表上时,将显示一个工具提示,其中包含确切的窗格名称和状态. [![部署板窗格列表](img/81c888ba61ab652f9505d5b51406ed22.png)](img/pod_logs_deploy_board.png) -4. 单击所需的窗格以显示**Log Explorer** . - -### Logs view[](#logs-view "Permalink") - -**日志浏览**器使您可以通过以下方式过滤日志: - -* Pods. -* [从 GitLab 12.4 开始](https://gitlab.com/gitlab-org/gitlab/-/issues/5769) ,环境. -* [From GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21656), [full text search](#full-text-search). -* [从 GitLab 12.8 开始](https://gitlab.com/gitlab-org/gitlab/-/issues/197879) ,日期. - -从[GitLab 12.9](https://gitlab.com/gitlab-org/gitlab/-/issues/198050)起可以加载 500 条以上的日志行. - -[在将来的版本中将](https://gitlab.com/gitlab-org/gitlab/-/issues/13404)支持具有多个容器的 Pod. - -[在将来的版本中将](https://gitlab.com/gitlab-org/gitlab/-/issues/196191)支持历史数据. - -### Filter by date[](#filter-by-date "Permalink") - -在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/197879) . - -在集群上启用[Elastic Stack](../../clusters/applications.html#elastic-stack)时,您可以按日期过滤" **日志浏览**器"中显示的**日志** . - -单击" **日志资源管理器"**中的" **显示最后一个** "以查看可用选项. - -### Full text search[](#full-text-search "Permalink") - -在 GitLab 12.7 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21656) . - -在集群上启用[Elastic Stack](../../clusters/applications.html#elastic-stack)时,可以通过搜索栏搜索日志的内容. - -搜索通过使用[simple_query_string](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html) Elasticsearch 函数传递给 Elasticsearch,该函数支持以下运算符: - -| Operator | Description | -| --- | --- | -| `\|` | 或运算. | -| `-` | 取反单个令牌. | -| `+` | AND 运算. | -| `"` | 包装许多标记以表示要搜索的短语. | -| `*` (每学期末) | 前缀查询. | -| `(` and `)` | Precedence. | -| `~N` (一个字之后) | 编辑距离(模糊性). | -| `~N` (在短语之后) | 斜率. | \ No newline at end of file diff --git a/_book/docs/029.md b/_book/docs/029.md deleted file mode 100644 index 695ccf7100dfe06c457b0f23654abdd5166b0968..0000000000000000000000000000000000000000 --- a/_book/docs/029.md +++ /dev/null @@ -1,104 +0,0 @@ -# Runbooks - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/runbooks/](https://docs.gitlab.com/ee/user/project/clusters/runbooks/) - -* [Executable Runbooks](#executable-runbooks) -* [Requirements](#requirements) -* [Nurtch](#nurtch) -* [Configure an executable runbook with GitLab](#configure-an-executable-runbook-with-gitlab) - -# Runbooks[](#runbooks "Permalink") - -Runbooks 是记录在案的过程的集合,这些过程解释了如何执行特定过程,包括启动,停止,调试特定系统或对特定系统进行故障排除. - -使用[Jupyter Notebook](https://jupyter.org/)和[Rubix 库](https://github.com/Nurtch/rubix) ,用户可以开始编写自己的可执行运行手册. - -从历史上看,运行手册根据情况或系统采用决策树或详细的分步指南的形式. - -现代的实现方式引入了"可执行的运行手册"的概念,其中,操作员可以结合定义良好的流程在给定的环境中执行预写的代码块或数据库查询. - -## Executable Runbooks[](#executable-runbooks "Permalink") - -在 GitLab 11.4 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/45912) . - -通过 GitLab 的 Kubernetes 集成提供的 JupyterHub 应用程序现在随 Nurtch 的 Rubix 库一起提供,提供了一种创建 DevOps Runbook 的简单方法. 提供了一个样本运行手册,其中展示了常见的操作. 虽然 Rubix 使创建常见的 Kubernetes 和 AWS 工作流变得简单,但是您也可以不使用 Rubix 手动创建它们. - -观看此[视频](https://www.youtube.com/watch?v=Q_OqHIIUPjE) ,了解如何在 GitLab 中完成此操作! - -## Requirements[](#requirements "Permalink") - -要创建可执行的运行本,您将需要: - -* **Kubernetes-**需要 Kubernetes 集群才能部署其余应用程序. 最简单的入门方法是使用[GitLab 的集成](../add_remove_clusters.html#create-new-cluster)之一添加集群. -* **入口** -入口可以提供负载平衡,SSL 终止和基于名称的虚拟主机. 它充当您的应用程序的 Web 代理. -* **JupyterHub** - [JupyterHub](https://jupyterhub.readthedocs.io/)是用于在团队中管理笔记本的多用户服务. Jupyter Notebook 提供了一个基于 Web 的交互式编程环境,用于数据分析,可视化和机器学习. - -## Nurtch[](#nurtch "Permalink") - -Nurtch 是[Rubix 库](https://github.com/Nurtch/rubix)背后的公司. Rubix 是一个开源 Python 库,可轻松在 Jupyter Notebooks 中执行常见的 DevOps 任务. 绘制 Cloudwatch 指标和滚动 ECS / Kubernetes 应用之类的任务将简化为几行代码. 有关更多信息,请参见[Nurtch 文档](http://docs.nurtch.com/en/latest/) . - -## Configure an executable runbook with GitLab[](#configure-an-executable-runbook-with-gitlab "Permalink") - -遵循此分步指南,使用上述组件和预加载的演示运行本在 GitLab 中配置可执行运行本. - -1. 遵循[创建新集群中](../add_remove_clusters.html#create-new-cluster)概述的步骤,将 Kubernetes 集群添加到您的项目中. - -2. 单击**Ingress**应用程序旁边的" **安装"**按钮以安装 Ingress. - - [![install ingress](img/5a2430ba8091036f8e9e3308aa845de8.png)](img/ingress-install.png) - -3. 成功安装 Ingress 后,单击**JupyterHub**应用程序旁边的" **安装"**按钮. **下一步,**您将需要此处提供的**Jupyter 主机名** . - - [![install JupyterHub](img/00fd9bca0c7bdc64f74a24b691e0adac.png)](img/jupyterhub-install.png) - -4. 成功安装**JupyterHub 后** ,在浏览器中打开**Jupyter 主机名** . 单击" **使用 GitLab 登录"**按钮登录到 JupyterHub 并启动服务器. 使用 OAuth2 为 GitLab 实例的任何用户启用身份验证. 此按钮将您重定向到 GitLab 上的页面,请求 JupyterHub 授权使用您的 GitLab 帐户. - - [![authorize Jupyter](img/9950340e3b641e3f63d70fb29b2b05bb.png)](img/authorize-jupyter.png) - -5. 单击**Authorize** ,您将被重定向到 JupyterHub 应用程序. -6. 单击" **启动我的服务器"** ,服务器将在几秒钟后启动. -7. 要配置 Runbook 对 GitLab 项目的访问,必须在演示 Runbook 的" **设置"**部分中输入您的[GitLab 访问令牌](../../../profile/personal_access_tokens.html)和项目 ID: - - 1. 双击左侧面板上的**DevOps-Runbook-Demo**文件夹. - - [![demo runbook](img/6809ef73be513357f41ebe6d325265d5.png)](img/demo-runbook.png) - - 2. 双击`Nurtch-DevOps-Demo.ipynb` . - - [![sample runbook](img/ae5a500e2333874603b33328b017eb35.png)](img/sample-runbook.png) - - Jupyter 在屏幕右侧显示 Runbook 的内容. **设置**部分显示您的`PRIVATE_TOKEN`和您的`PROJECT_ID` . 输入这些值,并保持单引号如下: - - ``` - PRIVATE_TOKEN = 'n671WNGecHugsdEDPsyo' - PROJECT_ID = '1234567' - ``` - - 3. Update the `VARIABLE_NAME` on the last line of this section to match the name of the variable you’re using for your access token. In this example, our variable name is `PRIVATE_TOKEN`. - - ``` - VARIABLE_VALUE = project.variables.get('PRIVATE_TOKEN').value - ``` - -8. 要配置运行手册的操作,请创建和配置变量: - - **注意:**对于此示例,我们使用示例**运行簿**中的**笔记本中**的**"运行 SQL 查询"**部分来查询 PostgreSQL 数据库. 以下代码块的前四行定义了此查询运行所需的变量: - - ``` - %env DB_USER={project.variables.get('DB_USER').value} - %env DB_PASSWORD={project.variables.get('DB_PASSWORD').value} - %env DB_ENDPOINT={project.variables.get('DB_ENDPOINT').value} - %env DB_NAME={project.variables.get('DB_NAME').value} - ``` - - 1. 导航 **设置»CI / CD»变量**以在项目中创建变量. - - [![GitLab variables](img/15b455cffa86c3a9234ad8c30082a4df.png)](img/gitlab-variables.png) - - 2. Click **保存变量**. - - 3. 在 Jupyter 中,单击**"笔记本"**标题中的**"运行 SQL 查询"** ,然后单击**"运行"** . 结果以内联方式显示如下: - - [![PostgreSQL query](img/1a1b871d7e874d4f8e2ab4905d000509.png)](img/postgres-query.png) - -您可以尝试其他操作,例如运行 Shell 脚本或与 Kubernetes 集群进行交互. 有关更多信息,请访问[Nurtch 文档](http://docs.nurtch.com/) . \ No newline at end of file diff --git a/_book/docs/030.md b/_book/docs/030.md deleted file mode 100644 index 84e2f128a8540c042191d922cfa21706a323ea2b..0000000000000000000000000000000000000000 --- a/_book/docs/030.md +++ /dev/null @@ -1,734 +0,0 @@ -# Serverless - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/serverless/](https://docs.gitlab.com/ee/user/project/clusters/serverless/) - -* [Overview](#overview) -* [Knative](#knative) -* [Prerequisites](#prerequisites) -* [Installing Knative via GitLab’s Kubernetes integration](#installing-knative-via-gitlabs-kubernetes-integration) -* [Using an existing installation of Knative](#using-an-existing-installation-of-knative) -* [Supported runtimes](#supported-runtimes) - * [GitLab-managed runtimes](#gitlab-managed-runtimes) - * [OpenFaaS runtimes](#openfaas-runtimes) -* [Deploying functions](#deploying-functions) - * [`service`](#service) - * [`provider`](#provider) - * [`functions`](#functions) - * [Deployment](#deployment) - * [Runtime aliases](#runtime-aliases) - * [Secrets](#secrets) - * [CLI example](#cli-example) - * [Part of deployment job](#part-of-deployment-job) - * [Running functions locally](#running-functions-locally) -* [Deploying Serverless applications](#deploying-serverless-applications) - * [Deploy the application with Knative](#deploy-the-application-with-knative) - * [Function details](#function-details) - * [Invocation metrics](#invocation-metrics) -* [Configuring logging](#configuring-logging) - * [Prerequisites](#prerequisites-1) - * [Enable request log template](#enable-request-log-template) - * [Enable request logs](#enable-request-logs) - * [Viewing request logs](#viewing-request-logs) -* [Enabling TLS for Knative services](#enabling-tls-for-knative-services) -* [Using an older version of `gitlabktl`](#using-an-older-version-of-gitlabktl) - -# Serverless[](#serverless "Permalink") - -在 GitLab 11.5 中引入. - -**警告:** Serverless 目前处于[alpha 状态](https://about.gitlab.com/handbook/product/#alpha) . - -## Overview[](#overview "Permalink") - -无服务器架构为运营商和开发人员提供了在不配置单个服务器的情况下编写高度可扩展的应用程序的能力. - -GitLab 支持在 Kubernetes 环境和主要的云 FAAS 环境中部署无服务器应用程序的几种方法. - -目前,我们支持: - -* [Knative](#knative) :在 GKE 和 EKS 上使用 Knative 和`gitlabktl`构建 Knative 应用程序. -* [AWS Lambda](aws.html) :通过无服务器框架和 GitLab CI / CD 创建无服务器应用程序. - -## Knative[](#knative "Permalink") - -使用[Knative](https://cloud.google.com/knative/)在 Kubernetes 上运行无服务器工作负载. - -Knative 扩展了 Kubernetes 以提供一组中间件组件,这些组件对于构建现代的,以源为中心的,基于容器的应用程序很有用. Knative 通过其主要组件带来了一些明显的好处: - -* [服务](https://github.com/knative/serving) :请求驱动的计算,可扩展为零. -* [事件](https://github.com/knative/eventing) : [事件的](https://github.com/knative/eventing)管理和交付. - -有关 Knative 的更多信息,请访问[Knative docs 资源库](https://github.com/knative/docs) . - -借助 GitLab Serverless,您可以部署功能即服务(FaaS)和无服务器应用程序. - -## Prerequisites[](#prerequisites "Permalink") - -要在 GitLab 上运行 Knative,您需要: - -1. **现有的 GitLab 项目:**您将需要一个 GitLab 项目来关联所有资源. 最简单的入门方法: - * 如果您打算[部署功能](#deploying-functions) ,请克隆[功能示例项目](https://gitlab.com/knative-examples/functions)以开始使用. - * 如果您打算[部署无服务器应用程序](#deploying-serverless-applications) ,请克隆示例[Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app)以开始使用. -2. **Kubernetes 集群:**部署 Knative 需要启用 RBAC 的 Kubernetes 集群. 最简单的入门方法是使用 GitLab 的[GKE 集成](../add_remove_clusters.html)添加集群. 建议的运行 Knative 的最低建议群集规格为 3 个节点,6 个 vCPU 和 22.50 GB 内存. -3. **GitLab 运行程序:**运行 CI 作业需要运行程序,该作业会将无服务器的应用程序或功能部署到您的集群上. 您可以将 GitLab Runner 安装到现有的 Kubernetes 集群上. 有关更多信息,请参见[安装应用程序](../index.html#installing-applications) . -4. **域名:** Knative 将使用 Istio 提供自己的负载平衡器. 它将为 Knative 服务的所有应用程序提供一个外部 IP 地址或主机名. 系统将提示您输入一个通配符域,将在其中提供您的应用程序. 配置您的 DNS 服务器以使用该域的外部 IP 地址或主机名. -5. **`.gitlab-ci.yml` :** GitLab 使用[Kaniko](https://github.com/GoogleContainerTools/kaniko)来构建应用程序. 我们还使用[GitLab Knative 工具](https://gitlab.com/gitlab-org/gitlabktl) CLI 来简化向 Knative 部署服务和功能. -6. **`serverless.yml`** ( [仅](#deploying-functions)适用于[功能](#deploying-functions) ):使用 lessserver 部署功能时, `serverless.yml`文件将包含存储库中托管的所有功能的信息以及所使用的运行时的引用. -7. **`Dockerfile`** ( [仅](#deploying-serverless-applications)适用于[应用程序](#deploying-serverless-applications) ):Knative 需要`Dockerfile`才能构建您的应用程序. 它应该包含在项目存储库的根目录中,并公开端口`8080` . 如果您打算使用我们的[运行时](https://gitlab.com/gitlab-org/serverless/runtimes)来构建无服务器功能,则不需要`Dockerfile` . -8. **Prometheus** (可选):安装 Prometheus 可使您监视无服务器功能/应用程序的规模和流量. 有关更多信息,请参见[安装应用程序](../index.html#installing-applications) . -9. **日志记录** (可选):配置日志记录可让您查看和搜索无服务器功能/应用程序的请求日志. 有关更多信息,请参见[配置日志记录](#configuring-logging) . - -## Installing Knative via GitLab’s Kubernetes integration[](#installing-knative-via-gitlabs-kubernetes-integration "Permalink") - -**注意:**运行 Knative 的最小建议群集大小是 3 节点,6 vCPU 和 22.50 GB 内存. **必须启用 RBAC.** - -1. [Add a Kubernetes cluster](../add_remove_clusters.html). -2. 选择" **应用程序"**选项卡,然后向下滚动到" Knative 应用程序"部分. 输入要用于您的应用程序/功能的域(例如`example.com` ),然后单击**Install** . - - [![install-knative](img/a93d26d68bbc1f4954a7038e601ba3b6.png)](img/install-knative.png) - -3. Knative 安装完成后,您可以等待 IP 地址或主机名显示在**Knative Endpoint**字段中,或[手动检索 Istio Ingress 端点](../../../clusters/applications.html#determining-the-external-endpoint-manually) . - - **注意:**在集群上运行`kubectl`命令需要首先设置对集群的访问. 对于在 GKE 上创建的集群,请参见[GKE 集群访问](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl) ,对于其他平台,请[安装 kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) . -4. 入口现在在此地址可用,并将基于请求中的 DNS 名称将传入请求路由到适当的服务. 为此,应为所需的域名创建通配符 DNS 记录. 例如,如果您的 Knative 基础域是`knative.info`则需要创建一个 A 记录或 CNAME 记录,其域`*.knative.info`指向 Ingress 的 IP 地址或主机名. - - [![DNS entry](img/e7acd74bc1dc7f0103e1b107aac74f84.png)](img/dns-entry.png) - -**注意:**可以在给定项目上部署[功能](#deploying-functions)或[无服务器应用程序](#deploying-serverless-applications) ,但不能两者都部署. 当前实现利用了的`serverless.yml`文件发信号 FAAS 项目. - -## Using an existing installation of Knative[](#using-an-existing-installation-of-knative "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/58941) in GitLab 12.0. - -**注意:**添加现有的 Knative 安装时,GitLabless server 的"调用"监视功能将不起作用. - -也可以将 GitLab Serverless 与已经安装 Knative 的现有 Kubernetes 集群一起使用. - -您必须执行以下操作: - -1. 按照步骤[添加现有的 Kubernetes 集群](../add_remove_clusters.html#add-existing-cluster) . - -2. 确保 GitLab 可以管理 Knative: - * 对于非 GitLab 托管群集,请确保提供的令牌的服务帐户可以管理`serving.knative.dev` API 组中的资源. - * 对于 GitLab 托管群集,如果您在[GitLab 12.1 或更高版本中](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30235)添加了群集,则 GitLab 将已经具有所需的访问权限,您可以继续进行下一步. - - 否则,您需要手动授权 GitLab 的服务帐户具有管理`serving.knative.dev` API 组中资源的能力. 由于每个 GitLab 服务帐户都具有`edit`集群角色,因此最简单的方法是通过将默认规则添加到默认`edit`集群角色的[聚合 ClusterRole](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles) :首先,将以下 YAML 保存为`knative-serving-only-role.yaml` : - - ``` - apiVersion : rbac.authorization.k8s.io/v1 kind : ClusterRole metadata : name : knative-serving-only-role labels : rbac.authorization.k8s.io/aggregate-to-edit : " true" rules : - apiGroups : - serving.knative.dev resources : - configurations - configurationgenerations - routes - revisions - revisionuids - autoscalers - services verbs : - get - list - create - update - delete - patch - watch - ``` - - 然后运行以下命令: - - ``` - kubectl apply -f knative-serving-only-role.yaml - ``` - - 如果您希望基于每个服务帐户授予权限,则可以使用特定于服务帐户和名称空间的`Role`和`RoleBinding`来执行此操作. - -3. 请按照以下步骤将[功能](#deploying-functions)或[无服务器应用程序](#deploying-serverless-applications)部署到群集上. - -## Supported runtimes[](#supported-runtimes "Permalink") - -GitLab 的无服务器功能可以使用以下命令运行: - -* [GitLab-managed](#gitlab-managed-runtimes) runtimes. -* [OpenFaaS](#openfaas-runtimes) runtimes. - -如果所需的编程语言无法使用运行时,请考虑部署[无服务器应用程序](#deploying-serverless-applications) . - -### GitLab-managed runtimes[](#gitlab-managed-runtimes "Permalink") - -当前,以下 GitLab 管理的[运行时](https://gitlab.com/gitlab-org/serverless/runtimes)可用: - -* `go` (概念证明) -* `nodejs` -* `ruby` - -如果未指定运行时,则必须提供一个`Dockerfile`来运行无服务器功能. - -### OpenFaaS runtimes[](#openfaas-runtimes "Permalink") - -在 GitLab 12.5 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/29253) . - -[OpenFaaS 经典运行时](https://github.com/openfaas/templates#templates-in-store)可与 GitLab 无服务器一起使用. - -OpenFaas 运行时可用于以下语言: - -* C# -* Go -* NodeJS -* PHP -* Python -* Ruby - -使用以下模式指定运行时: `openfaas/classic/` . 下面的示例示出了如何定义一个函数`serverless.yml`使用 OpenFaaS 运行时: - -``` -hello: - source: ./hello - runtime: openfaas/classic/ruby - description: "Ruby function using OpenFaaS classic runtime" -``` - -`handler` is not needed for OpenFaaS functions. The location of the handler is defined by the conventions of the runtime. - -有关使用 OpenFaaS 运行时的函数示例,请参见[`ruby-openfaas-function`](https://gitlab.com/knative-examples/ruby-openfaas-function)项目. - -## Deploying functions[](#deploying-functions "Permalink") - -在 GitLab 11.6 中引入. - -您可以在**[功能示例项目中](https://gitlab.com/knative-examples/functions)**找到并导入此文档中引用的所有文件. - -请按照以下步骤将使用 Node.js 运行时的功能部署到您的 Knative 实例(如果您已克隆示例项目,则可以跳过以下步骤): - -1. 创建一个目录来容纳该函数. 在此示例中,我们将在项目的根目录创建一个名为`echo`的目录. - -2. 创建将包含功能代码的文件. 在此示例中,我们的文件名为`echo.js` ,位于`echo`目录中. 如果您的项目是: - * 公开,继续下一步. - * 私有的,您将需要使用`gitlab-deploy-token`作为名称和`read_registry`范围[创建一个 GitLab 部署令牌](../../deploy_tokens/index.html#creating-a-deploy-token) . -3. `.gitlab-ci.yml` :这定义了用于部署功能的管道. 它必须包含在存储库的根目录中: - - ``` - include: - - template: Serverless.gitlab-ci.yml - - functions:build: - extends: .serverless:build:functions - environment: production - - functions:deploy: - extends: .serverless:deploy:functions - environment: production - ``` - - 这个`.gitlab-ci.yml`创建的作业会调用一些预定义的命令来构建功能并将其部署到集群中. - - `Serverless.gitlab-ci.yml` is a template that allows customization. You can either import it with `include` parameter and use `extends` to customize your jobs, or you can inline the entire template by choosing it from **套用范本** dropdown when editing the `.gitlab-ci.yml` file through the user interface. - -4. `serverless.yml` :此文件包含您的功能的元数据,例如名称,运行时和环境. - - 它必须包含在存储库的根目录中. 下面是一个示例`echo`函数,它显示了文件所需的结构. - - 您可以在[功能示例项目中](https://gitlab.com/knative-examples/functions)找到该项目的相关文件. - - ``` - service: functions - description: "GitLab Serverless functions using Knative" - - provider: - name: triggermesh - envs: - FOO: value - secrets: - - my-secrets - - functions: - echo-js: - handler: echo-js - source: ./echo-js - runtime: gitlab/runtimes/nodejs - description: "node.js runtime function" - envs: - MY_FUNCTION: echo-js - secrets: - - my-secrets - ``` - -上面使用的字段的说明: - -### `service`[](#service "Permalink") - -| Parameter | Description | -| --- | --- | -| `service` | 服务该功能的 Knative 服务的名称. | -| `description` | 在的简短描述`service` . | - -### `provider`[](#provider "Permalink") - -| Parameter | Description | -| --- | --- | -| `name` | 指示使用哪个提供程序来执行`serverless.yml`文件. 在这种情况下,使用 TriggerMesh 中间件. | -| `envs` | 包括要在文件中**所有**函数的函数执行过程中传递的环境变量,其中`FOO`是变量名, `BAR`是变量内容. 您可以将其替换为自己的变量. | -| `secrets` | 包含 Kubernetes 机密的内容作为环境变量,可访问该变量作为文件中**所有**函数的函数执行的一部分进行传递. 机密应采用 INI 格式. | - -### `functions`[](#functions "Permalink") - -在上面的`serverless.yml`示例中,函数名称为`echo` ,随后的行包含函数属性. - -| Parameter | Description | -| --- | --- | -| `handler` | 函数的名称. | -| `source` | 具有功能源的目录. | -| `runtime` (optional) | 用于执行功能的运行时. 这可以是运行时别名(请参阅[运行时别名](#runtime-aliases) ),也可以是自定义运行时存储库的完整 URL. 当未指定运行`Dockerfile` ,我们假定`Dockerfile`存在于`source`指定的函数目录中. | -| `description` | 功能的简短描述. | -| `envs` | 仅为特定功能设置环境变量. | -| `secrets` | 将 Kubernetes 机密的内容作为环境变量包含在内,这些变量只能作为特定函数的函数执行的一部分进行传递. 机密应采用 INI 格式. | - -### Deployment[](#deployment "Permalink") - -#### Runtime aliases[](#runtime-aliases "Permalink") - -可选的`runtime`参数可以引用以下运行时别名之一(另请参阅[受支持的运行时](#supported-runtimes) ): - -| 运行时别名 | 维护者 | -| --- | --- | -| `gitlab/runtimes/go` | GitLab | -| `gitlab/runtimes/nodejs` | GitLab | -| `gitlab/runtimes/ruby` | GitLab | -| `openfaas/classic/csharp` | OpenFaaS | -| `openfaas/classic/go` | OpenFaaS | -| `openfaas/classic/node` | OpenFaaS | -| `openfaas/classic/php7` | OpenFaaS | -| `openfaas/classic/python` | OpenFaaS | -| `openfaas/classic/python3` | OpenFaaS | -| `openfaas/classic/ruby` | OpenFaaS | - -经过`gitlab-ci.yml`模板已添加和`serverless.yml`文件被创建,推动提交到您的项目将导致 CI 管道被执行,而部署的每个功能的 Knative 服务. 部署阶段完成后,该功能的其他详细信息将显示在" **操作">"无服务器"下** . - -[![serverless page](img/e8c78799e0967a32ee1efeaea30f6213.png)](img/serverless-page.png) - -该页面包含可用于项目的所有功能,访问功能的描述以及(如果有)功能的运行时信息. 详细信息来自于项目的每个 Kubernetes 集群中的 Knative 安装. 单击每个功能以获得详细的规模和调用数据. - -可以从集群上的 Knative 直接检索函数详细信息: - -``` -kubectl -n "$KUBE_NAMESPACE" get services.serving.knative.dev -``` - -现在可以使用任何简单的`POST`调用从任何 HTTP 客户端触发示例函数: - -1. 使用 curl(将最后一行的 URL 替换为应用程序的 URL): - - ``` - curl \ - --header "Content-Type: application/json" \ - --request POST \ - --data '{"GitLab":"FaaS"}' \ - http://functions-echo.functions-1.functions.example.com/ - ``` - -2. 使用基于 Web 的工具(例如 Postman 或 Restlet) - - [![function execution](img/676537e7ead1101c5c0668a2adbc08d5.png)](img/function-execution.png) - -### Secrets[](#secrets "Permalink") - -要从函数内部访问 Kubernetes 机密,应在无服务器部署的名称空间下创建该机密,并在上述`serverless.yml`文件中指定这些机密. 您可以通过多种方式创建机密. 以下各节显示了一些示例. - -#### CLI example[](#cli-example "Permalink") - -``` -kubectl create secret generic my-secrets -n "$KUBE_NAMESPACE" --from-literal MY_SECRET=imverysecure -``` - -#### Part of deployment job[](#part-of-deployment-job "Permalink") - -您可以扩展`.gitlab-ci.yml`以在部署期间使用安全存储在 GitLab 项目下的[环境变量](../../../../ci/variables/README.html)来创建秘密. - -``` -deploy:function: - stage: deploy - environment: production - extends: .serverless:deploy:functions - before_script: - - kubectl create secret generic my-secret - --from-literal MY_SECRET="$GITLAB_SECRET_VARIABLE" - --namespace "$KUBE_NAMESPACE" - --dry-run -o yaml | kubectl apply -f - -``` - -### Running functions locally[](#running-functions-locally "Permalink") - -在本地运行功能是在开发过程中快速验证行为的好方法. - -在本地运行功能需要: - -* 转到 1.12 或更高版本. -* Docker Engine 已安装并正在运行. -* 使用 Go 软件包管理器安装的`gitlabktl` : - - ``` - GO111MODULE=on go get gitlab.com/gitlab-org/gitlabktl - ``` - -要在本地运行功能: - -1. 导航到您的 GitLab 无服务器项目的根目录. -2. 将功能构建到 Docker 映像中: - - ``` - gitlabktl serverless build - ``` - -3. 在 Docker 中运行您的函数: - - ``` - docker run -itp 8080:8080 - ``` - -4. 调用您的功能: - - ``` - curl http://localhost:8080 - ``` - -## Deploying Serverless applications[](#deploying-serverless-applications "Permalink") - -在 GitLab 11.5 中引入. - -无服务器应用程序是[无服务器功能](#deploying-functions)的替代[方法](#deploying-functions) . 它们在现有运行时不能满足应用程序需求的情况下很有用,例如以一种没有可用运行时的语言编写的应用程序. 请注意,尽管无服务器应用程序应该是无状态的! - -**注意:**您可以参考并导入示例[Knative Ruby 应用程序](https://gitlab.com/knative-examples/knative-ruby-app)以开始使用. - -将以下`.gitlab-ci.yml`添加到存储库的根目录中(如果您先前已经克隆了上述示例[Knative Ruby App,](https://gitlab.com/knative-examples/knative-ruby-app)则可以跳过此步骤): - -``` -include: - - template: Serverless.gitlab-ci.yml - -build: - extends: .serverless:build:image - -deploy: - extends: .serverless:deploy:image -``` - -`Serverless.gitlab-ci.yml`是允许自定义的模板. 您可以使用`include`参数导入它,并使用`extends`来自定义作业,或者可以通过在通过用户界面编辑`.gitlab-ci.yml`文件时从**Apply a template**下拉列表中选择它来内联整个模板. - -部署无服务器应用程序时,不需要`serverless.yml`文件. - -### Deploy the application with Knative[](#deploy-the-application-with-knative "Permalink") - -一切就绪后,下次运行 CI 管道时,将部署 Knative 应用程序. 导航到**CI / CD>管道** ,然后单击最新的管道. - -### Function details[](#function-details "Permalink") - -转到**操作>无服务器**页面以查看功能的最终 URL. - -[![function_details](img/4e0797b4100df465293bf0c8f24a097b.png)](img/function-list_v12_7.png) - -### Invocation metrics[](#invocation-metrics "Permalink") - -On the same page as above, click on one of the function rows to bring up the function details page. - -[![function_details](img/a0ea9fb503066a9bed377bc4dadb0d59.png)](img/function-details-loaded.png) - -容器数将为您提供在给定集群上运行无服务器功能实例的容器数. - -为了显示 Knative 函数调用, [必须安装 Prometheus](../index.html#installing-applications) . - -一旦安装了 Prometheus,可能会出现一条消息,指示度量标准数据*正在加载或当前不可用.* 它会在首次访问该页面时显示,但应在几秒钟后消失. 如果该消息没有消失,则可能是 GitLab 无法连接到集群上运行的 Prometheus 实例. - -## Configuring logging[](#configuring-logging "Permalink") - -在 GitLab 12.5 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/33330) . - -### Prerequisites[](#prerequisites-1 "Permalink") - -* 由 GitLab 管理的集群. -* `kubectl`已安装并正在运行. - -在集群上运行`kubectl`命令需要首先设置对集群的访问权限. 对于在以下位置创建的集群: - -* GKE,请参阅[GKE 群集访问](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl) -* 其他平台,请参阅[安装和设置 kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) . - -### Enable request log template[](#enable-request-log-template "Permalink") - -运行以下命令以启用请求日志: - -``` -kubectl edit cm -n knative-serving config-observability -``` - -将`logging.request-log-template`从`data._example`字段复制到层次结构中上一层的数据字段. - -### Enable request logs[](#enable-request-logs "Permalink") - -运行以下命令以将 Elasticsearch,Kibana 和 Filebeat 安装到`kube-logging`命名空间中,并配置所有节点以使用 Filebeat 转发日志: - -``` -kubectl apply -f https://gitlab.com/gitlab-org/serverless/configurations/knative/raw/v0.7.0/kube-logging-filebeat.yaml -kubectl label nodes --all beta.kubernetes.io/filebeat-ready="true" -``` - -### Viewing request logs[](#viewing-request-logs "Permalink") - -要查看请求日志: - -1. Run `kubectl proxy`. -2. 导航到[Kibana UI](http://localhost:8001/api/v1/namespaces/kube-logging/services/kibana/proxy/app/kibana) . - -Or: - -1. 打开[Kibana UI](http://localhost:8001/api/v1/namespaces/kube-logging/services/kibana/proxy/app/kibana) . -2. 单击" **发现"** ,然后从左侧的下拉列表中选择`filebeat-*` . -3. 在搜索框中输入`kubernetes.container.name:"queue-proxy" AND message:/httpRequest/` . - -## Enabling TLS for Knative services[](#enabling-tls-for-knative-services "Permalink") - -默认情况下,将通过`http`提供 GitLab 无服务器部署. 为了通过`https`提供服务,您必须手动获取并安装 TLS 证书. - -完成此操作的最简单方法是使用[Certbot 手动获取 Let's Encrypt 证书](https://knative.dev/docs/serving/using-a-tls-cert/#using-certbot-to-manually-obtain-let-s-encrypt-certificates) . Certbot 是一个免费的开源软件工具,可用于在手动管理的网站上自动使用 Let's Encrypt 证书来启用 HTTPS. - -**注意:**以下说明与在安装了 Python 3 且不能在其他操作系统或其他版本的 Python 上运行的 Linux 服务器上安装和运行 Certbot 有关. - -1. 通过运行[`certbot-auto` wrapper 脚本](https://certbot.eff.org/docs/install.html#certbot-auto)安装 Certbot. 在服务器的命令行上,运行以下命令: - - ``` - wget https://dl.eff.org/certbot-auto - sudo mv certbot-auto /usr/local/bin/certbot-auto - sudo chown root /usr/local/bin/certbot-auto - sudo chmod 0755 /usr/local/bin/certbot-auto - /usr/local/bin/certbot-auto --help - ``` - - 要检查`certbot-auto`脚本的完整性,请运行: - - ``` - wget -N https://dl.eff.org/certbot-auto.asc - gpg2 --keyserver ipv4.pool.sks-keyservers.net --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2 - gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc /usr/local/bin/certbot-auto - ``` - - The output of the last command should look something like: - - ``` - gpg: Signature made Mon 10 Jun 2019 06:24:40 PM EDT - gpg: using RSA key A2CFB51FA275A7286234E7B24D17C995CD9775F2 - gpg: key 4D17C995CD9775F2 marked as ultimately trusted - gpg: checking the trustdb - gpg: marginals needed: 3 completes needed: 1 trust model: pgp - gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u - gpg: next trustdb check due at 2027-11-22 - gpg: Good signature from "Let's Encrypt Client Team " [ultimate] - ``` - -2. 运行以下命令以使用 Certbot 在授权过程中使用 DNS 质询来请求证书: - - ``` - /usr/local/bin/certbot-auto certonly --manual --preferred-challenges dns -d '*..example.com' - ``` - - 其中``是 GitLab 为您的无服务器项目创建的名称空间(由`--` ),而`example.com`是用于项目的域. 如果不确定项目的名称空间是什么,请导航至项目的" **操作">"无服务器"**页面,然后检查为功能/应用程序提供的端点. - - [![function_endpoint](img/70c613da170fdfd7665282f16becad56.png)](img/function-endpoint.png) - - 在上图中,项目的名称空间为`node-function-11909507` ,域为`knative.info` ,因此证书申请行如下所示: - - ``` - ./certbot-auto certonly --manual --preferred-challenges dns -d '*.node-function-11909507.knative.info' - ``` - - Certbot 工具将引导您完成通过在这些域中创建 TXT 记录来验证您拥有的每个域的步骤. 此过程完成后,输出应如下所示: - - ``` - IMPORTANT NOTES: - - Congratulations! Your certificate and chain have been saved at: - /etc/letsencrypt/live/namespace.example.com/fullchain.pem - Your key file has been saved at: - /etc/letsencrypt/live/namespace.example/privkey.pem - Your cert will expire on 2019-09-19\. To obtain a new or tweaked - version of this certificate in the future, simply run certbot-auto - again. To non-interactively renew *all* of your certificates, run - "certbot-auto renew" - -----BEGIN PRIVATE KEY----- - - Your account credentials have been saved in your Certbot - configuration directory at /etc/letsencrypt. You should make a - secure backup of this folder now. This configuration directory will - also contain certificates and private keys obtained by Certbot so - making regular backups of this folder is ideal. - ``` - -3. 创建证书和私钥文件. 使用 Certbot 返回的文件的内容,我们将创建两个文件以创建 Kubernetes 机密: - - 运行以下命令以查看`fullchain.pem`的内容: - - ``` - sudo cat /etc/letsencrypt/live/node-function-11909507.knative.info/fullchain.pem - ``` - - 输出应如下所示: - - ``` - -----BEGIN CERTIFICATE----- - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b4ag== - -----END CERTIFICATE----- - -----BEGIN CERTIFICATE----- - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - K2fcb195768c39e9a94cec2c2e30Qg== - -----END CERTIFICATE----- - ``` - - 创建一个名称为`cert.pem`的文件,其中包含整个输出的内容. - - 创建`cert.pem` ,运行以下命令以查看`privkey.pem`的内容: - - ``` - sudo cat /etc/letsencrypt/live/namespace.example/privkey.pem - ``` - - 输出应如下所示: - - ``` - -----BEGIN PRIVATE KEY----- - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - -----BEGIN CERTIFICATE----- - fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 4f294d1eaca42b8692017b4262== - -----END PRIVATE KEY----- - ``` - - 使用整个输出的内容创建一个名称为`cert.pk`的新文件. - -4. 创建一个 Kubernetes 机密以保存您的 TLS 证书`cert.pem`和私钥`cert.pk` : - - **注意:**在集群上运行`kubectl`命令需要首先设置对集群的访问. 对于在 GKE 上创建的集群,请参阅[GKE 集群访问](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl) . 对于其他平台, [请安装`kubectl`](https://kubernetes.io/docs/tasks/tools/install-kubectl/) . - - ``` - kubectl create --namespace istio-system secret tls istio-ingressgateway-certs \ - --key cert.pk \ - --cert cert.pem - ``` - - 其中`cert.pem`和`cert.pk`是您的证书和私钥文件. 请注意, `istio-ingressgateway-certs`秘密名称是必需的. - -5. 配置 Knative 以使用为 HTTPS 连接创建的新密码. 运行以下命令以编辑方式打开 Knative 共享`gateway` : - - ``` - kubectl edit gateway knative-ingress-gateway --namespace knative-serving - ``` - - 更新网关以包括以下 tls:部分和配置: - - ``` - tls: - mode: SIMPLE - privateKey: /etc/istio/ingressgateway-certs/tls.key - serverCertificate: /etc/istio/ingressgateway-certs/tls.crt - ``` - - Example: - - ``` - apiVersion: networking.istio.io/v1alpha3 - kind: Gateway - metadata: - # ... skipped ... - spec: - selector: - istio: ingressgateway - servers: - - hosts: - - "*" - port: - name: http - number: 80 - protocol: HTTP - - hosts: - - "*" - port: - name: https - number: 443 - protocol: HTTPS - tls: - mode: SIMPLE - privateKey: /etc/istio/ingressgateway-certs/tls.key - serverCertificate: /etc/istio/ingressgateway-certs/tls.crt - ``` - - After your changes are running on your Knative cluster, you can begin using the HTTPS protocol for secure access your deployed Knative services. In the event a mistake is made during this process and you need to update the cert, you will need to edit the gateway `knative-ingress-gateway` to switch back to `PASSTHROUGH` mode. Once corrections are made, edit the file again so the gateway will use the new certificates. - -## Using an older version of `gitlabktl`[](#using-an-older-version-of-gitlabktl "Permalink") - -在某些情况下,您想运行旧版本的`gitlabktl` . 这需要在`.gitlab-ci.yml`文件中设置较旧版本的`gitlabktl`映像. - -要设置较旧的版本,请将`image:`添加到`functions:deploy`块中. 例如: - -``` -functions:deploy: - extends: .serverless:deploy:functions - environment: production - image: registry.gitlab.com/gitlab-org/gitlabktl:0.5.0 -``` - -通过更改注册表 URL 末尾的版本标签(格式为`registry.gitlab.com/gitlab-org/gitlabktl:`可以使用不同的版本. - -有关可用`gitlabktl`版本的完整清单,请参见`gitlabktl`项目的[容器注册表](https://gitlab.com/gitlab-org/gitlabktl/container_registry) . \ No newline at end of file diff --git a/_book/docs/031.md b/_book/docs/031.md deleted file mode 100644 index 79a6a450c6dc9236e4416d505f47aa430d2839ab..0000000000000000000000000000000000000000 --- a/_book/docs/031.md +++ /dev/null @@ -1,488 +0,0 @@ -# Deploying AWS Lambda function using GitLab CI/CD - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/serverless/aws.html](https://docs.gitlab.com/ee/user/project/clusters/serverless/aws.html) - -* [Serverless Framework](#serverless-framework) - * [Example](#example) - * [Steps](#steps) - * [Creating a Lambda handler function](#creating-a-lambda-handler-function) - * [Creating a `serverless.yml` file](#creating-a-serverlessyml-file) - * [Crafting the `.gitlab-ci.yml` file](#crafting-the-gitlab-ciyml-file) - * [Setting up your AWS credentials with your GitLab account](#setting-up-your-aws-credentials-with-your-gitlab-account) - * [Deploying your function](#deploying-your-function) - * [Manually testing your function](#manually-testing-your-function) - * [How To](#how-to) - * [Running function locally](#running-function-locally) - * [Secret variables](#secret-variables) - * [Setting up CORS](#setting-up-cors) - * [Writing automated tests](#writing-automated-tests) - * [Examples and template](#examples-and-template) -* [AWS Serverless Application Model](#aws-serverless-application-model) - * [Deploying AWS Lambda function using AWS SAM and GitLab CI/CD](#deploying-aws-lambda-function-using-aws-sam-and-gitlab-cicd) - * [Example](#example-1) - * [Steps](#steps-1) - * [Installing SAM CLI](#installing-sam-cli) - * [Creating an AWS SAM application using SAM CLI](#creating-an-aws-sam-application-using-sam-cli) - * [Setting up your AWS credentials with your GitLab account](#setting-up-your-aws-credentials-with-your-gitlab-account-1) - * [Crafting the `.gitlab-ci.yml` file](#crafting-the-gitlab-ciyml-file-1) - * [Deploying your application](#deploying-your-application) - * [Testing the deployed application](#testing-the-deployed-application) - * [Testing Locally](#testing-locally) - -# Deploying AWS Lambda function using GitLab CI/CD[](#deploying-aws-lambda-function-using-gitlab-cicd "Permalink") - -GitLab 允许用户轻松部署 AWS Lambda 函数并创建丰富的无服务器应用程序. - -GitLab 支持使用以下无服务器框架通过 GitLab CI / CD 部署 AWS Lambda 功能: - -* [Serverless Framework with AWS](#serverless-framework) -* [AWS’ Serverless Application Model (SAM)](#aws-serverless-application-model) - -## Serverless Framework[](#serverless-framework "Permalink") - -The [Serverless Framework can deploy to AWS](https://www.serverless.com/framework/docs/providers/aws/). - -我们准备了一个包含分步指南的示例,以创建一个简单功能并将其部署在 AWS 上. - -此外,在"操作方法["部分中](#how-to) ,您可以了解不同的用例,例如: - -* 在本地运行功能. -* 处理秘密. -* 设置 CORS. - -或者,您可以[使用 template](../../../../gitlab-basics/create-project.html#project-templates)快速[创建一个新项目](../../../../gitlab-basics/create-project.html#project-templates) . [`Serverless Framework/JS`模板](https://gitlab.com/gitlab-org/project-templates/serverless-framework/)已经包括下面描述的所有部分. - -### Example[](#example "Permalink") - -在以下示例中,您将: - -1. 创建一个基本的 AWS Lambda Node.js 函数. -2. 将该函数链接到 API Gateway `GET`端点. - -#### Steps[](#steps "Permalink") - -该示例包括以下步骤: - -1. 创建 Lambda 处理函数. -2. 创建一个`serverless.yml`文件. -3. 制作`.gitlab-ci.yml`文件. -4. 使用 GitLab 账户设置 AWS 凭证. -5. 部署您的功能. -6. 测试已部署的功能. - -让我们一步一步来. - -#### Creating a Lambda handler function[](#creating-a-lambda-handler-function "Permalink") - -您的 Lambda 函数将是请求的主要处理程序. 在这种情况下,我们将创建一个非常简单的 Node.js `hello`函数: - -``` -'use strict'; - -module.exports.hello = async event => { - return { - statusCode: 200, - body: JSON.stringify( - { - message: 'Your function executed successfully!' - }, - null, - 2 - ), - }; -}; -``` - -将此代码放在文件`src/handler.js` . - -`src`是无服务器功能的标准位置,但是您可以根据需要进行自定义. - -在我们的例子中, `module.exports.hello`定义了`hello` ,这将在以后的引用处理器`serverless.yml` - -您可以在此处了解有关 AWS Lambda Node.js 函数处理程序及其所有各种选项的更多信息: [https](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html) : [//docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html) - -#### Creating a `serverless.yml` file[](#creating-a-serverlessyml-file "Permalink") - -在项目的根目录中,创建一个`serverless.yml`文件,其中将包含 Serverless Framework 的配置详细信息. - -将以下代码放入文件中: - -``` -service: gitlab-example -provider: - name: aws - runtime: nodejs10.x - -functions: - hello: - handler: src/handler.hello - events: - - http: GET hello -``` - -我们的函数包含一个处理程序和一个事件. - -处理程序定义将使用位于`src/handler.hello`的源代码提供 Lambda 函数. - -`events`声明将创建一个 AWS API Gateway `GET`终端节点,以接收外部请求并将其通过服务集成传递给 Lambda 函数. - -您可以阅读有关无服务器框架的[可用属性和其他配置可能性](https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/)的更多信息. - -#### Crafting the `.gitlab-ci.yml` file[](#crafting-the-gitlab-ciyml-file "Permalink") - -在项目根目录下的`.gitlab-ci.yml`文件中,放置以下代码: - -``` -image: node:latest - -stages: - - deploy - -production: - stage: deploy - before_script: - - npm config set prefix /usr/local - - npm install -g serverless - script: - - serverless deploy --stage production --verbose - environment: production -``` - -此示例代码执行以下操作: - -1. 对所有 GitLab CI / CD 版本使用`node:latest`映像 -2. The `deploy` stage: - * 安装无服务器框架. - * 使用上面定义的 AWS 凭证将无服务器功能部署到您的 AWS 账户. - -#### Setting up your AWS credentials with your GitLab account[](#setting-up-your-aws-credentials-with-your-gitlab-account "Permalink") - -为了与您的 AWS 账户进行交互,GitLab CI / CD 管道要求在您的 GitLab 设置中的**设置> CI / CD>变量**下定义`AWS_ACCESS_KEY_ID`和`AWS_SECRET_ACCESS_KEY` . 有关更多信息,请参见[在 UI 中创建自定义变量](../../../../ci/variables/README.html#create-a-custom-variable-in-the-ui) . - -**注意:**您提供的 AWS 凭证必须包括 IAM 策略,以提供对 AWS Lambda,API 网关,CloudFormation 和 IAM 资源的正确访问控制. - -#### Deploying your function[](#deploying-your-function "Permalink") - -`git push` the changes to your GitLab repository and the GitLab build pipeline will automatically deploy your function. - -在您的 GitLab 部署阶段日志中,将包含您的 AWS Lambda 端点 URL 的输出. 日志行将类似于以下内容: - -``` -endpoints: - GET - https://u768nzby1j.execute-api.us-east-1.amazonaws.com/production/hello -``` - -#### Manually testing your function[](#manually-testing-your-function "Permalink") - -运行以下`curl`命令将触发您的功能. - -**注意:**您的 URL 应该是从 GitLab 部署阶段日志中检索到的 URL. - -``` -curl https://u768nzby1j.execute-api.us-east-1.amazonaws.com/production/hello -``` - -那应该输出: - -``` -{ "message": "Your function executed successfully!" } -``` - -万岁! 现在,您已经通过 GitLab CI / CD 部署了 AWS Lambda 函数. - -干得好! - -### How To[](#how-to "Permalink") - -在本节中,我们向您展示如何在基本示例上构建以下内容: - -* 在本地运行该功能. -* 设置秘密变量. -* 设置 CORS. - -#### Running function locally[](#running-function-locally "Permalink") - -`serverless-offline`插件允许在本地运行代码. 要在本地运行代码: - -1. 将以下内容添加到您的`serverless.yml` : - - ``` - plugins: - - serverless-offline - ``` - -2. 通过运行以下命令来启动服务: - - ``` - serverless offline - ``` - -运行以下`curl`命令将触发您的功能. - -``` -curl http://localhost:3000/hello -``` - -它应该输出: - -``` -{ "message": "Your function executed successfully!" } -``` - -#### Secret variables[](#secret-variables "Permalink") - -Secrets are injected into your functions using environment variables. - -通过在`serverless.yml`的 provider 部分中定义变量,可以将它们添加到已部署函数的环境中: - -``` -provider: - ... - environment: - A_VARIABLE: ${env:A_VARIABLE} -``` - -从那里,您也可以在函数中引用它们. 请记住,在**设置> CI / CD>**变量下,将`A_VARIABLE`添加到您的 GitLab CI / CD 变量中,它将随您的函数一起被拾取和部署. - -**注意:**有权访问 AWS 环境的任何人都可以查看 lambda 定义中保留的那些变量的值. - -#### Setting up CORS[](#setting-up-cors "Permalink") - -如果您想要建立一个调用函数的网页,就像我们在[模板中](https://gitlab.com/gitlab-org/project-templates/serverless-framework/)所做的那样,则需要处理跨域资源共享(CORS). - -快速的方法来做到这一点是添加`cors: true`标志的 HTTP 端点在你`serverless.yml` : - -``` -functions: - hello: - handler: src/handler.hello - events: - - http: # Rewrite this part to enable CORS - path: hello - method: get - cors: true # <-- CORS here -``` - -您还需要在函数响应中返回 CORS 特定的标头: - -``` -'use strict'; - -module.exports.hello = async event => { - return { - statusCode: 200, - headers: { - // Uncomment the line below if you need access to cookies or authentication - // 'Access-Control-Allow-Credentials': true, - 'Access-Control-Allow-Origin': '*' - }, - body: JSON.stringify( - { - message: 'Your function executed successfully!' - }, - null, - 2 - ), - }; -}; -``` - -有关更多信息,请参阅由无服务器框架团队撰写的《 [您的 CORS 和 API 网关生存指南》](https://www.serverless.com/blog/cors-api-gateway-survival-guide/)博客文章. - -#### Writing automated tests[](#writing-automated-tests "Permalink") - -[无服务器框架](https://gitlab.com/gitlab-org/project-templates/serverless-framework/)示例项目展示了如何使用 Jest,Axios 和`serverless-offline`插件对本地和已部署的无服务器功能进行自动化测试. - -### Examples and template[](#examples-and-template "Permalink") - -示例代码可用: - -* 作为[可克隆的存储库](https://gitlab.com/gitlab-org/serverless/examples/serverless-framework-js) . -* 在带有[测试和秘密变量](https://gitlab.com/gitlab-org/project-templates/serverless-framework/)的版本中. - -您还可以在 GitLab UI 中使用[模板](../../../../gitlab-basics/create-project.html#project-templates) (基于带有测试和秘密变量的版本)(请参阅`Serverless Framework/JS`模板). - -## AWS Serverless Application Model[](#aws-serverless-application-model "Permalink") - -AWS 无服务器应用程序模型是用于构建无服务器应用程序的开源框架. 它使构建和部署无服务器应用程序变得更加容易. 有关更多详细信息,请参阅有关[AWS 无服务器应用程序模型的](https://docs.aws.amazon.com/serverless-application-model/) AWS 文档. - -### Deploying AWS Lambda function using AWS SAM and GitLab CI/CD[](#deploying-aws-lambda-function-using-aws-sam-and-gitlab-cicd "Permalink") - -GitLab 允许开发人员使用以下组合来构建和部署无服务器应用程序: - -* [AWS Serverless Application Model (AWS SAM)](https://aws.amazon.com/serverless/sam/). -* 亚搏体育 app CI / CD. - -### Example[](#example-1 "Permalink") - -在以下示例中,您将: - -* 安装 SAM CLI. -* 创建一个示例 SAM 应用程序,其中包括 Lambda 函数和 API 网关. -* 使用 GitLab CI / CD 将应用程序构建并部署到您的 AWS 账户. - -### Steps[](#steps-1 "Permalink") - -该示例包括以下步骤: - -1. 安装 SAM CLI. -2. 使用 SAM CLI 创建 AWS SAM 应用程序. -3. 制作`.gitlab-ci.yml`文件. -4. 使用 GitLab 账户设置 AWS 凭证. -5. 部署您的应用程序. -6. 测试已部署的功能. - -### Installing SAM CLI[](#installing-sam-cli "Permalink") - -AWS SAM 提供了一个称为 AWS SAM CLI 的 CLI,可简化创建和管理应用程序的过程. - -本文档中的某些步骤使用 SAM CLI. 请按照说明[安装 SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)来安装和配置 SAM CLI. - -如果您将[AWS Cloud9](https://aws.amazon.com/cloud9/)用作集成开发环境(IDE),则会为您安装以下软件: - -* [AWS Command Line Interface](https://docs.aws.amazon.com/en_pv/cli/latest/userguide/cli-chap-install.html) -* [SAM CLI](https://docs.aws.amazon.com/en_pv/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) -* [Docker](https://s0docs0docker0com.icopy.site/install/)和必要的 Docker 映像 - -### Creating an AWS SAM application using SAM CLI[](#creating-an-aws-sam-application-using-sam-cli "Permalink") - -要创建新的 AWS SAM 应用程序: - -1. 创建一个新的 GitLab 项目. -2. `git clone`将项目`git clone`到您的本地环境中. -3. 更改为新克隆的项目,并使用以下命令创建新的 SAM 应用程序: - - ``` - sam init -r python3.8 -n gitlabpoc --app-template "hello-world" - ``` - -4. `git push`应用程序`git push`回到 GitLab 项目. - -这将使用默认配置创建一个名为`gitlabpoc`的 SAM 应用程序,该配置是[Amazon API Gateway](https://aws.amazon.com/api-gateway/)端点调用的单个 Python 3.8 函数. 要查看 SAM 支持的其他运行时以及`sam init`选项,请运行: - -``` -sam init -h -``` - -### Setting up your AWS credentials with your GitLab account[](#setting-up-your-aws-credentials-with-your-gitlab-account-1 "Permalink") - -为了与您的 AWS 账户进行交互,GitLab CI / CD 管道要求在项目的 CI / CD 变量中同时设置`AWS_ACCESS_KEY_ID`和`AWS_SECRET_ACCESS_KEY` . - -设置这些: - -1. 导航到项目的 **设置> CI / CD** . -2. 展开**变量**部分,并为`AWS_ACCESS_KEY_ID`和`AWS_SECRET_ACCESS_KEY`创建条目. -3. 屏蔽凭据,以免使用"已**屏蔽"**切换将其显示在日志中. - -**注意:**您提供的 AWS 凭证必须包括 IAM 策略,以提供对 AWS Lambda,API 网关,CloudFormation 和 IAM 资源的正确访问控制. - -### Crafting the `.gitlab-ci.yml` file[](#crafting-the-gitlab-ciyml-file-1 "Permalink") - -在项目根目录中的[`.gitlab-ci.yml`](../../../../ci/yaml/README.html)文件中,添加以下内容,并将``替换为要在其中存储软件包的 S3 存储桶的名称: - -``` -image: python:latest - -stages: - - deploy - -production: - stage: deploy - before_script: - - pip3 install awscli --upgrade - - pip3 install aws-sam-cli --upgrade - script: - - sam build - - sam package --output-template-file packaged.yaml --s3-bucket - - sam deploy --template-file packaged.yaml --stack-name gitlabpoc --s3-bucket --capabilities CAPABILITY_IAM --region us-east-1 - environment: production -``` - -让我们更仔细地检查配置文件: - -* `image`指定用于此构建的 Docker 映像. 由于示例应用程序是用 Python 编写的,因此这是最新的 Python 图像. -* AWS CLI 和 AWS SAM CLI 安装在`before_script`部分中. -* SAM 构建,打包和部署命令用于构建,打包和部署应用程序. - -### Deploying your application[](#deploying-your-application "Permalink") - -Push changes to your GitLab repository and the GitLab build pipeline will automatically deploy your application. If your: - -* 构建和部署成功, [测试已部署的应用程序](#testing-the-deployed-application) . -* 生成失败,请查看生成日志以查看生成失败的原因. 构建可能会失败的一些常见原因是: - - * 不兼容的软件版本. 例如,Python 运行时版本可能与构建计算机上的 Python 不同. 通过安装所需的软件版本来解决此问题. - * 您可能无法从 GitLab 访问您的 AWS 账户. 检查您使用 AWS 凭证设置的环境变量. - * 您可能没有权限部署无服务器应用程序. 确保提供了部署无服务器应用程序所需的所有权限. - -### Testing the deployed application[](#testing-the-deployed-application "Permalink") - -要测试您部署的应用程序,请转到构建日志,然后执行以下步骤: - -1. 点击右上角的"显示完整的原始数据": - - [![sam-complete-raw](img/fd24d5842b589870b2063edaca149511.png)](img/sam-complete-raw.png) - -2. 查找 HelloWorldApi –与以下所示类似的 API 网关端点: - - [![sam-api-endpoint](img/5dd66b504685d06e7b88c8f8a71d39ba.png)](img/sam-api-endpoint.png) - -3. 使用 curl 测试 API. 例如: - - ``` - curl https://py4rg7qtlg.execute-api.us-east-1.amazonaws.com/Prod/hello/ - ``` - -输出应为: - -``` -{"message": "hello world"} -``` - -### Testing Locally[](#testing-locally "Permalink") - -AWS SAM 提供了在本地测试应用程序的功能. 您必须在本地安装 AWS SAM CLI,才能在本地进行测试. - -首先,测试功能. - -SAM 在`events/event.json`中提供一个默认事件,其中包括以下消息主体: - -``` -{\"message\": \"hello world\"} -``` - -如果您将该事件传递给`HelloWorldFunction` ,则它应该以相同的主体响应. - -通过运行以下命令来调用该函数: - -``` -sam local invoke HelloWorldFunction -e events/event.json -``` - -输出应为: - -``` -{"message": "hello world"} -``` - -确认 Lambda 函数按预期工作后,请按照以下步骤测试 API 网关. - -通过运行以下命令在本地启动 API: - -``` -sam local start-api -``` - -SAM 再次启动 Docker 容器,这一次是在`localhost:3000`上侦听的模拟 Amazon API Gateway. - -通过运行以下命令来调用`hello` API: - -``` -curl http://127.0.0.1:3000/hello -``` - -再次输出应为: - -``` -{"message": "hello world"} -``` \ No newline at end of file diff --git a/_book/docs/032.md b/_book/docs/032.md deleted file mode 100644 index 172ec4d47766aaccad586bd350b46920483bb91a..0000000000000000000000000000000000000000 --- a/_book/docs/032.md +++ /dev/null @@ -1,101 +0,0 @@ -# Securing your deployed applications - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/securing.html](https://docs.gitlab.com/ee/user/project/clusters/securing.html) - -* [Overview](#overview) - * [Requirements](#requirements) - * [Understanding how GitLab Managed Apps are installed](#understanding-how-gitlab-managed-apps-are-installed) -* [Connect the cluster to GitLab](#connect-the-cluster-to-gitlab) -* [Set up a GitLab Runner](#set-up-a-gitlab-runner) -* [Create a Cluster Management Project](#create-a-cluster-management-project) -* [Install GitLab Container Network Policy](#install-gitlab-container-network-policy) -* [Install GitLab Container Host Security](#install-gitlab-container-host-security) - -# Securing your deployed applications[](#securing-your-deployed-applications "Permalink") - -使用 GitLab 可以轻松保护在[连接的 Kubernetes 集群中](index.html)部署的应用程序的安全. 您可以从[Web 应用程序防火墙](../../../topics/web_application_firewall/quick_start_guide.html) , [网络策略](../../../topics/autodevops/stages.html#network-policy)甚至[容器主机安全性](../../clusters/applications.html#install-falco-using-gitlab-cicd)的保护中受益. - -无论您的应用程序是否通过 GitLab CI / CD 进行部署,此页面均包含将群集连接到 GitLab 并安装这些功能的完整的端到端步骤和说明. 如果您使用[Auto DevOps](../../../topics/autodevops/index.html)与 GitLab 一起构建和部署您的应用程序,请参见上面有关[GitLab 托管应用程序](../../clusters/applications.html)的文档. - -## Overview[](#overview "Permalink") - -在较高级别,所需步骤包括以下步骤: - -* 将集群连接到 GitLab. -* 设置一个或多个跑步者. -* 设置集群管理项目. -* 安装 Web 应用程序防火墙,网络策略和/或容器主机安全性. -* 安装 Prometheus,以在[威胁监视](../../application_security/threat_monitoring/)仪表板中获取统计信息和指标. - -### Requirements[](#requirements "Permalink") - -最低要求(取决于您要安装的 GitLab 管理应用程序): - -* 您的群集已连接到 GitLab(ModSecurity,Cilium 和 Falco). -* 至少安装了一个 GitLab Runner(仅限 Cilium 和 Falco). - -### Understanding how GitLab Managed Apps are installed[](#understanding-how-gitlab-managed-apps-are-installed "Permalink") - -**注意:**为简单起见,这些图使用术语*Kubernetes* . 实际上,Sidekiq 连接到在集群中的 Pod 中运行的 Helm Tiller 守护程序. - -您可以通过一键式安装过程从 GitLab Web 界面安装 GitLab 托管应用程序. GitLab 使用 Sidekiq(后台处理服务)来简化此过程. - -sequenceDiagram 自动编号 GitLab->> + Sidekiq:安装 GitLab 托管应用程序 Sidekiq->> + Kubernetes:Helm 安装 Kubernetes->>-Sidekiq:安装完成 Sidekiq->>-GitLab:刷新 UI - -尽管此安装方法比较容易,因为它是用户界面中的"点击"操作,但它不灵活且难以调试. 当出现问题时,您将看不到部署日志. Web 应用程序防火墙功能使用此安装方法. - -但是,下一代的 GitLab 托管应用程序 V2( [基于 CI / CD 的 GitLab 托管应用程序](https://gitlab.com/groups/gitlab-org/-/epics/2103) )不使用 Sidekiq 进行部署. 所有应用程序都使用 GitLab CI / CD 管道以及因此使用的 GitLab Runners 进行部署. - -sequenceDiagram 自动编号 GitLab->> + GitLab:触发管道 GitLab->> + Runner:运行部署作业 Runner->> + Kubernetes:Helm 安装 Kubernetes->>-Runner:安装完成 Runner->>-GitLab:报告工作状态和更新流程 - -调试更容易,因为您可以访问这些作业的原始日志(在失败的情况下,可以将 Helm Tiller 输出作为工件使用),并且灵活性要好得多. 由于这些部署仅在管道正在运行时触发(很可能在集群管理存储库中有新提交时才触发),因此每个操作都具有书面记录,并遵循经典的合并请求工作流程(批准,合并,部署). 网络模型(Cilium)托管的应用程序和容器主机安全性(Falco)都使用此模型进行部署. - -## Connect the cluster to GitLab[](#connect-the-cluster-to-gitlab "Permalink") - -要将 GitLab 托管应用程序部署到群集,必须首先[将群集添加](add_remove_clusters.html)到 GitLab. 然后从项目或组 Kubernetes 页面[安装](../../clusters/applications.html#installing-applications) Web 应用程序防火墙. - -请注意,您的项目不必通过 GitLab 托管或部署. 您可以独立于使用群集的应用程序来管理群集. - -## Set up a GitLab Runner[](#set-up-a-gitlab-runner "Permalink") - -要安装基于 CI / CD 的 GitLab 托管应用程序,必须在 GitLab 中运行使用 GitLab Runner 的管道. 您可以在上一步中添加的 Kubernetes 集群中[安装 GitLab 运行程序](../../clusters/applications.html#gitlab-runner) ,或者如果使用的是 GitLab.com,则可以使用 GitLab 提供的共享运行程序之一. - -将群集连接到 GitLab 并安装好 GitLab Runner 之后,您可以继续执行下一步,并开始安装 Cilium 和 Falco GitLab 托管应用程序以保护托管在此群集上的应用程序. - -## Create a Cluster Management Project[](#create-a-cluster-management-project "Permalink") - -[群集管理项目](../../clusters/management_project.html)是一个 GitLab 项目,其中包含一个`.gitlab-ci.yml`文件,用于将 GitLab 托管应用程序部署到您的群集中. 该项目使用 Kubernetes [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)特权运行所需的图表. - -该项目的创建与其他任何 GitLab 项目一样开始. 使用一个空项目,并在根目录下添加一个`gitlab-ci.yml`文件,其中包含以下模板: - -``` -include: - - template: Managed-Cluster-Applications.gitlab-ci.yml -``` - -要使该项目成为集群管理项目,请遵循以下[说明](../../clusters/management_project.html#selecting-a-cluster-management-project) . 即使您的应用程序未托管在 GitLab 上,也可以这样指定该项目. 在这种情况下,请创建一个新的空项目,您可以在其中选择新创建的集群管理项目. - -## Install GitLab Container Network Policy[](#install-gitlab-container-network-policy "Permalink") - -GitLab 容器网络策略基于[Cilium](https://cilium.io/) . 要安装 Cilium GitLab 托管应用程序,请将`.gitlab/managed-apps/config.yaml`文件添加到群集管理项目中: - -``` -# possible values are gke, eks or you can leave it blank -clusterType: gke - -cilium: - installed: true -``` - -您的应用程序不必由 GitLab 进行管理或部署即可利用此功能. [阅读](../../clusters/applications.html#install-cilium-using-gitlab-cicd)有关配置容器网络策略的[更多](../../clusters/applications.html#install-cilium-using-gitlab-cicd)信息. - -## Install GitLab Container Host Security[](#install-gitlab-container-host-security "Permalink") - -同样,您可以在`.gitlab/managed-apps/config.yaml`基于[Falco](https://falco.org/)安装 Container Host Security: - -``` -falco: - installed: true -``` - -[阅读](../../clusters/applications.html#install-falco-using-gitlab-cicd)有关配置容器主机安全性的[更多](../../clusters/applications.html#install-falco-using-gitlab-cicd)信息. \ No newline at end of file diff --git a/_book/docs/033.md b/_book/docs/033.md deleted file mode 100644 index 1d21fad79812ce8e6179ba1acb3cd4a78abd23e3..0000000000000000000000000000000000000000 --- a/_book/docs/033.md +++ /dev/null @@ -1,687 +0,0 @@ -# Groups - -> 原文:[https://docs.gitlab.com/ee/user/group/](https://docs.gitlab.com/ee/user/group/) - -* [Use cases](#use-cases) -* [Namespaces](#namespaces) -* [Issues and merge requests within a group](#issues-and-merge-requests-within-a-group) - * [Bulk editing issues and merge requests](#bulk-editing-issues-and-merge-requests) -* [Create a new group](#create-a-new-group) -* [Add users to a group](#add-users-to-a-group) -* [Request access to a group](#request-access-to-a-group) -* [Changing the owner of a group](#changing-the-owner-of-a-group) -* [Remove a member from the group](#remove-a-member-from-the-group) -* [Changing the default branch protection of a group](#changing-the-default-branch-protection-of-a-group) -* [Add projects to a group](#add-projects-to-a-group) - * [Default project-creation level](#default-project-creation-level) -* [View group details](#view-group-details) - * [Group activity analytics overview](#group-activity-analytics-overview) -* [View group activity](#view-group-activity) -* [Transfer projects into groups](#transfer-projects-into-groups) -* [Sharing a project with a group](#sharing-a-project-with-a-group) -* [Sharing a group with another group](#sharing-a-group-with-another-group) -* [Manage group memberships via LDAP](#manage-group-memberships-via-ldap) - * [Creating group links via CN](#creating-group-links-via-cn-starter-only) - * [Creating group links via filter](#creating-group-links-via-filter-premium-only) - * [Overriding user permissions](#overriding-user-permissions-starter-only) -* [Epics](#epics-ultimate) -* [Group Security Dashboard](#group-security-dashboard-ultimate) -* [Insights](#insights-ultimate) -* [Transferring groups](#transferring-groups) -* [Group settings](#group-settings) - * [General settings](#general-settings) - * [Changing a group’s path](#changing-a-groups-path) - * [Remove a group](#remove-a-group) - * [Restore a group](#restore-a-group-premium) - * [Enforce 2FA to group members](#enforce-2fa-to-group-members) - * [Share with group lock](#share-with-group-lock) - * [Member Lock](#member-lock-starter) - * [IP access restriction](#ip-access-restriction-premium) - * [Allowed domain restriction](#allowed-domain-restriction-premium) - * [Group file templates](#group-file-templates-premium) - * [Group-level project templates](#group-level-project-templates-premium) - * [Disabling email notifications](#disabling-email-notifications) - * [Disabling group mentions](#disabling-group-mentions) - * [Enabling delayed Project removal](#enabling-delayed-project-removal-premium) - * [Advanced settings](#advanced-settings) - * [Storage usage quota](#storage-usage-quota-starter) - * [Group push rules](#group-push-rules-starter) - * [Enabling the feature](#enabling-the-feature) - * [Maximum artifacts size](#maximum-artifacts-size-core-only) -* [User contribution analysis](#user-contribution-analysis-starter) -* [Issues analytics](#issues-analytics-premium) -* [Dependency Proxy](#dependency-proxy-premium) - -# Groups[](#groups "Permalink") - -使用 GitLab 组,您可以: - -* 将相关项目组装在一起. -* 授予成员一次访问多个项目的权限. - -有关 GitLab 组的视频介绍,请参见[GitLab 大学:存储库,项目和组](https://www.youtube.com/watch?v=4TWfh1aKHHw) . - -组也可以嵌套在[子组中](subgroups/index.html) . - -通过单击顶部导航中的**组>您的组**来找到您的组. - -[![GitLab Groups](img/53bcd8c2d2c69aceb7db6677802be6b1.png)](img/groups.png) - -[GitLab 11.1](https://about.gitlab.com/releases/2018/07/22/gitlab-11-1-released/#groups-dropdown-in-navigation)中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/36234)了顶部导航中的" **组"**下拉列表. - -" **组"**页面显示: - -* 选择**您的组**后, **您将**是**您**所属的所有组. -* 选中" **浏览公共组"**时的公共组列表. - -" **组"**页面上的每个组都列出了: - -* 它有多少个子组. -* 它包含多少个项目. -* 该组有多少个成员,不包括从父组继承的成员. -* 小组的知名度. -* 如果您具有足够的权限,则指向组设置的链接. -* 如果您是成员,则退出该组的链接. - -## Use cases[](#use-cases "Permalink") - -您可以出于多种原因创建组. 列举几个: - -* 通过在同一[名称空间](#namespaces)下组织相关项目并将成员添加到顶级组,可以以较少的步骤授予对多个项目和多个团队成员的访问权限. -* 通过创建小组并包括适当的成员,可以轻松地`@mention`所有团队中的问题并合并请求. - -例如,您可以为公司成员创建一个[组](subgroups/index.html) ,并为每个单独的团队创建一个[子](subgroups/index.html)组. 假设您创建了一个名为`company-team` ,并且在该组中为各个团队`backend-team` , `frontend-team`和`production-team`创建了子组. - -* 从问题开始新的实现时,请添加评论: *" `@company-team` ,让我们开始吧!* *`@company-team/backend-team`您很高兴!"* -* 当您的后端团队需要前端提供帮助时,他们会添加一条评论: *" `@company-team/frontend-team`您能在这里帮助我们吗?"* -* 前端团队完成实施后,他们会评论: *" `@company-team/backend-team` ,它已经完成!* *让我们将其运送到`@company-team/production-team` !* - -## Namespaces[](#namespaces "Permalink") - -在 GitLab 中,名称空间是用作用户名,组名或子组名的唯一名称. - -* `http://gitlab.example.com/username` -* `http://gitlab.example.com/groupname` -* `http://gitlab.example.com/groupname/subgroup_name` - -例如,考虑一个名为 Alex 的用户: - -1. Alex 在 GitLab.com 上使用用户名`alex`创建了一个帐户; 他们的个人资料将在`https://gitlab.example.com/alex`下访问 -2. Alex 为他们的团队创建了一个小组,小组名称为`alex-team` ; 该小组及其项目将在`https://gitlab.example.com/alex-team`下访问 -3. 亚历克斯(Alex)创建了一个亚历克斯小组( `alex-team`子`alex-team` ,其子小组名称为`marketing` ; 该子小组及其项目将在`https://gitlab.example.com/alex-team/marketing`下访问 - -通过这样做: - -* 任何团队成员都使用`@alex`提及 Alex -* 亚历克斯通过`@alex-team`提及了团队中的每个人 -* 亚历克斯只提及`@alex-team/marketing` - -## Issues and merge requests within a group[](#issues-and-merge-requests-within-a-group "Permalink") - -问题和合并请求是项目的一部分. 对于给定的组,您可以在单个列表视图中查看所有[问题](../project/issues/index.html#issues-list)并将该组中所有项目的[请求合并](../project/merge_requests/reviewing_and_managing_merge_requests.html#view-merge-requests-for-all-projects-in-a-group)在一起. - -### Bulk editing issues and merge requests[](#bulk-editing-issues-and-merge-requests "Permalink") - -有关详细信息,请参阅[批量编辑问题和合并请求](../group/bulk_editing/index.html) . - -## Create a new group[](#create-a-new-group "Permalink") - -> 有关不允许用作组名的单词列表,请参见[保留名称](../reserved_names.html) . - -要创建新组,请执行以下任一操作: - -* 在顶部菜单中,依次单击" **组"**和" **您的组"** ,然后单击绿色按钮" **新建组"** . - - [![new group from groups page](img/7e5039b0d8fb74c5ea813e354f23493e.png)](img/new_group_from_groups.png) - -* 或者,在顶部菜单中,展开`plus`号并选择**新建组** . - - [![new group from elsewhere](img/ee8ead7652026dd03a75e2551122350f.png)](img/new_group_from_other_pages.png) - -添加以下信息: - -[![new group information](img/ad2cdacdd36348cddf7d5c19d8940d5b.png)](img/create_new_group_info.png) - -1. **组名将**自动填充 URL. (可选)您可以更改它. 这是在组视图中显示的名称. 该名称只能包含: - * 字母数字字符 - * 下划线 - * 划线和点 - * 空间 -2. **组 URL**是将托管项目的名称空间. 该网址只能包含: - * 字母数字字符 - * 下划线 - * 破折号和点(不能以破折号开头或以点结尾) -3. (可选)您可以添加简短说明,以告诉其他人该组的内容. -4. (可选)为您的群组选择一个头像. -5. Choose the [visibility level](../../public_access/public_access.html). - -有关创建组的更多详细信息,请观看视频[GitLab 命名空间(用户,组和子组)](https://youtu.be/r0sJgjR2f5A) . - -## Add users to a group[](#add-users-to-a-group "Permalink") - -将多个项目放在一个组中的好处是,您可以通过一个操作就授予用户访问该组中所有项目的权限. - -通过导航到组的仪表板并单击**Members**将成员添加到组. - -[![add members to group](img/ece990045e1a7ae1237b5f2912a2df3e.png)](img/add_new_members.png) - -选择[权限级别](../permissions.html#permissions) ,然后添加新成员. 您还可以设置该用户的到期日期. 这是他们将不再有权访问您的网上论坛的日期. - -考虑一个有两个项目的小组: - -* 现在,在" **组成员"**页面上,可以将新用户添加到组中. -* 现在,由于该用户是该组的**开发人员**成员,因此他们自动获得**开发人员**对该组内**所有项目的**访问权限. - -要提高特定项目的现有用户的访问级别,请将其作为新成员再次添加到具有所需权限级别的项目中. - -## Request access to a group[](#request-access-to-a-group "Permalink") - -作为论坛所有者,您可以启用或禁用非会员请求访问您论坛的功能. 转到组设置,然后单击**允许用户请求访问权限** . - -作为用户,如果启用了该设置,则可以请求成为组的成员. 转到您要加入的组,然后单击屏幕右侧的" **请求访问**权"按钮. - -[![Request access button](img/aa2dd1694d7e1573bbd49200ed1ccb04.png)](img/request_access_button.png) - -请求访问后: - -* 通过电子邮件将多达十个群组所有者的通知通知您. 电子邮件将发送给最近活动的组所有者. -* 任何论坛所有者都可以在会员页面上批准或拒绝您的请求. - -[![Manage access requests](img/fd0991d7941fed77c4d82bd219ec713b.png)](img/access_requests_management.png) - -如果您在批准请求之前改变主意,只需单击" **撤回访问请求"**按钮. - -[![Withdraw access request button](img/a6d5e94df0d5d50038a0909603d69933.png)](img/withdraw_access_request_button.png) - -## Changing the owner of a group[](#changing-the-owner-of-a-group "Permalink") - -Ownership of a group means at least one of its members has [Owner permission](../permissions.html#group-members-permissions). Groups must have at least one owner. - -可以只更改一个所有者的组所有者. 更改组的唯一所有者: - -* 作为管理员: - 1. 前往小组的 **成员**选项卡. - 2. 赋予其他成员**所有者**权限. - 3. 刷新页面. 现在,您可以从原始所有者中删除**所有者**权限. -* 作为当前组的所有者: - 1. 前往小组的 **成员**选项卡. - 2. 赋予其他成员**所有者**权限. - 3. 让新的所有者登录并从您中删除**所有者**权限. - -## Remove a member from the group[](#remove-a-member-from-the-group "Permalink") - -只有[拥有所有者](../permissions.html#group-members-permissions)权限的[用户](../permissions.html#group-members-permissions)才能管理组成员. - -如果给定成员在该组中具有直接成员资格,则可以从该组中删除该成员. 如果成员资格是从父组继承的,则该成员只能从父组本身中删除. - -删除成员时,您可以决定是从所有问题中取消分配用户,还是合并当前已分配的请求,还是保留分配. - -* 当用户离开私人组并且您希望撤消他们对所有问题的访问并分配他们的合并请求时,从所有问题和合并请求中**取消分配已删除的成员**可能会有所帮助. -* **保留问题和合并请求的分配**可能对于接受公共贡献的组很有帮助,在这些组中,用户不必是成员就可以为问题和合并请求做出贡献. - -要从组中删除成员: - -1. 在一个小组中,转到 **成员们** . -2. 点击**删除** 要删除的群组成员旁边的按钮. 出现" **删除成员"**模态. -3. (可选)选中" **也从相关问题中取消分配此用户并合并请求"**复选框. -4. Click **删除会员**. - -## Changing the default branch protection of a group[](#changing-the-default-branch-protection-of-a-group "Permalink") - -在 GitLab 12.9 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/7583) . - -默认情况下,每个组都继承全局级别的分支保护集. - -要为特定组更改此设置: - -1. 前往小组的 **设置>常规**页面. -2. 展开" **权限,LFS,2FA"**部分. -3. 在" **默认分支保护"**下拉列表中选择所需的选项. -4. Click **保存更改**. - -要全局更改此设置,请参阅[默认分支保护](../admin_area/settings/visibility_and_access_controls.html#default-branch-protection) . - -**注意:**在[GitLab Premium 或更高版本中](https://about.gitlab.com/pricing/) ,GitLab 管理员可以选择[禁止组所有者更新默认的分支保护](../admin_area/settings/visibility_and_access_controls.html#disable-group-owners-from-updating-default-branch-protection-premium-only) . - -## Add projects to a group[](#add-projects-to-a-group "Permalink") - -有两种方法可以将新项目添加到组中: - -* 选择一个组,然后单击" **新建项目"** . 然后,您可以继续[创建您的项目](../../gitlab-basics/create-project.html) . - - [![New project](img/ef67d77909a856277f9f2821fa0c18ea.png)](img/create_new_project_from_group.png) - -* 在创建项目时,请从下拉菜单中选择已经创建的组名称空间. - - [![Select group](img/674c1579957cca4a644bc90fb8fbb2f3.png)](img/select_group_dropdown.png) - -### Default project-creation level[](#default-project-creation-level "Permalink") - -版本历史 - -* 在[GitLab Premium](https://about.gitlab.com/pricing/) 10.5 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/2534) . -* 在 10.7 中带到[GitLab Starter](https://about.gitlab.com/pricing/) . -* 在 11.10 中[移至](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/25975) [GitLab Core](https://about.gitlab.com/pricing/) . - -默认情况下, [开发人员和维护人员](../permissions.html#group-members-permissions)可以在一个组下创建项目. - -要为特定组更改此设置: - -1. 转到论坛的**设置>常规**页面. -2. 展开" **权限,LFS,2FA"**部分. -3. 在" **允许创建项目"**下拉列表中选择所需的选项. -4. Click **保存更改**. - -要全局更改此设置,请参阅[默认项目创建保护](../admin_area/settings/visibility_and_access_controls.html#default-project-creation-protection) . - -## View group details[](#view-group-details "Permalink") - -组的" **详细信息"**页面包含以下选项卡: - -* 小组和项目. -* 共享的项目. -* 存档的项目. - -### Group activity analytics overview[](#group-activity-analytics-overview "Permalink") - -版本历史 - -* 在 GitLab [Starter](https://about.gitlab.com/pricing/) 12.10 中作为[测试版功能](https://about.gitlab.com/handbook/product/#beta) [引入](https://gitlab.com/gitlab-org/gitlab/-/issues/207164) - -组详细信息视图还显示最近 90 天内创建的以下项目数: - -* 合并请求. -* Issues. -* Members. - -可以使用`group_activity_analytics` [功能标记](../../development/feature_flags/development.html#enabling-a-feature-flag-in-development)启用这些组活动分析. - -[![Recent Group Activity](img/645965e7ebb61697ff42cc06214ca5af.png)](img/group_activity_analytics_v12_10.png) - -有关详细信息,请参阅有关如何[查看组活动的部分](#view-group-activity) . - -## View group activity[](#view-group-activity "Permalink") - -群组的" **活动"**页面显示群组中最近执行的操作,包括: - -* **推送事件** :最近推送到分支. -* **合并事件** :最近合并. -* **发行事件** :已发行或已关闭的发行. -* **史诗般的事件** :史诗集开启或关闭. -* **评论** :评论已打开或关闭. -* **小组** :已加入或离开小组的小组成员. -* **Wiki** :创建,删除或更新的 Wiki. - -单击**RSS**图标,还可以 Atom 格式获得整个活动供稿. - -要查看论坛的" **活动"**页面,请执行以下操作: - -1. 转到论坛的页面. -2. 在左侧导航菜单中,转到" **组概述",**然后选择" **活动"** . - -## Transfer projects into groups[](#transfer-projects-into-groups "Permalink") - -了解如何[将项目转移到小组中](../project/settings/index.html#transferring-an-existing-project-into-another-namespace) . - -## Sharing a project with a group[](#sharing-a-project-with-a-group "Permalink") - -您可以[与一个小组共享您的项目,](../project/members/share_project_with_groups.html)并向所有小组成员立即授予对该项目的访问权限. - -或者,您可以[锁定共享与组功能](#share-with-group-lock) . - -## Sharing a group with another group[](#sharing-a-group-with-another-group "Permalink") - -在 GitLab 12.7 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/18328) . - -与[与组共享项目](#sharing-a-project-with-a-group)类似,您可以与另一个组共享一个组,以使直接的组成员可以访问共享的组. 这对于继承的成员无效. - -要将给定的组(例如"前端")与另一个组(例如"工程")共享: - -1. 导航到"前端"群组页面,然后使用左侧的导航菜单转到群组" **成员"** . -2. Select the **邀请小组** tab. -3. 以您选择的最大访问权限级别添加"工程". -4. Click **Invite**. - -"工程"组的所有成员将被添加到"前端". - -## Manage group memberships via LDAP[](#manage-group-memberships-via-ldap "Permalink") - -组同步允许将 LDAP 组映射到 GitLab 组. 这样可以更好地控制每组用户的管理. 要配置组同步,请编辑`group_base` **DN** ( `'OU=Global Groups,OU=GitLab INT,DC=GitLab,DC=org'` ). 该**OU**包含将与 GitLab 组关联的所有组. - -可以使用 CN 或过滤器创建组链接. 这些组链接在**组设置-> LDAP 同步**页面上创建. 配置链接后,用户可能需要一个多小时才能与 GitLab 组进行同步. - -有关 LDAP 和组同步管理的更多信息,请参阅[LDAP 主文档](../../administration/auth/ldap/index.html#group-sync-starter-only) . - -**注意:**如果在添加 LDAP 同步时 LDAP 用户是组成员,并且它们不属于 LDAP 组,则将从该组中将其删除. - -### Creating group links via CN[](#creating-group-links-via-cn-starter-only "Permalink") - -通过 CN 创建群组链接: - -1. 选择**LDAP 服务器**作为链接. -2. 选择`LDAP Group cn`作为**同步方法** . -3. 在" **LDAP 组 cn"**文本输入框中,开始输入组的 CN. 在配置的`group_base`中将有一个带有匹配 CN 的下拉菜单. 从此列表中选择您的 CN. -4. 在" **LDAP 访问"**部分中,选择在该组中同步的用户的[权限级别](../permissions.html) . -5. 单击`Add Synchronization`按钮以保存该组链接. - -[![Creating group links via CN](img/5d200a6bcc883fcfa57dac51301bc2e3.png)](img/ldap_sync_cn_v13_1.png) - -### Creating group links via filter[](#creating-group-links-via-filter-premium-only "Permalink") - -通过过滤器创建组链接: - -1. 选择**LDAP 服务器**作为链接. -2. 选择`LDAP user filter`作为**Sync 方法** . -3. 在" **LDAP 用户"过滤器**框中输入过滤**器** . 请遵循[有关用户过滤器](../../administration/auth/ldap/index.html#set-up-ldap-user-filter-core-only)的[文档](../../administration/auth/ldap/index.html#set-up-ldap-user-filter-core-only) . -4. 在" **LDAP 访问"**部分中,选择在该组中同步的用户的[权限级别](../permissions.html) . -5. 单击`Add Synchronization`按钮以保存该组链接. - -[![Creating group links via filter](img/5b8558c08a5996468dcd0d1a119ac76b.png)](img/ldap_sync_filter_v13_1.png) - -### Overriding user permissions[](#overriding-user-permissions-starter-only "Permalink") - -从 GitLab [v8.15 开始,](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/822) LDAP 用户权限现在可以由管理员用户手动覆盖. 覆盖用户的权限: - -1. 转到您小组的" **成员"**页面. -2. 在您要编辑的用户的行中选择铅笔图标. -3. 选择橙色的`Change permissions`按钮. - -[![Setting manual permissions](img/c6273de0eb8e4c8e7750113a7a66e7d6.png)](img/manual_permissions_v13_1.png) - -现在,您将能够从" **成员"**页面编辑用户的权限. - -## Epics[](#epics-ultimate "Permalink") - -在[GitLab Ultimate](https://about.gitlab.com/pricing/) 10.2 中引入. - -Epics 通过跟踪跨项目和里程碑共享主题的问题组,使您可以更有效,更轻松地管理项目组合. - -[Learn more about Epics.](epics/index.html) - -## Group Security Dashboard[](#group-security-dashboard-ultimate "Permalink") - -概述组及其子组中所有项目的漏洞. - -[Learn more about the Group Security Dashboard.](security_dashboard/index.html) - -## Insights[](#insights-ultimate "Permalink") - -[Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0. - -配置对您的组或项目重要的见解,使用户可以浏览以下数据: - -* 分诊卫生 -* 在给定期间内创建/关闭的问题 -* 合并请求的平均合并时间 -* 多得多 - -[Learn more about Insights](insights/index.html). - -## Transferring groups[](#transferring-groups "Permalink") - -在 GitLab 10.5 中,您可以通过以下方式转移组: - -* 将子组转移到新的父组. -* 通过将顶级组转移到所需的组,将其转换为子组. -* Convert a subgroup into a top-level group by transferring it out of its current group. - -转移群组时,请注意: - -* 更改组的父母可能会产生意想不到的副作用. 请参阅[更改存储库路径时的重定向](../project/index.html#redirects-when-changing-repository-paths) . -* 您只能将群组转移到您管理的群组中. -* 您必须更新本地存储库以指向新位置. -* If the immediate parent group’s visibility is lower than the group’s current visibility, visibility levels for subgroups and projects will change to match the new parent group’s visibility. -* 仅传输显式组成员身份,不继承继承成员身份. 如果组的所有者仅继承了成员身份,则该组将没有所有者. 在这种情况下,转移组的用户将成为该组的所有者. - -## Group settings[](#group-settings "Permalink") - -创建群组后,您可以导航至该群组的信息中心,然后点击**设置**来管理其设置. - -[![group settings](img/b98f1bb6205ce5c692946b81e8c78003.png)](img/group_settings.png) - -### General settings[](#general-settings "Permalink") - -除了编辑您在[创建组](#create-a-new-group)时先前设置的任何设置之外,您还可以访问[该组的](#create-a-new-group)其他配置. - -#### Changing a group’s path[](#changing-a-groups-path "Permalink") - -更改组的路径可能会有意想不到的副作用. 在继续之前,请阅读[重定向的行为](../project/index.html#redirects-when-changing-repository-paths) . - -如果您要腾出路径,以便其他组或用户可以声明该路径,则由于名称和路径都必须是唯一的,因此您可能也需要重命名该组. - -更改组路径: - -1. 导航到论坛的**"设置">"常规"**页面. -2. 展开**路径,传输,删除**部分. -3. 在" **更改组路径"**下输入新名称. -4. Click **变更群组路径**. - -**注意:**如果命名空间包含带有[Container Registry](../packages/container_registry/index.html)标记的项目,则当前无法重命名该命名空间,因为该项目无法移动.**提示:**如果要保留对原始名称空间的所有权并保护 URL 重定向,则可以更改一个组并向其传输项目,而无需更改组的路径或重命名用户名. - -### Remove a group[](#remove-a-group "Permalink") - -删除组及其内容: - -1. 导航到您小组的 **设置>常规**页面. -2. 展开**路径,传输,删除**部分. -3. 在"删除组"部分中,单击" **删除组"**按钮. -4. 根据要求确认操作. - -此操作要么: - -* 删除组,并且将后台作业排队以删除该组中的所有项目. -* 从[GitLab 12.8 开始](https://gitlab.com/gitlab-org/gitlab/-/issues/33257) ,在[Premium 或 Silver](https://about.gitlab.com/pricing/premium/)或更高级别上,将一个组标记为删除. 默认情况下,删除将在 7 天后进行,但是可以在[实例设置中](../admin_area/settings/visibility_and_access_controls.html#default-deletion-adjourned-period-premium-only)进行更改. - -### Restore a group[](#restore-a-group-premium "Permalink") - -在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/33257) . - -要还原标记为删除的组: - -1. 导航到您小组的 **设置>常规**页面. -2. 展开**路径,传输,删除**部分. -3. 在"还原组"部分中,单击" **还原组"**按钮. - -#### Enforce 2FA to group members[](#enforce-2fa-to-group-members "Permalink") - -通过对所有组成员[强制执行两因素身份验证(2FA)](../../security/two_factor_authentication.html#enforcing-2fa-for-all-users-in-a-group) ,将安全层添加到您的组中. - -#### Share with group lock[](#share-with-group-lock "Permalink") - -防止一个组中[的项目与另一个组共享项目,](../project/members/share_project_with_groups.html)以便对项目访问进行更严格的控制. - -例如,假设您有两个不同的团队(A 组和 B 组)在一个项目中一起工作,并且要继承该组成员身份,您可以在 A 组和 B 组之间共享项目. **使用组锁共享**可以防止其中的任何项目该群组不会与其他群组共享,从而确保只有合适的群组成员才能访问这些项目. - -要启用此功能,请导航至组设置页面. 选择" **使用组锁定共享"**并**保存组** . - -[![Checkbox for share with group lock](img/788efc08015bf62f608d47f16b49b4d7.png)](img/share_with_group_lock.png) - -#### Member Lock[](#member-lock-starter "Permalink") - -成员锁定使组所有者可以阻止组中所有项目的任何新项目成员资格,从而可以更严格地控​​制项目成员资格. - -例如,如果要为" [审核事件"](../../administration/audit_events.html)锁定组,请启用"成员锁定"以确保在该审核期间不能修改项目成员身份. - -要启用此功能: - -1. 导航到组的**"设置">"常规"**页面. -2. 展开" **权限,LFS,2FA"**部分,然后选择" **成员锁"** . -3. Click **保存更改**. - -[![Checkbox for membership lock](img/5460742929164e737a1b4c1990b75fc3.png)](img/member_lock.png) - -这将对以前有权操作项目成员资格的所有用户禁用该选项,因此无法添加新用户. 此外,将无法通过 API 向项目添加新用户的任何请求. - -#### IP access restriction[](#ip-access-restriction-premium "Permalink") - -版本历史 - -* 在[GitLab Ultimate 和 Gold](https://about.gitlab.com/pricing/) 12.0 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/1985) . -* 在 13.1 中[移至](https://gitlab.com/gitlab-org/gitlab/-/issues/215410) [GitLab Premium 和 Silver](https://about.gitlab.com/pricing/) . - -为了确保只有组织内的人员可以访问特定资源,您可以选择通过 IP 地址限制对组及其基础项目,问题等的访问. 这可以帮助确保特定内容不会离开场所,同时又不会阻止对整个实例的访问. - -使用 CIDR 表示法将一个或多个允许的 IP 子网添加到组设置中,并且来自其他 IP 地址的任何人将无法访问受限制的内容. - -目前限制适用于: - -* UI. -* [从 GitLab 12.3 开始](https://gitlab.com/gitlab-org/gitlab/-/issues/12874) ,可以访问 API. -* [从 GitLab 12.4 开始](https://gitlab.com/gitlab-org/gitlab/-/issues/32113) ,Git 通过 SSH 进行操作. - -为了避免意外锁定,管理员和组所有者可以访问组,而不受 IP 限制. - -要启用此功能: - -1. 导航到组的**"设置">"常规"**页面. -2. 展开" **权限,LFS,2FA"**部分,然后在" **允许访问以下 IP 地址"**字段中输入 IP 地址范围. -3. Click **保存更改**. - -#### Allowed domain restriction[](#allowed-domain-restriction-premium "Permalink") - -版本历史 - -* 在[GitLab Premium 和 Silver](https://about.gitlab.com/pricing/) 12.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/7297) . -* 支持指定 GitLab 13.1 中[引入的](https://gitlab.com/gitlab-org/gitlab/-/issues/33143)多个电子邮件域 - -通过仅将具有特定域中电子邮件地址的用户添加到组中,可以限制对组的访问. - -添加您要允许的电子邮件域,并且不允许来自不同域的电子邮件用户添加到该组. - -某些域不能被限制. 这些是最受欢迎的公共电子邮件域,例如: - -* `gmail.com` -* `yahoo.com` -* `hotmail.com` -* `aol.com` -* `msn.com` -* `hotmail.co.uk` -* `hotmail.fr` -* `live.com` -* `outlook.com` -* `icloud.com` - -要启用此功能: - -1. 导航到组的**"设置">"常规"**页面. -2. 展开" **权限,LFS,2FA"**部分,然后在" **通过电子邮件限制成员身份"**字段中输入域名. -3. Click **保存更改**. - -此后,将对所有添加到组中的新用户启用域检查. - -#### Group file templates[](#group-file-templates-premium "Permalink") - -组文件模板使您可以与组中的每个项目共享一组通用文件类型的模板. 它类似于[实例模板存储库](../admin_area/settings/instance_template_repository.html)功能,所选项目应遵循该页面上记录的相同命名约定. - -您只能在组中选择项目作为模板源. 这包括与该组共享的项目,但**不包括**正在配置的组的子组或父组中的项目. - -您可以为子组和直接父组配置此功能. 子组中的项目将有权访问该子组以及任何直接父组的模板. - -[![Group file template dropdown](img/6c431eb1e4bc729eceb4a6a36f0ea6b0.png)](img/group_file_template_dropdown.png) - -要启用此功能,请导航至组设置页面,展开" **模板"**部分,选择一个项目作为模板存储库,然后选择" **保存组"** . - -[![Group file template settings](img/09e1824644c088dfbd0f2f9710fc7d77.png)](img/group_file_template_settings.png) - -#### Group-level project templates[](#group-level-project-templates-premium "Permalink") - -通过将组设置为模板源,在组级别定义项目模板. [了解有关组级项目模板的更多信息](custom_project_templates.html) . - -#### Disabling email notifications[](#disabling-email-notifications "Permalink") - -在 GitLab 12.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/23585) . - -您可以禁用与该组相关的所有电子邮件通知,其中包括其子组和项目. - -要启用此功能: - -1. 导航到组的**"设置">"常规"**页面. -2. 展开**权限,LFS,2FA**部分,然后选择**禁用电子邮件通知** . -3. Click **保存更改**. - -#### Disabling group mentions[](#disabling-group-mentions "Permalink") - -在 GitLab 12.6 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/21301) . - -您可以防止将用户添加到对话中,并且在任何人提及这些用户所属的组时通知他们. - -自动完成下拉列表中会相应地显示提及被禁用的组. - -这对于具有大量用户的组特别有用. - -要启用此功能: - -1. 导航到组的**"设置">"常规"**页面. -2. 展开" **权限"," LFS,2FA"**部分,然后选择" **禁用组提及"** . -3. Click **保存更改**. - -#### Enabling delayed Project removal[](#enabling-delayed-project-removal-premium "Permalink") - -在 GitLab 13.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/220382) . - -默认情况下,组中的项目会立即删除. (可选)在[Premium 或 Silver](https://about.gitlab.com/pricing/)或更高级别上,您可以将组内的项目配置为在延迟间隔后删除. - -在此间隔期间,项目将处于只读状态,并且可以根据需要还原. 间隔时间默认为 7 天,可以由管理员在[实例设置中](../admin_area/settings/visibility_and_access_controls.html#default-deletion-adjourned-period-premium-only)进行修改. - -要启用延迟删除项目: - -1. 导航到组的**"设置">"常规"**页面. -2. 展开" **权限"," LFS,2FA"**部分,然后选中" **启用延迟的项目删除"** . -3. Click **保存更改**. - -### Advanced settings[](#advanced-settings "Permalink") - -* **项目** :查看该组中的所有项目,将成员添加到每个项目,访问每个项目的设置,以及删除任何项目,所有操作均在同一屏幕上进行. -* **Webhooks** :为您的组配置[webhooks](../project/integrations/webhooks.html) . -* **Kubernetes 集群集成** :将您的 GitLab 组与[Kubernetes 集群连接](clusters/index.html) . -* **审核事件** :查看该组的[审核事件](../../administration/audit_events.html) . -* **管道配额** :跟踪组的[管道配额](../admin_area/settings/continuous_integration.html) . - -#### Storage usage quota[](#storage-usage-quota-starter "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/13294) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.0. - -组所有者可以在组页面设置列表可用的" **使用配额"**页面的" **存储"**选项卡中,查看一个组(包括子组)中所有项目的聚合存储使用情况. - -[![Group storage usage quota](img/7042e9f430cefb3a9c62194cec839692.png)](img/group_storage_usage_quota.png) - -如果触发了任何会影响其值的相关事件(例如,提交推送),则将更新存储的总使用量. 出于性能原因,我们可能会将更新延迟最多 1 小时 30 分钟. - -如果您的名称空间显示`N/A`作为总存储使用量,则可以通过将提交推送到该名称空间中的任何项目来触发重新计算. - -#### Group push rules[](#group-push-rules-starter "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34370) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.8. - -组推送规则允许组维护者为特定组内的新创建项目设置[推送规则](../../push_rules/push_rules.html) . - -要为组配置推送规则,请导航至 在小组的侧边栏上. - -设置后,新的子组将根据以下任一条件为其设置推送规则: - -* 定义了推送规则的最接近的父组. -* 如果没有父组定义推送规则,则在实例级别设置推送规则. - -##### Enabling the feature[](#enabling-the-feature "Permalink") - -默认情况下,此功能带有`:group_push_rules`功能标记. 可以使用功能标记[API 端点](../../api/features.html#set-or-create-a-feature)或通过具有 Rails 控制台访问权限的 GitLab 管理员为特定组启用它,方法是运行: - -``` -Feature.enable(:group_push_rules) -``` - -### Maximum artifacts size[](#maximum-artifacts-size-core-only "Permalink") - -有关为组设置最大工件大小的信息,请参见[最大工件大小](../admin_area/settings/continuous_integration.html#maximum-artifacts-size-core-only) . - -## User contribution analysis[](#user-contribution-analysis-starter "Permalink") - -使用[GitLab Contribution Analytics](contribution_analytics/index.html) ,您可以概述组成员执行的贡献(推送,合并请求和问题). - -## Issues analytics[](#issues-analytics-premium "Permalink") - -使用[GitLab Issues Analytics](issues_analytics/index.html) ,您可以查看组中每个月创建的问题数量的条形图. - -## Dependency Proxy[](#dependency-proxy-premium "Permalink") - -使用 GitLab 作为上游 Docker 映像的[依赖项代理](../packages/dependency_proxy/index.html) . \ No newline at end of file diff --git a/_book/gitbook/gitbook-plugin-sharing/buttons.js b/_book/gitbook/gitbook-plugin-sharing/buttons.js deleted file mode 100644 index 709a4e4c023c775e048b9afd7ca4ba9abd215601..0000000000000000000000000000000000000000 --- a/_book/gitbook/gitbook-plugin-sharing/buttons.js +++ /dev/null @@ -1,90 +0,0 @@ -require(['gitbook', 'jquery'], function(gitbook, $) { - var SITES = { - 'facebook': { - 'label': 'Facebook', - 'icon': 'fa fa-facebook', - 'onClick': function(e) { - e.preventDefault(); - window.open('http://www.facebook.com/sharer/sharer.php?s=100&p[url]='+encodeURIComponent(location.href)); - } - }, - 'twitter': { - 'label': 'Twitter', - 'icon': 'fa fa-twitter', - 'onClick': function(e) { - e.preventDefault(); - window.open('http://twitter.com/home?status='+encodeURIComponent(document.title+' '+location.href)); - } - }, - 'google': { - 'label': 'Google+', - 'icon': 'fa fa-google-plus', - 'onClick': function(e) { - e.preventDefault(); - window.open('https://plus.google.com/share?url='+encodeURIComponent(location.href)); - } - }, - 'weibo': { - 'label': 'Weibo', - 'icon': 'fa fa-weibo', - 'onClick': function(e) { - e.preventDefault(); - window.open('http://service.weibo.com/share/share.php?content=utf-8&url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)); - } - }, - 'instapaper': { - 'label': 'Instapaper', - 'icon': 'fa fa-instapaper', - 'onClick': function(e) { - e.preventDefault(); - window.open('http://www.instapaper.com/text?u='+encodeURIComponent(location.href)); - } - }, - 'vk': { - 'label': 'VK', - 'icon': 'fa fa-vk', - 'onClick': function(e) { - e.preventDefault(); - window.open('http://vkontakte.ru/share.php?url='+encodeURIComponent(location.href)); - } - } - }; - - - - gitbook.events.bind('start', function(e, config) { - var opts = config.sharing; - - // Create dropdown menu - var menu = $.map(opts.all, function(id) { - var site = SITES[id]; - - return { - text: site.label, - onClick: site.onClick - }; - }); - - // Create main button with dropdown - if (menu.length > 0) { - gitbook.toolbar.createButton({ - icon: 'fa fa-share-alt', - label: 'Share', - position: 'right', - dropdown: [menu] - }); - } - - // Direct actions to share - $.each(SITES, function(sideId, site) { - if (!opts[sideId]) return; - - gitbook.toolbar.createButton({ - icon: site.icon, - label: site.text, - position: 'right', - onClick: site.onClick - }); - }); - }); -}); diff --git a/_book/index.html b/_book/index.html index a39b5647a52b50dcc9a0e101c3aa69d42bb9f5ea..2b7012b434ce4987fde3ae80df0d8bf60bc74c43 100644 --- a/_book/index.html +++ b/_book/index.html @@ -1,14 +1,14 @@ - + - Introduction · GitBook + 首页 · CODEChina帮助文档 - + @@ -21,6 +21,10 @@ + + + + @@ -99,14 +103,14 @@ @@ -122,6 +126,8 @@ @@ -193,7 +212,7 @@

- Introduction + 首页

@@ -208,10 +227,10 @@
-

CODEChina

+

关于CODEChina

欢迎使用CodeChina代码托管平台,本产品基于 Gitlab CE 版本 (13.2 stable) 开发并,目前版本提供了代码仓库管理、组织管理等基本功能,欢迎体验使用。

体验使用过程中如果遇到任何问题,请与我们联系。

-

联系方式

+

联系我们

- +
Copyright © CODECHINA 2020 all right reserved,powered by Gitbook该文件修订时间: +2020-08-29 23:01:45 +
@@ -263,7 +284,7 @@ @@ -277,6 +298,10 @@ + + + + @@ -297,10 +322,6 @@ - - - - diff --git a/_book/search_index.json b/_book/search_index.json index 08f417f84ffed6531127d00afcd183b1555cb0e5..9e49fc09b2932f1221e2b350cf1ae97c6a777bf4 100644 --- a/_book/search_index.json +++ b/_book/search_index.json @@ -1 +1 @@ -{"index":{"version":"0.5.12","fields":[{"name":"title","boost":10},{"name":"keywords","boost":15},{"name":"body","boost":1}],"ref":"url","documentStore":{"store":{"./":["\"img\"","&&","(13.2","/","=","===","ce","codechina","codechina微信群(1)","codechina微信群(2)","codechina观察员(1)","codechina观察员(2)","console.log(\"plugin","e.target.tagnam","function(e){","gitlab","introduct","issu","popup....\");document.onclick","qq","stable)","wechat","window.open(e.target.src,e.target.src)}img{cursor:pointer}","产品提交","体验使用过程中如果遇到任何问题,请与我们联系。","开发并,目前版本提供了代码仓库管理、组织管理等基本功能,欢迎体验使用。","欢迎使用codechina代码托管平台,本产品基于","点此向","版本","联系方式"],"docs/002.html":["\"img\"","&&","=","===","analyt","basic","burndown","chart","cheat","cherri","codechina","codechina.","codechina。如果您熟悉以上两个产品中的一个或多个,您可以直接开始","codechina,您会发现以下有用信息:","codechina?","codechina?请查阅我们的便捷指南.","console.log(\"plugin","contribut","devop","e.target.tagnam","elasticsearch","epic","flow","function(e){","git","github","github,bitbucket,gitlab.com,fogbugz","gitlab","gitlab/github","gpg","guid","id","issu","jupyt","lf","markdown","merg","notebook","overview","pdf.","pick","pick.","popup....\");document.onclick","request","resolut","roadmap","scrum","search","sheet","ssh","svn","thread","through","waterfall,敏捷还是会话开发,codechina","web","webid","wiki","window.open(e.target.src,e.target.src)}img{cursor:pointer}","work","workflow","上工作.","下载描述最常用的","与","中使用分支.","中的功能和概念.","中编辑文件.","为","为codechina开源做贡献","主题","了解有关使用","了解有关帐户管理的更多信息:","了解项目中的每个角色可以做什么.","产品,在产品中我们也会为您设置帮助提示,您可以随时回来查看我们的产品文档。","从","从svn迁移","从另一个平台进入","代办事项","代码仓库","以下文档与","以下是我们推荐的一些主题:","以及将","使用","使用内置的","使用受保护的分支.","使用新系统可能让您觉得难以入手,我们有以下文档可快速提升您的相关知识:","使用高级查询获得更具针对性的搜索结果.","保护分支","做贡献为codechina开源贡献力量!","入门,分支策略,git","全局搜索","关联","具有两因素身份验证的帐户安全性,设置您的","分支和默认分支","分析","分类问题或使用描述性标签合并请求.","分组组织您的项目.","刚开始使用git/codechina/gitlab/github?","创建主题","创建分支","创建分支,创建和上传文件以及创建目录.","创建并fork项目,以及导入项目","创建并上传文件,并创建目录","创建,复制和移动项目.","删除已合并的分支","利用","利用最佳的工作流程增强您的工作流程.","协议","可视化史诗般的时间表.","合并更改后的批量删除分支.","合并请求","合并请求管理.","和","和高级用法.","在","在提交时启动合并请求.","在整个","在本地处理合并请求","在本地处理合并请求的提示.","在特定的里程碑中观察项目的进度.","在网页中管理源代码仓库.","在问题之间建立关系.","均可简化您的协作工作流程.","基本入门","基础入门","处理合并请求","处理提交,并使用","如何在","如何在开发上做贡献.","如何在文档上做贡献.","如果您是从另一个平台进入","子组织","存储库转换为","存储库随附分支工具和访问控制,可为项目和代码的协作提供可扩展的单一事实来源.","实例上进行更快,更高级的代码搜索.","实例之间","密钥,并部署密钥以安全地访问您的项目.","对.ipynb文件的支持.","对您的提交进行签名.","对更改进行","对项目推送的附加控制.","导入项目","导入项目.","将","将源代码整合到一个易于管理和控制的分布式版本控制系统中","帮助文档","开发","开始在命令行和","快捷方式","或","或看板上显示问题.","截止日期]","托管源代码,并控制项目的可见性和设置配置.","推入或拉出外部的代码仓库","推送规则","描述","提交","搜索问题,合并请求,项目,组和待办事项.","操作的","文件","文件模板","文件管理.","文档","新建","新建阶段有关:","无论您使用","时间跟踪","是","是开源的,您可以通过以下方式为我们的开源社区做出贡献:","来管理您的文档.","标签","检查每月创建了多少个问题.","概览","欢迎您使用codechina,如果您是","此外,在项目之间转移问题.","灵活的项目管理工具可视化,确定优先级,协调和跟踪进度.","热门话题","用户文件熟悉codechina","用户权限","用户账号","的初级用户,我们建议您从查看本文档开始学习如何使用","的新手吗?我们有资源可以帮助您入门.","的精华.","看板","策略探索","管理员文件管理员入门.","管理您的帐户.","组织","结合使用的更多信息:","署名提交","草稿合并请求","解析线程,将合并请求中的线程移至问题,并且仅在解决所有线程后才允许合并请求.","计划","计划主题","计划阶段有关:","讨论","设置发布问题和合并请求的里程碑,并带有可选的截止日期.","访问codechina.csdn.net/docs,以获得优化的导航,可发现性和可读性.","语法检索","请参阅小组贡献者的详细统计信息.","贡献者许可协议.","账号验证","账户管理","跟踪共享主题的问题组.","跟踪发行期限.","跟踪花费在问题和合并请求上的时间.","返回概览","通用文件的文件模板.","通过在简单仪表板上显示的时间顺序列表,跟踪需要注意的工作.","里程碑","针对问题或合并请求的常见操作的快捷方式,而无需单击按钮或在web界面中使用下拉菜单.","锁定文件","锁定文件以避免合并冲突.","镜像代码仓库","问题","问题,提交和合并请求中的线程,注释和可解决线程.","防止合并草稿合并请求.","项目","项目和组","项目和组织","项目问题并限制对问题的访问,并创建用于提交新问题和合并请求的模板.","高级格式化系统(markdown)",",",",包括机密问题",",包括项目访问和设置",",发布和合并请求模板",",和移动的问题",",而不会中断您的工作流程."]},"length":2},"tokenStore":{"root":{"docs":{},"\"":{"docs":{},"i":{"docs":{},"m":{"docs":{},"g":{"docs":{},"\"":{"docs":{"./":{"ref":"./","tf":0.030303030303030304},"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}},"&":{"docs":{},"&":{"docs":{"./":{"ref":"./","tf":0.030303030303030304},"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"(":{"1":{"3":{"docs":{},".":{"2":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}},"docs":{}}},"docs":{}},"docs":{}},"/":{"docs":{"./":{"ref":"./","tf":0.06060606060606061}}},"=":{"docs":{"./":{"ref":"./","tf":0.030303030303030304},"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"=":{"docs":{},"=":{"docs":{"./":{"ref":"./","tf":0.030303030303030304},"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"c":{"docs":{},"e":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{"./":{"ref":"./","tf":0.06060606060606061},"docs/002.html":{"ref":"docs/002.html","tf":0.03832752613240418}},"微":{"docs":{},"信":{"docs":{},"群":{"docs":{},"(":{"1":{"docs":{},")":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}},"2":{"docs":{},")":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}},"docs":{}}}}},"观":{"docs":{},"察":{"docs":{},"员":{"docs":{},"(":{"1":{"docs":{},")":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}},"2":{"docs":{},")":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}},"docs":{}}}}},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}},"。":{"docs":{},"如":{"docs":{},"果":{"docs":{},"您":{"docs":{},"熟":{"docs":{},"悉":{"docs":{},"以":{"docs":{},"上":{"docs":{},"两":{"docs":{},"个":{"docs":{},"产":{"docs":{},"品":{"docs":{},"中":{"docs":{},"的":{"docs":{},"一":{"docs":{},"个":{"docs":{},"或":{"docs":{},"多":{"docs":{},"个":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"直":{"docs":{},"接":{"docs":{},"开":{"docs":{},"始":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}},",":{"docs":{},"您":{"docs":{},"会":{"docs":{},"发":{"docs":{},"现":{"docs":{},"以":{"docs":{},"下":{"docs":{},"有":{"docs":{},"用":{"docs":{},"信":{"docs":{},"息":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}},"?":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"请":{"docs":{},"查":{"docs":{},"阅":{"docs":{},"我":{"docs":{},"们":{"docs":{},"的":{"docs":{},"便":{"docs":{},"捷":{"docs":{},"指":{"docs":{},"南":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}},"n":{"docs":{},"s":{"docs":{},"o":{"docs":{},"l":{"docs":{},"e":{"docs":{},".":{"docs":{},"l":{"docs":{},"o":{"docs":{},"g":{"docs":{},"(":{"docs":{},"\"":{"docs":{},"p":{"docs":{},"l":{"docs":{},"u":{"docs":{},"g":{"docs":{},"i":{"docs":{},"n":{"docs":{"./":{"ref":"./","tf":0.030303030303030304},"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}},"t":{"docs":{},"r":{"docs":{},"i":{"docs":{},"b":{"docs":{},"u":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}},"h":{"docs":{},"a":{"docs":{},"r":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"e":{"docs":{},"a":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"r":{"docs":{},"r":{"docs":{},"i":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}}}}}}}},"e":{"docs":{},".":{"docs":{},"t":{"docs":{},"a":{"docs":{},"r":{"docs":{},"g":{"docs":{},"e":{"docs":{},"t":{"docs":{},".":{"docs":{},"t":{"docs":{},"a":{"docs":{},"g":{"docs":{},"n":{"docs":{},"a":{"docs":{},"m":{"docs":{"./":{"ref":"./","tf":0.030303030303030304},"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}},"l":{"docs":{},"a":{"docs":{},"s":{"docs":{},"t":{"docs":{},"i":{"docs":{},"c":{"docs":{},"s":{"docs":{},"e":{"docs":{},"a":{"docs":{},"r":{"docs":{},"c":{"docs":{},"h":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}},"p":{"docs":{},"i":{"docs":{},"c":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"f":{"docs":{},"u":{"docs":{},"n":{"docs":{},"c":{"docs":{},"t":{"docs":{},"i":{"docs":{},"o":{"docs":{},"n":{"docs":{},"(":{"docs":{},"e":{"docs":{},")":{"docs":{},"{":{"docs":{"./":{"ref":"./","tf":0.030303030303030304},"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}},"l":{"docs":{},"o":{"docs":{},"w":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}}}}}},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.03484320557491289}},"l":{"docs":{},"a":{"docs":{},"b":{"docs":{"./":{"ref":"./","tf":0.030303030303030304},"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"/":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"h":{"docs":{},"u":{"docs":{},"b":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}},"h":{"docs":{},"u":{"docs":{},"b":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},",":{"docs":{},"b":{"docs":{},"i":{"docs":{},"t":{"docs":{},"b":{"docs":{},"u":{"docs":{},"c":{"docs":{},"k":{"docs":{},"e":{"docs":{},"t":{"docs":{},",":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"l":{"docs":{},"a":{"docs":{},"b":{"docs":{},".":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{},",":{"docs":{},"f":{"docs":{},"o":{"docs":{},"g":{"docs":{},"b":{"docs":{},"u":{"docs":{},"g":{"docs":{},"z":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"p":{"docs":{},"g":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"u":{"docs":{},"i":{"docs":{},"d":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"i":{"docs":{},"n":{"docs":{},"t":{"docs":{},"r":{"docs":{},"o":{"docs":{},"d":{"docs":{},"u":{"docs":{},"c":{"docs":{},"t":{"docs":{"./":{"ref":"./","tf":10}}}}}}}}}},"s":{"docs":{},"s":{"docs":{},"u":{"docs":{"./":{"ref":"./","tf":0.030303030303030304},"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}}}}},"d":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"p":{"docs":{},"o":{"docs":{},"p":{"docs":{},"u":{"docs":{},"p":{"docs":{},".":{"docs":{},".":{"docs":{},".":{"docs":{},".":{"docs":{},"\"":{"docs":{},")":{"docs":{},";":{"docs":{},"d":{"docs":{},"o":{"docs":{},"c":{"docs":{},"u":{"docs":{},"m":{"docs":{},"e":{"docs":{},"n":{"docs":{},"t":{"docs":{},".":{"docs":{},"o":{"docs":{},"n":{"docs":{},"c":{"docs":{},"l":{"docs":{},"i":{"docs":{},"c":{"docs":{},"k":{"docs":{"./":{"ref":"./","tf":0.030303030303030304},"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"d":{"docs":{},"f":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"i":{"docs":{},"c":{"docs":{},"k":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}},"q":{"docs":{},"q":{"docs":{"./":{"ref":"./","tf":0.06060606060606061}}}},"s":{"docs":{},"t":{"docs":{},"a":{"docs":{},"b":{"docs":{},"l":{"docs":{},"e":{"docs":{},")":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}}}}}},"c":{"docs":{},"r":{"docs":{},"u":{"docs":{},"m":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"e":{"docs":{},"a":{"docs":{},"r":{"docs":{},"c":{"docs":{},"h":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}},"h":{"docs":{},"e":{"docs":{},"e":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"s":{"docs":{},"h":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"v":{"docs":{},"n":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}}}}},"w":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"a":{"docs":{},"t":{"docs":{"./":{"ref":"./","tf":0.06060606060606061}}}}}},"b":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"i":{"docs":{},"d":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"i":{"docs":{},"n":{"docs":{},"d":{"docs":{},"o":{"docs":{},"w":{"docs":{},".":{"docs":{},"o":{"docs":{},"p":{"docs":{},"e":{"docs":{},"n":{"docs":{},"(":{"docs":{},"e":{"docs":{},".":{"docs":{},"t":{"docs":{},"a":{"docs":{},"r":{"docs":{},"g":{"docs":{},"e":{"docs":{},"t":{"docs":{},".":{"docs":{},"s":{"docs":{},"r":{"docs":{},"c":{"docs":{},",":{"docs":{},"e":{"docs":{},".":{"docs":{},"t":{"docs":{},"a":{"docs":{},"r":{"docs":{},"g":{"docs":{},"e":{"docs":{},"t":{"docs":{},".":{"docs":{},"s":{"docs":{},"r":{"docs":{},"c":{"docs":{},")":{"docs":{},"}":{"docs":{},"i":{"docs":{},"m":{"docs":{},"g":{"docs":{},"{":{"docs":{},"c":{"docs":{},"u":{"docs":{},"r":{"docs":{},"s":{"docs":{},"o":{"docs":{},"r":{"docs":{},":":{"docs":{},"p":{"docs":{},"o":{"docs":{},"i":{"docs":{},"n":{"docs":{},"t":{"docs":{},"e":{"docs":{},"r":{"docs":{},"}":{"docs":{"./":{"ref":"./","tf":0.030303030303030304},"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"k":{"docs":{},"i":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}}}}},"a":{"docs":{},"t":{"docs":{},"e":{"docs":{},"r":{"docs":{},"f":{"docs":{},"a":{"docs":{},"l":{"docs":{},"l":{"docs":{},",":{"docs":{},"敏":{"docs":{},"捷":{"docs":{},"还":{"docs":{},"是":{"docs":{},"会":{"docs":{},"话":{"docs":{},"开":{"docs":{},"发":{"docs":{},",":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"o":{"docs":{},"r":{"docs":{},"k":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}},"f":{"docs":{},"l":{"docs":{},"o":{"docs":{},"w":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}},"产":{"docs":{},"品":{"docs":{},"提":{"docs":{},"交":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}},",":{"docs":{},"在":{"docs":{},"产":{"docs":{},"品":{"docs":{},"中":{"docs":{},"我":{"docs":{},"们":{"docs":{},"也":{"docs":{},"会":{"docs":{},"为":{"docs":{},"您":{"docs":{},"设":{"docs":{},"置":{"docs":{},"帮":{"docs":{},"助":{"docs":{},"提":{"docs":{},"示":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"随":{"docs":{},"时":{"docs":{},"回":{"docs":{},"来":{"docs":{},"查":{"docs":{},"看":{"docs":{},"我":{"docs":{},"们":{"docs":{},"的":{"docs":{},"产":{"docs":{},"品":{"docs":{},"文":{"docs":{},"档":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"体":{"docs":{},"验":{"docs":{},"使":{"docs":{},"用":{"docs":{},"过":{"docs":{},"程":{"docs":{},"中":{"docs":{},"如":{"docs":{},"果":{"docs":{},"遇":{"docs":{},"到":{"docs":{},"任":{"docs":{},"何":{"docs":{},"问":{"docs":{},"题":{"docs":{},",":{"docs":{},"请":{"docs":{},"与":{"docs":{},"我":{"docs":{},"们":{"docs":{},"联":{"docs":{},"系":{"docs":{},"。":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}}}}}}}}}}}}}}}}}}}}}}},"开":{"docs":{},"发":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"并":{"docs":{},",":{"docs":{},"目":{"docs":{},"前":{"docs":{},"版":{"docs":{},"本":{"docs":{},"提":{"docs":{},"供":{"docs":{},"了":{"docs":{},"代":{"docs":{},"码":{"docs":{},"仓":{"docs":{},"库":{"docs":{},"管":{"docs":{},"理":{"docs":{},"、":{"docs":{},"组":{"docs":{},"织":{"docs":{},"管":{"docs":{},"理":{"docs":{},"等":{"docs":{},"基":{"docs":{},"本":{"docs":{},"功":{"docs":{},"能":{"docs":{},",":{"docs":{},"欢":{"docs":{},"迎":{"docs":{},"体":{"docs":{},"验":{"docs":{},"使":{"docs":{},"用":{"docs":{},"。":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"始":{"docs":{},"在":{"docs":{},"命":{"docs":{},"令":{"docs":{},"行":{"docs":{},"和":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}},"欢":{"docs":{},"迎":{"docs":{},"使":{"docs":{},"用":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},"代":{"docs":{},"码":{"docs":{},"托":{"docs":{},"管":{"docs":{},"平":{"docs":{},"台":{"docs":{},",":{"docs":{},"本":{"docs":{},"产":{"docs":{},"品":{"docs":{},"基":{"docs":{},"于":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}}}}}}}}}}}}}}}}}}}}}}},"您":{"docs":{},"使":{"docs":{},"用":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},",":{"docs":{},"如":{"docs":{},"果":{"docs":{},"您":{"docs":{},"是":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}},"点":{"docs":{},"此":{"docs":{},"向":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}}},"版":{"docs":{},"本":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}},"联":{"docs":{},"系":{"docs":{},"方":{"docs":{},"式":{"docs":{"./":{"ref":"./","tf":0.030303030303030304}}}}}},"a":{"docs":{},"n":{"docs":{},"a":{"docs":{},"l":{"docs":{},"y":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}},"b":{"docs":{},"a":{"docs":{},"s":{"docs":{},"i":{"docs":{},"c":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"u":{"docs":{},"r":{"docs":{},"n":{"docs":{},"d":{"docs":{},"o":{"docs":{},"w":{"docs":{},"n":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}},"d":{"docs":{},"e":{"docs":{},"v":{"docs":{},"o":{"docs":{},"p":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}}}}}}},"j":{"docs":{},"u":{"docs":{},"p":{"docs":{},"y":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}},"l":{"docs":{},"f":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"m":{"docs":{},"a":{"docs":{},"r":{"docs":{},"k":{"docs":{},"d":{"docs":{},"o":{"docs":{},"w":{"docs":{},"n":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}},"e":{"docs":{},"r":{"docs":{},"g":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"n":{"docs":{},"o":{"docs":{},"t":{"docs":{},"e":{"docs":{},"b":{"docs":{},"o":{"docs":{},"o":{"docs":{},"k":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}},"o":{"docs":{},"v":{"docs":{},"e":{"docs":{},"r":{"docs":{},"v":{"docs":{},"i":{"docs":{},"e":{"docs":{},"w":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}},"r":{"docs":{},"e":{"docs":{},"q":{"docs":{},"u":{"docs":{},"e":{"docs":{},"s":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}},"s":{"docs":{},"o":{"docs":{},"l":{"docs":{},"u":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}},"o":{"docs":{},"a":{"docs":{},"d":{"docs":{},"m":{"docs":{},"a":{"docs":{},"p":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}},"t":{"docs":{},"h":{"docs":{},"r":{"docs":{},"e":{"docs":{},"a":{"docs":{},"d":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"o":{"docs":{},"u":{"docs":{},"g":{"docs":{},"h":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}},"上":{"docs":{},"工":{"docs":{},"作":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"下":{"docs":{},"载":{"docs":{},"描":{"docs":{},"述":{"docs":{},"最":{"docs":{},"常":{"docs":{},"用":{"docs":{},"的":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}},"与":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}},"中":{"docs":{},"使":{"docs":{},"用":{"docs":{},"分":{"docs":{},"支":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}},"的":{"docs":{},"功":{"docs":{},"能":{"docs":{},"和":{"docs":{},"概":{"docs":{},"念":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}},"编":{"docs":{},"辑":{"docs":{},"文":{"docs":{},"件":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}},"为":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},"开":{"docs":{},"源":{"docs":{},"做":{"docs":{},"贡":{"docs":{},"献":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}},"主":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.017421602787456445}}}},"了":{"docs":{},"解":{"docs":{},"有":{"docs":{},"关":{"docs":{},"使":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"帐":{"docs":{},"户":{"docs":{},"管":{"docs":{},"理":{"docs":{},"的":{"docs":{},"更":{"docs":{},"多":{"docs":{},"信":{"docs":{},"息":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}},"项":{"docs":{},"目":{"docs":{},"中":{"docs":{},"的":{"docs":{},"每":{"docs":{},"个":{"docs":{},"角":{"docs":{},"色":{"docs":{},"可":{"docs":{},"以":{"docs":{},"做":{"docs":{},"什":{"docs":{},"么":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}},"从":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"s":{"docs":{},"v":{"docs":{},"n":{"docs":{},"迁":{"docs":{},"移":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}},"另":{"docs":{},"一":{"docs":{},"个":{"docs":{},"平":{"docs":{},"台":{"docs":{},"进":{"docs":{},"入":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}}}}}}}}}},"代":{"docs":{},"办":{"docs":{},"事":{"docs":{},"项":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"码":{"docs":{},"仓":{"docs":{},"库":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.010452961672473868}}}}}},"以":{"docs":{},"下":{"docs":{},"文":{"docs":{},"档":{"docs":{},"与":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}}}}},"是":{"docs":{},"我":{"docs":{},"们":{"docs":{},"推":{"docs":{},"荐":{"docs":{},"的":{"docs":{},"一":{"docs":{},"些":{"docs":{},"主":{"docs":{},"题":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}},"及":{"docs":{},"将":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"使":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}},"内":{"docs":{},"置":{"docs":{},"的":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"受":{"docs":{},"保":{"docs":{},"护":{"docs":{},"的":{"docs":{},"分":{"docs":{},"支":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}},"新":{"docs":{},"系":{"docs":{},"统":{"docs":{},"可":{"docs":{},"能":{"docs":{},"让":{"docs":{},"您":{"docs":{},"觉":{"docs":{},"得":{"docs":{},"难":{"docs":{},"以":{"docs":{},"入":{"docs":{},"手":{"docs":{},",":{"docs":{},"我":{"docs":{},"们":{"docs":{},"有":{"docs":{},"以":{"docs":{},"下":{"docs":{},"文":{"docs":{},"档":{"docs":{},"可":{"docs":{},"快":{"docs":{},"速":{"docs":{},"提":{"docs":{},"升":{"docs":{},"您":{"docs":{},"的":{"docs":{},"相":{"docs":{},"关":{"docs":{},"知":{"docs":{},"识":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"高":{"docs":{},"级":{"docs":{},"查":{"docs":{},"询":{"docs":{},"获":{"docs":{},"得":{"docs":{},"更":{"docs":{},"具":{"docs":{},"针":{"docs":{},"对":{"docs":{},"性":{"docs":{},"的":{"docs":{},"搜":{"docs":{},"索":{"docs":{},"结":{"docs":{},"果":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}},"保":{"docs":{},"护":{"docs":{},"分":{"docs":{},"支":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"做":{"docs":{},"贡":{"docs":{},"献":{"docs":{},"为":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},"开":{"docs":{},"源":{"docs":{},"贡":{"docs":{},"献":{"docs":{},"力":{"docs":{},"量":{"docs":{},"!":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}},"入":{"docs":{},"门":{"docs":{},",":{"docs":{},"分":{"docs":{},"支":{"docs":{},"策":{"docs":{},"略":{"docs":{},",":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}},"全":{"docs":{},"局":{"docs":{},"搜":{"docs":{},"索":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"关":{"docs":{},"联":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"具":{"docs":{},"有":{"docs":{},"两":{"docs":{},"因":{"docs":{},"素":{"docs":{},"身":{"docs":{},"份":{"docs":{},"验":{"docs":{},"证":{"docs":{},"的":{"docs":{},"帐":{"docs":{},"户":{"docs":{},"安":{"docs":{},"全":{"docs":{},"性":{"docs":{},",":{"docs":{},"设":{"docs":{},"置":{"docs":{},"您":{"docs":{},"的":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}},"分":{"docs":{},"支":{"docs":{},"和":{"docs":{},"默":{"docs":{},"认":{"docs":{},"分":{"docs":{},"支":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}},"析":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}},"类":{"docs":{},"问":{"docs":{},"题":{"docs":{},"或":{"docs":{},"使":{"docs":{},"用":{"docs":{},"描":{"docs":{},"述":{"docs":{},"性":{"docs":{},"标":{"docs":{},"签":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}},"组":{"docs":{},"组":{"docs":{},"织":{"docs":{},"您":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}},"刚":{"docs":{},"开":{"docs":{},"始":{"docs":{},"使":{"docs":{},"用":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"/":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},"/":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"l":{"docs":{},"a":{"docs":{},"b":{"docs":{},"/":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"h":{"docs":{},"u":{"docs":{},"b":{"docs":{},"?":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"创":{"docs":{},"建":{"docs":{},"主":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.010452961672473868}}}},"分":{"docs":{},"支":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},",":{"docs":{},"创":{"docs":{},"建":{"docs":{},"和":{"docs":{},"上":{"docs":{},"传":{"docs":{},"文":{"docs":{},"件":{"docs":{},"以":{"docs":{},"及":{"docs":{},"创":{"docs":{},"建":{"docs":{},"目":{"docs":{},"录":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}},"并":{"docs":{},"f":{"docs":{},"o":{"docs":{},"r":{"docs":{},"k":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"以":{"docs":{},"及":{"docs":{},"导":{"docs":{},"入":{"docs":{},"项":{"docs":{},"目":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}},"上":{"docs":{},"传":{"docs":{},"文":{"docs":{},"件":{"docs":{},",":{"docs":{},"并":{"docs":{},"创":{"docs":{},"建":{"docs":{},"目":{"docs":{},"录":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}},",":{"docs":{},"复":{"docs":{},"制":{"docs":{},"和":{"docs":{},"移":{"docs":{},"动":{"docs":{},"项":{"docs":{},"目":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}},"删":{"docs":{},"除":{"docs":{},"已":{"docs":{},"合":{"docs":{},"并":{"docs":{},"的":{"docs":{},"分":{"docs":{},"支":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}},"利":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"最":{"docs":{},"佳":{"docs":{},"的":{"docs":{},"工":{"docs":{},"作":{"docs":{},"流":{"docs":{},"程":{"docs":{},"增":{"docs":{},"强":{"docs":{},"您":{"docs":{},"的":{"docs":{},"工":{"docs":{},"作":{"docs":{},"流":{"docs":{},"程":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}},"协":{"docs":{},"议":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"可":{"docs":{},"视":{"docs":{},"化":{"docs":{},"史":{"docs":{},"诗":{"docs":{},"般":{"docs":{},"的":{"docs":{},"时":{"docs":{},"间":{"docs":{},"表":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}},"合":{"docs":{},"并":{"docs":{},"更":{"docs":{},"改":{"docs":{},"后":{"docs":{},"的":{"docs":{},"批":{"docs":{},"量":{"docs":{},"删":{"docs":{},"除":{"docs":{},"分":{"docs":{},"支":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}},"请":{"docs":{},"求":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.010452961672473868}},"管":{"docs":{},"理":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}},"和":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.013937282229965157}},"高":{"docs":{},"级":{"docs":{},"用":{"docs":{},"法":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}},"在":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}},"提":{"docs":{},"交":{"docs":{},"时":{"docs":{},"启":{"docs":{},"动":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}},"整":{"docs":{},"个":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"本":{"docs":{},"地":{"docs":{},"处":{"docs":{},"理":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"的":{"docs":{},"提":{"docs":{},"示":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}},"特":{"docs":{},"定":{"docs":{},"的":{"docs":{},"里":{"docs":{},"程":{"docs":{},"碑":{"docs":{},"中":{"docs":{},"观":{"docs":{},"察":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"进":{"docs":{},"度":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}},"网":{"docs":{},"页":{"docs":{},"中":{"docs":{},"管":{"docs":{},"理":{"docs":{},"源":{"docs":{},"代":{"docs":{},"码":{"docs":{},"仓":{"docs":{},"库":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}},"问":{"docs":{},"题":{"docs":{},"之":{"docs":{},"间":{"docs":{},"建":{"docs":{},"立":{"docs":{},"关":{"docs":{},"系":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}},"均":{"docs":{},"可":{"docs":{},"简":{"docs":{},"化":{"docs":{},"您":{"docs":{},"的":{"docs":{},"协":{"docs":{},"作":{"docs":{},"工":{"docs":{},"作":{"docs":{},"流":{"docs":{},"程":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}},"基":{"docs":{},"本":{"docs":{},"入":{"docs":{},"门":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"础":{"docs":{},"入":{"docs":{},"门":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"处":{"docs":{},"理":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"提":{"docs":{},"交":{"docs":{},",":{"docs":{},"并":{"docs":{},"使":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}},"如":{"docs":{},"何":{"docs":{},"在":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"开":{"docs":{},"发":{"docs":{},"上":{"docs":{},"做":{"docs":{},"贡":{"docs":{},"献":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}},"文":{"docs":{},"档":{"docs":{},"上":{"docs":{},"做":{"docs":{},"贡":{"docs":{},"献":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}},"果":{"docs":{},"您":{"docs":{},"是":{"docs":{},"从":{"docs":{},"另":{"docs":{},"一":{"docs":{},"个":{"docs":{},"平":{"docs":{},"台":{"docs":{},"进":{"docs":{},"入":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"存":{"docs":{},"储":{"docs":{},"库":{"docs":{},"转":{"docs":{},"换":{"docs":{},"为":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"随":{"docs":{},"附":{"docs":{},"分":{"docs":{},"支":{"docs":{},"工":{"docs":{},"具":{"docs":{},"和":{"docs":{},"访":{"docs":{},"问":{"docs":{},"控":{"docs":{},"制":{"docs":{},",":{"docs":{},"可":{"docs":{},"为":{"docs":{},"项":{"docs":{},"目":{"docs":{},"和":{"docs":{},"代":{"docs":{},"码":{"docs":{},"的":{"docs":{},"协":{"docs":{},"作":{"docs":{},"提":{"docs":{},"供":{"docs":{},"可":{"docs":{},"扩":{"docs":{},"展":{"docs":{},"的":{"docs":{},"单":{"docs":{},"一":{"docs":{},"事":{"docs":{},"实":{"docs":{},"来":{"docs":{},"源":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"实":{"docs":{},"例":{"docs":{},"上":{"docs":{},"进":{"docs":{},"行":{"docs":{},"更":{"docs":{},"快":{"docs":{},",":{"docs":{},"更":{"docs":{},"高":{"docs":{},"级":{"docs":{},"的":{"docs":{},"代":{"docs":{},"码":{"docs":{},"搜":{"docs":{},"索":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}},"之":{"docs":{},"间":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"密":{"docs":{},"钥":{"docs":{},",":{"docs":{},"并":{"docs":{},"部":{"docs":{},"署":{"docs":{},"密":{"docs":{},"钥":{"docs":{},"以":{"docs":{},"安":{"docs":{},"全":{"docs":{},"地":{"docs":{},"访":{"docs":{},"问":{"docs":{},"您":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}},"对":{"docs":{},".":{"docs":{},"i":{"docs":{},"p":{"docs":{},"y":{"docs":{},"n":{"docs":{},"b":{"docs":{},"文":{"docs":{},"件":{"docs":{},"的":{"docs":{},"支":{"docs":{},"持":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}},"您":{"docs":{},"的":{"docs":{},"提":{"docs":{},"交":{"docs":{},"进":{"docs":{},"行":{"docs":{},"签":{"docs":{},"名":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}},"更":{"docs":{},"改":{"docs":{},"进":{"docs":{},"行":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"项":{"docs":{},"目":{"docs":{},"推":{"docs":{},"送":{"docs":{},"的":{"docs":{},"附":{"docs":{},"加":{"docs":{},"控":{"docs":{},"制":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}},"导":{"docs":{},"入":{"docs":{},"项":{"docs":{},"目":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}},"将":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"源":{"docs":{},"代":{"docs":{},"码":{"docs":{},"整":{"docs":{},"合":{"docs":{},"到":{"docs":{},"一":{"docs":{},"个":{"docs":{},"易":{"docs":{},"于":{"docs":{},"管":{"docs":{},"理":{"docs":{},"和":{"docs":{},"控":{"docs":{},"制":{"docs":{},"的":{"docs":{},"分":{"docs":{},"布":{"docs":{},"式":{"docs":{},"版":{"docs":{},"本":{"docs":{},"控":{"docs":{},"制":{"docs":{},"系":{"docs":{},"统":{"docs":{},"中":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"帮":{"docs":{},"助":{"docs":{},"文":{"docs":{},"档":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"快":{"docs":{},"捷":{"docs":{},"方":{"docs":{},"式":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"或":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"看":{"docs":{},"板":{"docs":{},"上":{"docs":{},"显":{"docs":{},"示":{"docs":{},"问":{"docs":{},"题":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}},"截":{"docs":{},"止":{"docs":{},"日":{"docs":{},"期":{"docs":{},"]":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}},"托":{"docs":{},"管":{"docs":{},"源":{"docs":{},"代":{"docs":{},"码":{"docs":{},",":{"docs":{},"并":{"docs":{},"控":{"docs":{},"制":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"可":{"docs":{},"见":{"docs":{},"性":{"docs":{},"和":{"docs":{},"设":{"docs":{},"置":{"docs":{},"配":{"docs":{},"置":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}},"推":{"docs":{},"入":{"docs":{},"或":{"docs":{},"拉":{"docs":{},"出":{"docs":{},"外":{"docs":{},"部":{"docs":{},"的":{"docs":{},"代":{"docs":{},"码":{"docs":{},"仓":{"docs":{},"库":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}},"送":{"docs":{},"规":{"docs":{},"则":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"描":{"docs":{},"述":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.0313588850174216}}}},"提":{"docs":{},"交":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"搜":{"docs":{},"索":{"docs":{},"问":{"docs":{},"题":{"docs":{},",":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},",":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"组":{"docs":{},"和":{"docs":{},"待":{"docs":{},"办":{"docs":{},"事":{"docs":{},"项":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}},"操":{"docs":{},"作":{"docs":{},"的":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"文":{"docs":{},"件":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006968641114982578}},"模":{"docs":{},"板":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"管":{"docs":{},"理":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"档":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"新":{"docs":{},"建":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"阶":{"docs":{},"段":{"docs":{},"有":{"docs":{},"关":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}},"无":{"docs":{},"论":{"docs":{},"您":{"docs":{},"使":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}},"时":{"docs":{},"间":{"docs":{},"跟":{"docs":{},"踪":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"是":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"开":{"docs":{},"源":{"docs":{},"的":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"通":{"docs":{},"过":{"docs":{},"以":{"docs":{},"下":{"docs":{},"方":{"docs":{},"式":{"docs":{},"为":{"docs":{},"我":{"docs":{},"们":{"docs":{},"的":{"docs":{},"开":{"docs":{},"源":{"docs":{},"社":{"docs":{},"区":{"docs":{},"做":{"docs":{},"出":{"docs":{},"贡":{"docs":{},"献":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"来":{"docs":{},"管":{"docs":{},"理":{"docs":{},"您":{"docs":{},"的":{"docs":{},"文":{"docs":{},"档":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}},"标":{"docs":{},"签":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"检":{"docs":{},"查":{"docs":{},"每":{"docs":{},"月":{"docs":{},"创":{"docs":{},"建":{"docs":{},"了":{"docs":{},"多":{"docs":{},"少":{"docs":{},"个":{"docs":{},"问":{"docs":{},"题":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}},"概":{"docs":{},"览":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":10.003484320557492}}}},"此":{"docs":{},"外":{"docs":{},",":{"docs":{},"在":{"docs":{},"项":{"docs":{},"目":{"docs":{},"之":{"docs":{},"间":{"docs":{},"转":{"docs":{},"移":{"docs":{},"问":{"docs":{},"题":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}},"灵":{"docs":{},"活":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},"管":{"docs":{},"理":{"docs":{},"工":{"docs":{},"具":{"docs":{},"可":{"docs":{},"视":{"docs":{},"化":{"docs":{},",":{"docs":{},"确":{"docs":{},"定":{"docs":{},"优":{"docs":{},"先":{"docs":{},"级":{"docs":{},",":{"docs":{},"协":{"docs":{},"调":{"docs":{},"和":{"docs":{},"跟":{"docs":{},"踪":{"docs":{},"进":{"docs":{},"度":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"热":{"docs":{},"门":{"docs":{},"话":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"用":{"docs":{},"户":{"docs":{},"文":{"docs":{},"件":{"docs":{},"熟":{"docs":{},"悉":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}},"权":{"docs":{},"限":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"账":{"docs":{},"号":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"的":{"docs":{},"初":{"docs":{},"级":{"docs":{},"用":{"docs":{},"户":{"docs":{},",":{"docs":{},"我":{"docs":{},"们":{"docs":{},"建":{"docs":{},"议":{"docs":{},"您":{"docs":{},"从":{"docs":{},"查":{"docs":{},"看":{"docs":{},"本":{"docs":{},"文":{"docs":{},"档":{"docs":{},"开":{"docs":{},"始":{"docs":{},"学":{"docs":{},"习":{"docs":{},"如":{"docs":{},"何":{"docs":{},"使":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}},"新":{"docs":{},"手":{"docs":{},"吗":{"docs":{},"?":{"docs":{},"我":{"docs":{},"们":{"docs":{},"有":{"docs":{},"资":{"docs":{},"源":{"docs":{},"可":{"docs":{},"以":{"docs":{},"帮":{"docs":{},"助":{"docs":{},"您":{"docs":{},"入":{"docs":{},"门":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}},"精":{"docs":{},"华":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"看":{"docs":{},"板":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"策":{"docs":{},"略":{"docs":{},"探":{"docs":{},"索":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"管":{"docs":{},"理":{"docs":{},"员":{"docs":{},"文":{"docs":{},"件":{"docs":{},"管":{"docs":{},"理":{"docs":{},"员":{"docs":{},"入":{"docs":{},"门":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}},"您":{"docs":{},"的":{"docs":{},"帐":{"docs":{},"户":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}},"组":{"docs":{},"织":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"结":{"docs":{},"合":{"docs":{},"使":{"docs":{},"用":{"docs":{},"的":{"docs":{},"更":{"docs":{},"多":{"docs":{},"信":{"docs":{},"息":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}},"署":{"docs":{},"名":{"docs":{},"提":{"docs":{},"交":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"草":{"docs":{},"稿":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}},"解":{"docs":{},"析":{"docs":{},"线":{"docs":{},"程":{"docs":{},",":{"docs":{},"将":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"中":{"docs":{},"的":{"docs":{},"线":{"docs":{},"程":{"docs":{},"移":{"docs":{},"至":{"docs":{},"问":{"docs":{},"题":{"docs":{},",":{"docs":{},"并":{"docs":{},"且":{"docs":{},"仅":{"docs":{},"在":{"docs":{},"解":{"docs":{},"决":{"docs":{},"所":{"docs":{},"有":{"docs":{},"线":{"docs":{},"程":{"docs":{},"后":{"docs":{},"才":{"docs":{},"允":{"docs":{},"许":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"计":{"docs":{},"划":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"主":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"阶":{"docs":{},"段":{"docs":{},"有":{"docs":{},"关":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}},"讨":{"docs":{},"论":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}},"设":{"docs":{},"置":{"docs":{},"发":{"docs":{},"布":{"docs":{},"问":{"docs":{},"题":{"docs":{},"和":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"的":{"docs":{},"里":{"docs":{},"程":{"docs":{},"碑":{"docs":{},",":{"docs":{},"并":{"docs":{},"带":{"docs":{},"有":{"docs":{},"可":{"docs":{},"选":{"docs":{},"的":{"docs":{},"截":{"docs":{},"止":{"docs":{},"日":{"docs":{},"期":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"访":{"docs":{},"问":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},".":{"docs":{},"c":{"docs":{},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{},".":{"docs":{},"n":{"docs":{},"e":{"docs":{},"t":{"docs":{},"/":{"docs":{},"d":{"docs":{},"o":{"docs":{},"c":{"docs":{},"s":{"docs":{},",":{"docs":{},"以":{"docs":{},"获":{"docs":{},"得":{"docs":{},"优":{"docs":{},"化":{"docs":{},"的":{"docs":{},"导":{"docs":{},"航":{"docs":{},",":{"docs":{},"可":{"docs":{},"发":{"docs":{},"现":{"docs":{},"性":{"docs":{},"和":{"docs":{},"可":{"docs":{},"读":{"docs":{},"性":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"语":{"docs":{},"法":{"docs":{},"检":{"docs":{},"索":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"请":{"docs":{},"参":{"docs":{},"阅":{"docs":{},"小":{"docs":{},"组":{"docs":{},"贡":{"docs":{},"献":{"docs":{},"者":{"docs":{},"的":{"docs":{},"详":{"docs":{},"细":{"docs":{},"统":{"docs":{},"计":{"docs":{},"信":{"docs":{},"息":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}},"贡":{"docs":{},"献":{"docs":{},"者":{"docs":{},"许":{"docs":{},"可":{"docs":{},"协":{"docs":{},"议":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}},"账":{"docs":{},"号":{"docs":{},"验":{"docs":{},"证":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"户":{"docs":{},"管":{"docs":{},"理":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"跟":{"docs":{},"踪":{"docs":{},"共":{"docs":{},"享":{"docs":{},"主":{"docs":{},"题":{"docs":{},"的":{"docs":{},"问":{"docs":{},"题":{"docs":{},"组":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}},"发":{"docs":{},"行":{"docs":{},"期":{"docs":{},"限":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}},"花":{"docs":{},"费":{"docs":{},"在":{"docs":{},"问":{"docs":{},"题":{"docs":{},"和":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"上":{"docs":{},"的":{"docs":{},"时":{"docs":{},"间":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}},"返":{"docs":{},"回":{"docs":{},"概":{"docs":{},"览":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.0313588850174216}}}}}},"通":{"docs":{},"用":{"docs":{},"文":{"docs":{},"件":{"docs":{},"的":{"docs":{},"文":{"docs":{},"件":{"docs":{},"模":{"docs":{},"板":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}},"过":{"docs":{},"在":{"docs":{},"简":{"docs":{},"单":{"docs":{},"仪":{"docs":{},"表":{"docs":{},"板":{"docs":{},"上":{"docs":{},"显":{"docs":{},"示":{"docs":{},"的":{"docs":{},"时":{"docs":{},"间":{"docs":{},"顺":{"docs":{},"序":{"docs":{},"列":{"docs":{},"表":{"docs":{},",":{"docs":{},"跟":{"docs":{},"踪":{"docs":{},"需":{"docs":{},"要":{"docs":{},"注":{"docs":{},"意":{"docs":{},"的":{"docs":{},"工":{"docs":{},"作":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"里":{"docs":{},"程":{"docs":{},"碑":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"针":{"docs":{},"对":{"docs":{},"问":{"docs":{},"题":{"docs":{},"或":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"的":{"docs":{},"常":{"docs":{},"见":{"docs":{},"操":{"docs":{},"作":{"docs":{},"的":{"docs":{},"快":{"docs":{},"捷":{"docs":{},"方":{"docs":{},"式":{"docs":{},",":{"docs":{},"而":{"docs":{},"无":{"docs":{},"需":{"docs":{},"单":{"docs":{},"击":{"docs":{},"按":{"docs":{},"钮":{"docs":{},"或":{"docs":{},"在":{"docs":{},"w":{"docs":{},"e":{"docs":{},"b":{"docs":{},"界":{"docs":{},"面":{"docs":{},"中":{"docs":{},"使":{"docs":{},"用":{"docs":{},"下":{"docs":{},"拉":{"docs":{},"菜":{"docs":{},"单":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"锁":{"docs":{},"定":{"docs":{},"文":{"docs":{},"件":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"以":{"docs":{},"避":{"docs":{},"免":{"docs":{},"合":{"docs":{},"并":{"docs":{},"冲":{"docs":{},"突":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}},"镜":{"docs":{},"像":{"docs":{},"代":{"docs":{},"码":{"docs":{},"仓":{"docs":{},"库":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}},"问":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},",":{"docs":{},"提":{"docs":{},"交":{"docs":{},"和":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"中":{"docs":{},"的":{"docs":{},"线":{"docs":{},"程":{"docs":{},",":{"docs":{},"注":{"docs":{},"释":{"docs":{},"和":{"docs":{},"可":{"docs":{},"解":{"docs":{},"决":{"docs":{},"线":{"docs":{},"程":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}},"防":{"docs":{},"止":{"docs":{},"合":{"docs":{},"并":{"docs":{},"草":{"docs":{},"稿":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}},"项":{"docs":{},"目":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"和":{"docs":{},"组":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"织":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}},"问":{"docs":{},"题":{"docs":{},"并":{"docs":{},"限":{"docs":{},"制":{"docs":{},"对":{"docs":{},"问":{"docs":{},"题":{"docs":{},"的":{"docs":{},"访":{"docs":{},"问":{"docs":{},",":{"docs":{},"并":{"docs":{},"创":{"docs":{},"建":{"docs":{},"用":{"docs":{},"于":{"docs":{},"提":{"docs":{},"交":{"docs":{},"新":{"docs":{},"问":{"docs":{},"题":{"docs":{},"和":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"的":{"docs":{},"模":{"docs":{},"板":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"高":{"docs":{},"级":{"docs":{},"格":{"docs":{},"式":{"docs":{},"化":{"docs":{},"系":{"docs":{},"统":{"docs":{},"(":{"docs":{},"m":{"docs":{},"a":{"docs":{},"r":{"docs":{},"k":{"docs":{},"d":{"docs":{},"o":{"docs":{},"w":{"docs":{},"n":{"docs":{},")":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}}}}},",":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}},"包":{"docs":{},"括":{"docs":{},"机":{"docs":{},"密":{"docs":{},"问":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}},"项":{"docs":{},"目":{"docs":{},"访":{"docs":{},"问":{"docs":{},"和":{"docs":{},"设":{"docs":{},"置":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}},"发":{"docs":{},"布":{"docs":{},"和":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"模":{"docs":{},"板":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}},"和":{"docs":{},"移":{"docs":{},"动":{"docs":{},"的":{"docs":{},"问":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}},"而":{"docs":{},"不":{"docs":{},"会":{"docs":{},"中":{"docs":{},"断":{"docs":{},"您":{"docs":{},"的":{"docs":{},"工":{"docs":{},"作":{"docs":{},"流":{"docs":{},"程":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003484320557491289}}}}}}}}}}}}}}}},"length":514},"corpusTokens":["\"img\"","&&","(13.2","/","=","===","analyt","basic","burndown","ce","chart","cheat","cherri","codechina","codechina.","codechina。如果您熟悉以上两个产品中的一个或多个,您可以直接开始","codechina微信群(1)","codechina微信群(2)","codechina观察员(1)","codechina观察员(2)","codechina,您会发现以下有用信息:","codechina?","codechina?请查阅我们的便捷指南.","console.log(\"plugin","contribut","devop","e.target.tagnam","elasticsearch","epic","flow","function(e){","git","github","github,bitbucket,gitlab.com,fogbugz","gitlab","gitlab/github","gpg","guid","id","introduct","issu","jupyt","lf","markdown","merg","notebook","overview","pdf.","pick","pick.","popup....\");document.onclick","qq","request","resolut","roadmap","scrum","search","sheet","ssh","stable)","svn","thread","through","waterfall,敏捷还是会话开发,codechina","web","webid","wechat","wiki","window.open(e.target.src,e.target.src)}img{cursor:pointer}","work","workflow","上工作.","下载描述最常用的","与","中使用分支.","中的功能和概念.","中编辑文件.","为","为codechina开源做贡献","主题","了解有关使用","了解有关帐户管理的更多信息:","了解项目中的每个角色可以做什么.","产品提交","产品,在产品中我们也会为您设置帮助提示,您可以随时回来查看我们的产品文档。","从","从svn迁移","从另一个平台进入","代办事项","代码仓库","以下文档与","以下是我们推荐的一些主题:","以及将","体验使用过程中如果遇到任何问题,请与我们联系。","使用","使用内置的","使用受保护的分支.","使用新系统可能让您觉得难以入手,我们有以下文档可快速提升您的相关知识:","使用高级查询获得更具针对性的搜索结果.","保护分支","做贡献为codechina开源贡献力量!","入门,分支策略,git","全局搜索","关联","具有两因素身份验证的帐户安全性,设置您的","分支和默认分支","分析","分类问题或使用描述性标签合并请求.","分组组织您的项目.","刚开始使用git/codechina/gitlab/github?","创建主题","创建分支","创建分支,创建和上传文件以及创建目录.","创建并fork项目,以及导入项目","创建并上传文件,并创建目录","创建,复制和移动项目.","删除已合并的分支","利用","利用最佳的工作流程增强您的工作流程.","协议","可视化史诗般的时间表.","合并更改后的批量删除分支.","合并请求","合并请求管理.","和","和高级用法.","在","在提交时启动合并请求.","在整个","在本地处理合并请求","在本地处理合并请求的提示.","在特定的里程碑中观察项目的进度.","在网页中管理源代码仓库.","在问题之间建立关系.","均可简化您的协作工作流程.","基本入门","基础入门","处理合并请求","处理提交,并使用","如何在","如何在开发上做贡献.","如何在文档上做贡献.","如果您是从另一个平台进入","子组织","存储库转换为","存储库随附分支工具和访问控制,可为项目和代码的协作提供可扩展的单一事实来源.","实例上进行更快,更高级的代码搜索.","实例之间","密钥,并部署密钥以安全地访问您的项目.","对.ipynb文件的支持.","对您的提交进行签名.","对更改进行","对项目推送的附加控制.","导入项目","导入项目.","将","将源代码整合到一个易于管理和控制的分布式版本控制系统中","帮助文档","开发","开发并,目前版本提供了代码仓库管理、组织管理等基本功能,欢迎体验使用。","开始在命令行和","快捷方式","或","或看板上显示问题.","截止日期]","托管源代码,并控制项目的可见性和设置配置.","推入或拉出外部的代码仓库","推送规则","描述","提交","搜索问题,合并请求,项目,组和待办事项.","操作的","文件","文件模板","文件管理.","文档","新建","新建阶段有关:","无论您使用","时间跟踪","是","是开源的,您可以通过以下方式为我们的开源社区做出贡献:","来管理您的文档.","标签","检查每月创建了多少个问题.","概览","欢迎使用codechina代码托管平台,本产品基于","欢迎您使用codechina,如果您是","此外,在项目之间转移问题.","灵活的项目管理工具可视化,确定优先级,协调和跟踪进度.","点此向","热门话题","版本","用户文件熟悉codechina","用户权限","用户账号","的初级用户,我们建议您从查看本文档开始学习如何使用","的新手吗?我们有资源可以帮助您入门.","的精华.","看板","策略探索","管理员文件管理员入门.","管理您的帐户.","组织","结合使用的更多信息:","署名提交","联系方式","草稿合并请求","解析线程,将合并请求中的线程移至问题,并且仅在解决所有线程后才允许合并请求.","计划","计划主题","计划阶段有关:","讨论","设置发布问题和合并请求的里程碑,并带有可选的截止日期.","访问codechina.csdn.net/docs,以获得优化的导航,可发现性和可读性.","语法检索","请参阅小组贡献者的详细统计信息.","贡献者许可协议.","账号验证","账户管理","跟踪共享主题的问题组.","跟踪发行期限.","跟踪花费在问题和合并请求上的时间.","返回概览","通用文件的文件模板.","通过在简单仪表板上显示的时间顺序列表,跟踪需要注意的工作.","里程碑","针对问题或合并请求的常见操作的快捷方式,而无需单击按钮或在web界面中使用下拉菜单.","锁定文件","锁定文件以避免合并冲突.","镜像代码仓库","问题","问题,提交和合并请求中的线程,注释和可解决线程.","防止合并草稿合并请求.","项目","项目和组","项目和组织","项目问题并限制对问题的访问,并创建用于提交新问题和合并请求的模板.","高级格式化系统(markdown)",",",",包括机密问题",",包括项目访问和设置",",发布和合并请求模板",",和移动的问题",",而不会中断您的工作流程."],"pipeline":["stopWordFilter","stemmer"]},"store":{"./":{"url":"./","title":"Introduction","keywords":"","body":"CODEChina\n欢迎使用CodeChina代码托管平台,本产品基于 Gitlab CE 版本 (13.2 stable) 开发并,目前版本提供了代码仓库管理、组织管理等基本功能,欢迎体验使用。\n体验使用过程中如果遇到任何问题,请与我们联系。\n联系方式\n\n点此向 CODEChina 产品提交 issue\n\nCODEChina微信群(1)\n\nCODEChina微信群(2)\n\nCODEChina观察员(1) Wechat / QQ\n\nCODEChina观察员(2) Wechat / QQ\n\n\n\nconsole.log(\"plugin-popup....\");document.onclick = function(e){ e.target.tagName === \"IMG\" && window.open(e.target.src,e.target.src)}img{cursor:pointer}"},"docs/002.html":{"url":"docs/002.html","title":"概览","keywords":"","body":"帮助文档\n访问codechina.csdn.net/docs,以获得优化的导航,可发现性和可读性.\n概览\n欢迎您使用CODEChina,如果您是 Github 或 GitLab 的初级用户,我们建议您从查看本文档开始学习如何使用 CODEChina。如果您熟悉以上两个产品中的一个或多个,您可以直接开始 CODEChina 产品,在产品中我们也会为您设置帮助提示,您可以随时回来查看我们的产品文档。\n\n\n\n基础入门\n基本入门\n\n\n\n\n用户文件熟悉CODEChina 中的功能和概念.\n管理员文件管理员入门.\n\n\n为 CODEChina 做贡献为CODEChina开源贡献力量!\n是 Git 和 GitLab/GitHub 的新手吗?我们有资源可以帮助您入门.\n\n\n从另一个平台进入 CODEChina?请查阅我们的便捷指南.\n \n\n\n\n热门话题\n以下是我们推荐的一些主题:\n计划\n无论您使用 Waterfall,敏捷还是会话开发,CODEChina 均可简化您的协作工作流程.\n使用 CODEChina 灵活的项目管理工具可视化,确定优先级,协调和跟踪进度.\n以下文档与 DevOps 计划阶段有关:\n\n\n\n计划主题\n描述\n\n\n\n\nBurndown Charts\n在特定的里程碑中观察项目的进度.\n\n\n讨论\n问题,提交和合并请求中的线程,注释和可解决线程.\n\n\n截止日期]\n跟踪发行期限.\n\n\nEpics\n跟踪共享主题的问题组.\n\n\n问题 ,包括机密问题 ,发布和合并请求模板 ,和移动的问题\n项目问题并限制对问题的访问,并创建用于提交新问题和合并请求的模板. 此外,在项目之间转移问题.\n\n\n标签\n分类问题或使用描述性标签合并请求.\n\n\n里程碑\n设置发布问题和合并请求的里程碑,并带有可选的截止日期.\n\n\n看板\n在 Scrum 或看板上显示问题.\n\n\n快捷方式\n针对问题或合并请求的常见操作的快捷方式,而无需单击按钮或在WEB界面中使用下拉菜单.\n\n\n关联 Issue\n在问题之间建立关系.\n\n\nRoadmap\n可视化史诗般的时间表.\n\n\n时间跟踪\n跟踪花费在问题和合并请求上的时间.\n\n\n代办事项\n通过在简单仪表板上显示的时间顺序列表,跟踪需要注意的工作.\n\n\n\n返回概览\n新建\n将源代码整合到一个易于管理和控制的分布式版本控制系统中 ,而不会中断您的工作流程.\nCODEChina 存储库随附分支工具和访问控制,可为项目和代码的协作提供可扩展的单一事实来源.\n以下文档与 DevOps 新建阶段有关:\n项目和组织\n\n\n\n创建主题-项目和组\n描述\n\n\n\n\n全局搜索\n利用 Elasticsearch 在整个 CODEChina 实例上进行更快,更高级的代码搜索.\n\n\n语法检索\n使用高级查询获得更具针对性的搜索结果.\n\n\nContribution analytics\n请参阅小组贡献者的详细统计信息.\n\n\n创建并fork项目,以及导入项目 实例之间\n创建,复制和移动项目.\n\n\n锁定文件\n锁定文件以避免合并冲突.\n\n\n组织 and 子组织\n分组组织您的项目.\n\n\nIssue 分析\n检查每月创建了多少个问题.\n\n\n项目 ,包括项目访问和设置\n托管源代码,并控制项目的可见性和设置配置.\n\n\nSearch through CODEChina\n搜索问题,合并请求,项目,组和待办事项.\n\n\nWeb IDE\n在 WebIDE 中编辑文件.\n\n\nWikis\n使用内置的 Wiki 来管理您的文档.\n\n\n\n返回概览\n代码仓库\n\n\n\n创建主题-代码仓库\n描述\n\n\n\n\n分支和默认分支\n如何在 CODEChina 中使用分支.\n\n\n提交 and 署名提交\n处理提交,并使用 GPG 对您的提交进行签名.\n\n\n创建分支 , 创建并上传文件,并创建目录\n创建分支,创建和上传文件以及创建目录.\n\n\n删除已合并的分支\n合并更改后的批量删除分支.\n\n\n文件模板\n通用文件的文件模板.\n\n\n文件\n文件管理.\n\n\nJupyter Notebook 文件\n对.ipynb文件的支持.\n\n\n保护分支\n使用受保护的分支.\n\n\n推送规则\n对项目推送的附加控制.\n\n\n代码仓库\n在网页中管理源代码仓库.\n\n\n镜像代码仓库\n推入或拉出外部的代码仓库\n\n\n处理合并请求\n在提交时启动合并请求.\n\n\n\n返回概览\n合并请求\n\n\n\n创建主题-合并请求\n描述\n\n\n\n\n在本地处理合并请求\n在本地处理合并请求的提示.\n\n\nCherry-pick\n对更改进行 Cherry Pick.\n\n\nMerge request thread resolution\n解析线程,将合并请求中的线程移至问题,并且仅在解决所有线程后才允许合并请求.\n\n\n合并请求\n合并请求管理.\n\n\n草稿合并请求\n防止合并草稿合并请求.\n\n\n\n返回概览\n刚开始使用Git/CODEChina/GitLab/Github?\n使用新系统可能让您觉得难以入手,我们有以下文档可快速提升您的相关知识:\n\n\n\n主题\n描述\n\n\n\n\nBasics guides\n开始在命令行和 CODEChina 上工作.\n\n\nWorkflow overview\n利用最佳的工作流程增强您的工作流程.\n\n\nMarkdown\n高级格式化系统(Markdown)\n\n\n\n返回概览\n账户管理\n了解有关帐户管理的更多信息:\n\n\n\n主题\n描述\n\n\n\n\n用户账号\n管理您的帐户.\n\n\n账号验证\n具有两因素身份验证的帐户安全性,设置您的 SSH 密钥,并部署密钥以安全地访问您的项目.\n\n\n用户权限\n了解项目中的每个角色可以做什么.\n\n\n\n返回概览\nGit 和 CODEChina\n了解有关使用 Git 以及将 Git 与 CODEChina 结合使用的更多信息:\n\n\n\n主题\n描述\n\n\n\n\nGit\nGit 入门,分支策略,Git LFS 和高级用法.\n\n\nGit cheat sheet\n下载描述最常用的 Git 操作的 PDF.\n\n\nWork Flow\n使用 Work Flow 策略探索 Git 的精华.\n\n\n\n返回概览\n从另一个平台进入 CODEChina?\n如果您是从另一个平台进入 CODEChina,您会发现以下有用信息:\n\n\n\n主题\n描述\n\n\n\n\n导入项目\n从 GitHub,Bitbucket,GitLab.com,FogBugz 和 SVN 导入项目.\n\n\n从SVN迁移\n将 SVN 存储库转换为 Git 和 CODEChina.\n\n\n\n返回概览\n为CODEChina开源做贡献\nCODEChina 是开源的,您可以通过以下方式为我们的开源社区做出贡献:\n\n\n\n主题\n描述\n\n\n\n\n开发\n如何在开发上做贡献.\n\n\n协议\n贡献者许可协议.\n\n\n文档\n如何在文档上做贡献.\n\n\n\n返回概览\n\nconsole.log(\"plugin-popup....\");document.onclick = function(e){ e.target.tagName === \"IMG\" && window.open(e.target.src,e.target.src)}img{cursor:pointer}"}}} \ No newline at end of file +{"index":{"version":"0.5.12","fields":[{"name":"title","boost":10},{"name":"keywords","boost":15},{"name":"body","boost":1}],"ref":"url","documentStore":{"store":{"./":["\"img\"","&&","(13.2","/","08","2020","23:01:45","29","=","===","ce","codechina","codechina微信群(1)","codechina微信群(2)","codechina观察员(1)","codechina观察员(2)","console.log(\"plugin","copyright","e.target.tagnam","function(e){","gitbook该文件修订时间:","gitlab","issu","popup....\");document.onclick","qq","reserved,pow","right","stable)","wechat","window.open(e.target.src,e.target.src)}img{cursor:pointer}","©","产品提交","体验使用过程中如果遇到任何问题,请与我们联系。","关于codechina","开发并,目前版本提供了代码仓库管理、组织管理等基本功能,欢迎体验使用。","欢迎使用codechina代码托管平台,本产品基于","点此向","版本","联系我们","首页"],"docs/002.html":["\"img\"","&&","08","2020","23:01:51","29","=","===","analyt","basic","burndown","chart","cheat","cherri","codechina","codechina。如果您熟悉以上两个产品中的一个或多个,您可以直接开始","codechina,您会发现以下有用信息:","codechina?","codechina?请查阅我们的便捷指南","console.log(\"plugin","contribut","copyright","devop","e.target.tagnam","elasticsearch","epic","flow","function(e){","git","gitbook该文件修订时间:","github","github,bitbucket,gitlab.com,fogbugz","gitlab","gitlab/github","gpg","guid","id","issu","jupyt","lf","markdown","merg","notebook","overview","pdf","pick","popup....\");document.onclick","request","reserved,pow","resolut","right","roadmap","scrum","search","sheet","ssh","svn","thread","through","waterfall,敏捷还是会话开发,codechina","web","webid","wiki","window.open(e.target.src,e.target.src)}img{cursor:pointer}","work","workflow","©","上工作","下载描述最常用的","与","中使用分支","中的功能和概念.","中编辑文件","为","为codechina开源做贡献","主题","了解有关使用","了解有关帐户管理的更多信息:","了解项目中的每个角色可以做什么","产品,在产品中我们也会为您设置帮助提示,您可以随时回来查看我们的产品文档。","从","从svn迁移","从另一个平台进入","从另一个平台进入到","代办事项","代码仓库","以下文档与","以下是我们推荐的一些主题:","以及将","使用","使用内置的","使用受保护的分支","使用新系统可能让您觉得难以入手,我们有以下文档可快速提升您的相关知识:","使用高级查询获得更具针对性的搜索结果","保护分支","做贡献为codechina开源贡献力量!","入门,分支策略,git","全局搜索","关联","具有两因素身份验证的帐户安全性,设置您的","分支和默认分支","分析","分类问题或使用描述性标签合并请求","分组组织您的项目","刚开始使用git/codechina/gitlab/github?","创建主题","创建分支","创建分支,创建和上传文件以及创建目录。","创建并fork项目,以及导入项目","创建并上传文件,并创建目录","创建,复制和移动项目","删除已合并的分支","利用","利用最佳的工作流程增强您的工作流程","协议","可视化史诗般的时间表","合并更改后的批量删除分支","合并请求","合并请求管理","和","和高级用法","在","在提交时启动合并请求","在整个","在本地处理合并请求","在本地处理合并请求的提示","在特定的里程碑中观察项目的进度","在网页中管理源代码仓库","在问题之间建立关系.","均可简化您的协作工作流程。","基本入门","基础入门","处理合并请求","处理提交,并使用","如何在","如何在开发上做贡献","如何在文档上做贡献","如果您是从另一个平台进入","子组织","存储库转换为","存储库随附分支工具和访问控制,可为项目和代码的协作提供可扩展的单一事实来源。","实例上进行更快,更高级的代码搜索","实例之间","密钥,并部署密钥以安全地访问您的项目。","对.ipynb文件的支持","对您的提交进行签名。","对更改进行","对项目推送的附加控制","导入项目","将","将源代码整合到一个易于管理和控制的分布式版本控制系统中","帮助文档","开发","开始在命令行和","快捷方式","或","或看板上显示问题","截止日期","托管源代码,并控制项目的可见性和设置配置。","推入或拉出外部的代码仓库","推送规则","描述","提交","搜索问题,合并请求,项目,组和待办事项。","操作的","文件","文件模板","文件管理","文档","新建","新建阶段有关:","无论您使用","时间跟踪","是","是开源的,您可以通过以下方式为我们的开源社区做出贡献:","来管理您的文档","标签","检查每月创建了多少个问题","概览","欢迎您使用codechina,如果您是","此外,在项目之间转移问题。","灵活的项目管理工具可视化,确定优先级,协调和跟踪进度。","热门话题","用户文件熟悉codechina","用户权限","用户账号","的初级用户,我们建议您从查看本文档开始学习如何使用","的新手吗?我们有资源可以帮助您入门","的精华","看板","策略探索","管理员文件管理员入门","管理您的帐户","组织","结合使用的更多信息:","署名提交","草稿合并请求","解析线程,将合并请求中的线程移至问题,并且仅在解决所有线程后才允许合并请求。","计划","计划主题","计划阶段有关:","讨论","设置发布问题和合并请求的里程碑,并带有可选的截止日期","访问codechina.csdn.net/docs,以获得优化的导航,可发现性和可读性。","语法检索","请参阅小组贡献者的详细统计信息","贡献者许可协议","账号验证","账户管理","跟踪共享主题的问题组","跟踪发行期限","跟踪花费在问题和合并请求上的时间","返回概览","通用文件的文件模板","通过在简单仪表板上显示的时间顺序列表,跟踪需要注意的工作。","里程碑","针对问题或合并请求的常见操作的快捷方式,而无需单击按钮或在web界面中使用下拉菜单。","锁定文件","锁定文件以避免合并冲突","镜像代码仓库","问题","问题,提交和合并请求中的线程,注释和可解决线程","防止合并草稿合并请求","项目","项目和组","项目和组织","项目问题并限制对问题的访问,并创建用于提交新问题和合并请求的模板。","高级格式化系统(markdown)",",",",包括机密问题",",包括项目访问和设置",",发布和合并请求模板",",和移动的问题",",而不会中断您的工作流程。"],"docs/033.html":["\"","\"img\"","\"工程\"的所有成员将被添加到\"前端\"组织中。","&&",".","08","12.0","12.2","12.3","12.4","12.6","12.8","12.8.","13.1","13.2","2020","22:25:55","29","2fa","7",";","=","===","@compani","access","advanc","allow","aol.com","api","api.","b","cidr","click","codechina","console.log(\"plugin","copyright","csdn","csdn只提及@csdn","csdn通过@csdn","delay","disabl","domain","e.target.tagnam","email","enabl","enforc","file","frontend","function(e){","gitbook该文件修订时间:","gitlab","gmail.com","gold","group","hotmail.co.uk","hotmail.com","hotmail.fr","https://codechina.csdn.net/groupnam","https://codechina.csdn.net/groupname/subgroup_nam","https://codechina.csdn.net/usernam","icloud.com","introduc","ip","issu","issue及合并请求","issue及合并请求可以将已经分配给当前要移除用户的","issue及合并请求是项目的一部分。对于组织,您可以在单个列表视图中查看所有issue,也可以查看组织中所有项目的请求合并。","kubernet","level","lfs,2fa\"部分,然后选中\"","lfs,2fa\"部分,然后选择\"","live.com","lock","member","mention","miykael","msn.com","notif","outlook.com","popup....\");document.onclick","premium","project","push","registry标记的项目,则无法重命名该空间,因为该项目无法移动。","remov","reserved,pow","restor","restrict","right","rule","set","share","silver","silver或更高级别上,将一个组标记为删除.","silver或更高级别上,您可以将组内的项目配置为在延迟间隔后删除.","ssh","starter","team","team/backend","team/cod","team/coding下访问","team/frontend","team/product","team下访问","team创建了子组。","team和product","team您很高兴!\"","team您能在这里帮助我们吗?\"","team提及了团队中的每个人","templat","ui.","ultim","url","url是将托管项目的名称空间.","url(自动填充不支持中文的组织名称)。(可选)您可以修改它,这是在组视图中显示的名称,该名称只能包含:","webhook","window.open(e.target.src,e.target.src)}img{cursor:pointer}","yahoo.com","©","。","上使用用户名miykael创建了一个帐户;","下划线","与与组织共享项目类似,您可以与一个组织共享另一个组织,以使组织成员可以直接访问共享的组织(注:这对于继承的成员无效)。","与组织共享一个项目","与组织共享另一个组织","中引入","中引入的多个电子邮件域","中文","中移至","中,命名空间将会是用户名称、组织名称或子组名的唯一名称。","为了确保只有组织内的人员可以访问特定资源,您可以选择通过","为了避免意外锁定,管理员和组所有者可以访问组,而不受","为他们的团队创建了一个组织,名称为csdn","为组织添加一个用户","了解如何将项目转移到组织中","了解有关组级项目模板的更多信息","从","从gitlab","从问题开始新的实现时,请添加评论:","他们的个人资料将在https://codechina.csdn.net/miykael下访问","任何团队成员都使用@miykael提及","任何组织所有者都可以在组组织成员设置页面上批准或拒绝您的申请","作为组织所有者,您可以启用或禁用非组织成员请求访问组织的功能。该功能可以通过再组织设置","使用","使用组锁共享可以防止其中的任何项目该群组不会与其他群组共享,从而确保只有合适的群组成员才能访问这些项目.","使用组锁定共享\"并保存组","例如,假设您有两个不同的团队(a","例如,假设有一个名为","例如,如果要为\"","例如,您可以为公司成员创建一个组织","保存修改","保存更改.","保存组\"","保留issue和合并请求的分配可能对于接受公开贡献的组织很有帮助,用户可以不必是组织成员就可以为","假设一个有两个项目的组织:","假设您创建了一个名为compani","允许创建项目下拉列表中选择所需的选项","允许访问以下","创建了一个名为coding的子组织","创建组织后,在组织详情页您可以进入组织设置来对组织进行设置及管理:","删除组\"按钮.","删除组及其内容:","删除组,并且将后台作业排队以删除该组中的所有项目.","前往组织的","前端团队完成实施后,他们会评论:","单击","及合并请求。","及合并请求做出贡献","及合并请求重新进行分配","取消分配给已移除的成员的","变更组织的所有者","变更组织的路径","变更组织的路径也可能会产生一些副作用,具体的请参考重定向的行为","变更组织的默认保护分支","变更组织路径","只有拥有一个所有者的组织可以变更组织的所有者。","只有拥有所有者权限的用户才能管理组织成员。","可以通过以下操作为特定组更改此项设置:","可以通过以下操作将成员从组织中移除:","可以通过以下方式变更组织唯一所有者:","向项目添加新用户的任何请求.","启用延迟的项目删除\"","命名空间","和","和点","和点(不能以连接符","在","在\"删除组\"部分中,单击\"","在\"还原组\"部分中,单击\"","在gitlab","在一个组织中,进入","在创建项目时,从下拉菜单中选择已经创建的组名称空间","在小组的侧边栏上.","在此间隔期间,项目将处于只读状态,并且可以根据需要还原.","在组织中新建项目","在组织设置","在顶部菜单中,依次单击\"","在默认分支保护下拉列表中选择所需的选项","地址\"字段中输入","地址的任何人将无法访问受限制的内容.","地址范围.","地址限制对组及其基础项目,问题等的访问.","大学:存储库,项目和组","天后进行,但是可以在实例设置中进行更改.","天,可以由管理员在实例设置中进行修改.","如果将要转移的父组织的公开可见性设置低于当前父组织,那么待转移组织机器项目的公开可见性将会与即将要转移到的父组织保持一致;","如果您具有足够的权限,还将显示组织设置的按钮","如果您在申请权限被批准之前改变了主意,只需单击\"","如果您是成员,也会看到退出该组的按钮","如果您要腾出路径,以便其他组织或用户可以使用该路径,由于名称和路径都必须是唯一的,因此您在变更路径的同时也可能需要重命名该组织。","如果成员资格是从父组继承的,则该成员只能从父组中进行移除。","如果没有父组定义推送规则,则在实例级别设置推送规则.","如果组织启用了该设置,则非组织成员用户可以请求成为组织的成员。在您要加入的组织页中,单击组织名称后面的申请权限按钮即可。","如果要提高特定项目的现有用户的访问权限,请将其作为新成员再次添加到特定项目中,并为其添加相应的项目成员角色。","如果要移除的成员在该组中具有直接成员资格,则可以从该组织中移除该成员;","子组中的项目将有权访问该子组以及任何直接父组的模板.","子网添加到组设置中,并且来自其他","字母数字字符","它包含多少个项目","它有多少个子组","它类似于实例模板存储库功能,所选项目应遵循该页面上记录的相同命名约定.","定义了推送规则的最接近的父组.","审核事件","审核事件\"锁定组,请启用\"成员锁定\"以确保在该审核期间不能修改项目成员身份.","导航到您小组的","导航到组的\"设置\">\"常规\"页面.","将会显示您所属的全部组织(包括子组织)","将多个项目放在一个组织中的好处是,您可以通过一个操作就授予某个用户访问该组织中所有项目的权限。","将子组织转移到新的父组织","将相关项目组装在一起","将项目移到组织中","展开","展开\"","展开权限,lfs,2fa部分,然后选择禁用电子邮件通知","展开路径,传输,删除部分.","展开高级部分","常规设置","常规设置页面","开发人员和维护人员可以在一个组下创建项目。","开头或以点结尾)","开始","当将新用户设置为组织的开发人员成员时,他们将获得开发人员对该组内所有项目的访问权限。","当您的后端团队需要前端提供帮助时,他们会添加一条评论:","您只能在组中选择项目作为模板源.","您只能将组织/子组织转移到您管理的组织/子组织中;","您可以与组织共享您的项目,并向所有组织成员立即授予对该项目的访问权限。","您可以为子组和直接父组配置此功能.","您可以出于多种原因创建组织,例如:","您可以禁用与该组相关的所有电子邮件通知,其中包括其子组和项目.","您可以通过以下操作为特定组织变更此项设置:","您可以通过以下操作更改组织的路径:","您可以通过以下方式转移组织:","您可以防止将用户添加到对话中,并且在任何人提及这些用户所属的组时通知他们.","您必须手动更新本地存储库以指向新位置;","您的组织\"","成员锁\"","成员锁定使组所有者可以阻止组中所有项目的任何新项目成员资格,从而可以更严格地控​​制项目成员资格.","或","或者,在顶部菜单中,展开+号并选择新建组织","或者,您可以锁定共享与组功能","所有者权限,一个组织至少需要一名所有者。","打开组织的","批量编辑issue及合并请求","找到要移除的成员,并点击移除按钮,这时会弹出","按钮","授予成员一次访问多个项目的权限","提示:如果要保留对原始名称空间的所有权并保护","撤回访问请求\"按钮即可。","支持指定","新建一个组织","新建组织\"","是否公开可见","更改组织的父组织可能会产生一些副作用,具体的请参阅更改存储库路径时的重定向","更改组织路径下输入新的路径","有两种方法可以在组织中新建项目:","有关","有关不允许用作组名的单词列表,请参见保留名称","有关详细信息,请参考批量编辑issue及合并请求","权限\",\"","权限,lfs,2fa\"部分,然后在\"","权限,lfs,2fa\"部分,然后选择\"","权限,lfs,2fa部分","权限,lfs,2fs中单击允许用户请求访问(如果可见性是公开或内部的)进行开启,该功能默认为启用状态。","某些域不能被限制.","查看组织详情","根据要求确认操作.","模板\"部分,选择一个项目作为模板存储库,然后选择\"","此后,将对所有添加到组中的新用户启用域检查.","此外,将无法通过","此操作要么:","注意:如果命名空间包含带有contain","注:出于系统安全以及知识产权、商标保护等因素,我们预留了一部分namespace,如果您的用户名与预留这部分namespace有冲突,系统将会自动对您在codechina中的namespace进行调整。","浏览组织\"时将显示所有公开的组织列表","添加以下信息:","添加您要允许的电子邮件域,并且不允许来自不同域的电子邮件用户添加到该组.","点击","点击移除成员按钮","然后,您可以继续创建您的项目","版本历史","申请加入组织","申请访问权限后:","的复选框","的弹窗","的用户:","的组织,您可以:","目前限制适用于:","禁用组提及\"","移除成员","移除成员时,您可以决定是否取消已经指派给该成员的","移除组织成员","空格","管道配额","组","组与kubernet","组之间共享项目.","组也可以嵌套在子组织中","组和","组推送规则允许组维护者为特定组内的新创建项目设置推送规则","组文件模板使您可以与组中的每个项目共享一组通用文件类型的模板.","组的视频介绍,请参见gitlab","组织","组织\"和\"","组织\"页面上的每个组都列出了:","组织\"页面显示:","组织内的issue及合并请求","组织名称将自动填充","组织已存档的项目","组织成员设置","组织成员设置中将成员添加到组织,可以通过用户名或者注册邮箱来添加组织成员。","组织成员设置选项卡;","组织成员设置页面","组织成员设置页面上,可以将新用户添加到组织中;","组织用户示例","组织的","组织的基本信息和介绍","组织的成员","组织的所有关系是指至少有一个组织成员拥有组织的","组织的项目","组织设置","组)在一个项目中一起工作,并且要继承该组成员身份,您可以在","自动完成下拉列表中会相应地显示提及被禁用的组.","表示法将一个或多个允许的","要为组配置推送规则,请导航至","要启用延迟删除项目:","要启用此功能,请导航至组设置页面.","要启用此功能,请导航至组设置页面,展开\"","要启用此功能:","要将给定的组(例如\"前端\")与另一个组(例如\"工程\")共享:","要还原标记为删除的组:","让我们将其推送到@compani","让新的所有者删除您的所有者权限。","设置>常规页面.","设置后,新的子组将根据以下任一条件为其设置推送规则:","该子组织及其项目将在https://codechina.csdn.net/csdn","该组织及其项目将在https://codechina.csdn.net/csdn","该组织有多少个成员,注意这里面不包括从父组织继承的成员","该网址只能包含:","详细信息页面包含以下内容:","赋予其他成员所有者权限;","转移组织","转移组织时,只有组织直接成员会被转移,从之前父组织集成的成员不会被转移。如果待转移组织的所有者是继承的身份成员,则该组织转移过去后将不会设有所有者,转移组的用户将会自动成为该组的所有者。","转移组织时,请注意:","还原组\"按钮.","这些是最受欢迎的公共电子邮件域,例如:","这包括与该组共享的项目,但不包括正在配置的组的子组或父组中的项目.","这可以帮助确保特定内容不会离开场所,同时又不会阻止对整个实例的访问.","这对于具有大量用户的组特别有用.","这将对以前有权操作项目成员资格的所有用户禁用该选项,因此无法添加新用户.","进入到\"前端\"组织页面,然后进入组织设置","进入到组织的组织设置>常规设置页面","进入组织的组织设置>常规设置页面","进行操作.","连接符","选中\"","选择\"","选择一个组,单击新建项目按钮","选择您的组织后,","选择您要共享的组织\"工程\",并设置访问权限","选择新建的组织","选择权限级别","通过","通过仅将具有特定域中电子邮件地址的用户添加到组中,可以限制对组的访问.","通过以下方式,您可以创建一个新的组织:","通过创建小组并包括适当的成员,可以轻松地@mention所有团队中的问题并合并请求。","通过单击顶部导航中的组织>您的组织来找到您的组织。","通过在同一名称空间下组织相关项目并将成员添加到顶级组,可以以较少的步骤授予对多个项目和多个团队成员的访问权限。","通过对所有组成员强制执行两因素身份验证(2fa)","通过将子组织转移到顶级组织,可以将一个子组织转换为组织","通过将组设置为模板源,在组级别定义项目模板.","通过将顶级组织转移到所需的组织,并将其转换为子组织","通过电子邮件将您的申请告知给组织的所有者(电子邮件将发送给最近活跃的组织所有者)","通过电子邮件限制成员身份\"字段中输入域名.","通过这样做:","邀请","邀请组织","重定向,我们建议您新建一个群组并向其转移项目,而无需更改组织的路径或重命名用户名。","间隔时间默认为","防止一个组中的项目与另一个组共享项目,以便对项目访问进行更严格的控制.","限制.","除了编辑您在创建组织时预先设置的内容外,您还可以对该组织的其他内容进行设置。","集群连接","集群集成","项目","项目创建权限","默认情况下,","默认情况下,删除将在","默认情况下,每个组织都会继承全局级别的分支保护。","默认情况下,组中的项目会立即删除.","!","(可选)可以为新建的组织上传一个头像","(可选)可以为新建的组织添加一段简单介绍,以便其他用户了解该组织","(可选)在premium","(可选)选中",",",",git",",可以访问",",在premium",",它已经完成!",",将安全层添加到您的组中.",",并且在该组中为各个团队backend",",并为每个单独的团队创建一个子组织.",",然后单击绿色按钮\"",",然后添加新成员。您还可以设置该用户的到期日期。",",让我们开始吧!",":为您的组配置webhook",":将您的",":查看该组中的所有项目,将成员添加到每个项目,访问每个项目的设置,以及删除任何项目,所有操作均在同一屏幕上进行.",":查看该组的审核事件",":跟踪组的管道配额",";"]},"length":3},"tokenStore":{"root":{"0":{"8":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"docs":{}},"1":{"2":{"docs":{},".":{"0":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"2":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}},"3":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"4":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"6":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"8":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"docs":{}}},"3":{"docs":{},".":{"1":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}},"2":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"docs":{}}},"docs":{}},"2":{"0":{"2":{"0":{"docs":{"./":{"ref":"./","tf":0.045454545454545456},"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154},"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}},"docs":{}},"docs":{}},"2":{"docs":{},":":{"2":{"5":{"docs":{},":":{"5":{"5":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"docs":{}},"docs":{}}},"docs":{}},"docs":{}}},"3":{"docs":{},":":{"0":{"1":{"docs":{},":":{"4":{"5":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}},"docs":{}},"5":{"1":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}},"docs":{}},"docs":{}}},"docs":{}},"docs":{}}},"9":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"docs":{},"f":{"docs":{},"a":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"7":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}},"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.008620689655172414}},"i":{"docs":{},"m":{"docs":{},"g":{"docs":{},"\"":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"工":{"docs":{},"程":{"docs":{},"\"":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"成":{"docs":{},"员":{"docs":{},"将":{"docs":{},"被":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"\"":{"docs":{},"前":{"docs":{},"端":{"docs":{},"\"":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}},"&":{"docs":{},"&":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"(":{"1":{"3":{"docs":{},".":{"2":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}},"docs":{}}},"docs":{}},"docs":{}},"/":{"docs":{"./":{"ref":"./","tf":0.045454545454545456}}},"=":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"=":{"docs":{},"=":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"c":{"docs":{},"e":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{"./":{"ref":"./","tf":0.045454545454545456},"docs/002.html":{"ref":"docs/002.html","tf":0.0436241610738255},"docs/033.html":{"ref":"docs/033.html","tf":0.006896551724137931}},"微":{"docs":{},"信":{"docs":{},"群":{"docs":{},"(":{"1":{"docs":{},")":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}},"2":{"docs":{},")":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}},"docs":{}}}}},"观":{"docs":{},"察":{"docs":{},"员":{"docs":{},"(":{"1":{"docs":{},")":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}},"2":{"docs":{},")":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}},"docs":{}}}}},"。":{"docs":{},"如":{"docs":{},"果":{"docs":{},"您":{"docs":{},"熟":{"docs":{},"悉":{"docs":{},"以":{"docs":{},"上":{"docs":{},"两":{"docs":{},"个":{"docs":{},"产":{"docs":{},"品":{"docs":{},"中":{"docs":{},"的":{"docs":{},"一":{"docs":{},"个":{"docs":{},"或":{"docs":{},"多":{"docs":{},"个":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"直":{"docs":{},"接":{"docs":{},"开":{"docs":{},"始":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}},",":{"docs":{},"您":{"docs":{},"会":{"docs":{},"发":{"docs":{},"现":{"docs":{},"以":{"docs":{},"下":{"docs":{},"有":{"docs":{},"用":{"docs":{},"信":{"docs":{},"息":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}},"?":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"请":{"docs":{},"查":{"docs":{},"阅":{"docs":{},"我":{"docs":{},"们":{"docs":{},"的":{"docs":{},"便":{"docs":{},"捷":{"docs":{},"指":{"docs":{},"南":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}},"n":{"docs":{},"s":{"docs":{},"o":{"docs":{},"l":{"docs":{},"e":{"docs":{},".":{"docs":{},"l":{"docs":{},"o":{"docs":{},"g":{"docs":{},"(":{"docs":{},"\"":{"docs":{},"p":{"docs":{},"l":{"docs":{},"u":{"docs":{},"g":{"docs":{},"i":{"docs":{},"n":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}},"t":{"docs":{},"r":{"docs":{},"i":{"docs":{},"b":{"docs":{},"u":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}},"p":{"docs":{},"y":{"docs":{},"r":{"docs":{},"i":{"docs":{},"g":{"docs":{},"h":{"docs":{},"t":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"h":{"docs":{},"a":{"docs":{},"r":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"e":{"docs":{},"a":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"r":{"docs":{},"r":{"docs":{},"i":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154}}}}}}},"i":{"docs":{},"d":{"docs":{},"r":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"l":{"docs":{},"i":{"docs":{},"c":{"docs":{},"k":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.010344827586206896}}}}}},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"只":{"docs":{},"提":{"docs":{},"及":{"docs":{},"@":{"docs":{},"c":{"docs":{},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"通":{"docs":{},"过":{"docs":{},"@":{"docs":{},"c":{"docs":{},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"e":{"docs":{},".":{"docs":{},"t":{"docs":{},"a":{"docs":{},"r":{"docs":{},"g":{"docs":{},"e":{"docs":{},"t":{"docs":{},".":{"docs":{},"t":{"docs":{},"a":{"docs":{},"g":{"docs":{},"n":{"docs":{},"a":{"docs":{},"m":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}},"l":{"docs":{},"a":{"docs":{},"s":{"docs":{},"t":{"docs":{},"i":{"docs":{},"c":{"docs":{},"s":{"docs":{},"e":{"docs":{},"a":{"docs":{},"r":{"docs":{},"c":{"docs":{},"h":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}},"p":{"docs":{},"i":{"docs":{},"c":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"m":{"docs":{},"a":{"docs":{},"i":{"docs":{},"l":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"n":{"docs":{},"a":{"docs":{},"b":{"docs":{},"l":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"f":{"docs":{},"o":{"docs":{},"r":{"docs":{},"c":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"f":{"docs":{},"u":{"docs":{},"n":{"docs":{},"c":{"docs":{},"t":{"docs":{},"i":{"docs":{},"o":{"docs":{},"n":{"docs":{},"(":{"docs":{},"e":{"docs":{},")":{"docs":{},"{":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"l":{"docs":{},"o":{"docs":{},"w":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154}}}}},"i":{"docs":{},"l":{"docs":{},"e":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"r":{"docs":{},"o":{"docs":{},"n":{"docs":{},"t":{"docs":{},"e":{"docs":{},"n":{"docs":{},"d":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.03355704697986577}},"b":{"docs":{},"o":{"docs":{},"o":{"docs":{},"k":{"docs":{},"该":{"docs":{},"文":{"docs":{},"件":{"docs":{},"修":{"docs":{},"订":{"docs":{},"时":{"docs":{},"间":{"docs":{},":":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"l":{"docs":{},"a":{"docs":{},"b":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.017241379310344827}},"/":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"h":{"docs":{},"u":{"docs":{},"b":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}},"h":{"docs":{},"u":{"docs":{},"b":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},",":{"docs":{},"b":{"docs":{},"i":{"docs":{},"t":{"docs":{},"b":{"docs":{},"u":{"docs":{},"c":{"docs":{},"k":{"docs":{},"e":{"docs":{},"t":{"docs":{},",":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"l":{"docs":{},"a":{"docs":{},"b":{"docs":{},".":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{},",":{"docs":{},"f":{"docs":{},"o":{"docs":{},"g":{"docs":{},"b":{"docs":{},"u":{"docs":{},"g":{"docs":{},"z":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"p":{"docs":{},"g":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"u":{"docs":{},"i":{"docs":{},"d":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"m":{"docs":{},"a":{"docs":{},"i":{"docs":{},"l":{"docs":{},".":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"o":{"docs":{},"l":{"docs":{},"d":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"r":{"docs":{},"o":{"docs":{},"u":{"docs":{},"p":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.013793103448275862}}}}}}},"i":{"docs":{},"s":{"docs":{},"s":{"docs":{},"u":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154},"docs/033.html":{"ref":"docs/033.html","tf":0.005172413793103448}},"e":{"docs":{},"及":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"可":{"docs":{},"以":{"docs":{},"将":{"docs":{},"已":{"docs":{},"经":{"docs":{},"分":{"docs":{},"配":{"docs":{},"给":{"docs":{},"当":{"docs":{},"前":{"docs":{},"要":{"docs":{},"移":{"docs":{},"除":{"docs":{},"用":{"docs":{},"户":{"docs":{},"的":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}},"是":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"一":{"docs":{},"部":{"docs":{},"分":{"docs":{},"。":{"docs":{},"对":{"docs":{},"于":{"docs":{},"组":{"docs":{},"织":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"在":{"docs":{},"单":{"docs":{},"个":{"docs":{},"列":{"docs":{},"表":{"docs":{},"视":{"docs":{},"图":{"docs":{},"中":{"docs":{},"查":{"docs":{},"看":{"docs":{},"所":{"docs":{},"有":{"docs":{},"i":{"docs":{},"s":{"docs":{},"s":{"docs":{},"u":{"docs":{},"e":{"docs":{},",":{"docs":{},"也":{"docs":{},"可":{"docs":{},"以":{"docs":{},"查":{"docs":{},"看":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{},"所":{"docs":{},"有":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"请":{"docs":{},"求":{"docs":{},"合":{"docs":{},"并":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"d":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}},"c":{"docs":{},"l":{"docs":{},"o":{"docs":{},"u":{"docs":{},"d":{"docs":{},".":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"n":{"docs":{},"t":{"docs":{},"r":{"docs":{},"o":{"docs":{},"d":{"docs":{},"u":{"docs":{},"c":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"p":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.01206896551724138}}}},"p":{"docs":{},"o":{"docs":{},"p":{"docs":{},"u":{"docs":{},"p":{"docs":{},".":{"docs":{},".":{"docs":{},".":{"docs":{},".":{"docs":{},"\"":{"docs":{},")":{"docs":{},";":{"docs":{},"d":{"docs":{},"o":{"docs":{},"c":{"docs":{},"u":{"docs":{},"m":{"docs":{},"e":{"docs":{},"n":{"docs":{},"t":{"docs":{},".":{"docs":{},"o":{"docs":{},"n":{"docs":{},"c":{"docs":{},"l":{"docs":{},"i":{"docs":{},"c":{"docs":{},"k":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"d":{"docs":{},"f":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"i":{"docs":{},"c":{"docs":{},"k":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154}}}}},"r":{"docs":{},"e":{"docs":{},"m":{"docs":{},"i":{"docs":{},"u":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}}},"o":{"docs":{},"j":{"docs":{},"e":{"docs":{},"c":{"docs":{},"t":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}}}},"u":{"docs":{},"s":{"docs":{},"h":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"q":{"docs":{},"q":{"docs":{"./":{"ref":"./","tf":0.045454545454545456}}}},"r":{"docs":{},"e":{"docs":{},"s":{"docs":{},"e":{"docs":{},"r":{"docs":{},"v":{"docs":{},"e":{"docs":{},"d":{"docs":{},",":{"docs":{},"p":{"docs":{},"o":{"docs":{},"w":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"o":{"docs":{},"l":{"docs":{},"u":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"t":{"docs":{},"o":{"docs":{},"r":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"r":{"docs":{},"i":{"docs":{},"c":{"docs":{},"t":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}}}},"q":{"docs":{},"u":{"docs":{},"e":{"docs":{},"s":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}},"g":{"docs":{},"i":{"docs":{},"s":{"docs":{},"t":{"docs":{},"r":{"docs":{},"y":{"docs":{},"标":{"docs":{},"记":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"则":{"docs":{},"无":{"docs":{},"法":{"docs":{},"重":{"docs":{},"命":{"docs":{},"名":{"docs":{},"该":{"docs":{},"空":{"docs":{},"间":{"docs":{},",":{"docs":{},"因":{"docs":{},"为":{"docs":{},"该":{"docs":{},"项":{"docs":{},"目":{"docs":{},"无":{"docs":{},"法":{"docs":{},"移":{"docs":{},"动":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"m":{"docs":{},"o":{"docs":{},"v":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}},"i":{"docs":{},"g":{"docs":{},"h":{"docs":{},"t":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"o":{"docs":{},"a":{"docs":{},"d":{"docs":{},"m":{"docs":{},"a":{"docs":{},"p":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}},"u":{"docs":{},"l":{"docs":{},"e":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"s":{"docs":{},"t":{"docs":{},"a":{"docs":{},"b":{"docs":{},"l":{"docs":{},"e":{"docs":{},")":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}}}},"r":{"docs":{},"t":{"docs":{},"e":{"docs":{},"r":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"c":{"docs":{},"r":{"docs":{},"u":{"docs":{},"m":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"e":{"docs":{},"a":{"docs":{},"r":{"docs":{},"c":{"docs":{},"h":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"t":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"h":{"docs":{},"e":{"docs":{},"e":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"a":{"docs":{},"r":{"docs":{},"e":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"s":{"docs":{},"h":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"v":{"docs":{},"n":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154}}}},"i":{"docs":{},"l":{"docs":{},"v":{"docs":{},"e":{"docs":{},"r":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}},"或":{"docs":{},"更":{"docs":{},"高":{"docs":{},"级":{"docs":{},"别":{"docs":{},"上":{"docs":{},",":{"docs":{},"将":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"标":{"docs":{},"记":{"docs":{},"为":{"docs":{},"删":{"docs":{},"除":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"将":{"docs":{},"组":{"docs":{},"内":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},"配":{"docs":{},"置":{"docs":{},"为":{"docs":{},"在":{"docs":{},"延":{"docs":{},"迟":{"docs":{},"间":{"docs":{},"隔":{"docs":{},"后":{"docs":{},"删":{"docs":{},"除":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"w":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"a":{"docs":{},"t":{"docs":{"./":{"ref":"./","tf":0.045454545454545456}}}}}},"b":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"i":{"docs":{},"d":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"h":{"docs":{},"o":{"docs":{},"o":{"docs":{},"k":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"i":{"docs":{},"n":{"docs":{},"d":{"docs":{},"o":{"docs":{},"w":{"docs":{},".":{"docs":{},"o":{"docs":{},"p":{"docs":{},"e":{"docs":{},"n":{"docs":{},"(":{"docs":{},"e":{"docs":{},".":{"docs":{},"t":{"docs":{},"a":{"docs":{},"r":{"docs":{},"g":{"docs":{},"e":{"docs":{},"t":{"docs":{},".":{"docs":{},"s":{"docs":{},"r":{"docs":{},"c":{"docs":{},",":{"docs":{},"e":{"docs":{},".":{"docs":{},"t":{"docs":{},"a":{"docs":{},"r":{"docs":{},"g":{"docs":{},"e":{"docs":{},"t":{"docs":{},".":{"docs":{},"s":{"docs":{},"r":{"docs":{},"c":{"docs":{},")":{"docs":{},"}":{"docs":{},"i":{"docs":{},"m":{"docs":{},"g":{"docs":{},"{":{"docs":{},"c":{"docs":{},"u":{"docs":{},"r":{"docs":{},"s":{"docs":{},"o":{"docs":{},"r":{"docs":{},":":{"docs":{},"p":{"docs":{},"o":{"docs":{},"i":{"docs":{},"n":{"docs":{},"t":{"docs":{},"e":{"docs":{},"r":{"docs":{},"}":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"k":{"docs":{},"i":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154}}}}},"a":{"docs":{},"t":{"docs":{},"e":{"docs":{},"r":{"docs":{},"f":{"docs":{},"a":{"docs":{},"l":{"docs":{},"l":{"docs":{},",":{"docs":{},"敏":{"docs":{},"捷":{"docs":{},"还":{"docs":{},"是":{"docs":{},"会":{"docs":{},"话":{"docs":{},"开":{"docs":{},"发":{"docs":{},",":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"o":{"docs":{},"r":{"docs":{},"k":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154}},"f":{"docs":{},"l":{"docs":{},"o":{"docs":{},"w":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"©":{"docs":{"./":{"ref":"./","tf":0.022727272727272728},"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"产":{"docs":{},"品":{"docs":{},"提":{"docs":{},"交":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}},",":{"docs":{},"在":{"docs":{},"产":{"docs":{},"品":{"docs":{},"中":{"docs":{},"我":{"docs":{},"们":{"docs":{},"也":{"docs":{},"会":{"docs":{},"为":{"docs":{},"您":{"docs":{},"设":{"docs":{},"置":{"docs":{},"帮":{"docs":{},"助":{"docs":{},"提":{"docs":{},"示":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"随":{"docs":{},"时":{"docs":{},"回":{"docs":{},"来":{"docs":{},"查":{"docs":{},"看":{"docs":{},"我":{"docs":{},"们":{"docs":{},"的":{"docs":{},"产":{"docs":{},"品":{"docs":{},"文":{"docs":{},"档":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"体":{"docs":{},"验":{"docs":{},"使":{"docs":{},"用":{"docs":{},"过":{"docs":{},"程":{"docs":{},"中":{"docs":{},"如":{"docs":{},"果":{"docs":{},"遇":{"docs":{},"到":{"docs":{},"任":{"docs":{},"何":{"docs":{},"问":{"docs":{},"题":{"docs":{},",":{"docs":{},"请":{"docs":{},"与":{"docs":{},"我":{"docs":{},"们":{"docs":{},"联":{"docs":{},"系":{"docs":{},"。":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}}}}}}}}}}}}}}}}}}}}}}},"关":{"docs":{},"于":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}}}}}}}}}},"联":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"开":{"docs":{},"发":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"并":{"docs":{},",":{"docs":{},"目":{"docs":{},"前":{"docs":{},"版":{"docs":{},"本":{"docs":{},"提":{"docs":{},"供":{"docs":{},"了":{"docs":{},"代":{"docs":{},"码":{"docs":{},"仓":{"docs":{},"库":{"docs":{},"管":{"docs":{},"理":{"docs":{},"、":{"docs":{},"组":{"docs":{},"织":{"docs":{},"管":{"docs":{},"理":{"docs":{},"等":{"docs":{},"基":{"docs":{},"本":{"docs":{},"功":{"docs":{},"能":{"docs":{},",":{"docs":{},"欢":{"docs":{},"迎":{"docs":{},"体":{"docs":{},"验":{"docs":{},"使":{"docs":{},"用":{"docs":{},"。":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"人":{"docs":{},"员":{"docs":{},"和":{"docs":{},"维":{"docs":{},"护":{"docs":{},"人":{"docs":{},"员":{"docs":{},"可":{"docs":{},"以":{"docs":{},"在":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"下":{"docs":{},"创":{"docs":{},"建":{"docs":{},"项":{"docs":{},"目":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}},"始":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.005172413793103448}},"在":{"docs":{},"命":{"docs":{},"令":{"docs":{},"行":{"docs":{},"和":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}},"头":{"docs":{},"或":{"docs":{},"以":{"docs":{},"点":{"docs":{},"结":{"docs":{},"尾":{"docs":{},")":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"欢":{"docs":{},"迎":{"docs":{},"使":{"docs":{},"用":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},"代":{"docs":{},"码":{"docs":{},"托":{"docs":{},"管":{"docs":{},"平":{"docs":{},"台":{"docs":{},",":{"docs":{},"本":{"docs":{},"产":{"docs":{},"品":{"docs":{},"基":{"docs":{},"于":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}}}}}}}}}}}}}}}}}}}}}}},"您":{"docs":{},"使":{"docs":{},"用":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},",":{"docs":{},"如":{"docs":{},"果":{"docs":{},"您":{"docs":{},"是":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}},"点":{"docs":{},"此":{"docs":{},"向":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}},"击":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.006896551724137931}},"移":{"docs":{},"除":{"docs":{},"成":{"docs":{},"员":{"docs":{},"按":{"docs":{},"钮":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"版":{"docs":{},"本":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}},"历":{"docs":{},"史":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}},"联":{"docs":{},"系":{"docs":{},"我":{"docs":{},"们":{"docs":{"./":{"ref":"./","tf":0.022727272727272728}}}}}},"首":{"docs":{},"页":{"docs":{"./":{"ref":"./","tf":10}}}},"a":{"docs":{},"n":{"docs":{},"a":{"docs":{},"l":{"docs":{},"y":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}},"c":{"docs":{},"c":{"docs":{},"e":{"docs":{},"s":{"docs":{},"s":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"d":{"docs":{},"v":{"docs":{},"a":{"docs":{},"n":{"docs":{},"c":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"l":{"docs":{},"l":{"docs":{},"o":{"docs":{},"w":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"o":{"docs":{},"l":{"docs":{},".":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"p":{"docs":{},"i":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"b":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}},"a":{"docs":{},"s":{"docs":{},"i":{"docs":{},"c":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"u":{"docs":{},"r":{"docs":{},"n":{"docs":{},"d":{"docs":{},"o":{"docs":{},"w":{"docs":{},"n":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"d":{"docs":{},"e":{"docs":{},"v":{"docs":{},"o":{"docs":{},"p":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154}}}}},"l":{"docs":{},"a":{"docs":{},"y":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"i":{"docs":{},"s":{"docs":{},"a":{"docs":{},"b":{"docs":{},"l":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}}},"o":{"docs":{},"m":{"docs":{},"a":{"docs":{},"i":{"docs":{},"n":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"j":{"docs":{},"u":{"docs":{},"p":{"docs":{},"y":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}},"l":{"docs":{},"f":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"s":{"docs":{},",":{"2":{"docs":{},"f":{"docs":{},"a":{"docs":{},"\"":{"docs":{},"部":{"docs":{},"分":{"docs":{},",":{"docs":{},"然":{"docs":{},"后":{"docs":{},"选":{"docs":{},"中":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"择":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"docs":{}}}},"e":{"docs":{},"v":{"docs":{},"e":{"docs":{},"l":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"i":{"docs":{},"v":{"docs":{},"e":{"docs":{},".":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"o":{"docs":{},"c":{"docs":{},"k":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}},"m":{"docs":{},"a":{"docs":{},"r":{"docs":{},"k":{"docs":{},"d":{"docs":{},"o":{"docs":{},"w":{"docs":{},"n":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}},"e":{"docs":{},"r":{"docs":{},"g":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"m":{"docs":{},"b":{"docs":{},"e":{"docs":{},"r":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}},"n":{"docs":{},"t":{"docs":{},"i":{"docs":{},"o":{"docs":{},"n":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"i":{"docs":{},"y":{"docs":{},"k":{"docs":{},"a":{"docs":{},"e":{"docs":{},"l":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.006896551724137931}}}}}}}},"s":{"docs":{},"n":{"docs":{},".":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"n":{"docs":{},"o":{"docs":{},"t":{"docs":{},"e":{"docs":{},"b":{"docs":{},"o":{"docs":{},"o":{"docs":{},"k":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}},"i":{"docs":{},"f":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"o":{"docs":{},"v":{"docs":{},"e":{"docs":{},"r":{"docs":{},"v":{"docs":{},"i":{"docs":{},"e":{"docs":{},"w":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}},"u":{"docs":{},"t":{"docs":{},"l":{"docs":{},"o":{"docs":{},"o":{"docs":{},"k":{"docs":{},".":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"t":{"docs":{},"h":{"docs":{},"r":{"docs":{},"e":{"docs":{},"a":{"docs":{},"d":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"o":{"docs":{},"u":{"docs":{},"g":{"docs":{},"h":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}},"e":{"docs":{},"a":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.010344827586206896}},"/":{"docs":{},"b":{"docs":{},"a":{"docs":{},"c":{"docs":{},"k":{"docs":{},"e":{"docs":{},"n":{"docs":{},"d":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}}}}},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"i":{"docs":{},"n":{"docs":{},"g":{"docs":{},"下":{"docs":{},"访":{"docs":{},"问":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"f":{"docs":{},"r":{"docs":{},"o":{"docs":{},"n":{"docs":{},"t":{"docs":{},"e":{"docs":{},"n":{"docs":{},"d":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"p":{"docs":{},"r":{"docs":{},"o":{"docs":{},"d":{"docs":{},"u":{"docs":{},"c":{"docs":{},"t":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"下":{"docs":{},"访":{"docs":{},"问":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"创":{"docs":{},"建":{"docs":{},"了":{"docs":{},"子":{"docs":{},"组":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"和":{"docs":{},"p":{"docs":{},"r":{"docs":{},"o":{"docs":{},"d":{"docs":{},"u":{"docs":{},"c":{"docs":{},"t":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"您":{"docs":{},"很":{"docs":{},"高":{"docs":{},"兴":{"docs":{},"!":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"能":{"docs":{},"在":{"docs":{},"这":{"docs":{},"里":{"docs":{},"帮":{"docs":{},"助":{"docs":{},"我":{"docs":{},"们":{"docs":{},"吗":{"docs":{},"?":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"提":{"docs":{},"及":{"docs":{},"了":{"docs":{},"团":{"docs":{},"队":{"docs":{},"中":{"docs":{},"的":{"docs":{},"每":{"docs":{},"个":{"docs":{},"人":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"m":{"docs":{},"p":{"docs":{},"l":{"docs":{},"a":{"docs":{},"t":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}}}}},"上":{"docs":{},"工":{"docs":{},"作":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"使":{"docs":{},"用":{"docs":{},"用":{"docs":{},"户":{"docs":{},"名":{"docs":{},"m":{"docs":{},"i":{"docs":{},"y":{"docs":{},"k":{"docs":{},"a":{"docs":{},"e":{"docs":{},"l":{"docs":{},"创":{"docs":{},"建":{"docs":{},"了":{"docs":{},"一":{"docs":{},"个":{"docs":{},"帐":{"docs":{},"户":{"docs":{},";":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}},"下":{"docs":{},"载":{"docs":{},"描":{"docs":{},"述":{"docs":{},"最":{"docs":{},"常":{"docs":{},"用":{"docs":{},"的":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}},"划":{"docs":{},"线":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}},"与":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"与":{"docs":{},"组":{"docs":{},"织":{"docs":{},"共":{"docs":{},"享":{"docs":{},"项":{"docs":{},"目":{"docs":{},"类":{"docs":{},"似":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"与":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"织":{"docs":{},"共":{"docs":{},"享":{"docs":{},"另":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"织":{"docs":{},",":{"docs":{},"以":{"docs":{},"使":{"docs":{},"组":{"docs":{},"织":{"docs":{},"成":{"docs":{},"员":{"docs":{},"可":{"docs":{},"以":{"docs":{},"直":{"docs":{},"接":{"docs":{},"访":{"docs":{},"问":{"docs":{},"共":{"docs":{},"享":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"(":{"docs":{},"注":{"docs":{},":":{"docs":{},"这":{"docs":{},"对":{"docs":{},"于":{"docs":{},"继":{"docs":{},"承":{"docs":{},"的":{"docs":{},"成":{"docs":{},"员":{"docs":{},"无":{"docs":{},"效":{"docs":{},")":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"组":{"docs":{},"织":{"docs":{},"共":{"docs":{},"享":{"docs":{},"一":{"docs":{},"个":{"docs":{},"项":{"docs":{},"目":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"另":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}},"中":{"docs":{},"使":{"docs":{},"用":{"docs":{},"分":{"docs":{},"支":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"的":{"docs":{},"功":{"docs":{},"能":{"docs":{},"和":{"docs":{},"概":{"docs":{},"念":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}},"编":{"docs":{},"辑":{"docs":{},"文":{"docs":{},"件":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"引":{"docs":{},"入":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.010344827586206896}},"的":{"docs":{},"多":{"docs":{},"个":{"docs":{},"电":{"docs":{},"子":{"docs":{},"邮":{"docs":{},"件":{"docs":{},"域":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}},"文":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"移":{"docs":{},"至":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},",":{"docs":{},"命":{"docs":{},"名":{"docs":{},"空":{"docs":{},"间":{"docs":{},"将":{"docs":{},"会":{"docs":{},"是":{"docs":{},"用":{"docs":{},"户":{"docs":{},"名":{"docs":{},"称":{"docs":{},"、":{"docs":{},"组":{"docs":{},"织":{"docs":{},"名":{"docs":{},"称":{"docs":{},"或":{"docs":{},"子":{"docs":{},"组":{"docs":{},"名":{"docs":{},"的":{"docs":{},"唯":{"docs":{},"一":{"docs":{},"名":{"docs":{},"称":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"为":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},"开":{"docs":{},"源":{"docs":{},"做":{"docs":{},"贡":{"docs":{},"献":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}},"了":{"docs":{},"确":{"docs":{},"保":{"docs":{},"只":{"docs":{},"有":{"docs":{},"组":{"docs":{},"织":{"docs":{},"内":{"docs":{},"的":{"docs":{},"人":{"docs":{},"员":{"docs":{},"可":{"docs":{},"以":{"docs":{},"访":{"docs":{},"问":{"docs":{},"特":{"docs":{},"定":{"docs":{},"资":{"docs":{},"源":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"选":{"docs":{},"择":{"docs":{},"通":{"docs":{},"过":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}},"避":{"docs":{},"免":{"docs":{},"意":{"docs":{},"外":{"docs":{},"锁":{"docs":{},"定":{"docs":{},",":{"docs":{},"管":{"docs":{},"理":{"docs":{},"员":{"docs":{},"和":{"docs":{},"组":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"可":{"docs":{},"以":{"docs":{},"访":{"docs":{},"问":{"docs":{},"组":{"docs":{},",":{"docs":{},"而":{"docs":{},"不":{"docs":{},"受":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}},"他":{"docs":{},"们":{"docs":{},"的":{"docs":{},"团":{"docs":{},"队":{"docs":{},"创":{"docs":{},"建":{"docs":{},"了":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"织":{"docs":{},",":{"docs":{},"名":{"docs":{},"称":{"docs":{},"为":{"docs":{},"c":{"docs":{},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}},"组":{"docs":{},"织":{"docs":{},"添":{"docs":{},"加":{"docs":{},"一":{"docs":{},"个":{"docs":{},"用":{"docs":{},"户":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"主":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.016778523489932886}}}},"了":{"docs":{},"解":{"docs":{},"有":{"docs":{},"关":{"docs":{},"使":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"帐":{"docs":{},"户":{"docs":{},"管":{"docs":{},"理":{"docs":{},"的":{"docs":{},"更":{"docs":{},"多":{"docs":{},"信":{"docs":{},"息":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}},"组":{"docs":{},"级":{"docs":{},"项":{"docs":{},"目":{"docs":{},"模":{"docs":{},"板":{"docs":{},"的":{"docs":{},"更":{"docs":{},"多":{"docs":{},"信":{"docs":{},"息":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}},"项":{"docs":{},"目":{"docs":{},"中":{"docs":{},"的":{"docs":{},"每":{"docs":{},"个":{"docs":{},"角":{"docs":{},"色":{"docs":{},"可":{"docs":{},"以":{"docs":{},"做":{"docs":{},"什":{"docs":{},"么":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}},"如":{"docs":{},"何":{"docs":{},"将":{"docs":{},"项":{"docs":{},"目":{"docs":{},"转":{"docs":{},"移":{"docs":{},"到":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}},"从":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}},"s":{"docs":{},"v":{"docs":{},"n":{"docs":{},"迁":{"docs":{},"移":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}},"另":{"docs":{},"一":{"docs":{},"个":{"docs":{},"平":{"docs":{},"台":{"docs":{},"进":{"docs":{},"入":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"到":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"l":{"docs":{},"a":{"docs":{},"b":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"问":{"docs":{},"题":{"docs":{},"开":{"docs":{},"始":{"docs":{},"新":{"docs":{},"的":{"docs":{},"实":{"docs":{},"现":{"docs":{},"时":{"docs":{},",":{"docs":{},"请":{"docs":{},"添":{"docs":{},"加":{"docs":{},"评":{"docs":{},"论":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}},"代":{"docs":{},"办":{"docs":{},"事":{"docs":{},"项":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"码":{"docs":{},"仓":{"docs":{},"库":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.010067114093959731}}}}}},"以":{"docs":{},"下":{"docs":{},"文":{"docs":{},"档":{"docs":{},"与":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154}}}}},"是":{"docs":{},"我":{"docs":{},"们":{"docs":{},"推":{"docs":{},"荐":{"docs":{},"的":{"docs":{},"一":{"docs":{},"些":{"docs":{},"主":{"docs":{},"题":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}},"及":{"docs":{},"将":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"使":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"内":{"docs":{},"置":{"docs":{},"的":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"受":{"docs":{},"保":{"docs":{},"护":{"docs":{},"的":{"docs":{},"分":{"docs":{},"支":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}},"新":{"docs":{},"系":{"docs":{},"统":{"docs":{},"可":{"docs":{},"能":{"docs":{},"让":{"docs":{},"您":{"docs":{},"觉":{"docs":{},"得":{"docs":{},"难":{"docs":{},"以":{"docs":{},"入":{"docs":{},"手":{"docs":{},",":{"docs":{},"我":{"docs":{},"们":{"docs":{},"有":{"docs":{},"以":{"docs":{},"下":{"docs":{},"文":{"docs":{},"档":{"docs":{},"可":{"docs":{},"快":{"docs":{},"速":{"docs":{},"提":{"docs":{},"升":{"docs":{},"您":{"docs":{},"的":{"docs":{},"相":{"docs":{},"关":{"docs":{},"知":{"docs":{},"识":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"高":{"docs":{},"级":{"docs":{},"查":{"docs":{},"询":{"docs":{},"获":{"docs":{},"得":{"docs":{},"更":{"docs":{},"具":{"docs":{},"针":{"docs":{},"对":{"docs":{},"性":{"docs":{},"的":{"docs":{},"搜":{"docs":{},"索":{"docs":{},"结":{"docs":{},"果":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}},"组":{"docs":{},"锁":{"docs":{},"共":{"docs":{},"享":{"docs":{},"可":{"docs":{},"以":{"docs":{},"防":{"docs":{},"止":{"docs":{},"其":{"docs":{},"中":{"docs":{},"的":{"docs":{},"任":{"docs":{},"何":{"docs":{},"项":{"docs":{},"目":{"docs":{},"该":{"docs":{},"群":{"docs":{},"组":{"docs":{},"不":{"docs":{},"会":{"docs":{},"与":{"docs":{},"其":{"docs":{},"他":{"docs":{},"群":{"docs":{},"组":{"docs":{},"共":{"docs":{},"享":{"docs":{},",":{"docs":{},"从":{"docs":{},"而":{"docs":{},"确":{"docs":{},"保":{"docs":{},"只":{"docs":{},"有":{"docs":{},"合":{"docs":{},"适":{"docs":{},"的":{"docs":{},"群":{"docs":{},"组":{"docs":{},"成":{"docs":{},"员":{"docs":{},"才":{"docs":{},"能":{"docs":{},"访":{"docs":{},"问":{"docs":{},"这":{"docs":{},"些":{"docs":{},"项":{"docs":{},"目":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"定":{"docs":{},"共":{"docs":{},"享":{"docs":{},"\"":{"docs":{},"并":{"docs":{},"保":{"docs":{},"存":{"docs":{},"组":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"保":{"docs":{},"护":{"docs":{},"分":{"docs":{},"支":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"存":{"docs":{},"修":{"docs":{},"改":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}},"更":{"docs":{},"改":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.010344827586206896}}}}},"组":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"留":{"docs":{},"i":{"docs":{},"s":{"docs":{},"s":{"docs":{},"u":{"docs":{},"e":{"docs":{},"和":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"的":{"docs":{},"分":{"docs":{},"配":{"docs":{},"可":{"docs":{},"能":{"docs":{},"对":{"docs":{},"于":{"docs":{},"接":{"docs":{},"受":{"docs":{},"公":{"docs":{},"开":{"docs":{},"贡":{"docs":{},"献":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"很":{"docs":{},"有":{"docs":{},"帮":{"docs":{},"助":{"docs":{},",":{"docs":{},"用":{"docs":{},"户":{"docs":{},"可":{"docs":{},"以":{"docs":{},"不":{"docs":{},"必":{"docs":{},"是":{"docs":{},"组":{"docs":{},"织":{"docs":{},"成":{"docs":{},"员":{"docs":{},"就":{"docs":{},"可":{"docs":{},"以":{"docs":{},"为":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"做":{"docs":{},"贡":{"docs":{},"献":{"docs":{},"为":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},"开":{"docs":{},"源":{"docs":{},"贡":{"docs":{},"献":{"docs":{},"力":{"docs":{},"量":{"docs":{},"!":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}},"入":{"docs":{},"门":{"docs":{},",":{"docs":{},"分":{"docs":{},"支":{"docs":{},"策":{"docs":{},"略":{"docs":{},",":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}},"全":{"docs":{},"局":{"docs":{},"搜":{"docs":{},"索":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"具":{"docs":{},"有":{"docs":{},"两":{"docs":{},"因":{"docs":{},"素":{"docs":{},"身":{"docs":{},"份":{"docs":{},"验":{"docs":{},"证":{"docs":{},"的":{"docs":{},"帐":{"docs":{},"户":{"docs":{},"安":{"docs":{},"全":{"docs":{},"性":{"docs":{},",":{"docs":{},"设":{"docs":{},"置":{"docs":{},"您":{"docs":{},"的":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}},"分":{"docs":{},"支":{"docs":{},"和":{"docs":{},"默":{"docs":{},"认":{"docs":{},"分":{"docs":{},"支":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}},"析":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}},"类":{"docs":{},"问":{"docs":{},"题":{"docs":{},"或":{"docs":{},"使":{"docs":{},"用":{"docs":{},"描":{"docs":{},"述":{"docs":{},"性":{"docs":{},"标":{"docs":{},"签":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}},"组":{"docs":{},"组":{"docs":{},"织":{"docs":{},"您":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"刚":{"docs":{},"开":{"docs":{},"始":{"docs":{},"使":{"docs":{},"用":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"/":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},"/":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"l":{"docs":{},"a":{"docs":{},"b":{"docs":{},"/":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"h":{"docs":{},"u":{"docs":{},"b":{"docs":{},"?":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"创":{"docs":{},"建":{"docs":{},"主":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.010067114093959731}}}},"分":{"docs":{},"支":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},",":{"docs":{},"创":{"docs":{},"建":{"docs":{},"和":{"docs":{},"上":{"docs":{},"传":{"docs":{},"文":{"docs":{},"件":{"docs":{},"以":{"docs":{},"及":{"docs":{},"创":{"docs":{},"建":{"docs":{},"目":{"docs":{},"录":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}},"并":{"docs":{},"f":{"docs":{},"o":{"docs":{},"r":{"docs":{},"k":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"以":{"docs":{},"及":{"docs":{},"导":{"docs":{},"入":{"docs":{},"项":{"docs":{},"目":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}},"上":{"docs":{},"传":{"docs":{},"文":{"docs":{},"件":{"docs":{},",":{"docs":{},"并":{"docs":{},"创":{"docs":{},"建":{"docs":{},"目":{"docs":{},"录":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}},",":{"docs":{},"复":{"docs":{},"制":{"docs":{},"和":{"docs":{},"移":{"docs":{},"动":{"docs":{},"项":{"docs":{},"目":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"了":{"docs":{},"一":{"docs":{},"个":{"docs":{},"名":{"docs":{},"为":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"i":{"docs":{},"n":{"docs":{},"g":{"docs":{},"的":{"docs":{},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}},"组":{"docs":{},"织":{"docs":{},"后":{"docs":{},",":{"docs":{},"在":{"docs":{},"组":{"docs":{},"织":{"docs":{},"详":{"docs":{},"情":{"docs":{},"页":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"进":{"docs":{},"入":{"docs":{},"组":{"docs":{},"织":{"docs":{},"设":{"docs":{},"置":{"docs":{},"来":{"docs":{},"对":{"docs":{},"组":{"docs":{},"织":{"docs":{},"进":{"docs":{},"行":{"docs":{},"设":{"docs":{},"置":{"docs":{},"及":{"docs":{},"管":{"docs":{},"理":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"删":{"docs":{},"除":{"docs":{},"已":{"docs":{},"合":{"docs":{},"并":{"docs":{},"的":{"docs":{},"分":{"docs":{},"支":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}},"组":{"docs":{},"\"":{"docs":{},"按":{"docs":{},"钮":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"及":{"docs":{},"其":{"docs":{},"内":{"docs":{},"容":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},",":{"docs":{},"并":{"docs":{},"且":{"docs":{},"将":{"docs":{},"后":{"docs":{},"台":{"docs":{},"作":{"docs":{},"业":{"docs":{},"排":{"docs":{},"队":{"docs":{},"以":{"docs":{},"删":{"docs":{},"除":{"docs":{},"该":{"docs":{},"组":{"docs":{},"中":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"项":{"docs":{},"目":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}},"利":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"最":{"docs":{},"佳":{"docs":{},"的":{"docs":{},"工":{"docs":{},"作":{"docs":{},"流":{"docs":{},"程":{"docs":{},"增":{"docs":{},"强":{"docs":{},"您":{"docs":{},"的":{"docs":{},"工":{"docs":{},"作":{"docs":{},"流":{"docs":{},"程":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}},"协":{"docs":{},"议":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"可":{"docs":{},"视":{"docs":{},"化":{"docs":{},"史":{"docs":{},"诗":{"docs":{},"般":{"docs":{},"的":{"docs":{},"时":{"docs":{},"间":{"docs":{},"表":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}},"以":{"docs":{},"通":{"docs":{},"过":{"docs":{},"以":{"docs":{},"下":{"docs":{},"操":{"docs":{},"作":{"docs":{},"为":{"docs":{},"特":{"docs":{},"定":{"docs":{},"组":{"docs":{},"更":{"docs":{},"改":{"docs":{},"此":{"docs":{},"项":{"docs":{},"设":{"docs":{},"置":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"将":{"docs":{},"成":{"docs":{},"员":{"docs":{},"从":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{},"移":{"docs":{},"除":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"方":{"docs":{},"式":{"docs":{},"变":{"docs":{},"更":{"docs":{},"组":{"docs":{},"织":{"docs":{},"唯":{"docs":{},"一":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}},"合":{"docs":{},"并":{"docs":{},"更":{"docs":{},"改":{"docs":{},"后":{"docs":{},"的":{"docs":{},"批":{"docs":{},"量":{"docs":{},"删":{"docs":{},"除":{"docs":{},"分":{"docs":{},"支":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}},"请":{"docs":{},"求":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.010067114093959731}},"管":{"docs":{},"理":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}},"和":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.013422818791946308},"docs/033.html":{"ref":"docs/033.html","tf":0.005172413793103448}},"高":{"docs":{},"级":{"docs":{},"用":{"docs":{},"法":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"点":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"(":{"docs":{},"不":{"docs":{},"能":{"docs":{},"以":{"docs":{},"连":{"docs":{},"接":{"docs":{},"符":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"在":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154},"docs/033.html":{"ref":"docs/033.html","tf":0.015517241379310345}},"提":{"docs":{},"交":{"docs":{},"时":{"docs":{},"启":{"docs":{},"动":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}},"整":{"docs":{},"个":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"本":{"docs":{},"地":{"docs":{},"处":{"docs":{},"理":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"的":{"docs":{},"提":{"docs":{},"示":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}},"特":{"docs":{},"定":{"docs":{},"的":{"docs":{},"里":{"docs":{},"程":{"docs":{},"碑":{"docs":{},"中":{"docs":{},"观":{"docs":{},"察":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"进":{"docs":{},"度":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}},"网":{"docs":{},"页":{"docs":{},"中":{"docs":{},"管":{"docs":{},"理":{"docs":{},"源":{"docs":{},"代":{"docs":{},"码":{"docs":{},"仓":{"docs":{},"库":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}},"问":{"docs":{},"题":{"docs":{},"之":{"docs":{},"间":{"docs":{},"建":{"docs":{},"立":{"docs":{},"关":{"docs":{},"系":{"docs":{},".":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}},"\"":{"docs":{},"删":{"docs":{},"除":{"docs":{},"组":{"docs":{},"\"":{"docs":{},"部":{"docs":{},"分":{"docs":{},"中":{"docs":{},",":{"docs":{},"单":{"docs":{},"击":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"还":{"docs":{},"原":{"docs":{},"组":{"docs":{},"\"":{"docs":{},"部":{"docs":{},"分":{"docs":{},"中":{"docs":{},",":{"docs":{},"单":{"docs":{},"击":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"l":{"docs":{},"a":{"docs":{},"b":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}}}},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{},",":{"docs":{},"进":{"docs":{},"入":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"创":{"docs":{},"建":{"docs":{},"项":{"docs":{},"目":{"docs":{},"时":{"docs":{},",":{"docs":{},"从":{"docs":{},"下":{"docs":{},"拉":{"docs":{},"菜":{"docs":{},"单":{"docs":{},"中":{"docs":{},"选":{"docs":{},"择":{"docs":{},"已":{"docs":{},"经":{"docs":{},"创":{"docs":{},"建":{"docs":{},"的":{"docs":{},"组":{"docs":{},"名":{"docs":{},"称":{"docs":{},"空":{"docs":{},"间":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}},"小":{"docs":{},"组":{"docs":{},"的":{"docs":{},"侧":{"docs":{},"边":{"docs":{},"栏":{"docs":{},"上":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"此":{"docs":{},"间":{"docs":{},"隔":{"docs":{},"期":{"docs":{},"间":{"docs":{},",":{"docs":{},"项":{"docs":{},"目":{"docs":{},"将":{"docs":{},"处":{"docs":{},"于":{"docs":{},"只":{"docs":{},"读":{"docs":{},"状":{"docs":{},"态":{"docs":{},",":{"docs":{},"并":{"docs":{},"且":{"docs":{},"可":{"docs":{},"以":{"docs":{},"根":{"docs":{},"据":{"docs":{},"需":{"docs":{},"要":{"docs":{},"还":{"docs":{},"原":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{},"新":{"docs":{},"建":{"docs":{},"项":{"docs":{},"目":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"设":{"docs":{},"置":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}},"顶":{"docs":{},"部":{"docs":{},"菜":{"docs":{},"单":{"docs":{},"中":{"docs":{},",":{"docs":{},"依":{"docs":{},"次":{"docs":{},"单":{"docs":{},"击":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"默":{"docs":{},"认":{"docs":{},"分":{"docs":{},"支":{"docs":{},"保":{"docs":{},"护":{"docs":{},"下":{"docs":{},"拉":{"docs":{},"列":{"docs":{},"表":{"docs":{},"中":{"docs":{},"选":{"docs":{},"择":{"docs":{},"所":{"docs":{},"需":{"docs":{},"的":{"docs":{},"选":{"docs":{},"项":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}},"均":{"docs":{},"可":{"docs":{},"简":{"docs":{},"化":{"docs":{},"您":{"docs":{},"的":{"docs":{},"协":{"docs":{},"作":{"docs":{},"工":{"docs":{},"作":{"docs":{},"流":{"docs":{},"程":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}},"基":{"docs":{},"本":{"docs":{},"入":{"docs":{},"门":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"础":{"docs":{},"入":{"docs":{},"门":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"处":{"docs":{},"理":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"提":{"docs":{},"交":{"docs":{},",":{"docs":{},"并":{"docs":{},"使":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"如":{"docs":{},"何":{"docs":{},"在":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"开":{"docs":{},"发":{"docs":{},"上":{"docs":{},"做":{"docs":{},"贡":{"docs":{},"献":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}},"文":{"docs":{},"档":{"docs":{},"上":{"docs":{},"做":{"docs":{},"贡":{"docs":{},"献":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"果":{"docs":{},"您":{"docs":{},"是":{"docs":{},"从":{"docs":{},"另":{"docs":{},"一":{"docs":{},"个":{"docs":{},"平":{"docs":{},"台":{"docs":{},"进":{"docs":{},"入":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"成":{"docs":{},"员":{"docs":{},",":{"docs":{},"也":{"docs":{},"会":{"docs":{},"看":{"docs":{},"到":{"docs":{},"退":{"docs":{},"出":{"docs":{},"该":{"docs":{},"组":{"docs":{},"的":{"docs":{},"按":{"docs":{},"钮":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}},"具":{"docs":{},"有":{"docs":{},"足":{"docs":{},"够":{"docs":{},"的":{"docs":{},"权":{"docs":{},"限":{"docs":{},",":{"docs":{},"还":{"docs":{},"将":{"docs":{},"显":{"docs":{},"示":{"docs":{},"组":{"docs":{},"织":{"docs":{},"设":{"docs":{},"置":{"docs":{},"的":{"docs":{},"按":{"docs":{},"钮":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}},"在":{"docs":{},"申":{"docs":{},"请":{"docs":{},"权":{"docs":{},"限":{"docs":{},"被":{"docs":{},"批":{"docs":{},"准":{"docs":{},"之":{"docs":{},"前":{"docs":{},"改":{"docs":{},"变":{"docs":{},"了":{"docs":{},"主":{"docs":{},"意":{"docs":{},",":{"docs":{},"只":{"docs":{},"需":{"docs":{},"单":{"docs":{},"击":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}},"要":{"docs":{},"腾":{"docs":{},"出":{"docs":{},"路":{"docs":{},"径":{"docs":{},",":{"docs":{},"以":{"docs":{},"便":{"docs":{},"其":{"docs":{},"他":{"docs":{},"组":{"docs":{},"织":{"docs":{},"或":{"docs":{},"用":{"docs":{},"户":{"docs":{},"可":{"docs":{},"以":{"docs":{},"使":{"docs":{},"用":{"docs":{},"该":{"docs":{},"路":{"docs":{},"径":{"docs":{},",":{"docs":{},"由":{"docs":{},"于":{"docs":{},"名":{"docs":{},"称":{"docs":{},"和":{"docs":{},"路":{"docs":{},"径":{"docs":{},"都":{"docs":{},"必":{"docs":{},"须":{"docs":{},"是":{"docs":{},"唯":{"docs":{},"一":{"docs":{},"的":{"docs":{},",":{"docs":{},"因":{"docs":{},"此":{"docs":{},"您":{"docs":{},"在":{"docs":{},"变":{"docs":{},"更":{"docs":{},"路":{"docs":{},"径":{"docs":{},"的":{"docs":{},"同":{"docs":{},"时":{"docs":{},"也":{"docs":{},"可":{"docs":{},"能":{"docs":{},"需":{"docs":{},"要":{"docs":{},"重":{"docs":{},"命":{"docs":{},"名":{"docs":{},"该":{"docs":{},"组":{"docs":{},"织":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"将":{"docs":{},"要":{"docs":{},"转":{"docs":{},"移":{"docs":{},"的":{"docs":{},"父":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"公":{"docs":{},"开":{"docs":{},"可":{"docs":{},"见":{"docs":{},"性":{"docs":{},"设":{"docs":{},"置":{"docs":{},"低":{"docs":{},"于":{"docs":{},"当":{"docs":{},"前":{"docs":{},"父":{"docs":{},"组":{"docs":{},"织":{"docs":{},",":{"docs":{},"那":{"docs":{},"么":{"docs":{},"待":{"docs":{},"转":{"docs":{},"移":{"docs":{},"组":{"docs":{},"织":{"docs":{},"机":{"docs":{},"器":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"公":{"docs":{},"开":{"docs":{},"可":{"docs":{},"见":{"docs":{},"性":{"docs":{},"将":{"docs":{},"会":{"docs":{},"与":{"docs":{},"即":{"docs":{},"将":{"docs":{},"要":{"docs":{},"转":{"docs":{},"移":{"docs":{},"到":{"docs":{},"的":{"docs":{},"父":{"docs":{},"组":{"docs":{},"织":{"docs":{},"保":{"docs":{},"持":{"docs":{},"一":{"docs":{},"致":{"docs":{},";":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"成":{"docs":{},"员":{"docs":{},"资":{"docs":{},"格":{"docs":{},"是":{"docs":{},"从":{"docs":{},"父":{"docs":{},"组":{"docs":{},"继":{"docs":{},"承":{"docs":{},"的":{"docs":{},",":{"docs":{},"则":{"docs":{},"该":{"docs":{},"成":{"docs":{},"员":{"docs":{},"只":{"docs":{},"能":{"docs":{},"从":{"docs":{},"父":{"docs":{},"组":{"docs":{},"中":{"docs":{},"进":{"docs":{},"行":{"docs":{},"移":{"docs":{},"除":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"没":{"docs":{},"有":{"docs":{},"父":{"docs":{},"组":{"docs":{},"定":{"docs":{},"义":{"docs":{},"推":{"docs":{},"送":{"docs":{},"规":{"docs":{},"则":{"docs":{},",":{"docs":{},"则":{"docs":{},"在":{"docs":{},"实":{"docs":{},"例":{"docs":{},"级":{"docs":{},"别":{"docs":{},"设":{"docs":{},"置":{"docs":{},"推":{"docs":{},"送":{"docs":{},"规":{"docs":{},"则":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}},"组":{"docs":{},"织":{"docs":{},"启":{"docs":{},"用":{"docs":{},"了":{"docs":{},"该":{"docs":{},"设":{"docs":{},"置":{"docs":{},",":{"docs":{},"则":{"docs":{},"非":{"docs":{},"组":{"docs":{},"织":{"docs":{},"成":{"docs":{},"员":{"docs":{},"用":{"docs":{},"户":{"docs":{},"可":{"docs":{},"以":{"docs":{},"请":{"docs":{},"求":{"docs":{},"成":{"docs":{},"为":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"成":{"docs":{},"员":{"docs":{},"。":{"docs":{},"在":{"docs":{},"您":{"docs":{},"要":{"docs":{},"加":{"docs":{},"入":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"页":{"docs":{},"中":{"docs":{},",":{"docs":{},"单":{"docs":{},"击":{"docs":{},"组":{"docs":{},"织":{"docs":{},"名":{"docs":{},"称":{"docs":{},"后":{"docs":{},"面":{"docs":{},"的":{"docs":{},"申":{"docs":{},"请":{"docs":{},"权":{"docs":{},"限":{"docs":{},"按":{"docs":{},"钮":{"docs":{},"即":{"docs":{},"可":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"要":{"docs":{},"提":{"docs":{},"高":{"docs":{},"特":{"docs":{},"定":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"现":{"docs":{},"有":{"docs":{},"用":{"docs":{},"户":{"docs":{},"的":{"docs":{},"访":{"docs":{},"问":{"docs":{},"权":{"docs":{},"限":{"docs":{},",":{"docs":{},"请":{"docs":{},"将":{"docs":{},"其":{"docs":{},"作":{"docs":{},"为":{"docs":{},"新":{"docs":{},"成":{"docs":{},"员":{"docs":{},"再":{"docs":{},"次":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"特":{"docs":{},"定":{"docs":{},"项":{"docs":{},"目":{"docs":{},"中":{"docs":{},",":{"docs":{},"并":{"docs":{},"为":{"docs":{},"其":{"docs":{},"添":{"docs":{},"加":{"docs":{},"相":{"docs":{},"应":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},"成":{"docs":{},"员":{"docs":{},"角":{"docs":{},"色":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"移":{"docs":{},"除":{"docs":{},"的":{"docs":{},"成":{"docs":{},"员":{"docs":{},"在":{"docs":{},"该":{"docs":{},"组":{"docs":{},"中":{"docs":{},"具":{"docs":{},"有":{"docs":{},"直":{"docs":{},"接":{"docs":{},"成":{"docs":{},"员":{"docs":{},"资":{"docs":{},"格":{"docs":{},",":{"docs":{},"则":{"docs":{},"可":{"docs":{},"以":{"docs":{},"从":{"docs":{},"该":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{},"移":{"docs":{},"除":{"docs":{},"该":{"docs":{},"成":{"docs":{},"员":{"docs":{},";":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}},"中":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},"将":{"docs":{},"有":{"docs":{},"权":{"docs":{},"访":{"docs":{},"问":{"docs":{},"该":{"docs":{},"子":{"docs":{},"组":{"docs":{},"以":{"docs":{},"及":{"docs":{},"任":{"docs":{},"何":{"docs":{},"直":{"docs":{},"接":{"docs":{},"父":{"docs":{},"组":{"docs":{},"的":{"docs":{},"模":{"docs":{},"板":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}},"网":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"组":{"docs":{},"设":{"docs":{},"置":{"docs":{},"中":{"docs":{},",":{"docs":{},"并":{"docs":{},"且":{"docs":{},"来":{"docs":{},"自":{"docs":{},"其":{"docs":{},"他":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}},"存":{"docs":{},"储":{"docs":{},"库":{"docs":{},"转":{"docs":{},"换":{"docs":{},"为":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"随":{"docs":{},"附":{"docs":{},"分":{"docs":{},"支":{"docs":{},"工":{"docs":{},"具":{"docs":{},"和":{"docs":{},"访":{"docs":{},"问":{"docs":{},"控":{"docs":{},"制":{"docs":{},",":{"docs":{},"可":{"docs":{},"为":{"docs":{},"项":{"docs":{},"目":{"docs":{},"和":{"docs":{},"代":{"docs":{},"码":{"docs":{},"的":{"docs":{},"协":{"docs":{},"作":{"docs":{},"提":{"docs":{},"供":{"docs":{},"可":{"docs":{},"扩":{"docs":{},"展":{"docs":{},"的":{"docs":{},"单":{"docs":{},"一":{"docs":{},"事":{"docs":{},"实":{"docs":{},"来":{"docs":{},"源":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"实":{"docs":{},"例":{"docs":{},"上":{"docs":{},"进":{"docs":{},"行":{"docs":{},"更":{"docs":{},"快":{"docs":{},",":{"docs":{},"更":{"docs":{},"高":{"docs":{},"级":{"docs":{},"的":{"docs":{},"代":{"docs":{},"码":{"docs":{},"搜":{"docs":{},"索":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}},"之":{"docs":{},"间":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"密":{"docs":{},"钥":{"docs":{},",":{"docs":{},"并":{"docs":{},"部":{"docs":{},"署":{"docs":{},"密":{"docs":{},"钥":{"docs":{},"以":{"docs":{},"安":{"docs":{},"全":{"docs":{},"地":{"docs":{},"访":{"docs":{},"问":{"docs":{},"您":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}},"对":{"docs":{},".":{"docs":{},"i":{"docs":{},"p":{"docs":{},"y":{"docs":{},"n":{"docs":{},"b":{"docs":{},"文":{"docs":{},"件":{"docs":{},"的":{"docs":{},"支":{"docs":{},"持":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}},"您":{"docs":{},"的":{"docs":{},"提":{"docs":{},"交":{"docs":{},"进":{"docs":{},"行":{"docs":{},"签":{"docs":{},"名":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}},"更":{"docs":{},"改":{"docs":{},"进":{"docs":{},"行":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"项":{"docs":{},"目":{"docs":{},"推":{"docs":{},"送":{"docs":{},"的":{"docs":{},"附":{"docs":{},"加":{"docs":{},"控":{"docs":{},"制":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}},"导":{"docs":{},"入":{"docs":{},"项":{"docs":{},"目":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154}}}}},"航":{"docs":{},"到":{"docs":{},"您":{"docs":{},"小":{"docs":{},"组":{"docs":{},"的":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}},"组":{"docs":{},"的":{"docs":{},"\"":{"docs":{},"设":{"docs":{},"置":{"docs":{},"\"":{"docs":{},">":{"docs":{},"\"":{"docs":{},"常":{"docs":{},"规":{"docs":{},"\"":{"docs":{},"页":{"docs":{},"面":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.010344827586206896}}}}}}}}}}}}}}}}}}},"将":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"源":{"docs":{},"代":{"docs":{},"码":{"docs":{},"整":{"docs":{},"合":{"docs":{},"到":{"docs":{},"一":{"docs":{},"个":{"docs":{},"易":{"docs":{},"于":{"docs":{},"管":{"docs":{},"理":{"docs":{},"和":{"docs":{},"控":{"docs":{},"制":{"docs":{},"的":{"docs":{},"分":{"docs":{},"布":{"docs":{},"式":{"docs":{},"版":{"docs":{},"本":{"docs":{},"控":{"docs":{},"制":{"docs":{},"系":{"docs":{},"统":{"docs":{},"中":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}},"会":{"docs":{},"显":{"docs":{},"示":{"docs":{},"您":{"docs":{},"所":{"docs":{},"属":{"docs":{},"的":{"docs":{},"全":{"docs":{},"部":{"docs":{},"组":{"docs":{},"织":{"docs":{},"(":{"docs":{},"包":{"docs":{},"括":{"docs":{},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{},")":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}},"多":{"docs":{},"个":{"docs":{},"项":{"docs":{},"目":{"docs":{},"放":{"docs":{},"在":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{},"的":{"docs":{},"好":{"docs":{},"处":{"docs":{},"是":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"通":{"docs":{},"过":{"docs":{},"一":{"docs":{},"个":{"docs":{},"操":{"docs":{},"作":{"docs":{},"就":{"docs":{},"授":{"docs":{},"予":{"docs":{},"某":{"docs":{},"个":{"docs":{},"用":{"docs":{},"户":{"docs":{},"访":{"docs":{},"问":{"docs":{},"该":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{},"所":{"docs":{},"有":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"权":{"docs":{},"限":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{},"转":{"docs":{},"移":{"docs":{},"到":{"docs":{},"新":{"docs":{},"的":{"docs":{},"父":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"相":{"docs":{},"关":{"docs":{},"项":{"docs":{},"目":{"docs":{},"组":{"docs":{},"装":{"docs":{},"在":{"docs":{},"一":{"docs":{},"起":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"项":{"docs":{},"目":{"docs":{},"移":{"docs":{},"到":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"帮":{"docs":{},"助":{"docs":{},"文":{"docs":{},"档":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"快":{"docs":{},"捷":{"docs":{},"方":{"docs":{},"式":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"或":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}},"看":{"docs":{},"板":{"docs":{},"上":{"docs":{},"显":{"docs":{},"示":{"docs":{},"问":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}},"者":{"docs":{},",":{"docs":{},"在":{"docs":{},"顶":{"docs":{},"部":{"docs":{},"菜":{"docs":{},"单":{"docs":{},"中":{"docs":{},",":{"docs":{},"展":{"docs":{},"开":{"docs":{},"+":{"docs":{},"号":{"docs":{},"并":{"docs":{},"选":{"docs":{},"择":{"docs":{},"新":{"docs":{},"建":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"锁":{"docs":{},"定":{"docs":{},"共":{"docs":{},"享":{"docs":{},"与":{"docs":{},"组":{"docs":{},"功":{"docs":{},"能":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}},"截":{"docs":{},"止":{"docs":{},"日":{"docs":{},"期":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"托":{"docs":{},"管":{"docs":{},"源":{"docs":{},"代":{"docs":{},"码":{"docs":{},",":{"docs":{},"并":{"docs":{},"控":{"docs":{},"制":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"可":{"docs":{},"见":{"docs":{},"性":{"docs":{},"和":{"docs":{},"设":{"docs":{},"置":{"docs":{},"配":{"docs":{},"置":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}},"推":{"docs":{},"入":{"docs":{},"或":{"docs":{},"拉":{"docs":{},"出":{"docs":{},"外":{"docs":{},"部":{"docs":{},"的":{"docs":{},"代":{"docs":{},"码":{"docs":{},"仓":{"docs":{},"库":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}},"送":{"docs":{},"规":{"docs":{},"则":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"描":{"docs":{},"述":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.030201342281879196}}}},"提":{"docs":{},"交":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}},"示":{"docs":{},":":{"docs":{},"如":{"docs":{},"果":{"docs":{},"要":{"docs":{},"保":{"docs":{},"留":{"docs":{},"对":{"docs":{},"原":{"docs":{},"始":{"docs":{},"名":{"docs":{},"称":{"docs":{},"空":{"docs":{},"间":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"权":{"docs":{},"并":{"docs":{},"保":{"docs":{},"护":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}},"搜":{"docs":{},"索":{"docs":{},"问":{"docs":{},"题":{"docs":{},",":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},",":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"组":{"docs":{},"和":{"docs":{},"待":{"docs":{},"办":{"docs":{},"事":{"docs":{},"项":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}},"操":{"docs":{},"作":{"docs":{},"的":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"文":{"docs":{},"件":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.006711409395973154}},"模":{"docs":{},"板":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"管":{"docs":{},"理":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"档":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"新":{"docs":{},"建":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"阶":{"docs":{},"段":{"docs":{},"有":{"docs":{},"关":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"组":{"docs":{},"织":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"无":{"docs":{},"论":{"docs":{},"您":{"docs":{},"使":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}},"时":{"docs":{},"间":{"docs":{},"跟":{"docs":{},"踪":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"是":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"开":{"docs":{},"源":{"docs":{},"的":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"通":{"docs":{},"过":{"docs":{},"以":{"docs":{},"下":{"docs":{},"方":{"docs":{},"式":{"docs":{},"为":{"docs":{},"我":{"docs":{},"们":{"docs":{},"的":{"docs":{},"开":{"docs":{},"源":{"docs":{},"社":{"docs":{},"区":{"docs":{},"做":{"docs":{},"出":{"docs":{},"贡":{"docs":{},"献":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}},"否":{"docs":{},"公":{"docs":{},"开":{"docs":{},"可":{"docs":{},"见":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"来":{"docs":{},"管":{"docs":{},"理":{"docs":{},"您":{"docs":{},"的":{"docs":{},"文":{"docs":{},"档":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}},"标":{"docs":{},"签":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"检":{"docs":{},"查":{"docs":{},"每":{"docs":{},"月":{"docs":{},"创":{"docs":{},"建":{"docs":{},"了":{"docs":{},"多":{"docs":{},"少":{"docs":{},"个":{"docs":{},"问":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}},"概":{"docs":{},"览":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":10.003355704697986}}}},"此":{"docs":{},"外":{"docs":{},",":{"docs":{},"在":{"docs":{},"项":{"docs":{},"目":{"docs":{},"之":{"docs":{},"间":{"docs":{},"转":{"docs":{},"移":{"docs":{},"问":{"docs":{},"题":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}},"将":{"docs":{},"无":{"docs":{},"法":{"docs":{},"通":{"docs":{},"过":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"后":{"docs":{},",":{"docs":{},"将":{"docs":{},"对":{"docs":{},"所":{"docs":{},"有":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"组":{"docs":{},"中":{"docs":{},"的":{"docs":{},"新":{"docs":{},"用":{"docs":{},"户":{"docs":{},"启":{"docs":{},"用":{"docs":{},"域":{"docs":{},"检":{"docs":{},"查":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}},"操":{"docs":{},"作":{"docs":{},"要":{"docs":{},"么":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"灵":{"docs":{},"活":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},"管":{"docs":{},"理":{"docs":{},"工":{"docs":{},"具":{"docs":{},"可":{"docs":{},"视":{"docs":{},"化":{"docs":{},",":{"docs":{},"确":{"docs":{},"定":{"docs":{},"优":{"docs":{},"先":{"docs":{},"级":{"docs":{},",":{"docs":{},"协":{"docs":{},"调":{"docs":{},"和":{"docs":{},"跟":{"docs":{},"踪":{"docs":{},"进":{"docs":{},"度":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"热":{"docs":{},"门":{"docs":{},"话":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"用":{"docs":{},"户":{"docs":{},"文":{"docs":{},"件":{"docs":{},"熟":{"docs":{},"悉":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}},"权":{"docs":{},"限":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"账":{"docs":{},"号":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"的":{"docs":{},"初":{"docs":{},"级":{"docs":{},"用":{"docs":{},"户":{"docs":{},",":{"docs":{},"我":{"docs":{},"们":{"docs":{},"建":{"docs":{},"议":{"docs":{},"您":{"docs":{},"从":{"docs":{},"查":{"docs":{},"看":{"docs":{},"本":{"docs":{},"文":{"docs":{},"档":{"docs":{},"开":{"docs":{},"始":{"docs":{},"学":{"docs":{},"习":{"docs":{},"如":{"docs":{},"何":{"docs":{},"使":{"docs":{},"用":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}},"新":{"docs":{},"手":{"docs":{},"吗":{"docs":{},"?":{"docs":{},"我":{"docs":{},"们":{"docs":{},"有":{"docs":{},"资":{"docs":{},"源":{"docs":{},"可":{"docs":{},"以":{"docs":{},"帮":{"docs":{},"助":{"docs":{},"您":{"docs":{},"入":{"docs":{},"门":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}},"精":{"docs":{},"华":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"复":{"docs":{},"选":{"docs":{},"框":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"弹":{"docs":{},"窗":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"用":{"docs":{},"户":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"组":{"docs":{},"织":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"看":{"docs":{},"板":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"策":{"docs":{},"略":{"docs":{},"探":{"docs":{},"索":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"管":{"docs":{},"理":{"docs":{},"员":{"docs":{},"文":{"docs":{},"件":{"docs":{},"管":{"docs":{},"理":{"docs":{},"员":{"docs":{},"入":{"docs":{},"门":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"您":{"docs":{},"的":{"docs":{},"帐":{"docs":{},"户":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}},"道":{"docs":{},"配":{"docs":{},"额":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"组":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"织":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":10.001724137931035}},"\"":{"docs":{},"和":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"页":{"docs":{},"面":{"docs":{},"上":{"docs":{},"的":{"docs":{},"每":{"docs":{},"个":{"docs":{},"组":{"docs":{},"都":{"docs":{},"列":{"docs":{},"出":{"docs":{},"了":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}},"显":{"docs":{},"示":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"内":{"docs":{},"的":{"docs":{},"i":{"docs":{},"s":{"docs":{},"s":{"docs":{},"u":{"docs":{},"e":{"docs":{},"及":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"名":{"docs":{},"称":{"docs":{},"将":{"docs":{},"自":{"docs":{},"动":{"docs":{},"填":{"docs":{},"充":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"已":{"docs":{},"存":{"docs":{},"档":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"成":{"docs":{},"员":{"docs":{},"设":{"docs":{},"置":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"中":{"docs":{},"将":{"docs":{},"成":{"docs":{},"员":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"组":{"docs":{},"织":{"docs":{},",":{"docs":{},"可":{"docs":{},"以":{"docs":{},"通":{"docs":{},"过":{"docs":{},"用":{"docs":{},"户":{"docs":{},"名":{"docs":{},"或":{"docs":{},"者":{"docs":{},"注":{"docs":{},"册":{"docs":{},"邮":{"docs":{},"箱":{"docs":{},"来":{"docs":{},"添":{"docs":{},"加":{"docs":{},"组":{"docs":{},"织":{"docs":{},"成":{"docs":{},"员":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"选":{"docs":{},"项":{"docs":{},"卡":{"docs":{},";":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"页":{"docs":{},"面":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"上":{"docs":{},",":{"docs":{},"可":{"docs":{},"以":{"docs":{},"将":{"docs":{},"新":{"docs":{},"用":{"docs":{},"户":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{},";":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}},"用":{"docs":{},"户":{"docs":{},"示":{"docs":{},"例":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"的":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"基":{"docs":{},"本":{"docs":{},"信":{"docs":{},"息":{"docs":{},"和":{"docs":{},"介":{"docs":{},"绍":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"成":{"docs":{},"员":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"所":{"docs":{},"有":{"docs":{},"关":{"docs":{},"系":{"docs":{},"是":{"docs":{},"指":{"docs":{},"至":{"docs":{},"少":{"docs":{},"有":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"织":{"docs":{},"成":{"docs":{},"员":{"docs":{},"拥":{"docs":{},"有":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}},"项":{"docs":{},"目":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"设":{"docs":{},"置":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.006896551724137931}}}}},"与":{"docs":{},"k":{"docs":{},"u":{"docs":{},"b":{"docs":{},"e":{"docs":{},"r":{"docs":{},"n":{"docs":{},"e":{"docs":{},"t":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"之":{"docs":{},"间":{"docs":{},"共":{"docs":{},"享":{"docs":{},"项":{"docs":{},"目":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"也":{"docs":{},"可":{"docs":{},"以":{"docs":{},"嵌":{"docs":{},"套":{"docs":{},"在":{"docs":{},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}},"和":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}},"推":{"docs":{},"送":{"docs":{},"规":{"docs":{},"则":{"docs":{},"允":{"docs":{},"许":{"docs":{},"组":{"docs":{},"维":{"docs":{},"护":{"docs":{},"者":{"docs":{},"为":{"docs":{},"特":{"docs":{},"定":{"docs":{},"组":{"docs":{},"内":{"docs":{},"的":{"docs":{},"新":{"docs":{},"创":{"docs":{},"建":{"docs":{},"项":{"docs":{},"目":{"docs":{},"设":{"docs":{},"置":{"docs":{},"推":{"docs":{},"送":{"docs":{},"规":{"docs":{},"则":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"文":{"docs":{},"件":{"docs":{},"模":{"docs":{},"板":{"docs":{},"使":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"与":{"docs":{},"组":{"docs":{},"中":{"docs":{},"的":{"docs":{},"每":{"docs":{},"个":{"docs":{},"项":{"docs":{},"目":{"docs":{},"共":{"docs":{},"享":{"docs":{},"一":{"docs":{},"组":{"docs":{},"通":{"docs":{},"用":{"docs":{},"文":{"docs":{},"件":{"docs":{},"类":{"docs":{},"型":{"docs":{},"的":{"docs":{},"模":{"docs":{},"板":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"的":{"docs":{},"视":{"docs":{},"频":{"docs":{},"介":{"docs":{},"绍":{"docs":{},",":{"docs":{},"请":{"docs":{},"参":{"docs":{},"见":{"docs":{},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{},"l":{"docs":{},"a":{"docs":{},"b":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}},")":{"docs":{},"在":{"docs":{},"一":{"docs":{},"个":{"docs":{},"项":{"docs":{},"目":{"docs":{},"中":{"docs":{},"一":{"docs":{},"起":{"docs":{},"工":{"docs":{},"作":{"docs":{},",":{"docs":{},"并":{"docs":{},"且":{"docs":{},"要":{"docs":{},"继":{"docs":{},"承":{"docs":{},"该":{"docs":{},"组":{"docs":{},"成":{"docs":{},"员":{"docs":{},"身":{"docs":{},"份":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"在":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"结":{"docs":{},"合":{"docs":{},"使":{"docs":{},"用":{"docs":{},"的":{"docs":{},"更":{"docs":{},"多":{"docs":{},"信":{"docs":{},"息":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}},"署":{"docs":{},"名":{"docs":{},"提":{"docs":{},"交":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"草":{"docs":{},"稿":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}},"解":{"docs":{},"析":{"docs":{},"线":{"docs":{},"程":{"docs":{},",":{"docs":{},"将":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"中":{"docs":{},"的":{"docs":{},"线":{"docs":{},"程":{"docs":{},"移":{"docs":{},"至":{"docs":{},"问":{"docs":{},"题":{"docs":{},",":{"docs":{},"并":{"docs":{},"且":{"docs":{},"仅":{"docs":{},"在":{"docs":{},"解":{"docs":{},"决":{"docs":{},"所":{"docs":{},"有":{"docs":{},"线":{"docs":{},"程":{"docs":{},"后":{"docs":{},"才":{"docs":{},"允":{"docs":{},"许":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"计":{"docs":{},"划":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"主":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"阶":{"docs":{},"段":{"docs":{},"有":{"docs":{},"关":{"docs":{},":":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}},"讨":{"docs":{},"论":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}},"设":{"docs":{},"置":{"docs":{},"发":{"docs":{},"布":{"docs":{},"问":{"docs":{},"题":{"docs":{},"和":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"的":{"docs":{},"里":{"docs":{},"程":{"docs":{},"碑":{"docs":{},",":{"docs":{},"并":{"docs":{},"带":{"docs":{},"有":{"docs":{},"可":{"docs":{},"选":{"docs":{},"的":{"docs":{},"截":{"docs":{},"止":{"docs":{},"日":{"docs":{},"期":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}},">":{"docs":{},"常":{"docs":{},"规":{"docs":{},"页":{"docs":{},"面":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}}}},"后":{"docs":{},",":{"docs":{},"新":{"docs":{},"的":{"docs":{},"子":{"docs":{},"组":{"docs":{},"将":{"docs":{},"根":{"docs":{},"据":{"docs":{},"以":{"docs":{},"下":{"docs":{},"任":{"docs":{},"一":{"docs":{},"条":{"docs":{},"件":{"docs":{},"为":{"docs":{},"其":{"docs":{},"设":{"docs":{},"置":{"docs":{},"推":{"docs":{},"送":{"docs":{},"规":{"docs":{},"则":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}},"访":{"docs":{},"问":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},".":{"docs":{},"c":{"docs":{},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{},".":{"docs":{},"n":{"docs":{},"e":{"docs":{},"t":{"docs":{},"/":{"docs":{},"d":{"docs":{},"o":{"docs":{},"c":{"docs":{},"s":{"docs":{},",":{"docs":{},"以":{"docs":{},"获":{"docs":{},"得":{"docs":{},"优":{"docs":{},"化":{"docs":{},"的":{"docs":{},"导":{"docs":{},"航":{"docs":{},",":{"docs":{},"可":{"docs":{},"发":{"docs":{},"现":{"docs":{},"性":{"docs":{},"和":{"docs":{},"可":{"docs":{},"读":{"docs":{},"性":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"语":{"docs":{},"法":{"docs":{},"检":{"docs":{},"索":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"请":{"docs":{},"参":{"docs":{},"阅":{"docs":{},"小":{"docs":{},"组":{"docs":{},"贡":{"docs":{},"献":{"docs":{},"者":{"docs":{},"的":{"docs":{},"详":{"docs":{},"细":{"docs":{},"统":{"docs":{},"计":{"docs":{},"信":{"docs":{},"息":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}},"贡":{"docs":{},"献":{"docs":{},"者":{"docs":{},"许":{"docs":{},"可":{"docs":{},"协":{"docs":{},"议":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}},"账":{"docs":{},"号":{"docs":{},"验":{"docs":{},"证":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"户":{"docs":{},"管":{"docs":{},"理":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"跟":{"docs":{},"踪":{"docs":{},"共":{"docs":{},"享":{"docs":{},"主":{"docs":{},"题":{"docs":{},"的":{"docs":{},"问":{"docs":{},"题":{"docs":{},"组":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"发":{"docs":{},"行":{"docs":{},"期":{"docs":{},"限":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"花":{"docs":{},"费":{"docs":{},"在":{"docs":{},"问":{"docs":{},"题":{"docs":{},"和":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"上":{"docs":{},"的":{"docs":{},"时":{"docs":{},"间":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}},"返":{"docs":{},"回":{"docs":{},"概":{"docs":{},"览":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.030201342281879196}}}}}},"通":{"docs":{},"用":{"docs":{},"文":{"docs":{},"件":{"docs":{},"的":{"docs":{},"文":{"docs":{},"件":{"docs":{},"模":{"docs":{},"板":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"过":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}},"在":{"docs":{},"简":{"docs":{},"单":{"docs":{},"仪":{"docs":{},"表":{"docs":{},"板":{"docs":{},"上":{"docs":{},"显":{"docs":{},"示":{"docs":{},"的":{"docs":{},"时":{"docs":{},"间":{"docs":{},"顺":{"docs":{},"序":{"docs":{},"列":{"docs":{},"表":{"docs":{},",":{"docs":{},"跟":{"docs":{},"踪":{"docs":{},"需":{"docs":{},"要":{"docs":{},"注":{"docs":{},"意":{"docs":{},"的":{"docs":{},"工":{"docs":{},"作":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}},"同":{"docs":{},"一":{"docs":{},"名":{"docs":{},"称":{"docs":{},"空":{"docs":{},"间":{"docs":{},"下":{"docs":{},"组":{"docs":{},"织":{"docs":{},"相":{"docs":{},"关":{"docs":{},"项":{"docs":{},"目":{"docs":{},"并":{"docs":{},"将":{"docs":{},"成":{"docs":{},"员":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"顶":{"docs":{},"级":{"docs":{},"组":{"docs":{},",":{"docs":{},"可":{"docs":{},"以":{"docs":{},"以":{"docs":{},"较":{"docs":{},"少":{"docs":{},"的":{"docs":{},"步":{"docs":{},"骤":{"docs":{},"授":{"docs":{},"予":{"docs":{},"对":{"docs":{},"多":{"docs":{},"个":{"docs":{},"项":{"docs":{},"目":{"docs":{},"和":{"docs":{},"多":{"docs":{},"个":{"docs":{},"团":{"docs":{},"队":{"docs":{},"成":{"docs":{},"员":{"docs":{},"的":{"docs":{},"访":{"docs":{},"问":{"docs":{},"权":{"docs":{},"限":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"仅":{"docs":{},"将":{"docs":{},"具":{"docs":{},"有":{"docs":{},"特":{"docs":{},"定":{"docs":{},"域":{"docs":{},"中":{"docs":{},"电":{"docs":{},"子":{"docs":{},"邮":{"docs":{},"件":{"docs":{},"地":{"docs":{},"址":{"docs":{},"的":{"docs":{},"用":{"docs":{},"户":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"组":{"docs":{},"中":{"docs":{},",":{"docs":{},"可":{"docs":{},"以":{"docs":{},"限":{"docs":{},"制":{"docs":{},"对":{"docs":{},"组":{"docs":{},"的":{"docs":{},"访":{"docs":{},"问":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"以":{"docs":{},"下":{"docs":{},"方":{"docs":{},"式":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"创":{"docs":{},"建":{"docs":{},"一":{"docs":{},"个":{"docs":{},"新":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}},"创":{"docs":{},"建":{"docs":{},"小":{"docs":{},"组":{"docs":{},"并":{"docs":{},"包":{"docs":{},"括":{"docs":{},"适":{"docs":{},"当":{"docs":{},"的":{"docs":{},"成":{"docs":{},"员":{"docs":{},",":{"docs":{},"可":{"docs":{},"以":{"docs":{},"轻":{"docs":{},"松":{"docs":{},"地":{"docs":{},"@":{"docs":{},"m":{"docs":{},"e":{"docs":{},"n":{"docs":{},"t":{"docs":{},"i":{"docs":{},"o":{"docs":{},"n":{"docs":{},"所":{"docs":{},"有":{"docs":{},"团":{"docs":{},"队":{"docs":{},"中":{"docs":{},"的":{"docs":{},"问":{"docs":{},"题":{"docs":{},"并":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"单":{"docs":{},"击":{"docs":{},"顶":{"docs":{},"部":{"docs":{},"导":{"docs":{},"航":{"docs":{},"中":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},">":{"docs":{},"您":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"来":{"docs":{},"找":{"docs":{},"到":{"docs":{},"您":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}},"对":{"docs":{},"所":{"docs":{},"有":{"docs":{},"组":{"docs":{},"成":{"docs":{},"员":{"docs":{},"强":{"docs":{},"制":{"docs":{},"执":{"docs":{},"行":{"docs":{},"两":{"docs":{},"因":{"docs":{},"素":{"docs":{},"身":{"docs":{},"份":{"docs":{},"验":{"docs":{},"证":{"docs":{},"(":{"2":{"docs":{},"f":{"docs":{},"a":{"docs":{},")":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"docs":{}}}}}}}}}}}}}}}}}}},"将":{"docs":{},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{},"转":{"docs":{},"移":{"docs":{},"到":{"docs":{},"顶":{"docs":{},"级":{"docs":{},"组":{"docs":{},"织":{"docs":{},",":{"docs":{},"可":{"docs":{},"以":{"docs":{},"将":{"docs":{},"一":{"docs":{},"个":{"docs":{},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{},"转":{"docs":{},"换":{"docs":{},"为":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}},"组":{"docs":{},"设":{"docs":{},"置":{"docs":{},"为":{"docs":{},"模":{"docs":{},"板":{"docs":{},"源":{"docs":{},",":{"docs":{},"在":{"docs":{},"组":{"docs":{},"级":{"docs":{},"别":{"docs":{},"定":{"docs":{},"义":{"docs":{},"项":{"docs":{},"目":{"docs":{},"模":{"docs":{},"板":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}},"顶":{"docs":{},"级":{"docs":{},"组":{"docs":{},"织":{"docs":{},"转":{"docs":{},"移":{"docs":{},"到":{"docs":{},"所":{"docs":{},"需":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},",":{"docs":{},"并":{"docs":{},"将":{"docs":{},"其":{"docs":{},"转":{"docs":{},"换":{"docs":{},"为":{"docs":{},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}},"电":{"docs":{},"子":{"docs":{},"邮":{"docs":{},"件":{"docs":{},"将":{"docs":{},"您":{"docs":{},"的":{"docs":{},"申":{"docs":{},"请":{"docs":{},"告":{"docs":{},"知":{"docs":{},"给":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"(":{"docs":{},"电":{"docs":{},"子":{"docs":{},"邮":{"docs":{},"件":{"docs":{},"将":{"docs":{},"发":{"docs":{},"送":{"docs":{},"给":{"docs":{},"最":{"docs":{},"近":{"docs":{},"活":{"docs":{},"跃":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},")":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"限":{"docs":{},"制":{"docs":{},"成":{"docs":{},"员":{"docs":{},"身":{"docs":{},"份":{"docs":{},"\"":{"docs":{},"字":{"docs":{},"段":{"docs":{},"中":{"docs":{},"输":{"docs":{},"入":{"docs":{},"域":{"docs":{},"名":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}},"这":{"docs":{},"样":{"docs":{},"做":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"里":{"docs":{},"程":{"docs":{},"碑":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"针":{"docs":{},"对":{"docs":{},"问":{"docs":{},"题":{"docs":{},"或":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"的":{"docs":{},"常":{"docs":{},"见":{"docs":{},"操":{"docs":{},"作":{"docs":{},"的":{"docs":{},"快":{"docs":{},"捷":{"docs":{},"方":{"docs":{},"式":{"docs":{},",":{"docs":{},"而":{"docs":{},"无":{"docs":{},"需":{"docs":{},"单":{"docs":{},"击":{"docs":{},"按":{"docs":{},"钮":{"docs":{},"或":{"docs":{},"在":{"docs":{},"w":{"docs":{},"e":{"docs":{},"b":{"docs":{},"界":{"docs":{},"面":{"docs":{},"中":{"docs":{},"使":{"docs":{},"用":{"docs":{},"下":{"docs":{},"拉":{"docs":{},"菜":{"docs":{},"单":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"锁":{"docs":{},"定":{"docs":{},"文":{"docs":{},"件":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"以":{"docs":{},"避":{"docs":{},"免":{"docs":{},"合":{"docs":{},"并":{"docs":{},"冲":{"docs":{},"突":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}},"镜":{"docs":{},"像":{"docs":{},"代":{"docs":{},"码":{"docs":{},"仓":{"docs":{},"库":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}},"问":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},",":{"docs":{},"提":{"docs":{},"交":{"docs":{},"和":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"中":{"docs":{},"的":{"docs":{},"线":{"docs":{},"程":{"docs":{},",":{"docs":{},"注":{"docs":{},"释":{"docs":{},"和":{"docs":{},"可":{"docs":{},"解":{"docs":{},"决":{"docs":{},"线":{"docs":{},"程":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}},"防":{"docs":{},"止":{"docs":{},"合":{"docs":{},"并":{"docs":{},"草":{"docs":{},"稿":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"中":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},"与":{"docs":{},"另":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"共":{"docs":{},"享":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"以":{"docs":{},"便":{"docs":{},"对":{"docs":{},"项":{"docs":{},"目":{"docs":{},"访":{"docs":{},"问":{"docs":{},"进":{"docs":{},"行":{"docs":{},"更":{"docs":{},"严":{"docs":{},"格":{"docs":{},"的":{"docs":{},"控":{"docs":{},"制":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"项":{"docs":{},"目":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"和":{"docs":{},"组":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}},"织":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}},"问":{"docs":{},"题":{"docs":{},"并":{"docs":{},"限":{"docs":{},"制":{"docs":{},"对":{"docs":{},"问":{"docs":{},"题":{"docs":{},"的":{"docs":{},"访":{"docs":{},"问":{"docs":{},",":{"docs":{},"并":{"docs":{},"创":{"docs":{},"建":{"docs":{},"用":{"docs":{},"于":{"docs":{},"提":{"docs":{},"交":{"docs":{},"新":{"docs":{},"问":{"docs":{},"题":{"docs":{},"和":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"的":{"docs":{},"模":{"docs":{},"板":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"创":{"docs":{},"建":{"docs":{},"权":{"docs":{},"限":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"高":{"docs":{},"级":{"docs":{},"格":{"docs":{},"式":{"docs":{},"化":{"docs":{},"系":{"docs":{},"统":{"docs":{},"(":{"docs":{},"m":{"docs":{},"a":{"docs":{},"r":{"docs":{},"k":{"docs":{},"d":{"docs":{},"o":{"docs":{},"w":{"docs":{},"n":{"docs":{},")":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}}}}}}},",":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577},"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"包":{"docs":{},"括":{"docs":{},"机":{"docs":{},"密":{"docs":{},"问":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}},"项":{"docs":{},"目":{"docs":{},"访":{"docs":{},"问":{"docs":{},"和":{"docs":{},"设":{"docs":{},"置":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}},"发":{"docs":{},"布":{"docs":{},"和":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"模":{"docs":{},"板":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}},"和":{"docs":{},"移":{"docs":{},"动":{"docs":{},"的":{"docs":{},"问":{"docs":{},"题":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}},"而":{"docs":{},"不":{"docs":{},"会":{"docs":{},"中":{"docs":{},"断":{"docs":{},"您":{"docs":{},"的":{"docs":{},"工":{"docs":{},"作":{"docs":{},"流":{"docs":{},"程":{"docs":{},"。":{"docs":{"docs/002.html":{"ref":"docs/002.html","tf":0.003355704697986577}}}}}}}}}}}}}},"g":{"docs":{},"i":{"docs":{},"t":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"可":{"docs":{},"以":{"docs":{},"访":{"docs":{},"问":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"在":{"docs":{},"p":{"docs":{},"r":{"docs":{},"e":{"docs":{},"m":{"docs":{},"i":{"docs":{},"u":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"它":{"docs":{},"已":{"docs":{},"经":{"docs":{},"完":{"docs":{},"成":{"docs":{},"!":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"将":{"docs":{},"安":{"docs":{},"全":{"docs":{},"层":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"您":{"docs":{},"的":{"docs":{},"组":{"docs":{},"中":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"并":{"docs":{},"且":{"docs":{},"在":{"docs":{},"该":{"docs":{},"组":{"docs":{},"中":{"docs":{},"为":{"docs":{},"各":{"docs":{},"个":{"docs":{},"团":{"docs":{},"队":{"docs":{},"b":{"docs":{},"a":{"docs":{},"c":{"docs":{},"k":{"docs":{},"e":{"docs":{},"n":{"docs":{},"d":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}},"为":{"docs":{},"每":{"docs":{},"个":{"docs":{},"单":{"docs":{},"独":{"docs":{},"的":{"docs":{},"团":{"docs":{},"队":{"docs":{},"创":{"docs":{},"建":{"docs":{},"一":{"docs":{},"个":{"docs":{},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}},"然":{"docs":{},"后":{"docs":{},"单":{"docs":{},"击":{"docs":{},"绿":{"docs":{},"色":{"docs":{},"按":{"docs":{},"钮":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"添":{"docs":{},"加":{"docs":{},"新":{"docs":{},"成":{"docs":{},"员":{"docs":{},"。":{"docs":{},"您":{"docs":{},"还":{"docs":{},"可":{"docs":{},"以":{"docs":{},"设":{"docs":{},"置":{"docs":{},"该":{"docs":{},"用":{"docs":{},"户":{"docs":{},"的":{"docs":{},"到":{"docs":{},"期":{"docs":{},"日":{"docs":{},"期":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}},"让":{"docs":{},"我":{"docs":{},"们":{"docs":{},"开":{"docs":{},"始":{"docs":{},"吧":{"docs":{},"!":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.039655172413793106}}},";":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"@":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{},"p":{"docs":{},"a":{"docs":{},"n":{"docs":{},"i":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.006896551724137931}}}}}}}}}},"h":{"docs":{},"o":{"docs":{},"t":{"docs":{},"m":{"docs":{},"a":{"docs":{},"i":{"docs":{},"l":{"docs":{},".":{"docs":{},"c":{"docs":{},"o":{"docs":{},".":{"docs":{},"u":{"docs":{},"k":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"f":{"docs":{},"r":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"t":{"docs":{},"t":{"docs":{},"p":{"docs":{},"s":{"docs":{},":":{"docs":{},"/":{"docs":{},"/":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},".":{"docs":{},"c":{"docs":{},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{},".":{"docs":{},"n":{"docs":{},"e":{"docs":{},"t":{"docs":{},"/":{"docs":{},"g":{"docs":{},"r":{"docs":{},"o":{"docs":{},"u":{"docs":{},"p":{"docs":{},"n":{"docs":{},"a":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"e":{"docs":{},"/":{"docs":{},"s":{"docs":{},"u":{"docs":{},"b":{"docs":{},"g":{"docs":{},"r":{"docs":{},"o":{"docs":{},"u":{"docs":{},"p":{"docs":{},"_":{"docs":{},"n":{"docs":{},"a":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}},"u":{"docs":{},"s":{"docs":{},"e":{"docs":{},"r":{"docs":{},"n":{"docs":{},"a":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"k":{"docs":{},"u":{"docs":{},"b":{"docs":{},"e":{"docs":{},"r":{"docs":{},"n":{"docs":{},"e":{"docs":{},"t":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"u":{"docs":{},"i":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"l":{"docs":{},"t":{"docs":{},"i":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"r":{"docs":{},"l":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"是":{"docs":{},"将":{"docs":{},"托":{"docs":{},"管":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"名":{"docs":{},"称":{"docs":{},"空":{"docs":{},"间":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"(":{"docs":{},"自":{"docs":{},"动":{"docs":{},"填":{"docs":{},"充":{"docs":{},"不":{"docs":{},"支":{"docs":{},"持":{"docs":{},"中":{"docs":{},"文":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"名":{"docs":{},"称":{"docs":{},")":{"docs":{},"。":{"docs":{},"(":{"docs":{},"可":{"docs":{},"选":{"docs":{},")":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"修":{"docs":{},"改":{"docs":{},"它":{"docs":{},",":{"docs":{},"这":{"docs":{},"是":{"docs":{},"在":{"docs":{},"组":{"docs":{},"视":{"docs":{},"图":{"docs":{},"中":{"docs":{},"显":{"docs":{},"示":{"docs":{},"的":{"docs":{},"名":{"docs":{},"称":{"docs":{},",":{"docs":{},"该":{"docs":{},"名":{"docs":{},"称":{"docs":{},"只":{"docs":{},"能":{"docs":{},"包":{"docs":{},"含":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"y":{"docs":{},"a":{"docs":{},"h":{"docs":{},"o":{"docs":{},"o":{"docs":{},".":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.006896551724137931}}},"他":{"docs":{},"们":{"docs":{},"的":{"docs":{},"个":{"docs":{},"人":{"docs":{},"资":{"docs":{},"料":{"docs":{},"将":{"docs":{},"在":{"docs":{},"h":{"docs":{},"t":{"docs":{},"t":{"docs":{},"p":{"docs":{},"s":{"docs":{},":":{"docs":{},"/":{"docs":{},"/":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},".":{"docs":{},"c":{"docs":{},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{},".":{"docs":{},"n":{"docs":{},"e":{"docs":{},"t":{"docs":{},"/":{"docs":{},"m":{"docs":{},"i":{"docs":{},"y":{"docs":{},"k":{"docs":{},"a":{"docs":{},"e":{"docs":{},"l":{"docs":{},"下":{"docs":{},"访":{"docs":{},"问":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"任":{"docs":{},"何":{"docs":{},"团":{"docs":{},"队":{"docs":{},"成":{"docs":{},"员":{"docs":{},"都":{"docs":{},"使":{"docs":{},"用":{"docs":{},"@":{"docs":{},"m":{"docs":{},"i":{"docs":{},"y":{"docs":{},"k":{"docs":{},"a":{"docs":{},"e":{"docs":{},"l":{"docs":{},"提":{"docs":{},"及":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}},"组":{"docs":{},"织":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"都":{"docs":{},"可":{"docs":{},"以":{"docs":{},"在":{"docs":{},"组":{"docs":{},"组":{"docs":{},"织":{"docs":{},"成":{"docs":{},"员":{"docs":{},"设":{"docs":{},"置":{"docs":{},"页":{"docs":{},"面":{"docs":{},"上":{"docs":{},"批":{"docs":{},"准":{"docs":{},"或":{"docs":{},"拒":{"docs":{},"绝":{"docs":{},"您":{"docs":{},"的":{"docs":{},"申":{"docs":{},"请":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"作":{"docs":{},"为":{"docs":{},"组":{"docs":{},"织":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"启":{"docs":{},"用":{"docs":{},"或":{"docs":{},"禁":{"docs":{},"用":{"docs":{},"非":{"docs":{},"组":{"docs":{},"织":{"docs":{},"成":{"docs":{},"员":{"docs":{},"请":{"docs":{},"求":{"docs":{},"访":{"docs":{},"问":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"功":{"docs":{},"能":{"docs":{},"。":{"docs":{},"该":{"docs":{},"功":{"docs":{},"能":{"docs":{},"可":{"docs":{},"以":{"docs":{},"通":{"docs":{},"过":{"docs":{},"再":{"docs":{},"组":{"docs":{},"织":{"docs":{},"设":{"docs":{},"置":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"例":{"docs":{},"如":{"docs":{},",":{"docs":{},"假":{"docs":{},"设":{"docs":{},"您":{"docs":{},"有":{"docs":{},"两":{"docs":{},"个":{"docs":{},"不":{"docs":{},"同":{"docs":{},"的":{"docs":{},"团":{"docs":{},"队":{"docs":{},"(":{"docs":{},"a":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"有":{"docs":{},"一":{"docs":{},"个":{"docs":{},"名":{"docs":{},"为":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"如":{"docs":{},"果":{"docs":{},"要":{"docs":{},"为":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"为":{"docs":{},"公":{"docs":{},"司":{"docs":{},"成":{"docs":{},"员":{"docs":{},"创":{"docs":{},"建":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}},"假":{"docs":{},"设":{"docs":{},"一":{"docs":{},"个":{"docs":{},"有":{"docs":{},"两":{"docs":{},"个":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"您":{"docs":{},"创":{"docs":{},"建":{"docs":{},"了":{"docs":{},"一":{"docs":{},"个":{"docs":{},"名":{"docs":{},"为":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{},"p":{"docs":{},"a":{"docs":{},"n":{"docs":{},"i":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}},"允":{"docs":{},"许":{"docs":{},"创":{"docs":{},"建":{"docs":{},"项":{"docs":{},"目":{"docs":{},"下":{"docs":{},"拉":{"docs":{},"列":{"docs":{},"表":{"docs":{},"中":{"docs":{},"选":{"docs":{},"择":{"docs":{},"所":{"docs":{},"需":{"docs":{},"的":{"docs":{},"选":{"docs":{},"项":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}},"访":{"docs":{},"问":{"docs":{},"以":{"docs":{},"下":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"前":{"docs":{},"往":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"端":{"docs":{},"团":{"docs":{},"队":{"docs":{},"完":{"docs":{},"成":{"docs":{},"实":{"docs":{},"施":{"docs":{},"后":{"docs":{},",":{"docs":{},"他":{"docs":{},"们":{"docs":{},"会":{"docs":{},"评":{"docs":{},"论":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}},"单":{"docs":{},"击":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"及":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"做":{"docs":{},"出":{"docs":{},"贡":{"docs":{},"献":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"重":{"docs":{},"新":{"docs":{},"进":{"docs":{},"行":{"docs":{},"分":{"docs":{},"配":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"取":{"docs":{},"消":{"docs":{},"分":{"docs":{},"配":{"docs":{},"给":{"docs":{},"已":{"docs":{},"移":{"docs":{},"除":{"docs":{},"的":{"docs":{},"成":{"docs":{},"员":{"docs":{},"的":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}}}}}}}}}},"变":{"docs":{},"更":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"路":{"docs":{},"径":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"也":{"docs":{},"可":{"docs":{},"能":{"docs":{},"会":{"docs":{},"产":{"docs":{},"生":{"docs":{},"一":{"docs":{},"些":{"docs":{},"副":{"docs":{},"作":{"docs":{},"用":{"docs":{},",":{"docs":{},"具":{"docs":{},"体":{"docs":{},"的":{"docs":{},"请":{"docs":{},"参":{"docs":{},"考":{"docs":{},"重":{"docs":{},"定":{"docs":{},"向":{"docs":{},"的":{"docs":{},"行":{"docs":{},"为":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}},"默":{"docs":{},"认":{"docs":{},"保":{"docs":{},"护":{"docs":{},"分":{"docs":{},"支":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"路":{"docs":{},"径":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"只":{"docs":{},"有":{"docs":{},"拥":{"docs":{},"有":{"docs":{},"一":{"docs":{},"个":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"可":{"docs":{},"以":{"docs":{},"变":{"docs":{},"更":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"权":{"docs":{},"限":{"docs":{},"的":{"docs":{},"用":{"docs":{},"户":{"docs":{},"才":{"docs":{},"能":{"docs":{},"管":{"docs":{},"理":{"docs":{},"组":{"docs":{},"织":{"docs":{},"成":{"docs":{},"员":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}},"向":{"docs":{},"项":{"docs":{},"目":{"docs":{},"添":{"docs":{},"加":{"docs":{},"新":{"docs":{},"用":{"docs":{},"户":{"docs":{},"的":{"docs":{},"任":{"docs":{},"何":{"docs":{},"请":{"docs":{},"求":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}},"启":{"docs":{},"用":{"docs":{},"延":{"docs":{},"迟":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},"删":{"docs":{},"除":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}},"命":{"docs":{},"名":{"docs":{},"空":{"docs":{},"间":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"地":{"docs":{},"址":{"docs":{},"\"":{"docs":{},"字":{"docs":{},"段":{"docs":{},"中":{"docs":{},"输":{"docs":{},"入":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"的":{"docs":{},"任":{"docs":{},"何":{"docs":{},"人":{"docs":{},"将":{"docs":{},"无":{"docs":{},"法":{"docs":{},"访":{"docs":{},"问":{"docs":{},"受":{"docs":{},"限":{"docs":{},"制":{"docs":{},"的":{"docs":{},"内":{"docs":{},"容":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}},"范":{"docs":{},"围":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"限":{"docs":{},"制":{"docs":{},"对":{"docs":{},"组":{"docs":{},"及":{"docs":{},"其":{"docs":{},"基":{"docs":{},"础":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"问":{"docs":{},"题":{"docs":{},"等":{"docs":{},"的":{"docs":{},"访":{"docs":{},"问":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}},"大":{"docs":{},"学":{"docs":{},":":{"docs":{},"存":{"docs":{},"储":{"docs":{},"库":{"docs":{},",":{"docs":{},"项":{"docs":{},"目":{"docs":{},"和":{"docs":{},"组":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"天":{"docs":{},"后":{"docs":{},"进":{"docs":{},"行":{"docs":{},",":{"docs":{},"但":{"docs":{},"是":{"docs":{},"可":{"docs":{},"以":{"docs":{},"在":{"docs":{},"实":{"docs":{},"例":{"docs":{},"设":{"docs":{},"置":{"docs":{},"中":{"docs":{},"进":{"docs":{},"行":{"docs":{},"更":{"docs":{},"改":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}},",":{"docs":{},"可":{"docs":{},"以":{"docs":{},"由":{"docs":{},"管":{"docs":{},"理":{"docs":{},"员":{"docs":{},"在":{"docs":{},"实":{"docs":{},"例":{"docs":{},"设":{"docs":{},"置":{"docs":{},"中":{"docs":{},"进":{"docs":{},"行":{"docs":{},"修":{"docs":{},"改":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}},"字":{"docs":{},"母":{"docs":{},"数":{"docs":{},"字":{"docs":{},"字":{"docs":{},"符":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}}}},"它":{"docs":{},"包":{"docs":{},"含":{"docs":{},"多":{"docs":{},"少":{"docs":{},"个":{"docs":{},"项":{"docs":{},"目":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"有":{"docs":{},"多":{"docs":{},"少":{"docs":{},"个":{"docs":{},"子":{"docs":{},"组":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"类":{"docs":{},"似":{"docs":{},"于":{"docs":{},"实":{"docs":{},"例":{"docs":{},"模":{"docs":{},"板":{"docs":{},"存":{"docs":{},"储":{"docs":{},"库":{"docs":{},"功":{"docs":{},"能":{"docs":{},",":{"docs":{},"所":{"docs":{},"选":{"docs":{},"项":{"docs":{},"目":{"docs":{},"应":{"docs":{},"遵":{"docs":{},"循":{"docs":{},"该":{"docs":{},"页":{"docs":{},"面":{"docs":{},"上":{"docs":{},"记":{"docs":{},"录":{"docs":{},"的":{"docs":{},"相":{"docs":{},"同":{"docs":{},"命":{"docs":{},"名":{"docs":{},"约":{"docs":{},"定":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"定":{"docs":{},"义":{"docs":{},"了":{"docs":{},"推":{"docs":{},"送":{"docs":{},"规":{"docs":{},"则":{"docs":{},"的":{"docs":{},"最":{"docs":{},"接":{"docs":{},"近":{"docs":{},"的":{"docs":{},"父":{"docs":{},"组":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}},"审":{"docs":{},"核":{"docs":{},"事":{"docs":{},"件":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"\"":{"docs":{},"锁":{"docs":{},"定":{"docs":{},"组":{"docs":{},",":{"docs":{},"请":{"docs":{},"启":{"docs":{},"用":{"docs":{},"\"":{"docs":{},"成":{"docs":{},"员":{"docs":{},"锁":{"docs":{},"定":{"docs":{},"\"":{"docs":{},"以":{"docs":{},"确":{"docs":{},"保":{"docs":{},"在":{"docs":{},"该":{"docs":{},"审":{"docs":{},"核":{"docs":{},"期":{"docs":{},"间":{"docs":{},"不":{"docs":{},"能":{"docs":{},"修":{"docs":{},"改":{"docs":{},"项":{"docs":{},"目":{"docs":{},"成":{"docs":{},"员":{"docs":{},"身":{"docs":{},"份":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"展":{"docs":{},"开":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.008620689655172414}}},"权":{"docs":{},"限":{"docs":{},",":{"docs":{},"l":{"docs":{},"f":{"docs":{},"s":{"docs":{},",":{"2":{"docs":{},"f":{"docs":{},"a":{"docs":{},"部":{"docs":{},"分":{"docs":{},",":{"docs":{},"然":{"docs":{},"后":{"docs":{},"选":{"docs":{},"择":{"docs":{},"禁":{"docs":{},"用":{"docs":{},"电":{"docs":{},"子":{"docs":{},"邮":{"docs":{},"件":{"docs":{},"通":{"docs":{},"知":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}},"docs":{}}}}}}}},"路":{"docs":{},"径":{"docs":{},",":{"docs":{},"传":{"docs":{},"输":{"docs":{},",":{"docs":{},"删":{"docs":{},"除":{"docs":{},"部":{"docs":{},"分":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}}}}}}}}}},"高":{"docs":{},"级":{"docs":{},"部":{"docs":{},"分":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"常":{"docs":{},"规":{"docs":{},"设":{"docs":{},"置":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}},"页":{"docs":{},"面":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"当":{"docs":{},"将":{"docs":{},"新":{"docs":{},"用":{"docs":{},"户":{"docs":{},"设":{"docs":{},"置":{"docs":{},"为":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"开":{"docs":{},"发":{"docs":{},"人":{"docs":{},"员":{"docs":{},"成":{"docs":{},"员":{"docs":{},"时":{"docs":{},",":{"docs":{},"他":{"docs":{},"们":{"docs":{},"将":{"docs":{},"获":{"docs":{},"得":{"docs":{},"开":{"docs":{},"发":{"docs":{},"人":{"docs":{},"员":{"docs":{},"对":{"docs":{},"该":{"docs":{},"组":{"docs":{},"内":{"docs":{},"所":{"docs":{},"有":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"访":{"docs":{},"问":{"docs":{},"权":{"docs":{},"限":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"您":{"docs":{},"的":{"docs":{},"后":{"docs":{},"端":{"docs":{},"团":{"docs":{},"队":{"docs":{},"需":{"docs":{},"要":{"docs":{},"前":{"docs":{},"端":{"docs":{},"提":{"docs":{},"供":{"docs":{},"帮":{"docs":{},"助":{"docs":{},"时":{"docs":{},",":{"docs":{},"他":{"docs":{},"们":{"docs":{},"会":{"docs":{},"添":{"docs":{},"加":{"docs":{},"一":{"docs":{},"条":{"docs":{},"评":{"docs":{},"论":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"您":{"docs":{},"只":{"docs":{},"能":{"docs":{},"在":{"docs":{},"组":{"docs":{},"中":{"docs":{},"选":{"docs":{},"择":{"docs":{},"项":{"docs":{},"目":{"docs":{},"作":{"docs":{},"为":{"docs":{},"模":{"docs":{},"板":{"docs":{},"源":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}},"将":{"docs":{},"组":{"docs":{},"织":{"docs":{},"/":{"docs":{},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{},"转":{"docs":{},"移":{"docs":{},"到":{"docs":{},"您":{"docs":{},"管":{"docs":{},"理":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"/":{"docs":{},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{},";":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}},"可":{"docs":{},"以":{"docs":{},"与":{"docs":{},"组":{"docs":{},"织":{"docs":{},"共":{"docs":{},"享":{"docs":{},"您":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"并":{"docs":{},"向":{"docs":{},"所":{"docs":{},"有":{"docs":{},"组":{"docs":{},"织":{"docs":{},"成":{"docs":{},"员":{"docs":{},"立":{"docs":{},"即":{"docs":{},"授":{"docs":{},"予":{"docs":{},"对":{"docs":{},"该":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"访":{"docs":{},"问":{"docs":{},"权":{"docs":{},"限":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"为":{"docs":{},"子":{"docs":{},"组":{"docs":{},"和":{"docs":{},"直":{"docs":{},"接":{"docs":{},"父":{"docs":{},"组":{"docs":{},"配":{"docs":{},"置":{"docs":{},"此":{"docs":{},"功":{"docs":{},"能":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}},"出":{"docs":{},"于":{"docs":{},"多":{"docs":{},"种":{"docs":{},"原":{"docs":{},"因":{"docs":{},"创":{"docs":{},"建":{"docs":{},"组":{"docs":{},"织":{"docs":{},",":{"docs":{},"例":{"docs":{},"如":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}},"禁":{"docs":{},"用":{"docs":{},"与":{"docs":{},"该":{"docs":{},"组":{"docs":{},"相":{"docs":{},"关":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"电":{"docs":{},"子":{"docs":{},"邮":{"docs":{},"件":{"docs":{},"通":{"docs":{},"知":{"docs":{},",":{"docs":{},"其":{"docs":{},"中":{"docs":{},"包":{"docs":{},"括":{"docs":{},"其":{"docs":{},"子":{"docs":{},"组":{"docs":{},"和":{"docs":{},"项":{"docs":{},"目":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"通":{"docs":{},"过":{"docs":{},"以":{"docs":{},"下":{"docs":{},"操":{"docs":{},"作":{"docs":{},"为":{"docs":{},"特":{"docs":{},"定":{"docs":{},"组":{"docs":{},"织":{"docs":{},"变":{"docs":{},"更":{"docs":{},"此":{"docs":{},"项":{"docs":{},"设":{"docs":{},"置":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"更":{"docs":{},"改":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"路":{"docs":{},"径":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}},"方":{"docs":{},"式":{"docs":{},"转":{"docs":{},"移":{"docs":{},"组":{"docs":{},"织":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"防":{"docs":{},"止":{"docs":{},"将":{"docs":{},"用":{"docs":{},"户":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"对":{"docs":{},"话":{"docs":{},"中":{"docs":{},",":{"docs":{},"并":{"docs":{},"且":{"docs":{},"在":{"docs":{},"任":{"docs":{},"何":{"docs":{},"人":{"docs":{},"提":{"docs":{},"及":{"docs":{},"这":{"docs":{},"些":{"docs":{},"用":{"docs":{},"户":{"docs":{},"所":{"docs":{},"属":{"docs":{},"的":{"docs":{},"组":{"docs":{},"时":{"docs":{},"通":{"docs":{},"知":{"docs":{},"他":{"docs":{},"们":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"必":{"docs":{},"须":{"docs":{},"手":{"docs":{},"动":{"docs":{},"更":{"docs":{},"新":{"docs":{},"本":{"docs":{},"地":{"docs":{},"存":{"docs":{},"储":{"docs":{},"库":{"docs":{},"以":{"docs":{},"指":{"docs":{},"向":{"docs":{},"新":{"docs":{},"位":{"docs":{},"置":{"docs":{},";":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"成":{"docs":{},"员":{"docs":{},"锁":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"定":{"docs":{},"使":{"docs":{},"组":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"可":{"docs":{},"以":{"docs":{},"阻":{"docs":{},"止":{"docs":{},"组":{"docs":{},"中":{"docs":{},"所":{"docs":{},"有":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"任":{"docs":{},"何":{"docs":{},"新":{"docs":{},"项":{"docs":{},"目":{"docs":{},"成":{"docs":{},"员":{"docs":{},"资":{"docs":{},"格":{"docs":{},",":{"docs":{},"从":{"docs":{},"而":{"docs":{},"可":{"docs":{},"以":{"docs":{},"更":{"docs":{},"严":{"docs":{},"格":{"docs":{},"地":{"docs":{},"控":{"docs":{},"​":{"docs":{},"​":{"docs":{},"制":{"docs":{},"项":{"docs":{},"目":{"docs":{},"成":{"docs":{},"员":{"docs":{},"资":{"docs":{},"格":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"权":{"docs":{},"限":{"docs":{},",":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"织":{"docs":{},"至":{"docs":{},"少":{"docs":{},"需":{"docs":{},"要":{"docs":{},"一":{"docs":{},"名":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}},"打":{"docs":{},"开":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"批":{"docs":{},"量":{"docs":{},"编":{"docs":{},"辑":{"docs":{},"i":{"docs":{},"s":{"docs":{},"s":{"docs":{},"u":{"docs":{},"e":{"docs":{},"及":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}},"找":{"docs":{},"到":{"docs":{},"要":{"docs":{},"移":{"docs":{},"除":{"docs":{},"的":{"docs":{},"成":{"docs":{},"员":{"docs":{},",":{"docs":{},"并":{"docs":{},"点":{"docs":{},"击":{"docs":{},"移":{"docs":{},"除":{"docs":{},"按":{"docs":{},"钮":{"docs":{},",":{"docs":{},"这":{"docs":{},"时":{"docs":{},"会":{"docs":{},"弹":{"docs":{},"出":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}},"按":{"docs":{},"钮":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"授":{"docs":{},"予":{"docs":{},"成":{"docs":{},"员":{"docs":{},"一":{"docs":{},"次":{"docs":{},"访":{"docs":{},"问":{"docs":{},"多":{"docs":{},"个":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"权":{"docs":{},"限":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}},"撤":{"docs":{},"回":{"docs":{},"访":{"docs":{},"问":{"docs":{},"请":{"docs":{},"求":{"docs":{},"\"":{"docs":{},"按":{"docs":{},"钮":{"docs":{},"即":{"docs":{},"可":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"支":{"docs":{},"持":{"docs":{},"指":{"docs":{},"定":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"更":{"docs":{},"改":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"父":{"docs":{},"组":{"docs":{},"织":{"docs":{},"可":{"docs":{},"能":{"docs":{},"会":{"docs":{},"产":{"docs":{},"生":{"docs":{},"一":{"docs":{},"些":{"docs":{},"副":{"docs":{},"作":{"docs":{},"用":{"docs":{},",":{"docs":{},"具":{"docs":{},"体":{"docs":{},"的":{"docs":{},"请":{"docs":{},"参":{"docs":{},"阅":{"docs":{},"更":{"docs":{},"改":{"docs":{},"存":{"docs":{},"储":{"docs":{},"库":{"docs":{},"路":{"docs":{},"径":{"docs":{},"时":{"docs":{},"的":{"docs":{},"重":{"docs":{},"定":{"docs":{},"向":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"路":{"docs":{},"径":{"docs":{},"下":{"docs":{},"输":{"docs":{},"入":{"docs":{},"新":{"docs":{},"的":{"docs":{},"路":{"docs":{},"径":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}},"有":{"docs":{},"两":{"docs":{},"种":{"docs":{},"方":{"docs":{},"法":{"docs":{},"可":{"docs":{},"以":{"docs":{},"在":{"docs":{},"组":{"docs":{},"织":{"docs":{},"中":{"docs":{},"新":{"docs":{},"建":{"docs":{},"项":{"docs":{},"目":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}},"关":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"不":{"docs":{},"允":{"docs":{},"许":{"docs":{},"用":{"docs":{},"作":{"docs":{},"组":{"docs":{},"名":{"docs":{},"的":{"docs":{},"单":{"docs":{},"词":{"docs":{},"列":{"docs":{},"表":{"docs":{},",":{"docs":{},"请":{"docs":{},"参":{"docs":{},"见":{"docs":{},"保":{"docs":{},"留":{"docs":{},"名":{"docs":{},"称":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}},"详":{"docs":{},"细":{"docs":{},"信":{"docs":{},"息":{"docs":{},",":{"docs":{},"请":{"docs":{},"参":{"docs":{},"考":{"docs":{},"批":{"docs":{},"量":{"docs":{},"编":{"docs":{},"辑":{"docs":{},"i":{"docs":{},"s":{"docs":{},"s":{"docs":{},"u":{"docs":{},"e":{"docs":{},"及":{"docs":{},"合":{"docs":{},"并":{"docs":{},"请":{"docs":{},"求":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}},"权":{"docs":{},"限":{"docs":{},"\"":{"docs":{},",":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}},",":{"docs":{},"l":{"docs":{},"f":{"docs":{},"s":{"docs":{},",":{"2":{"docs":{},"f":{"docs":{},"a":{"docs":{},"\"":{"docs":{},"部":{"docs":{},"分":{"docs":{},",":{"docs":{},"然":{"docs":{},"后":{"docs":{},"在":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}},"选":{"docs":{},"择":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"部":{"docs":{},"分":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}},"s":{"docs":{},"中":{"docs":{},"单":{"docs":{},"击":{"docs":{},"允":{"docs":{},"许":{"docs":{},"用":{"docs":{},"户":{"docs":{},"请":{"docs":{},"求":{"docs":{},"访":{"docs":{},"问":{"docs":{},"(":{"docs":{},"如":{"docs":{},"果":{"docs":{},"可":{"docs":{},"见":{"docs":{},"性":{"docs":{},"是":{"docs":{},"公":{"docs":{},"开":{"docs":{},"或":{"docs":{},"内":{"docs":{},"部":{"docs":{},"的":{"docs":{},")":{"docs":{},"进":{"docs":{},"行":{"docs":{},"开":{"docs":{},"启":{"docs":{},",":{"docs":{},"该":{"docs":{},"功":{"docs":{},"能":{"docs":{},"默":{"docs":{},"认":{"docs":{},"为":{"docs":{},"启":{"docs":{},"用":{"docs":{},"状":{"docs":{},"态":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"docs":{}}}}}}}},"某":{"docs":{},"些":{"docs":{},"域":{"docs":{},"不":{"docs":{},"能":{"docs":{},"被":{"docs":{},"限":{"docs":{},"制":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"查":{"docs":{},"看":{"docs":{},"组":{"docs":{},"织":{"docs":{},"详":{"docs":{},"情":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"根":{"docs":{},"据":{"docs":{},"要":{"docs":{},"求":{"docs":{},"确":{"docs":{},"认":{"docs":{},"操":{"docs":{},"作":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"模":{"docs":{},"板":{"docs":{},"\"":{"docs":{},"部":{"docs":{},"分":{"docs":{},",":{"docs":{},"选":{"docs":{},"择":{"docs":{},"一":{"docs":{},"个":{"docs":{},"项":{"docs":{},"目":{"docs":{},"作":{"docs":{},"为":{"docs":{},"模":{"docs":{},"板":{"docs":{},"存":{"docs":{},"储":{"docs":{},"库":{"docs":{},",":{"docs":{},"然":{"docs":{},"后":{"docs":{},"选":{"docs":{},"择":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}},"注":{"docs":{},"意":{"docs":{},":":{"docs":{},"如":{"docs":{},"果":{"docs":{},"命":{"docs":{},"名":{"docs":{},"空":{"docs":{},"间":{"docs":{},"包":{"docs":{},"含":{"docs":{},"带":{"docs":{},"有":{"docs":{},"c":{"docs":{},"o":{"docs":{},"n":{"docs":{},"t":{"docs":{},"a":{"docs":{},"i":{"docs":{},"n":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}},":":{"docs":{},"出":{"docs":{},"于":{"docs":{},"系":{"docs":{},"统":{"docs":{},"安":{"docs":{},"全":{"docs":{},"以":{"docs":{},"及":{"docs":{},"知":{"docs":{},"识":{"docs":{},"产":{"docs":{},"权":{"docs":{},"、":{"docs":{},"商":{"docs":{},"标":{"docs":{},"保":{"docs":{},"护":{"docs":{},"等":{"docs":{},"因":{"docs":{},"素":{"docs":{},",":{"docs":{},"我":{"docs":{},"们":{"docs":{},"预":{"docs":{},"留":{"docs":{},"了":{"docs":{},"一":{"docs":{},"部":{"docs":{},"分":{"docs":{},"n":{"docs":{},"a":{"docs":{},"m":{"docs":{},"e":{"docs":{},"s":{"docs":{},"p":{"docs":{},"a":{"docs":{},"c":{"docs":{},"e":{"docs":{},",":{"docs":{},"如":{"docs":{},"果":{"docs":{},"您":{"docs":{},"的":{"docs":{},"用":{"docs":{},"户":{"docs":{},"名":{"docs":{},"与":{"docs":{},"预":{"docs":{},"留":{"docs":{},"这":{"docs":{},"部":{"docs":{},"分":{"docs":{},"n":{"docs":{},"a":{"docs":{},"m":{"docs":{},"e":{"docs":{},"s":{"docs":{},"p":{"docs":{},"a":{"docs":{},"c":{"docs":{},"e":{"docs":{},"有":{"docs":{},"冲":{"docs":{},"突":{"docs":{},",":{"docs":{},"系":{"docs":{},"统":{"docs":{},"将":{"docs":{},"会":{"docs":{},"自":{"docs":{},"动":{"docs":{},"对":{"docs":{},"您":{"docs":{},"在":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},"中":{"docs":{},"的":{"docs":{},"n":{"docs":{},"a":{"docs":{},"m":{"docs":{},"e":{"docs":{},"s":{"docs":{},"p":{"docs":{},"a":{"docs":{},"c":{"docs":{},"e":{"docs":{},"进":{"docs":{},"行":{"docs":{},"调":{"docs":{},"整":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"浏":{"docs":{},"览":{"docs":{},"组":{"docs":{},"织":{"docs":{},"\"":{"docs":{},"时":{"docs":{},"将":{"docs":{},"显":{"docs":{},"示":{"docs":{},"所":{"docs":{},"有":{"docs":{},"公":{"docs":{},"开":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"列":{"docs":{},"表":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}},"添":{"docs":{},"加":{"docs":{},"以":{"docs":{},"下":{"docs":{},"信":{"docs":{},"息":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"您":{"docs":{},"要":{"docs":{},"允":{"docs":{},"许":{"docs":{},"的":{"docs":{},"电":{"docs":{},"子":{"docs":{},"邮":{"docs":{},"件":{"docs":{},"域":{"docs":{},",":{"docs":{},"并":{"docs":{},"且":{"docs":{},"不":{"docs":{},"允":{"docs":{},"许":{"docs":{},"来":{"docs":{},"自":{"docs":{},"不":{"docs":{},"同":{"docs":{},"域":{"docs":{},"的":{"docs":{},"电":{"docs":{},"子":{"docs":{},"邮":{"docs":{},"件":{"docs":{},"用":{"docs":{},"户":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"该":{"docs":{},"组":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"然":{"docs":{},"后":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"继":{"docs":{},"续":{"docs":{},"创":{"docs":{},"建":{"docs":{},"您":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}},"申":{"docs":{},"请":{"docs":{},"加":{"docs":{},"入":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"访":{"docs":{},"问":{"docs":{},"权":{"docs":{},"限":{"docs":{},"后":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"目":{"docs":{},"前":{"docs":{},"限":{"docs":{},"制":{"docs":{},"适":{"docs":{},"用":{"docs":{},"于":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"禁":{"docs":{},"用":{"docs":{},"组":{"docs":{},"提":{"docs":{},"及":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"移":{"docs":{},"除":{"docs":{},"成":{"docs":{},"员":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"时":{"docs":{},",":{"docs":{},"您":{"docs":{},"可":{"docs":{},"以":{"docs":{},"决":{"docs":{},"定":{"docs":{},"是":{"docs":{},"否":{"docs":{},"取":{"docs":{},"消":{"docs":{},"已":{"docs":{},"经":{"docs":{},"指":{"docs":{},"派":{"docs":{},"给":{"docs":{},"该":{"docs":{},"成":{"docs":{},"员":{"docs":{},"的":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}},"组":{"docs":{},"织":{"docs":{},"成":{"docs":{},"员":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"空":{"docs":{},"格":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"自":{"docs":{},"动":{"docs":{},"完":{"docs":{},"成":{"docs":{},"下":{"docs":{},"拉":{"docs":{},"列":{"docs":{},"表":{"docs":{},"中":{"docs":{},"会":{"docs":{},"相":{"docs":{},"应":{"docs":{},"地":{"docs":{},"显":{"docs":{},"示":{"docs":{},"提":{"docs":{},"及":{"docs":{},"被":{"docs":{},"禁":{"docs":{},"用":{"docs":{},"的":{"docs":{},"组":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}},"表":{"docs":{},"示":{"docs":{},"法":{"docs":{},"将":{"docs":{},"一":{"docs":{},"个":{"docs":{},"或":{"docs":{},"多":{"docs":{},"个":{"docs":{},"允":{"docs":{},"许":{"docs":{},"的":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"要":{"docs":{},"为":{"docs":{},"组":{"docs":{},"配":{"docs":{},"置":{"docs":{},"推":{"docs":{},"送":{"docs":{},"规":{"docs":{},"则":{"docs":{},",":{"docs":{},"请":{"docs":{},"导":{"docs":{},"航":{"docs":{},"至":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}},"启":{"docs":{},"用":{"docs":{},"延":{"docs":{},"迟":{"docs":{},"删":{"docs":{},"除":{"docs":{},"项":{"docs":{},"目":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"此":{"docs":{},"功":{"docs":{},"能":{"docs":{},",":{"docs":{},"请":{"docs":{},"导":{"docs":{},"航":{"docs":{},"至":{"docs":{},"组":{"docs":{},"设":{"docs":{},"置":{"docs":{},"页":{"docs":{},"面":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},",":{"docs":{},"展":{"docs":{},"开":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.008620689655172414}}}}}}}},"将":{"docs":{},"给":{"docs":{},"定":{"docs":{},"的":{"docs":{},"组":{"docs":{},"(":{"docs":{},"例":{"docs":{},"如":{"docs":{},"\"":{"docs":{},"前":{"docs":{},"端":{"docs":{},"\"":{"docs":{},")":{"docs":{},"与":{"docs":{},"另":{"docs":{},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},"(":{"docs":{},"例":{"docs":{},"如":{"docs":{},"\"":{"docs":{},"工":{"docs":{},"程":{"docs":{},"\"":{"docs":{},")":{"docs":{},"共":{"docs":{},"享":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"还":{"docs":{},"原":{"docs":{},"标":{"docs":{},"记":{"docs":{},"为":{"docs":{},"删":{"docs":{},"除":{"docs":{},"的":{"docs":{},"组":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}},"让":{"docs":{},"我":{"docs":{},"们":{"docs":{},"将":{"docs":{},"其":{"docs":{},"推":{"docs":{},"送":{"docs":{},"到":{"docs":{},"@":{"docs":{},"c":{"docs":{},"o":{"docs":{},"m":{"docs":{},"p":{"docs":{},"a":{"docs":{},"n":{"docs":{},"i":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}},"新":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"删":{"docs":{},"除":{"docs":{},"您":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"权":{"docs":{},"限":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}},"该":{"docs":{},"子":{"docs":{},"组":{"docs":{},"织":{"docs":{},"及":{"docs":{},"其":{"docs":{},"项":{"docs":{},"目":{"docs":{},"将":{"docs":{},"在":{"docs":{},"h":{"docs":{},"t":{"docs":{},"t":{"docs":{},"p":{"docs":{},"s":{"docs":{},":":{"docs":{},"/":{"docs":{},"/":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},".":{"docs":{},"c":{"docs":{},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{},".":{"docs":{},"n":{"docs":{},"e":{"docs":{},"t":{"docs":{},"/":{"docs":{},"c":{"docs":{},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"组":{"docs":{},"织":{"docs":{},"及":{"docs":{},"其":{"docs":{},"项":{"docs":{},"目":{"docs":{},"将":{"docs":{},"在":{"docs":{},"h":{"docs":{},"t":{"docs":{},"t":{"docs":{},"p":{"docs":{},"s":{"docs":{},":":{"docs":{},"/":{"docs":{},"/":{"docs":{},"c":{"docs":{},"o":{"docs":{},"d":{"docs":{},"e":{"docs":{},"c":{"docs":{},"h":{"docs":{},"i":{"docs":{},"n":{"docs":{},"a":{"docs":{},".":{"docs":{},"c":{"docs":{},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{},".":{"docs":{},"n":{"docs":{},"e":{"docs":{},"t":{"docs":{},"/":{"docs":{},"c":{"docs":{},"s":{"docs":{},"d":{"docs":{},"n":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"有":{"docs":{},"多":{"docs":{},"少":{"docs":{},"个":{"docs":{},"成":{"docs":{},"员":{"docs":{},",":{"docs":{},"注":{"docs":{},"意":{"docs":{},"这":{"docs":{},"里":{"docs":{},"面":{"docs":{},"不":{"docs":{},"包":{"docs":{},"括":{"docs":{},"从":{"docs":{},"父":{"docs":{},"组":{"docs":{},"织":{"docs":{},"继":{"docs":{},"承":{"docs":{},"的":{"docs":{},"成":{"docs":{},"员":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}},"网":{"docs":{},"址":{"docs":{},"只":{"docs":{},"能":{"docs":{},"包":{"docs":{},"含":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"详":{"docs":{},"细":{"docs":{},"信":{"docs":{},"息":{"docs":{},"页":{"docs":{},"面":{"docs":{},"包":{"docs":{},"含":{"docs":{},"以":{"docs":{},"下":{"docs":{},"内":{"docs":{},"容":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}},"赋":{"docs":{},"予":{"docs":{},"其":{"docs":{},"他":{"docs":{},"成":{"docs":{},"员":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"权":{"docs":{},"限":{"docs":{},";":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"转":{"docs":{},"移":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"时":{"docs":{},",":{"docs":{},"只":{"docs":{},"有":{"docs":{},"组":{"docs":{},"织":{"docs":{},"直":{"docs":{},"接":{"docs":{},"成":{"docs":{},"员":{"docs":{},"会":{"docs":{},"被":{"docs":{},"转":{"docs":{},"移":{"docs":{},",":{"docs":{},"从":{"docs":{},"之":{"docs":{},"前":{"docs":{},"父":{"docs":{},"组":{"docs":{},"织":{"docs":{},"集":{"docs":{},"成":{"docs":{},"的":{"docs":{},"成":{"docs":{},"员":{"docs":{},"不":{"docs":{},"会":{"docs":{},"被":{"docs":{},"转":{"docs":{},"移":{"docs":{},"。":{"docs":{},"如":{"docs":{},"果":{"docs":{},"待":{"docs":{},"转":{"docs":{},"移":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"是":{"docs":{},"继":{"docs":{},"承":{"docs":{},"的":{"docs":{},"身":{"docs":{},"份":{"docs":{},"成":{"docs":{},"员":{"docs":{},",":{"docs":{},"则":{"docs":{},"该":{"docs":{},"组":{"docs":{},"织":{"docs":{},"转":{"docs":{},"移":{"docs":{},"过":{"docs":{},"去":{"docs":{},"后":{"docs":{},"将":{"docs":{},"不":{"docs":{},"会":{"docs":{},"设":{"docs":{},"有":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},",":{"docs":{},"转":{"docs":{},"移":{"docs":{},"组":{"docs":{},"的":{"docs":{},"用":{"docs":{},"户":{"docs":{},"将":{"docs":{},"会":{"docs":{},"自":{"docs":{},"动":{"docs":{},"成":{"docs":{},"为":{"docs":{},"该":{"docs":{},"组":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"者":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"请":{"docs":{},"注":{"docs":{},"意":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}},"还":{"docs":{},"原":{"docs":{},"组":{"docs":{},"\"":{"docs":{},"按":{"docs":{},"钮":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"这":{"docs":{},"些":{"docs":{},"是":{"docs":{},"最":{"docs":{},"受":{"docs":{},"欢":{"docs":{},"迎":{"docs":{},"的":{"docs":{},"公":{"docs":{},"共":{"docs":{},"电":{"docs":{},"子":{"docs":{},"邮":{"docs":{},"件":{"docs":{},"域":{"docs":{},",":{"docs":{},"例":{"docs":{},"如":{"docs":{},":":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}},"包":{"docs":{},"括":{"docs":{},"与":{"docs":{},"该":{"docs":{},"组":{"docs":{},"共":{"docs":{},"享":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"但":{"docs":{},"不":{"docs":{},"包":{"docs":{},"括":{"docs":{},"正":{"docs":{},"在":{"docs":{},"配":{"docs":{},"置":{"docs":{},"的":{"docs":{},"组":{"docs":{},"的":{"docs":{},"子":{"docs":{},"组":{"docs":{},"或":{"docs":{},"父":{"docs":{},"组":{"docs":{},"中":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"可":{"docs":{},"以":{"docs":{},"帮":{"docs":{},"助":{"docs":{},"确":{"docs":{},"保":{"docs":{},"特":{"docs":{},"定":{"docs":{},"内":{"docs":{},"容":{"docs":{},"不":{"docs":{},"会":{"docs":{},"离":{"docs":{},"开":{"docs":{},"场":{"docs":{},"所":{"docs":{},",":{"docs":{},"同":{"docs":{},"时":{"docs":{},"又":{"docs":{},"不":{"docs":{},"会":{"docs":{},"阻":{"docs":{},"止":{"docs":{},"对":{"docs":{},"整":{"docs":{},"个":{"docs":{},"实":{"docs":{},"例":{"docs":{},"的":{"docs":{},"访":{"docs":{},"问":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"对":{"docs":{},"于":{"docs":{},"具":{"docs":{},"有":{"docs":{},"大":{"docs":{},"量":{"docs":{},"用":{"docs":{},"户":{"docs":{},"的":{"docs":{},"组":{"docs":{},"特":{"docs":{},"别":{"docs":{},"有":{"docs":{},"用":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}},"将":{"docs":{},"对":{"docs":{},"以":{"docs":{},"前":{"docs":{},"有":{"docs":{},"权":{"docs":{},"操":{"docs":{},"作":{"docs":{},"项":{"docs":{},"目":{"docs":{},"成":{"docs":{},"员":{"docs":{},"资":{"docs":{},"格":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"用":{"docs":{},"户":{"docs":{},"禁":{"docs":{},"用":{"docs":{},"该":{"docs":{},"选":{"docs":{},"项":{"docs":{},",":{"docs":{},"因":{"docs":{},"此":{"docs":{},"无":{"docs":{},"法":{"docs":{},"添":{"docs":{},"加":{"docs":{},"新":{"docs":{},"用":{"docs":{},"户":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"进":{"docs":{},"入":{"docs":{},"到":{"docs":{},"\"":{"docs":{},"前":{"docs":{},"端":{"docs":{},"\"":{"docs":{},"组":{"docs":{},"织":{"docs":{},"页":{"docs":{},"面":{"docs":{},",":{"docs":{},"然":{"docs":{},"后":{"docs":{},"进":{"docs":{},"入":{"docs":{},"组":{"docs":{},"织":{"docs":{},"设":{"docs":{},"置":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"设":{"docs":{},"置":{"docs":{},">":{"docs":{},"常":{"docs":{},"规":{"docs":{},"设":{"docs":{},"置":{"docs":{},"页":{"docs":{},"面":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"设":{"docs":{},"置":{"docs":{},">":{"docs":{},"常":{"docs":{},"规":{"docs":{},"设":{"docs":{},"置":{"docs":{},"页":{"docs":{},"面":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}},"行":{"docs":{},"操":{"docs":{},"作":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"连":{"docs":{},"接":{"docs":{},"符":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}}},"选":{"docs":{},"中":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"择":{"docs":{},"\"":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"一":{"docs":{},"个":{"docs":{},"组":{"docs":{},",":{"docs":{},"单":{"docs":{},"击":{"docs":{},"新":{"docs":{},"建":{"docs":{},"项":{"docs":{},"目":{"docs":{},"按":{"docs":{},"钮":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}},"您":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"后":{"docs":{},",":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"要":{"docs":{},"共":{"docs":{},"享":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"\"":{"docs":{},"工":{"docs":{},"程":{"docs":{},"\"":{"docs":{},",":{"docs":{},"并":{"docs":{},"设":{"docs":{},"置":{"docs":{},"访":{"docs":{},"问":{"docs":{},"权":{"docs":{},"限":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}},"新":{"docs":{},"建":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}},"权":{"docs":{},"限":{"docs":{},"级":{"docs":{},"别":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"邀":{"docs":{},"请":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"重":{"docs":{},"定":{"docs":{},"向":{"docs":{},",":{"docs":{},"我":{"docs":{},"们":{"docs":{},"建":{"docs":{},"议":{"docs":{},"您":{"docs":{},"新":{"docs":{},"建":{"docs":{},"一":{"docs":{},"个":{"docs":{},"群":{"docs":{},"组":{"docs":{},"并":{"docs":{},"向":{"docs":{},"其":{"docs":{},"转":{"docs":{},"移":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"而":{"docs":{},"无":{"docs":{},"需":{"docs":{},"更":{"docs":{},"改":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"路":{"docs":{},"径":{"docs":{},"或":{"docs":{},"重":{"docs":{},"命":{"docs":{},"名":{"docs":{},"用":{"docs":{},"户":{"docs":{},"名":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"间":{"docs":{},"隔":{"docs":{},"时":{"docs":{},"间":{"docs":{},"默":{"docs":{},"认":{"docs":{},"为":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}},"限":{"docs":{},"制":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"除":{"docs":{},"了":{"docs":{},"编":{"docs":{},"辑":{"docs":{},"您":{"docs":{},"在":{"docs":{},"创":{"docs":{},"建":{"docs":{},"组":{"docs":{},"织":{"docs":{},"时":{"docs":{},"预":{"docs":{},"先":{"docs":{},"设":{"docs":{},"置":{"docs":{},"的":{"docs":{},"内":{"docs":{},"容":{"docs":{},"外":{"docs":{},",":{"docs":{},"您":{"docs":{},"还":{"docs":{},"可":{"docs":{},"以":{"docs":{},"对":{"docs":{},"该":{"docs":{},"组":{"docs":{},"织":{"docs":{},"的":{"docs":{},"其":{"docs":{},"他":{"docs":{},"内":{"docs":{},"容":{"docs":{},"进":{"docs":{},"行":{"docs":{},"设":{"docs":{},"置":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"集":{"docs":{},"群":{"docs":{},"连":{"docs":{},"接":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}},"集":{"docs":{},"成":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"默":{"docs":{},"认":{"docs":{},"情":{"docs":{},"况":{"docs":{},"下":{"docs":{},",":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}},"删":{"docs":{},"除":{"docs":{},"将":{"docs":{},"在":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}},"每":{"docs":{},"个":{"docs":{},"组":{"docs":{},"织":{"docs":{},"都":{"docs":{},"会":{"docs":{},"继":{"docs":{},"承":{"docs":{},"全":{"docs":{},"局":{"docs":{},"级":{"docs":{},"别":{"docs":{},"的":{"docs":{},"分":{"docs":{},"支":{"docs":{},"保":{"docs":{},"护":{"docs":{},"。":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}},"组":{"docs":{},"中":{"docs":{},"的":{"docs":{},"项":{"docs":{},"目":{"docs":{},"会":{"docs":{},"立":{"docs":{},"即":{"docs":{},"删":{"docs":{},"除":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}},"!":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}},"(":{"docs":{},"可":{"docs":{},"选":{"docs":{},")":{"docs":{},"可":{"docs":{},"以":{"docs":{},"为":{"docs":{},"新":{"docs":{},"建":{"docs":{},"的":{"docs":{},"组":{"docs":{},"织":{"docs":{},"上":{"docs":{},"传":{"docs":{},"一":{"docs":{},"个":{"docs":{},"头":{"docs":{},"像":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},"添":{"docs":{},"加":{"docs":{},"一":{"docs":{},"段":{"docs":{},"简":{"docs":{},"单":{"docs":{},"介":{"docs":{},"绍":{"docs":{},",":{"docs":{},"以":{"docs":{},"便":{"docs":{},"其":{"docs":{},"他":{"docs":{},"用":{"docs":{},"户":{"docs":{},"了":{"docs":{},"解":{"docs":{},"该":{"docs":{},"组":{"docs":{},"织":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"在":{"docs":{},"p":{"docs":{},"r":{"docs":{},"e":{"docs":{},"m":{"docs":{},"i":{"docs":{},"u":{"docs":{},"m":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}},"选":{"docs":{},"中":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}},":":{"docs":{},"为":{"docs":{},"您":{"docs":{},"的":{"docs":{},"组":{"docs":{},"配":{"docs":{},"置":{"docs":{},"w":{"docs":{},"e":{"docs":{},"b":{"docs":{},"h":{"docs":{},"o":{"docs":{},"o":{"docs":{},"k":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}},"将":{"docs":{},"您":{"docs":{},"的":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}},"查":{"docs":{},"看":{"docs":{},"该":{"docs":{},"组":{"docs":{},"中":{"docs":{},"的":{"docs":{},"所":{"docs":{},"有":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"将":{"docs":{},"成":{"docs":{},"员":{"docs":{},"添":{"docs":{},"加":{"docs":{},"到":{"docs":{},"每":{"docs":{},"个":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"访":{"docs":{},"问":{"docs":{},"每":{"docs":{},"个":{"docs":{},"项":{"docs":{},"目":{"docs":{},"的":{"docs":{},"设":{"docs":{},"置":{"docs":{},",":{"docs":{},"以":{"docs":{},"及":{"docs":{},"删":{"docs":{},"除":{"docs":{},"任":{"docs":{},"何":{"docs":{},"项":{"docs":{},"目":{"docs":{},",":{"docs":{},"所":{"docs":{},"有":{"docs":{},"操":{"docs":{},"作":{"docs":{},"均":{"docs":{},"在":{"docs":{},"同":{"docs":{},"一":{"docs":{},"屏":{"docs":{},"幕":{"docs":{},"上":{"docs":{},"进":{"docs":{},"行":{"docs":{},".":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}},"的":{"docs":{},"审":{"docs":{},"核":{"docs":{},"事":{"docs":{},"件":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},"跟":{"docs":{},"踪":{"docs":{},"组":{"docs":{},"的":{"docs":{},"管":{"docs":{},"道":{"docs":{},"配":{"docs":{},"额":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0017241379310344827}}}}}}}}}}},";":{"docs":{"docs/033.html":{"ref":"docs/033.html","tf":0.0034482758620689655}}}},"length":704},"corpusTokens":["\"","\"img\"","\"工程\"的所有成员将被添加到\"前端\"组织中。","&&","(13.2",".","/","08","12.0","12.2","12.3","12.4","12.6","12.8","12.8.","13.1","13.2","2020","22:25:55","23:01:45","23:01:51","29","2fa","7",";","=","===","@compani","access","advanc","allow","analyt","aol.com","api","api.","b","basic","burndown","ce","chart","cheat","cherri","cidr","click","codechina","codechina。如果您熟悉以上两个产品中的一个或多个,您可以直接开始","codechina微信群(1)","codechina微信群(2)","codechina观察员(1)","codechina观察员(2)","codechina,您会发现以下有用信息:","codechina?","codechina?请查阅我们的便捷指南","console.log(\"plugin","contribut","copyright","csdn","csdn只提及@csdn","csdn通过@csdn","delay","devop","disabl","domain","e.target.tagnam","elasticsearch","email","enabl","enforc","epic","file","flow","frontend","function(e){","git","gitbook该文件修订时间:","github","github,bitbucket,gitlab.com,fogbugz","gitlab","gitlab/github","gmail.com","gold","gpg","group","guid","hotmail.co.uk","hotmail.com","hotmail.fr","https://codechina.csdn.net/groupnam","https://codechina.csdn.net/groupname/subgroup_nam","https://codechina.csdn.net/usernam","icloud.com","id","introduc","ip","issu","issue及合并请求","issue及合并请求可以将已经分配给当前要移除用户的","issue及合并请求是项目的一部分。对于组织,您可以在单个列表视图中查看所有issue,也可以查看组织中所有项目的请求合并。","jupyt","kubernet","level","lf","lfs,2fa\"部分,然后选中\"","lfs,2fa\"部分,然后选择\"","live.com","lock","markdown","member","mention","merg","miykael","msn.com","notebook","notif","outlook.com","overview","pdf","pick","popup....\");document.onclick","premium","project","push","qq","registry标记的项目,则无法重命名该空间,因为该项目无法移动。","remov","request","reserved,pow","resolut","restor","restrict","right","roadmap","rule","scrum","search","set","share","sheet","silver","silver或更高级别上,将一个组标记为删除.","silver或更高级别上,您可以将组内的项目配置为在延迟间隔后删除.","ssh","stable)","starter","svn","team","team/backend","team/cod","team/coding下访问","team/frontend","team/product","team下访问","team创建了子组。","team和product","team您很高兴!\"","team您能在这里帮助我们吗?\"","team提及了团队中的每个人","templat","thread","through","ui.","ultim","url","url是将托管项目的名称空间.","url(自动填充不支持中文的组织名称)。(可选)您可以修改它,这是在组视图中显示的名称,该名称只能包含:","waterfall,敏捷还是会话开发,codechina","web","webhook","webid","wechat","wiki","window.open(e.target.src,e.target.src)}img{cursor:pointer}","work","workflow","yahoo.com","©","。","上使用用户名miykael创建了一个帐户;","上工作","下划线","下载描述最常用的","与","与与组织共享项目类似,您可以与一个组织共享另一个组织,以使组织成员可以直接访问共享的组织(注:这对于继承的成员无效)。","与组织共享一个项目","与组织共享另一个组织","中使用分支","中引入","中引入的多个电子邮件域","中文","中的功能和概念.","中移至","中编辑文件","中,命名空间将会是用户名称、组织名称或子组名的唯一名称。","为","为codechina开源做贡献","为了确保只有组织内的人员可以访问特定资源,您可以选择通过","为了避免意外锁定,管理员和组所有者可以访问组,而不受","为他们的团队创建了一个组织,名称为csdn","为组织添加一个用户","主题","了解如何将项目转移到组织中","了解有关使用","了解有关帐户管理的更多信息:","了解有关组级项目模板的更多信息","了解项目中的每个角色可以做什么","产品提交","产品,在产品中我们也会为您设置帮助提示,您可以随时回来查看我们的产品文档。","从","从gitlab","从svn迁移","从另一个平台进入","从另一个平台进入到","从问题开始新的实现时,请添加评论:","他们的个人资料将在https://codechina.csdn.net/miykael下访问","代办事项","代码仓库","以下文档与","以下是我们推荐的一些主题:","以及将","任何团队成员都使用@miykael提及","任何组织所有者都可以在组组织成员设置页面上批准或拒绝您的申请","体验使用过程中如果遇到任何问题,请与我们联系。","作为组织所有者,您可以启用或禁用非组织成员请求访问组织的功能。该功能可以通过再组织设置","使用","使用内置的","使用受保护的分支","使用新系统可能让您觉得难以入手,我们有以下文档可快速提升您的相关知识:","使用组锁共享可以防止其中的任何项目该群组不会与其他群组共享,从而确保只有合适的群组成员才能访问这些项目.","使用组锁定共享\"并保存组","使用高级查询获得更具针对性的搜索结果","例如,假设您有两个不同的团队(a","例如,假设有一个名为","例如,如果要为\"","例如,您可以为公司成员创建一个组织","保存修改","保存更改.","保存组\"","保护分支","保留issue和合并请求的分配可能对于接受公开贡献的组织很有帮助,用户可以不必是组织成员就可以为","假设一个有两个项目的组织:","假设您创建了一个名为compani","做贡献为codechina开源贡献力量!","允许创建项目下拉列表中选择所需的选项","允许访问以下","入门,分支策略,git","全局搜索","关于codechina","关联","具有两因素身份验证的帐户安全性,设置您的","分支和默认分支","分析","分类问题或使用描述性标签合并请求","分组组织您的项目","刚开始使用git/codechina/gitlab/github?","创建主题","创建了一个名为coding的子组织","创建分支","创建分支,创建和上传文件以及创建目录。","创建并fork项目,以及导入项目","创建并上传文件,并创建目录","创建组织后,在组织详情页您可以进入组织设置来对组织进行设置及管理:","创建,复制和移动项目","删除已合并的分支","删除组\"按钮.","删除组及其内容:","删除组,并且将后台作业排队以删除该组中的所有项目.","利用","利用最佳的工作流程增强您的工作流程","前往组织的","前端团队完成实施后,他们会评论:","协议","单击","及合并请求。","及合并请求做出贡献","及合并请求重新进行分配","取消分配给已移除的成员的","变更组织的所有者","变更组织的路径","变更组织的路径也可能会产生一些副作用,具体的请参考重定向的行为","变更组织的默认保护分支","变更组织路径","只有拥有一个所有者的组织可以变更组织的所有者。","只有拥有所有者权限的用户才能管理组织成员。","可以通过以下操作为特定组更改此项设置:","可以通过以下操作将成员从组织中移除:","可以通过以下方式变更组织唯一所有者:","可视化史诗般的时间表","合并更改后的批量删除分支","合并请求","合并请求管理","向项目添加新用户的任何请求.","启用延迟的项目删除\"","命名空间","和","和点","和点(不能以连接符","和高级用法","在","在\"删除组\"部分中,单击\"","在\"还原组\"部分中,单击\"","在gitlab","在一个组织中,进入","在创建项目时,从下拉菜单中选择已经创建的组名称空间","在小组的侧边栏上.","在提交时启动合并请求","在整个","在本地处理合并请求","在本地处理合并请求的提示","在此间隔期间,项目将处于只读状态,并且可以根据需要还原.","在特定的里程碑中观察项目的进度","在组织中新建项目","在组织设置","在网页中管理源代码仓库","在问题之间建立关系.","在顶部菜单中,依次单击\"","在默认分支保护下拉列表中选择所需的选项","地址\"字段中输入","地址的任何人将无法访问受限制的内容.","地址范围.","地址限制对组及其基础项目,问题等的访问.","均可简化您的协作工作流程。","基本入门","基础入门","处理合并请求","处理提交,并使用","大学:存储库,项目和组","天后进行,但是可以在实例设置中进行更改.","天,可以由管理员在实例设置中进行修改.","如何在","如何在开发上做贡献","如何在文档上做贡献","如果将要转移的父组织的公开可见性设置低于当前父组织,那么待转移组织机器项目的公开可见性将会与即将要转移到的父组织保持一致;","如果您具有足够的权限,还将显示组织设置的按钮","如果您在申请权限被批准之前改变了主意,只需单击\"","如果您是从另一个平台进入","如果您是成员,也会看到退出该组的按钮","如果您要腾出路径,以便其他组织或用户可以使用该路径,由于名称和路径都必须是唯一的,因此您在变更路径的同时也可能需要重命名该组织。","如果成员资格是从父组继承的,则该成员只能从父组中进行移除。","如果没有父组定义推送规则,则在实例级别设置推送规则.","如果组织启用了该设置,则非组织成员用户可以请求成为组织的成员。在您要加入的组织页中,单击组织名称后面的申请权限按钮即可。","如果要提高特定项目的现有用户的访问权限,请将其作为新成员再次添加到特定项目中,并为其添加相应的项目成员角色。","如果要移除的成员在该组中具有直接成员资格,则可以从该组织中移除该成员;","子组中的项目将有权访问该子组以及任何直接父组的模板.","子组织","子网添加到组设置中,并且来自其他","字母数字字符","存储库转换为","存储库随附分支工具和访问控制,可为项目和代码的协作提供可扩展的单一事实来源。","它包含多少个项目","它有多少个子组","它类似于实例模板存储库功能,所选项目应遵循该页面上记录的相同命名约定.","定义了推送规则的最接近的父组.","实例上进行更快,更高级的代码搜索","实例之间","审核事件","审核事件\"锁定组,请启用\"成员锁定\"以确保在该审核期间不能修改项目成员身份.","密钥,并部署密钥以安全地访问您的项目。","对.ipynb文件的支持","对您的提交进行签名。","对更改进行","对项目推送的附加控制","导入项目","导航到您小组的","导航到组的\"设置\">\"常规\"页面.","将","将会显示您所属的全部组织(包括子组织)","将多个项目放在一个组织中的好处是,您可以通过一个操作就授予某个用户访问该组织中所有项目的权限。","将子组织转移到新的父组织","将源代码整合到一个易于管理和控制的分布式版本控制系统中","将相关项目组装在一起","将项目移到组织中","展开","展开\"","展开权限,lfs,2fa部分,然后选择禁用电子邮件通知","展开路径,传输,删除部分.","展开高级部分","帮助文档","常规设置","常规设置页面","开发","开发人员和维护人员可以在一个组下创建项目。","开发并,目前版本提供了代码仓库管理、组织管理等基本功能,欢迎体验使用。","开头或以点结尾)","开始","开始在命令行和","当将新用户设置为组织的开发人员成员时,他们将获得开发人员对该组内所有项目的访问权限。","当您的后端团队需要前端提供帮助时,他们会添加一条评论:","快捷方式","您只能在组中选择项目作为模板源.","您只能将组织/子组织转移到您管理的组织/子组织中;","您可以与组织共享您的项目,并向所有组织成员立即授予对该项目的访问权限。","您可以为子组和直接父组配置此功能.","您可以出于多种原因创建组织,例如:","您可以禁用与该组相关的所有电子邮件通知,其中包括其子组和项目.","您可以通过以下操作为特定组织变更此项设置:","您可以通过以下操作更改组织的路径:","您可以通过以下方式转移组织:","您可以防止将用户添加到对话中,并且在任何人提及这些用户所属的组时通知他们.","您必须手动更新本地存储库以指向新位置;","您的组织\"","成员锁\"","成员锁定使组所有者可以阻止组中所有项目的任何新项目成员资格,从而可以更严格地控​​制项目成员资格.","或","或看板上显示问题","或者,在顶部菜单中,展开+号并选择新建组织","或者,您可以锁定共享与组功能","截止日期","所有者权限,一个组织至少需要一名所有者。","打开组织的","托管源代码,并控制项目的可见性和设置配置。","批量编辑issue及合并请求","找到要移除的成员,并点击移除按钮,这时会弹出","按钮","授予成员一次访问多个项目的权限","推入或拉出外部的代码仓库","推送规则","描述","提交","提示:如果要保留对原始名称空间的所有权并保护","搜索问题,合并请求,项目,组和待办事项。","撤回访问请求\"按钮即可。","操作的","支持指定","文件","文件模板","文件管理","文档","新建","新建一个组织","新建组织\"","新建阶段有关:","无论您使用","时间跟踪","是","是否公开可见","是开源的,您可以通过以下方式为我们的开源社区做出贡献:","更改组织的父组织可能会产生一些副作用,具体的请参阅更改存储库路径时的重定向","更改组织路径下输入新的路径","有两种方法可以在组织中新建项目:","有关","有关不允许用作组名的单词列表,请参见保留名称","有关详细信息,请参考批量编辑issue及合并请求","权限\",\"","权限,lfs,2fa\"部分,然后在\"","权限,lfs,2fa\"部分,然后选择\"","权限,lfs,2fa部分","权限,lfs,2fs中单击允许用户请求访问(如果可见性是公开或内部的)进行开启,该功能默认为启用状态。","来管理您的文档","某些域不能被限制.","查看组织详情","标签","根据要求确认操作.","检查每月创建了多少个问题","概览","模板\"部分,选择一个项目作为模板存储库,然后选择\"","欢迎使用codechina代码托管平台,本产品基于","欢迎您使用codechina,如果您是","此后,将对所有添加到组中的新用户启用域检查.","此外,在项目之间转移问题。","此外,将无法通过","此操作要么:","注意:如果命名空间包含带有contain","注:出于系统安全以及知识产权、商标保护等因素,我们预留了一部分namespace,如果您的用户名与预留这部分namespace有冲突,系统将会自动对您在codechina中的namespace进行调整。","浏览组织\"时将显示所有公开的组织列表","添加以下信息:","添加您要允许的电子邮件域,并且不允许来自不同域的电子邮件用户添加到该组.","灵活的项目管理工具可视化,确定优先级,协调和跟踪进度。","点击","点击移除成员按钮","点此向","热门话题","然后,您可以继续创建您的项目","版本","版本历史","用户文件熟悉codechina","用户权限","用户账号","申请加入组织","申请访问权限后:","的初级用户,我们建议您从查看本文档开始学习如何使用","的复选框","的弹窗","的新手吗?我们有资源可以帮助您入门","的用户:","的精华","的组织,您可以:","目前限制适用于:","看板","禁用组提及\"","移除成员","移除成员时,您可以决定是否取消已经指派给该成员的","移除组织成员","空格","策略探索","管理员文件管理员入门","管理您的帐户","管道配额","组","组与kubernet","组之间共享项目.","组也可以嵌套在子组织中","组和","组推送规则允许组维护者为特定组内的新创建项目设置推送规则","组文件模板使您可以与组中的每个项目共享一组通用文件类型的模板.","组的视频介绍,请参见gitlab","组织","组织\"和\"","组织\"页面上的每个组都列出了:","组织\"页面显示:","组织内的issue及合并请求","组织名称将自动填充","组织已存档的项目","组织成员设置","组织成员设置中将成员添加到组织,可以通过用户名或者注册邮箱来添加组织成员。","组织成员设置选项卡;","组织成员设置页面","组织成员设置页面上,可以将新用户添加到组织中;","组织用户示例","组织的","组织的基本信息和介绍","组织的成员","组织的所有关系是指至少有一个组织成员拥有组织的","组织的项目","组织设置","组)在一个项目中一起工作,并且要继承该组成员身份,您可以在","结合使用的更多信息:","署名提交","联系我们","自动完成下拉列表中会相应地显示提及被禁用的组.","草稿合并请求","表示法将一个或多个允许的","要为组配置推送规则,请导航至","要启用延迟删除项目:","要启用此功能,请导航至组设置页面.","要启用此功能,请导航至组设置页面,展开\"","要启用此功能:","要将给定的组(例如\"前端\")与另一个组(例如\"工程\")共享:","要还原标记为删除的组:","解析线程,将合并请求中的线程移至问题,并且仅在解决所有线程后才允许合并请求。","计划","计划主题","计划阶段有关:","讨论","让我们将其推送到@compani","让新的所有者删除您的所有者权限。","设置>常规页面.","设置发布问题和合并请求的里程碑,并带有可选的截止日期","设置后,新的子组将根据以下任一条件为其设置推送规则:","访问codechina.csdn.net/docs,以获得优化的导航,可发现性和可读性。","该子组织及其项目将在https://codechina.csdn.net/csdn","该组织及其项目将在https://codechina.csdn.net/csdn","该组织有多少个成员,注意这里面不包括从父组织继承的成员","该网址只能包含:","详细信息页面包含以下内容:","语法检索","请参阅小组贡献者的详细统计信息","贡献者许可协议","账号验证","账户管理","赋予其他成员所有者权限;","跟踪共享主题的问题组","跟踪发行期限","跟踪花费在问题和合并请求上的时间","转移组织","转移组织时,只有组织直接成员会被转移,从之前父组织集成的成员不会被转移。如果待转移组织的所有者是继承的身份成员,则该组织转移过去后将不会设有所有者,转移组的用户将会自动成为该组的所有者。","转移组织时,请注意:","返回概览","还原组\"按钮.","这些是最受欢迎的公共电子邮件域,例如:","这包括与该组共享的项目,但不包括正在配置的组的子组或父组中的项目.","这可以帮助确保特定内容不会离开场所,同时又不会阻止对整个实例的访问.","这对于具有大量用户的组特别有用.","这将对以前有权操作项目成员资格的所有用户禁用该选项,因此无法添加新用户.","进入到\"前端\"组织页面,然后进入组织设置","进入到组织的组织设置>常规设置页面","进入组织的组织设置>常规设置页面","进行操作.","连接符","选中\"","选择\"","选择一个组,单击新建项目按钮","选择您的组织后,","选择您要共享的组织\"工程\",并设置访问权限","选择新建的组织","选择权限级别","通用文件的文件模板","通过","通过仅将具有特定域中电子邮件地址的用户添加到组中,可以限制对组的访问.","通过以下方式,您可以创建一个新的组织:","通过创建小组并包括适当的成员,可以轻松地@mention所有团队中的问题并合并请求。","通过单击顶部导航中的组织>您的组织来找到您的组织。","通过在同一名称空间下组织相关项目并将成员添加到顶级组,可以以较少的步骤授予对多个项目和多个团队成员的访问权限。","通过在简单仪表板上显示的时间顺序列表,跟踪需要注意的工作。","通过对所有组成员强制执行两因素身份验证(2fa)","通过将子组织转移到顶级组织,可以将一个子组织转换为组织","通过将组设置为模板源,在组级别定义项目模板.","通过将顶级组织转移到所需的组织,并将其转换为子组织","通过电子邮件将您的申请告知给组织的所有者(电子邮件将发送给最近活跃的组织所有者)","通过电子邮件限制成员身份\"字段中输入域名.","通过这样做:","邀请","邀请组织","里程碑","重定向,我们建议您新建一个群组并向其转移项目,而无需更改组织的路径或重命名用户名。","针对问题或合并请求的常见操作的快捷方式,而无需单击按钮或在web界面中使用下拉菜单。","锁定文件","锁定文件以避免合并冲突","镜像代码仓库","问题","问题,提交和合并请求中的线程,注释和可解决线程","间隔时间默认为","防止一个组中的项目与另一个组共享项目,以便对项目访问进行更严格的控制.","防止合并草稿合并请求","限制.","除了编辑您在创建组织时预先设置的内容外,您还可以对该组织的其他内容进行设置。","集群连接","集群集成","项目","项目创建权限","项目和组","项目和组织","项目问题并限制对问题的访问,并创建用于提交新问题和合并请求的模板。","首页","高级格式化系统(markdown)","默认情况下,","默认情况下,删除将在","默认情况下,每个组织都会继承全局级别的分支保护。","默认情况下,组中的项目会立即删除.","!","(可选)可以为新建的组织上传一个头像","(可选)可以为新建的组织添加一段简单介绍,以便其他用户了解该组织","(可选)在premium","(可选)选中",",",",git",",包括机密问题",",包括项目访问和设置",",发布和合并请求模板",",可以访问",",和移动的问题",",在premium",",它已经完成!",",将安全层添加到您的组中.",",并且在该组中为各个团队backend",",并为每个单独的团队创建一个子组织.",",然后单击绿色按钮\"",",然后添加新成员。您还可以设置该用户的到期日期。",",而不会中断您的工作流程。",",让我们开始吧!",":为您的组配置webhook",":将您的",":查看该组中的所有项目,将成员添加到每个项目,访问每个项目的设置,以及删除任何项目,所有操作均在同一屏幕上进行.",":查看该组的审核事件",":跟踪组的管道配额",";"],"pipeline":["stopWordFilter","stemmer"]},"store":{"./":{"url":"./","title":"首页","keywords":"","body":"关于CODEChina\n欢迎使用CodeChina代码托管平台,本产品基于 Gitlab CE 版本 (13.2 stable) 开发并,目前版本提供了代码仓库管理、组织管理等基本功能,欢迎体验使用。\n体验使用过程中如果遇到任何问题,请与我们联系。\n联系我们\n\n点此向 CODEChina 产品提交 issue\n\nCODEChina微信群(1)\n\nCODEChina微信群(2)\n\nCODEChina观察员(1) Wechat / QQ\n\nCODEChina观察员(2) Wechat / QQ \n\n\nCopyright © CODECHINA 2020 all right reserved,powered by Gitbook该文件修订时间:\n2020-08-29 23:01:45\n\nconsole.log(\"plugin-popup....\");document.onclick = function(e){ e.target.tagName === \"IMG\" && window.open(e.target.src,e.target.src)}img{cursor:pointer}"},"docs/002.html":{"url":"docs/002.html","title":"概览","keywords":"","body":"帮助文档\n访问codechina.csdn.net/docs,以获得优化的导航,可发现性和可读性。\n概览\n欢迎您使用CODEChina,如果您是 Github 或 GitLab 的初级用户,我们建议您从查看本文档开始学习如何使用 CODEChina。如果您熟悉以上两个产品中的一个或多个,您可以直接开始 CODEChina 产品,在产品中我们也会为您设置帮助提示,您可以随时回来查看我们的产品文档。\n\n\n\n基础入门\n基本入门\n\n\n\n\n用户文件熟悉CODEChina 中的功能和概念.\n管理员文件管理员入门\n\n\n为 CODEChina 做贡献为CODEChina开源贡献力量!\n是 Git 和 GitLab/GitHub 的新手吗?我们有资源可以帮助您入门\n\n\n从另一个平台进入 CODEChina?请查阅我们的便捷指南\n \n\n\n\n热门话题\n以下是我们推荐的一些主题:\n计划\n无论您使用 Waterfall,敏捷还是会话开发,CODEChina 均可简化您的协作工作流程。\n使用 CODEChina 灵活的项目管理工具可视化,确定优先级,协调和跟踪进度。\n以下文档与 DevOps 计划阶段有关:\n\n\n\n计划主题\n描述\n\n\n\n\nBurndown Charts\n在特定的里程碑中观察项目的进度\n\n\n讨论\n问题,提交和合并请求中的线程,注释和可解决线程\n\n\n截止日期\n跟踪发行期限\n\n\nEpics\n跟踪共享主题的问题组\n\n\n问题 ,包括机密问题 ,发布和合并请求模板 ,和移动的问题\n项目问题并限制对问题的访问,并创建用于提交新问题和合并请求的模板。 此外,在项目之间转移问题。\n\n\n标签\n分类问题或使用描述性标签合并请求\n\n\n里程碑\n设置发布问题和合并请求的里程碑,并带有可选的截止日期\n\n\n看板\n在 Scrum 或看板上显示问题\n\n\n快捷方式\n针对问题或合并请求的常见操作的快捷方式,而无需单击按钮或在WEB界面中使用下拉菜单。\n\n\n关联 Issue\n在问题之间建立关系.\n\n\nRoadmap\n可视化史诗般的时间表\n\n\n时间跟踪\n跟踪花费在问题和合并请求上的时间\n\n\n代办事项\n通过在简单仪表板上显示的时间顺序列表,跟踪需要注意的工作。\n\n\n\n返回概览\n新建\n将源代码整合到一个易于管理和控制的分布式版本控制系统中 ,而不会中断您的工作流程。\nCODEChina 存储库随附分支工具和访问控制,可为项目和代码的协作提供可扩展的单一事实来源。\n以下文档与 DevOps 新建阶段有关:\n项目和组织\n\n\n\n创建主题-项目和组\n描述\n\n\n\n\n全局搜索\n利用 Elasticsearch 在整个 CODEChina 实例上进行更快,更高级的代码搜索\n\n\n语法检索\n使用高级查询获得更具针对性的搜索结果\n\n\nContribution analytics\n请参阅小组贡献者的详细统计信息\n\n\n创建并fork项目,以及导入项目 实例之间\n创建,复制和移动项目\n\n\n锁定文件\n锁定文件以避免合并冲突\n\n\n组织 and 子组织\n分组组织您的项目\n\n\nIssue 分析\n检查每月创建了多少个问题\n\n\n项目 ,包括项目访问和设置\n托管源代码,并控制项目的可见性和设置配置。\n\n\nSearch through CODEChina\n搜索问题,合并请求,项目,组和待办事项。\n\n\nWeb IDE\n在 WebIDE 中编辑文件\n\n\nWikis\n使用内置的 Wiki 来管理您的文档\n\n\n\n返回概览\n代码仓库\n\n\n\n创建主题-代码仓库\n描述\n\n\n\n\n分支和默认分支\n如何在 CODEChina 中使用分支\n\n\n提交 and 署名提交\n处理提交,并使用 GPG 对您的提交进行签名。\n\n\n创建分支 , 创建并上传文件,并创建目录\n创建分支,创建和上传文件以及创建目录。\n\n\n删除已合并的分支\n合并更改后的批量删除分支\n\n\n文件模板\n通用文件的文件模板\n\n\n文件\n文件管理\n\n\nJupyter Notebook 文件\n对.ipynb文件的支持\n\n\n保护分支\n使用受保护的分支\n\n\n推送规则\n对项目推送的附加控制\n\n\n代码仓库\n在网页中管理源代码仓库\n\n\n镜像代码仓库\n推入或拉出外部的代码仓库\n\n\n处理合并请求\n在提交时启动合并请求\n\n\n\n返回概览\n合并请求\n\n\n\n创建主题-合并请求\n描述\n\n\n\n\n在本地处理合并请求\n在本地处理合并请求的提示\n\n\nCherry-pick\n对更改进行 Cherry Pick\n\n\nMerge request thread resolution\n解析线程,将合并请求中的线程移至问题,并且仅在解决所有线程后才允许合并请求。\n\n\n合并请求\n合并请求管理\n\n\n草稿合并请求\n防止合并草稿合并请求\n\n\n\n返回概览\n刚开始使用Git/CODEChina/GitLab/Github?\n使用新系统可能让您觉得难以入手,我们有以下文档可快速提升您的相关知识:\n\n\n\n主题\n描述\n\n\n\n\nBasics guides\n开始在命令行和 CODEChina 上工作\n\n\nWorkflow overview\n利用最佳的工作流程增强您的工作流程\n\n\nMarkdown\n高级格式化系统(Markdown)\n\n\n\n返回概览\n账户管理\n了解有关帐户管理的更多信息:\n\n\n\n主题\n描述\n\n\n\n\n用户账号\n管理您的帐户\n\n\n账号验证\n具有两因素身份验证的帐户安全性,设置您的 SSH 密钥,并部署密钥以安全地访问您的项目。\n\n\n用户权限\n了解项目中的每个角色可以做什么\n\n\n\n返回概览\nGit 和 CODEChina\n了解有关使用 Git 以及将 Git 与 CODEChina 结合使用的更多信息:\n\n\n\n主题\n描述\n\n\n\n\nGit\nGit 入门,分支策略,Git LFS 和高级用法\n\n\nGit cheat sheet\n下载描述最常用的 Git 操作的 PDF\n\n\nWork Flow\n使用 Work Flow 策略探索 Git 的精华\n\n\n\n返回概览\n从另一个平台进入到 CODEChina?\n如果您是从另一个平台进入 CODEChina,您会发现以下有用信息:\n\n\n\n主题\n描述\n\n\n\n\n导入项目\n从 GitHub,Bitbucket,GitLab.com,FogBugz 和 SVN 导入项目\n\n\n从SVN迁移\n将 SVN 存储库转换为 Git 和 CODEChina\n\n\n\n返回概览\n为CODEChina开源做贡献\nCODEChina 是开源的,您可以通过以下方式为我们的开源社区做出贡献:\n\n\n\n主题\n描述\n\n\n\n\n开发\n如何在开发上做贡献\n\n\n协议\n贡献者许可协议\n\n\n文档\n如何在文档上做贡献\n\n\n\n返回概览 \nCopyright © CODECHINA 2020 all right reserved,powered by Gitbook该文件修订时间:\n2020-08-29 23:01:51\n\nconsole.log(\"plugin-popup....\");document.onclick = function(e){ e.target.tagName === \"IMG\" && window.open(e.target.src,e.target.src)}img{cursor:pointer}"},"docs/033.html":{"url":"docs/033.html","title":"组织","keywords":"","body":"组织\n通过 CODEChina 的组织,您可以:\n\n将相关项目组装在一起\n授予成员一次访问多个项目的权限\n\n有关 组的视频介绍,请参见GitLab 大学:存储库,项目和组\n组也可以嵌套在子组织中 。\n通过单击顶部导航中的组织>您的组织来找到您的组织。\n\n\" 组织\"页面显示:\n\n选择您的组织后, 将会显示您所属的全部组织(包括子组织)\n选中\" 浏览组织\"时将显示所有公开的组织列表\n\n\" 组织\"页面上的每个组都列出了:\n\n它有多少个子组\n它包含多少个项目\n该组织有多少个成员,注意这里面不包括从父组织继承的成员\n如果您具有足够的权限,还将显示组织设置的按钮\n如果您是成员,也会看到退出该组的按钮\n\n组织用户示例\n您可以出于多种原因创建组织,例如:\n\n通过在同一名称空间下组织相关项目并将成员添加到顶级组,可以以较少的步骤授予对多个项目和多个团队成员的访问权限。\n通过创建小组并包括适当的成员,可以轻松地@mention所有团队中的问题并合并请求。\n\n例如,您可以为公司成员创建一个组织 ,并为每个单独的团队创建一个子组织. 假设您创建了一个名为company-team ,并且在该组中为各个团队backend-team , frontend-team和production-team创建了子组。\n\n从问题开始新的实现时,请添加评论: \" @company-team ,让我们开始吧! @company-team/backend-team您很高兴!\"\n当您的后端团队需要前端提供帮助时,他们会添加一条评论: \" @company-team/frontend-team您能在这里帮助我们吗?\"\n前端团队完成实施后,他们会评论: \" @company-team/backend-team ,它已经完成! 让我们将其推送到@company-team/production-team !\n\n命名空间\n在 CODEChina 中,命名空间将会是用户名称、组织名称或子组名的唯一名称。\n\nhttps://codechina.csdn.net/username\nhttps://codechina.csdn.net/groupname\nhttps://codechina.csdn.net/groupname/subgroup_name\n\n例如,假设有一个名为 Miykael 的用户:\n\nMiykael 在 CODEChina 上使用用户名Miykael创建了一个帐户; 他们的个人资料将在https://codechina.csdn.net/miykael下访问\nMiykael 为他们的团队创建了一个组织,名称为csdn-team ; 该组织及其项目将在https://codechina.csdn.net/csdn-team下访问\nCSDN 创建了一个名为coding的子组织 ; 该子组织及其项目将在https://codechina.csdn.net/csdn-team/coding下访问\n\n通过这样做:\n\n任何团队成员都使用@miykael提及 Miykael\nCSDN通过@csdn-team提及了团队中的每个人\nCSDN只提及@csdn-team/coding\n\n\n注:出于系统安全以及知识产权、商标保护等因素,我们预留了一部分namespace,如果您的用户名与预留这部分namespace有冲突,系统将会自动对您在CODEChina中的namespace进行调整。\n\n组织内的Issue及合并请求\nIssue及合并请求是项目的一部分。对于组织,您可以在单个列表视图中查看所有Issue,也可以查看组织中所有项目的请求合并。\n批量编辑Issue及合并请求\n有关详细信息,请参考批量编辑Issue及合并请求 。\n新建一个组织\n\n有关不允许用作组名的单词列表,请参见保留名称 .\n\n通过以下方式,您可以创建一个新的组织:\n\n在顶部菜单中,依次单击\" 组织\"和\" 您的组织\" ,然后单击绿色按钮\" 新建组织\" \n\n\n或者,在顶部菜单中,展开+号并选择新建组织 \n\n\n\n添加以下信息:\n\n\n组织名称将自动填充 URL(自动填充不支持中文的组织名称)。(可选)您可以修改它,这是在组视图中显示的名称,该名称只能包含:\n字母数字字符\n中文\n下划线\n连接符-和点\n空格\n\n\n组 URL是将托管项目的名称空间. 该网址只能包含:\n字母数字字符\n下划线\n连接符-和点(不能以连接符-开头或以点结尾)\n\n\n(可选)可以为新建的组织添加一段简单介绍,以便其他用户了解该组织\n(可选)可以为新建的组织上传一个头像\n选择新建的组织 是否公开可见\n\n为组织添加一个用户\n将多个项目放在一个组织中的好处是,您可以通过一个操作就授予某个用户访问该组织中所有项目的权限。\n在组织设置-组织成员设置中将成员添加到组织,可以通过用户名或者注册邮箱来添加组织成员。\n\n选择权限级别 ,然后添加新成员。您还可以设置该用户的到期日期。\n假设一个有两个项目的组织:\n\n在组织设置-组织成员设置页面上,可以将新用户添加到组织中;\n当将新用户设置为组织的开发人员成员时,他们将获得开发人员对该组内所有项目的访问权限。\n\n如果要提高特定项目的现有用户的访问权限,请将其作为新成员再次添加到特定项目中,并为其添加相应的项目成员角色。\n申请加入组织\n作为组织所有者,您可以启用或禁用非组织成员请求访问组织的功能。该功能可以通过再组织设置-常规设置-权限,LFS,2FS中单击允许用户请求访问(如果可见性是公开或内部的)进行开启,该功能默认为启用状态。\n如果组织启用了该设置,则非组织成员用户可以请求成为组织的成员。在您要加入的组织页中,单击组织名称后面的申请权限按钮即可。\n\n申请访问权限后:\n\n通过电子邮件将您的申请告知给组织的所有者(电子邮件将发送给最近活跃的组织所有者)\n任何组织所有者都可以在组组织成员设置页面上批准或拒绝您的申请\n\n\n如果您在申请权限被批准之前改变了主意,只需单击\" 撤回访问请求\"按钮即可。\n\n变更组织的所有者\n组织的所有关系是指至少有一个组织成员拥有组织的 所有者权限,一个组织至少需要一名所有者。\n只有拥有一个所有者的组织可以变更组织的所有者。 可以通过以下方式变更组织唯一所有者:\n\n前往组织的 组织设置-组织成员设置选项卡;\n赋予其他成员所有者权限;\n让新的所有者删除您的所有者权限。\n\n移除组织成员\n只有拥有所有者权限的用户才能管理组织成员。\n如果要移除的成员在该组中具有直接成员资格,则可以从该组织中移除该成员; 如果成员资格是从父组继承的,则该成员只能从父组中进行移除。\n移除成员时,您可以决定是否取消已经指派给该成员的 Issue 及合并请求。\n\n取消分配给已移除的成员的 Issue及合并请求可以将已经分配给当前要移除用户的 Issue 及合并请求重新进行分配\n保留Issue和合并请求的分配可能对于接受公开贡献的组织很有帮助,用户可以不必是组织成员就可以为 Issue 及合并请求做出贡献\n\n可以通过以下操作将成员从组织中移除:\n\n在一个组织中,进入 组织设置-组织成员设置 \n找到要移除的成员,并点击移除按钮,这时会弹出 移除成员 的弹窗\n(可选)选中 取消分配给已移除的成员的 Issue及合并请求 的复选框\n点击移除成员按钮\n\n变更组织的默认保护分支\n默认情况下,每个组织都会继承全局级别的分支保护。\n您可以通过以下操作为特定组织变更此项设置:\n\n打开组织的 组织设置-常规设置页面\n展开 权限,LFS,2FA部分\n在默认分支保护下拉列表中选择所需的选项\n点击 保存修改\n\n在组织中新建项目\n有两种方法可以在组织中新建项目:\n\n选择一个组,单击新建项目按钮 。 然后,您可以继续创建您的项目 .\n\n\n在创建项目时,从下拉菜单中选择已经创建的组名称空间\n\n\n\n项目创建权限\n默认情况下, 开发人员和维护人员可以在一个组下创建项目。\n可以通过以下操作为特定组更改此项设置:\n\n进入组织的组织设置>常规设置页面\n展开 权限,LFS,2FA部分\n在 允许创建项目下拉列表中选择所需的选项\n点击 保存修改\n\n查看组织详情\n组织的 详细信息页面包含以下内容:\n\n组织的基本信息和介绍\n组织的项目\n组织已存档的项目\n组织的成员\n\n将项目移到组织中\n了解如何将项目转移到组织中 .\n与组织共享一个项目\n您可以与组织共享您的项目,并向所有组织成员立即授予对该项目的访问权限。\n或者,您可以锁定共享与组功能 .\n与组织共享另一个组织\n与与组织共享项目类似,您可以与一个组织共享另一个组织,以使组织成员可以直接访问共享的组织(注:这对于继承的成员无效)。\n要将给定的组(例如\"前端\")与另一个组(例如\"工程\")共享:\n\n进入到\"前端\"组织页面,然后进入组织设置-组织成员设置页面\n单击 邀请组织 按钮\n选择您要共享的组织\"工程\",并设置访问权限\n点击 邀请\n\n\"工程\"的所有成员将被添加到\"前端\"组织中。\n转移组织\n您可以通过以下方式转移组织:\n\n将子组织转移到新的父组织\n通过将顶级组织转移到所需的组织,并将其转换为子组织\n通过将子组织转移到顶级组织,可以将一个子组织转换为组织\n\n转移组织时,请注意:\n\n更改组织的父组织可能会产生一些副作用,具体的请参阅更改存储库路径时的重定向 ;\n您只能将组织/子组织转移到您管理的组织/子组织中;\n您必须手动更新本地存储库以指向新位置;\n如果将要转移的父组织的公开可见性设置低于当前父组织,那么待转移组织机器项目的公开可见性将会与即将要转移到的父组织保持一致;\n转移组织时,只有组织直接成员会被转移,从之前父组织集成的成员不会被转移。如果待转移组织的所有者是继承的身份成员,则该组织转移过去后将不会设有所有者,转移组的用户将会自动成为该组的所有者。\n\n组织设置\n创建组织后,在组织详情页您可以进入组织设置来对组织进行设置及管理:\n\n常规设置\n除了编辑您在创建组织时预先设置的内容外,您还可以对该组织的其他内容进行设置。\n变更组织的路径\n变更组织的路径也可能会产生一些副作用,具体的请参考重定向的行为 。\n如果您要腾出路径,以便其他组织或用户可以使用该路径,由于名称和路径都必须是唯一的,因此您在变更路径的同时也可能需要重命名该组织。\n您可以通过以下操作更改组织的路径:\n\n进入到组织的组织设置>常规设置页面\n展开高级部分\n在 更改组织路径下输入新的路径\n点击 变更组织路径\n\n\n注意:如果命名空间包含带有Container Registry标记的项目,则无法重命名该空间,因为该项目无法移动。\n提示:如果要保留对原始名称空间的所有权并保护 URL 重定向,我们建议您新建一个群组并向其转移项目,而无需更改组织的路径或重命名用户名。\n\nRemove a group\n删除组及其内容:\n\n导航到您小组的 设置>常规页面.\n展开路径,传输,删除部分.\n在\"删除组\"部分中,单击\" 删除组\"按钮.\n根据要求确认操作.\n\n此操作要么:\n\n删除组,并且将后台作业排队以删除该组中的所有项目.\n从GitLab 12.8 开始 ,在Premium 或 Silver或更高级别上,将一个组标记为删除. 默认情况下,删除将在 7 天后进行,但是可以在实例设置中进行更改.\n\nRestore a group\n在 GitLab 12.8 中引入 .\n要还原标记为删除的组:\n\n导航到您小组的 设置>常规页面.\n展开路径,传输,删除部分.\n在\"还原组\"部分中,单击\" 还原组\"按钮.\n\nEnforce 2FA to group members\n通过对所有组成员强制执行两因素身份验证(2FA) ,将安全层添加到您的组中.\nShare with group lock\n防止一个组中的项目与另一个组共享项目,以便对项目访问进行更严格的控制.\n例如,假设您有两个不同的团队(A 组和 B 组)在一个项目中一起工作,并且要继承该组成员身份,您可以在 A 组和 B 组之间共享项目. 使用组锁共享可以防止其中的任何项目该群组不会与其他群组共享,从而确保只有合适的群组成员才能访问这些项目.\n要启用此功能,请导航至组设置页面. 选择\" 使用组锁定共享\"并保存组 .\n\nMember Lock\n成员锁定使组所有者可以阻止组中所有项目的任何新项目成员资格,从而可以更严格地控​​制项目成员资格.\n例如,如果要为\" 审核事件\"锁定组,请启用\"成员锁定\"以确保在该审核期间不能修改项目成员身份.\n要启用此功能:\n\n导航到组的\"设置\">\"常规\"页面.\n展开\" 权限,LFS,2FA\"部分,然后选择\" 成员锁\" .\nClick 保存更改.\n\n\n这将对以前有权操作项目成员资格的所有用户禁用该选项,因此无法添加新用户. 此外,将无法通过 API 向项目添加新用户的任何请求.\nIP access restriction\n版本历史\n\n在GitLab Ultimate 和 Gold 12.0 中引入 .\n在 13.1 中移至 GitLab Premium 和 Silver .\n\n为了确保只有组织内的人员可以访问特定资源,您可以选择通过 IP 地址限制对组及其基础项目,问题等的访问. 这可以帮助确保特定内容不会离开场所,同时又不会阻止对整个实例的访问.\n使用 CIDR 表示法将一个或多个允许的 IP 子网添加到组设置中,并且来自其他 IP 地址的任何人将无法访问受限制的内容.\n目前限制适用于:\n\nUI.\n从 GitLab 12.3 开始 ,可以访问 API.\n从 GitLab 12.4 开始 ,Git 通过 SSH 进行操作.\n\n为了避免意外锁定,管理员和组所有者可以访问组,而不受 IP 限制.\n要启用此功能:\n\n导航到组的\"设置\">\"常规\"页面.\n展开\" 权限,LFS,2FA\"部分,然后在\" 允许访问以下 IP 地址\"字段中输入 IP 地址范围.\nClick 保存更改.\n\nAllowed domain restriction\n版本历史\n\n在GitLab Premium 和 Silver 12.2 中引入 .\n支持指定 GitLab 13.1 中引入的多个电子邮件域\n\n通过仅将具有特定域中电子邮件地址的用户添加到组中,可以限制对组的访问.\n添加您要允许的电子邮件域,并且不允许来自不同域的电子邮件用户添加到该组.\n某些域不能被限制. 这些是最受欢迎的公共电子邮件域,例如:\n\ngmail.com\nyahoo.com\nhotmail.com\naol.com\nmsn.com\nhotmail.co.uk\nhotmail.fr\nlive.com\noutlook.com\nicloud.com\n\n要启用此功能:\n\n导航到组的\"设置\">\"常规\"页面.\n展开\" 权限,LFS,2FA\"部分,然后在\" 通过电子邮件限制成员身份\"字段中输入域名.\nClick 保存更改.\n\n此后,将对所有添加到组中的新用户启用域检查.\nGroup file templates\n组文件模板使您可以与组中的每个项目共享一组通用文件类型的模板. 它类似于实例模板存储库功能,所选项目应遵循该页面上记录的相同命名约定.\n您只能在组中选择项目作为模板源. 这包括与该组共享的项目,但不包括正在配置的组的子组或父组中的项目.\n您可以为子组和直接父组配置此功能. 子组中的项目将有权访问该子组以及任何直接父组的模板.\n\n要启用此功能,请导航至组设置页面,展开\" 模板\"部分,选择一个项目作为模板存储库,然后选择\" 保存组\" .\n\nGroup-level project templates\n通过将组设置为模板源,在组级别定义项目模板. 了解有关组级项目模板的更多信息 .\nDisabling email notifications\n在 GitLab 12.2 中引入 .\n您可以禁用与该组相关的所有电子邮件通知,其中包括其子组和项目.\n要启用此功能:\n\n导航到组的\"设置\">\"常规\"页面.\n展开权限,LFS,2FA部分,然后选择禁用电子邮件通知 .\nClick 保存更改.\n\nDisabling group mentions\n在 GitLab 12.6 中引入 .\n您可以防止将用户添加到对话中,并且在任何人提及这些用户所属的组时通知他们.\n自动完成下拉列表中会相应地显示提及被禁用的组.\n这对于具有大量用户的组特别有用.\n要启用此功能:\n\n导航到组的\"设置\">\"常规\"页面.\n展开\" 权限\",\" LFS,2FA\"部分,然后选择\" 禁用组提及\" .\nClick 保存更改.\n\nEnabling delayed Project removal\n在 GitLab 13.2 中引入 .\n默认情况下,组中的项目会立即删除. (可选)在Premium 或 Silver或更高级别上,您可以将组内的项目配置为在延迟间隔后删除.\n在此间隔期间,项目将处于只读状态,并且可以根据需要还原. 间隔时间默认为 7 天,可以由管理员在实例设置中进行修改.\n要启用延迟删除项目:\n\n导航到组的\"设置\">\"常规\"页面.\n展开\" 权限\",\" LFS,2FA\"部分,然后选中\" 启用延迟的项目删除\" .\nClick 保存更改.\n\nAdvanced settings\n\n项目 :查看该组中的所有项目,将成员添加到每个项目,访问每个项目的设置,以及删除任何项目,所有操作均在同一屏幕上进行.\nWebhooks :为您的组配置webhooks .\nKubernetes 集群集成 :将您的 GitLab 组与Kubernetes 集群连接 .\n审核事件 :查看该组的审核事件 .\n管道配额 :跟踪组的管道配额 .\n\nGroup push rules\nIntroduced in GitLab Starter 12.8.\n组推送规则允许组维护者为特定组内的新创建项目设置推送规则 .\n要为组配置推送规则,请导航至 在小组的侧边栏上.\n设置后,新的子组将根据以下任一条件为其设置推送规则:\n\n定义了推送规则的最接近的父组.\n如果没有父组定义推送规则,则在实例级别设置推送规则. \n\nCopyright © CODECHINA 2020 all right reserved,powered by Gitbook该文件修订时间:\n2020-08-29 22:25:55\n\nconsole.log(\"plugin-popup....\");document.onclick = function(e){ e.target.tagName === \"IMG\" && window.open(e.target.src,e.target.src)}img{cursor:pointer}"}}} \ No newline at end of file diff --git a/book.json b/book.json index 74a38998245d36197bba6c653dc3e5fab4a305ad..204019323f1e1746b4c0b0a4d02ae7e256300d9d 100644 --- a/book.json +++ b/book.json @@ -1,17 +1,29 @@ { +"title" : "CODEChina帮助文档", +"author" : "Miykael", +"description" : "CODEChina开源社区用户使用及帮助文档", +"language" : "zh-hans", +"links" : { + "sidebar" : { + + } +}, "plugins" : [ "favicon", "back-to-top-button", "popup", - "theme-fexa" + "theme-fexa", + "-sharing", + "sharing-plus", + "tbfed-pagefooter" ], "variables": { "themeFexa":{ "nav":[ { - "url":".", + "url":"/", "target":"_blank", - "name": "CODEChina Issue" + "name": "开始使用" } ] } @@ -29,7 +41,26 @@ "theme-fexa":{ "search-placeholder":"输入关键字搜索", "logo":"/docs/img/logo.png", - "favicon": "" + "favicon": "", + "url":"/" + }, + "sharing": { + "douban": true, + "facebook": false, + "google": false, + "qq": true, + "qzone": true, + "twitter": false, + "weibo": true, + "all": [ + "douban", "facebook", "google", "instapaper", "linkedin","twitter", "weibo", + "messenger","qq", "qzone","viber","whatsapp" + ] + }, + "tbfed-pagefooter": { + "copyright":"Copyright © CODECHINA 2020", + "modify_label": "该文件修订时间:", + "modify_format": "YYYY-MM-DD HH:mm:ss" } } } \ No newline at end of file diff --git a/docs/002.md b/docs/002.md index e213b1693683f2f446dd821b9d56abb67745a9b6..fb989660d65cd51fa5728b3e350b15b804ec69b3 100644 --- a/docs/002.md +++ b/docs/002.md @@ -1,163 +1,163 @@ # 帮助文档 -*访问[codechina.csdn.net/docs,](codechina.csdn.net/docs)以获得优化的导航,可发现性和可读性.* +*访问[codechina.csdn.net/docs,](codechina.csdn.net/docs)以获得优化的导航,可发现性和可读性。* -## 概览[](#overview "Permalink") +## 概览[](#概览 "Permalink") 欢迎您使用CODEChina,如果您是 Github 或 GitLab 的初级用户,我们建议您从查看本文档开始学习如何使用 CODEChina。如果您熟悉以上两个产品中的一个或多个,您可以直接开始 CODEChina 产品,在产品中我们也会为您设置帮助提示,您可以随时回来查看我们的产品文档。 | 基础入门 | 基本入门 | | --- | --- | -| [**用户文件**](#user/index.html)熟悉CODEChina 中的功能和概念. | [**管理员文件**](#administration/index.html)管理员入门. | -| [**为 CODEChina 做贡献**](#contributing-to-codechina)为CODEChina开源贡献力量! | [**是 Git 和 GitLab/GitHub 的新手吗?**](#new-to-git-and-gitlab-or-github)我们有资源可以帮助您入门. | -| [**从另一个平台进入 CODEChina?**](#coming-to-codechina-from-another-platform)请查阅我们的便捷指南. |  | +| [**用户文件**](user/index.html)熟悉CODEChina 中的功能和概念. | [**管理员文件**](administration/index.html)管理员入门 | +| [**为 CODEChina 做贡献**](#为codechina开源做贡献)为CODEChina开源贡献力量! | [**是 Git 和 GitLab/GitHub 的新手吗?**](#刚开始使用git吗)我们有资源可以帮助您入门 | +| [**从另一个平台进入 CODEChina?**](#从另一个平台进入到codechina)请查阅我们的便捷指南 |  | -## 热门话题[](#popular-topics "Permalink") +## 热门话题[](#热门话题 "Permalink") 以下是我们推荐的一些主题: -### 计划[](#plan "Permalink") +### 计划[](#计划 "Permalink") -无论您使用 Waterfall,敏捷还是会话开发,CODEChina 均可简化您的协作工作流程. +无论您使用 Waterfall,敏捷还是会话开发,CODEChina 均可简化您的协作工作流程。 -使用 CODEChina 灵活的项目管理工具可视化,确定优先级,协调和跟踪进度. +使用 CODEChina 灵活的项目管理工具可视化,确定优先级,协调和跟踪进度。 以下文档与 DevOps **计划**阶段有关: | 计划主题 | 描述 | | --- | --- | -| [Burndown Charts](user/project/milestones/burndown_charts.html) | 在特定的里程碑中观察项目的进度. | -| [讨论](user/discussions/index.html) | 问题,提交和合并请求中的线程,注释和可解决线程. | -| [截止日期]](user/project/issues/due_dates.html) | 跟踪发行期限. | -| [Epics](user/group/epics/index.html) | 跟踪共享主题的问题组. | -| [问题](user/project/issues/index.html) ,包括[机密问题](user/project/issues/confidential_issues.html) ,[发布和合并请求模板](user/project/description_templates.html) ,和[移动的问题](user/project/issues/managing_issues.html#moving-issues) | 项目问题并限制对问题的访问,并创建用于提交新问题和合并请求的模板. 此外,在项目之间转移问题. | -| [标签](user/project/labels.html) | 分类问题或使用描述性标签合并请求. | -| [里程碑](user/project/milestones/index.html) | 设置发布问题和合并请求的里程碑,并带有可选的截止日期. | -| [看板](user/project/issue_board.html) | 在 Scrum 或看板上显示问题. | -| [快捷方式](user/project/quick_actions.html) | 针对问题或合并请求的常见操作的快捷方式,而无需单击按钮或在WEB界面中使用下拉菜单. | +| [Burndown Charts](user/project/milestones/burndown_charts.html) | 在特定的里程碑中观察项目的进度 | +| [讨论](user/discussions/index.html) | 问题,提交和合并请求中的线程,注释和可解决线程 | +| [截止日期](user/project/issues/due_dates.html) | 跟踪发行期限| +| [Epics](user/group/epics/index.html) | 跟踪共享主题的问题组| +| [问题](user/project/issues/index.html) ,包括[机密问题](user/project/issues/confidential_issues.html) ,[发布和合并请求模板](user/project/description_templates.html) ,和[移动的问题](user/project/issues/managing_issues.html#moving-issues) | 项目问题并限制对问题的访问,并创建用于提交新问题和合并请求的模板。 此外,在项目之间转移问题。| +| [标签](user/project/labels.html) | 分类问题或使用描述性标签合并请求| +| [里程碑](user/project/milestones/index.html) | 设置发布问题和合并请求的里程碑,并带有可选的截止日期| +| [看板](user/project/issue_board.html) | 在 Scrum 或看板上显示问题| +| [快捷方式](user/project/quick_actions.html) | 针对问题或合并请求的常见操作的快捷方式,而无需单击按钮或在WEB界面中使用下拉菜单。 | | [关联 Issue](user/project/issues/related_issues.html) | 在问题之间建立关系. | -| [Roadmap](user/group/roadmap/index.html) | 可视化史诗般的时间表. | -| [时间跟踪](user/project/time_tracking.html) | 跟踪花费在问题和合并请求上的时间. | -| [代办事项](user/todos.html) | 通过在简单仪表板上显示的时间顺序列表,跟踪需要注意的工作. | +| [Roadmap](user/group/roadmap/index.html) | 可视化史诗般的时间表 | +| [时间跟踪](user/project/time_tracking.html) | 跟踪花费在问题和合并请求上的时间 | +| [代办事项](user/todos.html) | 通过在简单仪表板上显示的时间顺序列表,跟踪需要注意的工作。 | [返回概览](#概览) -### 新建[](#create "Permalink") +### 新建[](#新建 "Permalink") -将源代码整合到一个易于管理和控制的[分布式版本控制系统中](https://en.wikipedia.org/wiki/Distributed_version_control) ,而不会中断您的工作流程. +将源代码整合到一个易于管理和控制的[分布式版本控制系统中](https://en.wikipedia.org/wiki/Distributed_version_control) ,而不会中断您的工作流程。 -CODEChina 存储库随附分支工具和访问控制,可为项目和代码的协作提供可扩展的单一事实来源. +CODEChina 存储库随附分支工具和访问控制,可为项目和代码的协作提供可扩展的单一事实来源。 以下文档与 DevOps **新建**阶段有关: -#### 项目和组织[](#projects-and-groups "Permalink") +#### 项目和组织[](#项目和组织 "Permalink") | 创建主题-项目和组 | 描述 | | --- | --- | -| [全局搜索](user/search/advanced_global_search.html) | 利用 Elasticsearch 在整个 CODEChina 实例上进行更快,更高级的代码搜索. | -| [语法检索](user/search/advanced_search_syntax.html) | 使用高级查询获得更具针对性的搜索结果. | -| [Contribution analytics](user/group/contribution_analytics/index.html) | 请参阅小组贡献者的详细统计信息. | -| [创建](basics/create-project.html)并[fork](basics/fork-project.html)项目,以及[导入项目](user/project/settings/import_export.html) [](user/project/settings/import_export.html) [实例之间](user/project/settings/import_export.html) | 创建,复制和移动项目. | -| [锁定文件](user/project/file_lock.html) | 锁定文件以避免合并冲突. | -| [组织](user/group/index.html) and [子组织](user/group/subgroups/index.html) | 分组组织您的项目. | -| [Issue 分析](user/group/issues_analytics/index.html) | 检查每月创建了多少个问题. | -| [项目](user/project/index.html) ,包括[项目访问](public_access/public_access.html)和[设置](user/project/settings/index.html) | 托管源代码,并控制项目的可见性和设置配置. | -| [Search through CODEChina](user/search/index.html) | 搜索问题,合并请求,项目,组和待办事项. | -| [Web IDE](user/project/web_ide/index.html) | 在 WebIDE 中编辑文件. | -| [Wikis](user/project/wiki/index.html) | 使用内置的 Wiki 来管理您的文档. | +| [全局搜索](user/search/advanced_global_search.html) | 利用 Elasticsearch 在整个 CODEChina 实例上进行更快,更高级的代码搜索| +| [语法检索](user/search/advanced_search_syntax.html) | 使用高级查询获得更具针对性的搜索结果| +| [Contribution analytics](user/group/contribution_analytics/index.html) | 请参阅小组贡献者的详细统计信息| +| [创建](basics/create-project.html)并[fork](basics/fork-project.html)项目,以及[导入项目](user/project/settings/import_export.html) [](user/project/settings/import_export.html) [实例之间](user/project/settings/import_export.html) | 创建,复制和移动项目 | +| [锁定文件](user/project/file_lock.html) | 锁定文件以避免合并冲突 | +| [组织](user/group/index.html) and [子组织](user/group/subgroups/index.html) | 分组组织您的项目 | +| [Issue 分析](user/group/issues_analytics/index.html) | 检查每月创建了多少个问题| +| [项目](user/project/index.html) ,包括[项目访问](public_access/public_access.html)和[设置](user/project/settings/index.html) | 托管源代码,并控制项目的可见性和设置配置。| +| [Search through CODEChina](user/search/index.html) | 搜索问题,合并请求,项目,组和待办事项。| +| [Web IDE](user/project/web_ide/index.html) | 在 WebIDE 中编辑文件| +| [Wikis](user/project/wiki/index.html) | 使用内置的 Wiki 来管理您的文档| [返回概览](#概览) -#### 代码仓库[](#repositories "Permalink") +#### 代码仓库[](#代码仓库 "Permalink") | 创建主题-代码仓库 | 描述 | | --- | --- | -| [分支](user/project/repository/branches/index.html)和[默认分支](user/project/repository/branches/index.html#default-branch) | 如何在 CODEChina 中使用分支. | -| [提交](user/project/repository/index.html#commits) and [署名提交](user/project/repository/gpg_signed_commits/index.html) | 处理提交,并使用 GPG 对您的提交进行签名. | -| [创建分支](user/project/repository/web_editor.html#create-a-new-branch) , [创建](user/project/repository/web_editor.html#create-a-file)并[上传](user/project/repository/web_editor.html#upload-a-file)文件,并[创建目录](user/project/repository/web_editor.html#create-a-directory) | 创建分支,创建和上传文件以及创建目录. | -| [删除已合并的分支](user/project/repository/branches/index.html#delete-merged-branches) | 合并更改后的批量删除分支. | -| [文件模板](user/project/repository/web_editor.html#template-dropdowns) | 通用文件的文件模板. | -| [文件](user/project/repository/index.html#files) | 文件管理. | -| [Jupyter Notebook 文件](user/project/repository/jupyter_notebooks/index.html#jupyter-notebook-files) | 对`.ipynb`文件的支持. | -| [保护分支](user/project/protected_branches.html) | 使用受保护的分支. | -| [推送规则](push_rules/push_rules.html) | 对项目推送的附加控制. | -| [代码仓库](user/project/repository/index.html) | 在网页中管理源代码仓库. | +| [分支](user/project/repository/branches/index.html)和[默认分支](user/project/repository/branches/index.html#default-branch) | 如何在 CODEChina 中使用分支 | +| [提交](user/project/repository/index.html#commits) and [署名提交](user/project/repository/gpg_signed_commits/index.html) | 处理提交,并使用 GPG 对您的提交进行签名。 | +| [创建分支](user/project/repository/web_editor.html#create-a-new-branch) , [创建](user/project/repository/web_editor.html#create-a-file)并[上传](user/project/repository/web_editor.html#upload-a-file)文件,并[创建目录](user/project/repository/web_editor.html#create-a-directory) | 创建分支,创建和上传文件以及创建目录。| +| [删除已合并的分支](user/project/repository/branches/index.html#delete-merged-branches) | 合并更改后的批量删除分支| +| [文件模板](user/project/repository/web_editor.html#template-dropdowns) | 通用文件的文件模板 | +| [文件](user/project/repository/index.html#files) | 文件管理 | +| [Jupyter Notebook 文件](user/project/repository/jupyter_notebooks/index.html#jupyter-notebook-files) | 对`.ipynb`文件的支持 | +| [保护分支](user/project/protected_branches.html) | 使用受保护的分支 | +| [推送规则](push_rules/push_rules.html) | 对项目推送的附加控制 | +| [代码仓库](user/project/repository/index.html) | 在网页中管理源代码仓库 | | [镜像代码仓库](user/project/repository/repository_mirroring.html) | 推入或拉出外部的代码仓库 | -| [处理合并请求](user/project/repository/web_editor.html#tips) | 在提交时启动合并请求. | +| [处理合并请求](user/project/repository/web_editor.html#tips) | 在提交时启动合并请求 | [返回概览](#概览) -#### 合并请求[](#merge-requests "Permalink") +#### 合并请求[](#合并请求 "Permalink") | 创建主题-合并请求 | 描述 | | --- | --- | -| [在本地处理合并请求](user/project/merge_requests/reviewing_and_managing_merge_requests.html#checkout-merge-requests-locally) | 在本地处理合并请求的提示. | -| [Cherry-pick](user/project/merge_requests/cherry_pick_changes.html) | 对更改进行 Cherry Pick. | -| [Merge request thread resolution](user/discussions/index.html#moving-a-single-thread-to-a-new-issue) | 解析线程,将合并请求中的线程移至问题,并且仅在解决所有线程后才允许合并请求. | -| [合并请求](user/project/merge_requests/index.html) | 合并请求管理. | -| [草稿合并请求](user/project/merge_requests/work_in_progress_merge_requests.html) | 防止合并草稿合并请求. | +| [在本地处理合并请求](user/project/merge_requests/reviewing_and_managing_merge_requests.html#checkout-merge-requests-locally) | 在本地处理合并请求的提示| +| [Cherry-pick](user/project/merge_requests/cherry_pick_changes.html) | 对更改进行 Cherry Pick | +| [Merge request thread resolution](user/discussions/index.html#moving-a-single-thread-to-a-new-issue) | 解析线程,将合并请求中的线程移至问题,并且仅在解决所有线程后才允许合并请求。 | +| [合并请求](user/project/merge_requests/index.html) | 合并请求管理 | +| [草稿合并请求](user/project/merge_requests/work_in_progress_merge_requests.html) | 防止合并草稿合并请求 | [返回概览](#概览) -## 刚开始使用Git/CODEChina/GitLab/Github?[](#new-to-git-and-gitlab-or-github "Permalink") +## 刚开始使用Git/CODEChina/GitLab/Github?[](#刚开始使用git吗 "Permalink") 使用新系统可能让您觉得难以入手,我们有以下文档可快速提升您的相关知识: | 主题 | 描述 | | --- | --- | -| [Basics guides](basics/README.html) | 开始在命令行和 CODEChina 上工作. | -| [Workflow overview]() | 利用最佳的工作流程增强您的工作流程. | +| [Basics guides](basics/README.html) | 开始在命令行和 CODEChina 上工作 | +| [Workflow overview]() | 利用最佳的工作流程增强您的工作流程 | | [Markdown](user/markdown.html) | 高级格式化系统(Markdown) | [返回概览](#概览) -### 账户管理[](#user-account "Permalink") +### 账户管理[](#账户管理 "Permalink") 了解有关帐户管理的更多信息: | 主题 | 描述 | | --- | --- | -| [用户账号](user/profile/index.html) | 管理您的帐户. | -| [账号验证](topics/authentication/index.html) | 具有两因素身份验证的帐户安全性,设置您的 SSH 密钥,并部署密钥以安全地访问您的项目. | -| [用户权限](user/permissions.html) | 了解项目中的每个角色可以做什么. | +| [用户账号](user/profile/index.html) | 管理您的帐户 | +| [账号验证](topics/authentication/index.html) | 具有两因素身份验证的帐户安全性,设置您的 SSH 密钥,并部署密钥以安全地访问您的项目。 | +| [用户权限](user/permissions.html) | 了解项目中的每个角色可以做什么 | [返回概览](#概览) -### Git 和 CODEChina[](#git-and-codechina "Permalink") +### Git 和 CODEChina[](#Git和CODEChina "Permalink") 了解有关使用 Git 以及将 Git 与 CODEChina 结合使用的更多信息: | 主题 | 描述 | | --- | --- | -| [Git](topics/git/index.html) | Git 入门,分支策略,Git LFS 和高级用法. | -| [Git cheat sheet](https://about.gitlab.com/images/press/git-cheat-sheet.pdf) | 下载描述最常用的 Git 操作的 PDF. | -| [Work Flow](topics/flow.html) | 使用 Work Flow 策略探索 Git 的精华. | +| [Git](topics/git/index.html) | Git 入门,分支策略,Git LFS 和高级用法 | +| [Git cheat sheet](https://about.gitlab.com/images/press/git-cheat-sheet.pdf) | 下载描述最常用的 Git 操作的 PDF| +| [Work Flow](topics/flow.html) | 使用 Work Flow 策略探索 Git 的精华 | [返回概览](#概览) -## 从另一个平台进入 CODEChina?[](#coming-to-codechina-from-another-platform "Permalink") +## 从另一个平台进入到 CODEChina?[](#从另一个平台进入到 codechina "Permalink") 如果您是从另一个平台进入 CODEChina,您会发现以下有用信息: | 主题 | 描述 | | --- | --- | -| [导入项目](user/project/import/index.html) | 从 GitHub,Bitbucket,GitLab.com,FogBugz 和 SVN 导入项目. | -| [从SVN迁移](user/project/import/svn.html) | 将 SVN 存储库转换为 Git 和 CODEChina. | +| [导入项目](user/project/import/index.html) | 从 GitHub,Bitbucket,GitLab.com,FogBugz 和 SVN 导入项目 | +| [从SVN迁移](user/project/import/svn.html) | 将 SVN 存储库转换为 Git 和 CODEChina | [返回概览](#概览) -## 为CODEChina开源做贡献[](#contributing-to-codechina "Permalink") +## 为CODEChina开源做贡献[](#为codehina开源做贡献 "Permalink") CODEChina 是开源的,您可以通过以下方式为我们的开源社区做出贡献: | 主题 | 描述 | | --- | --- | -| [开发](development/README.html) | 如何在开发上做贡献. | -| [协议](legal/README.html) | 贡献者许可协议. | -| [文档](development/documentation/index.html) | 如何在文档上做贡献. | +| [开发](development/README.html) | 如何在开发上做贡献 | +| [协议](legal/README.html) | 贡献者许可协议 | +| [文档](development/documentation/index.html) | 如何在文档上做贡献| [返回概览](#概览) \ No newline at end of file diff --git a/docs/003.md b/docs/003.md deleted file mode 100644 index 1ff4afc6e9be8753b25555b544d10175642d4abd..0000000000000000000000000000000000000000 --- a/docs/003.md +++ /dev/null @@ -1,76 +0,0 @@ -# Installation - -> 原文:[https://docs.gitlab.com/ee/install/README.html](https://docs.gitlab.com/ee/install/README.html) - -* [Requirements](#requirements) -* [Installing GitLab using the Omnibus GitLab package (recommended)](#installing-gitlab-using-the-omnibus-gitlab-package-recommended) -* [Installing GitLab on Kubernetes via the GitLab Helm charts](#installing-gitlab-on-kubernetes-via-the-gitlab-helm-charts) -* [Installing GitLab with Docker](#installing-gitlab-with-docker) -* [Installing GitLab from source](#installing-gitlab-from-source) -* [Installing GitLab on cloud providers](#installing-gitlab-on-cloud-providers) -* [Securing your GitLab installation](#securing-your-gitlab-installation) - -# Installation[](#installation-core-only "Permalink") - -GitLab 可以安装在大多数 GNU / Linux 发行版以及许多云提供商中. 为了从 GitLab 获得最佳体验,您需要在性能,可靠性,易于管理(备份,升级和故障排除)以及托管成本之间取得平衡. - -根据平台的不同,可以通过多种方式安装 GitLab: - -1. **Omnibus GitLab** :官方的 deb / rpm 软件包,包含捆绑的 GitLab 及其依赖的各种组件,例如 PostgreSQL,Redis,Sidekiq 等. -2. **GitLab Helm 图表** :用于在 Kubernetes 上安装 GitLab 及其所有组件的云原生 Helm 图表. -3. **码头**工人:Omnibus GitLab 软件包码头化. -4. **来源** :从头开始安装 GitLab 及其所有组件. - -**如有疑问,请选择 Omnibus:** Omnibus GitLab 软件包已经成熟, [可扩展,](../administration/reference_architectures/index.html)并且已在 GitLab.com 上使用. 建议向熟悉 Kubernetes 的人使用 Helm 图表. - -## Requirements[](#requirements "Permalink") - -在安装 GitLab 之前,查看系统[要求](requirements.html)至关重要. 系统要求包括有关最低硬件,软件,数据库以及支持 GitLab 的其他要求的详细信息. - -## Installing GitLab using the Omnibus GitLab package (recommended)[](#installing-gitlab-using-the-omnibus-gitlab-package-recommended "Permalink") - -Omnibus GitLab 软件包使用我们的官方 deb / rpm 存储库. 建议大多数用户使用. - -如果您需要更多的灵活性和弹性,我们建议按照[参考架构文档](../administration/reference_architectures/index.html)中的[说明](../administration/reference_architectures/index.html)部署 GitLab. - -[**> Install GitLab using the Omnibus GitLab package.**](https://about.gitlab.com/install/) - -## Installing GitLab on Kubernetes via the GitLab Helm charts[](#installing-gitlab-on-kubernetes-via-the-gitlab-helm-charts "Permalink") - -**需要 Kubernetes 经验:**我们建议您先熟悉 Kubernetes,然后再使用 Kubernetes 在生产中部署 GitLab. 管理,可观察性和某些概念的方法与传统部署不同. - -在 Kubernetes 上安装 GitLab 时,需要注意一些折衷: - -* 管理和故障排除需要 Kubernetes 知识. -* 对于较小的安装,它可能会更昂贵. 默认安装比单节点 Omnibus 部署需要更多的资源,因为大多数服务都是以冗余方式部署的. -* 有一些功能[限制需要注意](https://docs.gitlab.com/charts/) . - -[**> Install GitLab on Kubernetes using the GitLab Helm charts.**](https://docs.gitlab.com/charts/) - -## Installing GitLab with Docker[](#installing-gitlab-with-docker "Permalink") - -GitLab 基于 Omnibus GitLab 软件包维护一组正式的 Docker 映像. - -[**> Install GitLab using the official GitLab Docker images.**](docker.html) - -## Installing GitLab from source[](#installing-gitlab-from-source "Permalink") - -如果您的发行版中没有 Omnibus GitLab 软件包,则可以从源代码安装 GitLab:对于* BSD 等不受支持的系统很有用. 有关目录结构的概述,请阅读[结构文档](structure.html) . - -[**> Install GitLab from source.**](installation.html) - -## Installing GitLab on cloud providers[](#installing-gitlab-on-cloud-providers "Permalink") - -只要有云提供商支持,就可以使用上述任何一种方法将 GitLab 安装在各种云提供商上. - -* [在 AWS 上](aws/index.html)安装:使用 GitLab 提供的社区 AMI 在 AWS [上](aws/index.html)安装 Omnibus GitLab. -* [在 Google Cloud Platform 上安装 GitLab](google_cloud_platform/index.html) :在 GCP 中的 VM 上安装 Omnibus GitLab. -* [在 Azure 上](azure/index.html)安装 GitLab:从 Azure 市场安装 Omnibus GitLab. -* [在 OpenShift 上](https://docs.gitlab.com/charts/installation/cloud/openshift.html)安装 GitLab:通过使用 GitLab 的 Helm 图表在 OpenShift [上](https://docs.gitlab.com/charts/installation/cloud/openshift.html)安装 GitLab. -* [在 DC / OS 上](https://d2iq.com/blog/gitlab-dcos)安装 GitLab:通过[GitLab-Mesosphere 集成](https://about.gitlab.com/blog/2016/09/16/announcing-gitlab-and-mesosphere/)在 Mesosphere DC / OS 上安装 GitLab. -* [在 DigitalOcean 上安装 GitLab:在 DigitalOcean 上](https://about.gitlab.com/blog/2016/04/27/getting-started-with-gitlab-and-digitalocean/)安装 Omnibus GitLab. -* *仅测试!* [DigitalOcean 和 Docker Machine](digitaloceandocker.html) :使用 Docker Machine 在 DigitalOcean 上快速测试任何版本的 GitLab. - -## Securing your GitLab installation[](#securing-your-gitlab-installation "Permalink") - -完成安装后,请查看我们[建议的做法以保护您的 GitLab 实例](../security/README.html#securing-your-gitlab-installation) . \ No newline at end of file diff --git a/docs/004.md b/docs/004.md deleted file mode 100644 index 195670cc6a4867e74e3110db9019017296083cef..0000000000000000000000000000000000000000 --- a/docs/004.md +++ /dev/null @@ -1,245 +0,0 @@ -# Requirements - -> 原文:[https://docs.gitlab.com/ee/install/requirements.html](https://docs.gitlab.com/ee/install/requirements.html) - -* [Operating Systems](#operating-systems) - * [Supported Linux distributions](#supported-linux-distributions) - * [Unsupported Linux distributions and Unix-like operating systems](#unsupported-linux-distributions-and-unix-like-operating-systems) - * [Microsoft Windows](#microsoft-windows) -* [Software requirements](#software-requirements) - * [Ruby versions](#ruby-versions) - * [Go versions](#go-versions) - * [Git versions](#git-versions) - * [Node.js versions](#nodejs-versions) -* [Redis versions](#redis-versions) -* [Hardware requirements](#hardware-requirements) - * [Storage](#storage) - * [CPU](#cpu) - * [Memory](#memory) -* [Database](#database) - * [PostgreSQL Requirements](#postgresql-requirements) - * [Additional requirements for GitLab Geo](#additional-requirements-for-gitlab-geo) -* [Puma settings](#puma-settings) - * [Puma workers](#puma-workers) - * [Puma threads](#puma-threads) -* [Unicorn Workers](#unicorn-workers) -* [Redis and Sidekiq](#redis-and-sidekiq) -* [Prometheus and its exporters](#prometheus-and-its-exporters) -* [GitLab Runner](#gitlab-runner) -* [Supported web browsers](#supported-web-browsers) - -# Requirements[](#requirements "Permalink") - -该页面包含有关受支持的操作系统以及安装和使用 GitLab 所需的硬件要求的有用信息. - -## Operating Systems[](#operating-systems "Permalink") - -### Supported Linux distributions[](#supported-linux-distributions "Permalink") - -* Ubuntu(16.04 / 18.04) -* Debian(8/9/10) -* CentOS 的(6/7/8) -* openSUSE(Leap 15.1 / Enterprise Server 12.2) -* 红帽企业版 Linux(请使用 CentOS 软件包和说明) -* 科学版 Linux(请使用 CentOS 软件包和说明) -* Oracle Linux(请使用 CentOS 软件包和说明) - -有关安装选项,请参见[主要安装页面](README.html) . - -### Unsupported Linux distributions and Unix-like operating systems[](#unsupported-linux-distributions-and-unix-like-operating-systems "Permalink") - -* Arch Linux -* Fedora -* FreeBSD -* Gentoo -* macOS - -可以在这些操作系统上安装 GitLab,但不支持. 请参阅[源安装指南](installation.html)和[安装指南](https://about.gitlab.com/install/)以获取更多信息. - -### Microsoft Windows[](#microsoft-windows "Permalink") - -GitLab 是针对基于 Linux 的操作系统开发的. 它**不能**在 Microsoft Windows 上运行,并且我们没有计划在不久的将来支持它. 有关最新的开发状态,请查看此[问题](https://gitlab.com/gitlab-org/gitlab/-/issues/22337) . 请考虑使用虚拟机运行 GitLab. - -## Software requirements[](#software-requirements "Permalink") - -### Ruby versions[](#ruby-versions "Permalink") - -GitLab 需要 Ruby(MRI)2.6\. 从 GitLab 12.2 开始,我们不再支持 Ruby 2.5 及更低版本. - -您必须使用 Ruby 的标准 MRI 实现. 我们喜欢[JRuby](https://www.jruby.org/)和[Rubinius](https://github.com/rubinius/rubinius#the-rubinius-language-platform) ,但是 GitLab 需要几个具有本机扩展的 Gems. - -### Go versions[](#go-versions "Permalink") - -所需的最低 Go 版本为 1.13. - -### Git versions[](#git-versions "Permalink") - -从 GitLab 13.1: - -* 需要 Git 2.25.x 及更高版本. -* [建议使用](https://gitlab.com/gitlab-org/gitaly/-/issues/2829) Git 2.27.x 及更高版本. - -### Node.js versions[](#nodejs-versions "Permalink") - -从 GitLab 12.9 开始,我们仅支持 node.js 10.13.0 或更高版本,并且我们放弃了对 node.js 8 的支持.(在 GitLab 11.8 中取消了对 node.js 6 的支持). - -我们建议使用 Node 12.x,因为它速度更快. - -GitLab 使用[Webpack](https://webpack.js.org/)编译前端资产,这需要最低版本的 Node.js 10.13.0. - -您可以使用`node -v`检查您正在运行哪个版本. 如果您运行的版本低于`v10.13.0` ,则需要将其更新为较新的版本. 您可以在[Node.js 网站上](https://s0nodejs0org.icopy.site/en/download/)找到从社区维护的软件包安装或从源代码进行编译的[说明](https://s0nodejs0org.icopy.site/en/download/) . - -## Redis versions[](#redis-versions "Permalink") - -GitLab 需要 Redis 5.0+. 从 GitLab 13.0 开始,不支持较低版本. - -## Hardware requirements[](#hardware-requirements "Permalink") - -### Storage[](#storage "Permalink") - -所需的硬盘空间在很大程度上取决于要存储在 GitLab 中的存储库的大小,但是根据*经验,*您应该至少具有与所有存储库加起来一样大的可用空间. - -如果您将来想灵活地增加硬盘驱动器空间,请考虑使用[逻辑卷管理(LVM)进行](https://en.wikipedia.org/wiki/Logical_volume_management)安装,以便在需要时可以添加更多硬盘驱动器. - -除本地硬盘驱动器外,您还可以安装支持网络文件系统(NFS)协议的卷. 该卷可能位于文件服务器,网络连接存储(NAS)设备,存储区域网络(SAN)或 Amazon Web Services(AWS)弹性块存储(EBS)卷上. - -如果您有足够的 RAM 和最新的 CPU,则 GitLab 的速度主要受硬盘搜索时间限制. 具有快速驱动器(7200 RPM 及更高版本)或固态驱动器(SSD)将提高 GitLab 的响应速度. - -**注意:**由于文件系统性能可能会影响 GitLab 的整体性能,因此[我们不建议使用 AWS EFS 进行存储](../administration/high_availability/nfs.html#avoid-using-awss-elastic-file-system-efs) . - -### CPU[](#cpu "Permalink") - -CPU 需求取决于用户数量和预期的工作量. 您的确切需求可能更多,具体取决于您的工作量. 您的工作负载受以下因素影响,这些因素包括但不限于:用户的活跃程度,使用的自动化程度,镜像和回购/更改大小. - -以下是一些示例 GitLab 用户库大小的建议最低 CPU 硬件指南. - -* **4 芯**是核心的**推荐**最小数目和多达 500 个用户支持 -* 8 个内核最多支持 1000 个用户 -* 更多用户? 查阅[参考架构页面](../administration/reference_architectures/index.html) - -### Memory[](#memory "Permalink") - -内存需求取决于用户数量和预期的工作量. 您的确切需求可能更多,具体取决于您的工作量. 您的工作负载受以下因素影响,这些因素包括但不限于:用户的活跃程度,使用的自动化程度,镜像和回购/更改大小. - -以下是一些示例 GitLab 用户库大小的建议最低内存硬件指南. - -* **4GB RAM**是**必需的**最小内存大小,最多可支持 500 个用户 - * 我们的[内存团队](https://about.gitlab.com/handbook/engineering/development/enablement/memory/)正在努力减少内存需求. -* 8GB RAM 最多支持 1000 个用户 -* 更多用户? 查阅[参考架构页面](../administration/reference_architectures/index.html) - -除上述之外,即使您当前有足够的可用 RAM,我们通常也建议在服务器上至少有 2GB 的交换空间. 如果您的可用内存发生更改,那么进行交换将有助于减少发生错误的机会. 我们还建议将内核的 swappiness 设置配置为较低的值(例如`10`以充分利用您的 RAM,同时在需要时仍可使用交换功能. - -## Database[](#database "Permalink") - -PostgreSQL 是唯一受支持的数据库,与 Omnibus GitLab 软件包捆绑在一起. 您也可以使用[外部 PostgreSQL 数据库](https://docs.gitlab.com/omnibus/settings/database.html) . 在 GitLab 12.1 中删除了对 MySQL 的支持. 建议在 MySQL / MariaDB 上使用 GitLab 的现有用户在升级之前[迁移到 PostgreSQL](../update/mysql_to_postgresql.html) . - -### PostgreSQL Requirements[](#postgresql-requirements "Permalink") - -运行 PostgreSQL 的服务器应*至少有* 5-10 GB 的可用存储空间,尽管确切的要求[取决于用户数量](../administration/reference_architectures/index.html) . - -我们强烈建议用户使用下面指定的最低 PostgreSQL 版本,因为这些是用于开发和测试的版本. - -| GitLab 版本 | 最低 PostgreSQL 版本 | -| --- | --- | -| 10.0 | 9.6 | -| 12.10 | 11 | -| 13.0 | 11 | - -您还必须确保将`pg_trgm`扩展加载到每个 GitLab 数据库中. [可以](https://s0www0postgresql0org.icopy.site/docs/11/sql-createextension.html)使用 PostgreSQL 超级用户[启用](https://s0www0postgresql0org.icopy.site/docs/11/sql-createextension.html)此扩展. - -在某些系统上,您可能需要安装一个附加软件包(例如`postgresql-contrib` ),此扩展才可以使用. - -**注意:** [在 GitLab 13.0 中已删除了](https://about.gitlab.com/releases/2020/05/22/gitlab-13-0-released/#postgresql-11-is-now-the-minimum-required-version-to-install-gitlab)对[PostgreSQL 9.6 和 10 的](https://about.gitlab.com/releases/2020/05/22/gitlab-13-0-released/#postgresql-11-is-now-the-minimum-required-version-to-install-gitlab)支持,因此 GitLab 可以从 PostgreSQL 11 的改进(例如分区)中受益. 有关过渡到 PostgreSQL 12 的时间表,请参阅[相关的 epic](https://gitlab.com/groups/gitlab-org/-/epics/2184) . - -#### Additional requirements for GitLab Geo[](#additional-requirements-for-gitlab-geo "Permalink") - -如果您使用的是[GitLab Geo](../administration/geo/replication/index.html) : - -* 我们强烈建议您在积极开发和测试的情况下运行由 Omnibus 管理的实例. 我们的目标是与大多数外部数据库(不由 Omnibus 管理)兼容(例如, [AWS Relational Database Service(RDS)](https://aws.amazon.com/rds/) ),但我们不保证兼容性. -* 您还必须确保将`postgres_fdw`扩展加载到每个 GitLab 数据库中. [可以](https://s0www0postgresql0org.icopy.site/docs/11/sql-createextension.html)使用 PostgreSQL 超级用户[启用](https://s0www0postgresql0org.icopy.site/docs/11/sql-createextension.html)此扩展. - -## Puma settings[](#puma-settings "Permalink") - -建议的 Puma 设置取决于运行它的基础结构. Omnibus GitLab 默认为建议的 Puma 设置. 无论安装方法如何,都可以调整 Puma 设置. - -如果您使用的是 Omnibus GitLab,请参阅[Puma 设置](https://docs.gitlab.com/omnibus/settings/puma.html)以获取有关更改 Puma 设置的说明. 如果您使用的是 GitLab Helm 图表,请参阅[Webservice 图表](https://docs.gitlab.com/charts/charts/gitlab/webservice/index.html) . - -### Puma workers[](#puma-workers "Permalink") - -推荐的工人人数是根据以下最高者计算得出的: - -* `2` -* CPU 核心数-1 - -例如,一个具有 4 个核心的节点应配置 3 个 Puma Worker. - -如果可以提供足够的 CPU 和内存容量,则可以增加 Puma worker 的数量. 数量更多的 Puma 工作人员通常将有助于减少应用程序的响应时间并提高处理并行请求的能力. 您必须执行测试以验证基础架构的最佳设置. - -### Puma threads[](#puma-threads "Permalink") - -推荐的线程数取决于几个因素,包括总内存和[传统 Rugged 代码的使用](../development/gitaly.html#legacy-rugged-code) . - -* 如果操作系统最多具有 2 GB 的内存,则建议的线程数为`1` . 较高的值将导致过多的交换,并降低性能. -* If legacy Rugged code is in use, the recommended number of threads is `1`. -* 在所有其他情况下,建议的线程数为`4` . 由于[Ruby MRI 多线程的](https://en.wikipedia.org/wiki/Global_interpreter_lock)工作方式,我们不建议设置更高的值. - -## Unicorn Workers[](#unicorn-workers "Permalink") - -对于大多数情况,我们建议使用:(CPU 内核* 1.5)+ 1 = Unicorn worker. 例如,一个具有 4 个核心的节点将有 7 个 Unicorn worker. - -对于所有 2GB 以上的计算机,我们建议至少三名 Unicorn 工人. 如果您有一台 1GB 的计算机,我们建议仅配置两个 Unicorn worker,以防止过度交换. - -只要您有足够的可用 CPU 和内存容量,就可以增加 Unicorn worker 的数量,这通常将有助于减少应用程序的响应时间并提高处理并行请求的能力. - -要在拥有 Omnibus 软件包(默认为上述建议)时更改 Unicorn worker,请参阅[Omnibus GitLab 文档中的 Unicorn 设置](https://docs.gitlab.com/omnibus/settings/unicorn.html) . - -## Redis and Sidekiq[](#redis-and-sidekiq "Permalink") - -Redis 存储所有用户会话和后台任务队列. Redis 的存储要求极低,每个用户大约 25kB. Sidekiq 使用多线程进程来处理后台作业. 此过程从整个 Rails 堆栈(200MB +)开始,但是由于内存泄漏,它可能随着时间的推移而增长. 在非常活跃的服务器(10,000 个活跃用户)上,Sidekiq 进程可以使用 1GB +的内存. - -## Prometheus and its exporters[](#prometheus-and-its-exporters "Permalink") - -从 Omnibus GitLab 9.0 起,默认启用[Prometheus](https://s0prometheus0io.icopy.site)及其相关出口商,以实现对 GitLab 的轻松和深度监控. 使用默认设置,这些进程将消耗大约 200MB 的内存. - -如果您想禁用 Prometheus 及其出口商或阅读有关它的更多信息,请查阅[Prometheus 文档](../administration/monitoring/prometheus/index.html) . - -## GitLab Runner[](#gitlab-runner "Permalink") - -强烈建议不要在打算安装 GitLab 的同一台计算机上安装 GitLab Runner. 根据您决定配置 GitLab Runner 的方式以及用于在 CI 环境中运行应用程序的工具的不同,GitLab Runner 会消耗大量可用内存. - -如果您决定在同一台计算机上运行 GitLab Runner 和 GitLab Rails 应用程序,则上面提供的内存消耗计算将无效. - -由于[安全原因](https://docs.gitlab.com/runner/security/) ,将所有内容都安装在一台机器上也不安全,尤其是当您计划将 Shell executor 与 GitLab Runner 一起使用时. - -如果您打算使用 CI 功能,我们建议为每个 GitLab Runner 使用单独的机器. GitLab Runner 服务器要求取决于: - -* 您在 GitLab Runner 上配置的[执行程序](https://docs.gitlab.com/runner/executors/)的类型. -* 运行构建作业所需的资源. -* 作业并发设置. - -由于作业的性质因每个用例而异,因此您将需要通过调整作业并发来进行实验以获得最佳设置. - -作为参考,对 GitLab.com 的[自动缩放共享](../user/gitlab_com/index.html#shared-runners)运行器进行了配置,以便**单个作业**将在**单个实例中**运行,并具有: - -* 1vCPU. -* 3.75GB 的 RAM. - -## Supported web browsers[](#supported-web-browsers "Permalink") - -**警告:**在 GitLab 13.0(2020 年 5 月)中,我们删除了对 Internet Explorer 11 的官方支持.在 GitLab 13.4 发行版(2020 年 9 月)中,我们将删除了所有支持 Internet Explorer 11 的代码.您可以提供[有关此问题的](https://gitlab.com/gitlab-org/gitlab/-/issues/197987)反馈[,](https://gitlab.com/gitlab-org/gitlab/-/issues/197987)也可以通过通常的支持渠道. - -GitLab supports the following web browsers: - -* [Mozilla Firefox](https://www.mozilla.org/en-US/firefox/new/) -* [Google Chrome](https://www.google.com/chrome/) -* [Chromium](https://www.chromium.org/getting-involved/dev-channel) -* [Apple Safari](https://www.apple.com/safari/) -* [Microsoft Edge](https://www.microsoft.com/en-us/edge) - -对于列出的 Web 浏览器,GitLab 支持: - -* 当前和以前的主要浏览器版本(Internet Explorer 除外). -* 受支持的主要版本的当前次要版本. - -**注意:**我们不支持在浏览器中禁用 JavaScript 的情况下运行 GitLab,并且将来也没有支持该计划的计划,因为我们具有诸如 Issue Boards 之类的功能,这些功能广泛需要 JavaScript. \ No newline at end of file diff --git a/docs/005.md b/docs/005.md deleted file mode 100644 index 0b8423e6516d336a1fee5bc0b1837fdb766a6dc5..0000000000000000000000000000000000000000 --- a/docs/005.md +++ /dev/null @@ -1 +0,0 @@ -> 原文:[https://about.gitlab.com/install/](https://about.gitlab.com/install/) \ No newline at end of file diff --git a/docs/006.md b/docs/006.md deleted file mode 100644 index f9d6aa3fc2263d2d747eeecfbbe0b4d004d4ed61..0000000000000000000000000000000000000000 --- a/docs/006.md +++ /dev/null @@ -1,181 +0,0 @@ -# GitLab cloud native Helm Chart - -> 原文:[https://docs.gitlab.com/charts/](https://docs.gitlab.com/charts/) - -* [Introduction](#introduction) -* [Limitations](#limitations) -* [GitLab Helm chart quick start guide](#gitlab-helm-chart-quick-start-guide) -* [Troubleshooting](#troubleshooting) -* [Installation](#installation) - * [Global settings](#global-settings) - * [Complete properties list](#complete-properties-list) -* [Upgrading](#upgrading) -* [Uninstall](#uninstall) -* [Advanced](#advanced) - * [Advanced Configuration](#advanced-configuration) - * [Migrate from Omnibus GitLab to Kubernetes](#migrate-from-omnibus-gitlab-to-kubernetes) -* [Architecture](#architecture) -* [Development](#development) - * [GitLab version mappings](#gitlab-version-mappings) - * [Contributing](#contributing) - -# GitLab cloud native Helm Chart[](#gitlab-cloud-native-helm-chart "Permalink") - -这是在云本机环境上安装 GitLab 的官方,推荐和受支持的方法. - -**注意:**不必在 Kubernetes 上安装 GitLab 即可使用[GitLab Kubernetes 集成](https://docs.gitlab.com/ee/user/project/clusters/) . - -## Introduction[](#introduction "Permalink") - -The `gitlab/gitlab` chart is the best way to operate GitLab on Kubernetes. This chart contains all the required components to get started, and can scale to large deployments. - -该图表包括完整的体验所需的所有组件,但是每个部分都可以单独安装. - -* GitLab 核心组件: - * [NGINX 入口](charts/nginx/index.html) - * [登记处](charts/registry/index.html) - * [亚搏体育 app](charts/gitlab/gitaly/index.html) / [Gitaly](charts/gitlab/gitaly/index.html) - * GitLab / [GitLab 出口商](charts/gitlab/gitlab-exporter/index.html) - * GitLab / [GitLab Grafana](charts/gitlab/gitlab-grafana/index.html) - * GitLab / [GitLab 外壳](charts/gitlab/gitlab-shell/index.html) - * GitLab / [迁移](charts/gitlab/migrations/index.html) - * [亚搏体育 app](charts/gitlab/sidekiq/index.html) / [Sidekiq](charts/gitlab/sidekiq/index.html) - * GitLab / [web 服务](charts/gitlab/webservice/index.html) -* 可选依赖项: - * [PostgreSQL 的](https://hub.helm.sh/charts/bitnami/postgresql) - * [雷迪斯](https://hub.helm.sh/charts/bitnami/redis) - * [MinIO](charts/minio/index.html) -* 可选的补充: - * [普罗米修斯](https://hub.helm.sh/charts/stable/prometheus) - * [格拉法纳](https://hub.helm.sh/charts/stable/grafana) - * 使用 Kubernetes 执行器的[*非特权*](https://docs.gitlab.com/runner/install/kubernetes.html) [GitLab Runner](https://docs.gitlab.com/runner/) - * 使用[Jetstack](https://www.jetstack.io/)的[cert-manager](https://cert-manager.io/docs/)通过[Let's Encrypt](https://letsencrypt.org/)自动提供 SSL - -## Limitations[](#limitations "Permalink") - -使用 Helm 图表当前无法使用 GitLab 的某些功能: - -* [GitLab Pages](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/37) -* [Smartcard authentication](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/988) - -数据库限制: - -* GitLab Geo 功能[需要使用外部数据库服务](installation/deployment.html#postgresql) . - -## GitLab Helm chart quick start guide[](#gitlab-helm-chart-quick-start-guide "Permalink") - -对于那些希望在*非生产*用例中尽快建立并运行这些图表的人,我们提供了概念验证(PoC)部署[快速入门指南](quickstart/index.html) . - -本指南将通过部署这些图表使用默认值和功能引导用户,但*不*符合生产做好准备的要求. 如果希望在持续负载下将这些图表部署到生产中,则应遵循以下完整的[安装指南](#installation) . - -## Troubleshooting[](#troubleshooting "Permalink") - -我们已尽力使这些图表尽可能地无缝,但偶尔也会出现无法控制的问题. 我们已收集了一些常见问题的疑难解答技巧. 在提出[问题](https://gitlab.com/gitlab-org/charts/gitlab/-/issues)之前,请先检查这些内容,并通过提出[合并请求](https://gitlab.com/gitlab-org/charts/gitlab/-/merge_requests)随意添加它们! - -See [Troubleshooting](troubleshooting/index.html). - -## Installation[](#installation "Permalink") - -`gitlab/gitlab`图表包含所有必需的依赖项. 在生产中,您可能需要启用可选功能或[高级配置](#advanced-configuration) . 本指南深入介绍了这些图表的所有选项和功能. - -如果您只是想部署概念验证进行测试,我们强烈建议您遵循我们的[快速入门](#gitlab-helm-chart-quick-start-guide)进行第一次迭代. - -1. [Preparation](installation/index.html) -2. [Deployment](installation/deployment.html) - -### Global settings[](#global-settings "Permalink") - -这些图表的复杂性使其可以使用全局属性. 有许多通用全局设置适用于多个图表. 有关不同的全局配置值及其应用程序的详细信息,请参见[Globals 文档](charts/globals.html) . - -### Complete properties list[](#complete-properties-list "Permalink") - -经常要求我们将所有可能的属性表直接放入此索引. 这些图表是规模*庞大* ,并作为属性的这种数量超过背景的量,我们在这里很舒服配售. 请参阅我们(几乎) [全面的属性和默认值列表](installation/command-line-options.html) . - -## Upgrading[](#upgrading "Permalink") - -安装了 GitLab 图表后,应使用`helm upgrade`完成配置更改和图表更新: - -``` -helm repo add gitlab https://charts.gitlab.io/ -helm repo update -helm get values gitlab > gitlab.yaml -helm upgrade gitlab gitlab/gitlab -f gitlab.yaml -``` - -有关更多详细信息,请参阅[升级](installation/upgrade.html) . - -## Uninstall[](#uninstall "Permalink") - -要卸载 GitLab Chart,请运行以下命令: - -``` -helm uninstall gitlab -``` - -**注意:**在 Helm v2 中,您需要使用`helm delete --purge gitlab`命令. - -为了连续起见,这些图表具有一些在执行`helm uninstall`时不会删除的 Kubernetes 对象. 这些是我们要求您有*意识地*删除的项目,因为它们会影响您应选择的重新部署. - -* 用于状态数据的 PVC,必须*自觉*删除 - * Gitaly:这是您的存储库数据. - * PostgreSQL(如果内部):这是您的元数据. - * Redis(如果内部):这是缓存和作业队列,可以安全地将其删除. -* 机密(如果由我们的共享机密工作生成). 这些图表旨在避免直接通过 Helm 生成 Kubernetes 秘密. 因此,Helm 无法删除它们. 它们包含密码,加密机密等.它们不应被恶意破坏. -* ConfigMaps - * `ingress-controller-leader-RELEASE-nginx` :这是由 NGINX Ingress 控制器本身生成的,不在我们图表的控制范围内. 可以安全地将其删除. - -PVC 和秘密将设置`release`标签,因此您可以通过以下方式找到它们: - -``` -kubectl get pvc,secret -lrelease=gitlab -``` - -## Advanced[](#advanced "Permalink") - -除了在云本机环境中进行 GitLab 的基本部署以外,还可以进行更复杂的配置. 本节为需要进一步计划的任务提供指导,例如大规模部署或从 Omnibus GitLab 迁移. - -### Advanced Configuration[](#advanced-configuration "Permalink") - -高级和大规模部署具有利用外部服务,扩展功能和备用提供程序的能力. - -高级配置示例: - -* 亚搏体育 app Geo -* 外部对象存储提供者 -* 外部 PostgreSQL,Redis,Gitaly -* 外部入口提供商 - -See [Advanced Configuration](advanced/index.html). - -### Migrate from Omnibus GitLab to Kubernetes[](#migrate-from-omnibus-gitlab-to-kubernetes "Permalink") - -可以从[Omnibus GitLab](https://docs.gitlab.com/omnibus/)迁移到这些图表. 这样做通常需要将现有数据迁移到对象存储,因此是[高级配置](advanced/index.html) . - -要将现有的 Omnibus GitLab 实例迁移到这些图表,请遵循[迁移文档](installation/migration/index.html) . - -## Architecture[](#architecture "Permalink") - -这些图表非常复杂,因为它们可以协调整个应用程序套件的部署. 我们提供有关目标,结构,设计决策和资源消耗的[文档](architecture/index.html) . - -## Development[](#development "Permalink") - -对于那些有兴趣为这些图表做出贡献的人,我们提供了涵盖该项目工作范围的开发指南. 它们可以在[开发中](development/index.html) . - -### GitLab version mappings[](#gitlab-version-mappings "Permalink") - -GitLab 图表与 GitLab 本身的版本号不同. 预计可能需要在图表中引入一些重大更改,这些更改可能会导致重大版本颠簸,而对这些更改的要求可能会完全阻止这些图表上的其他开发,直到完成为止. - -要快速查看它们映射到的`gitlab`图表版本和 GitLab 版本的完整列表,请对[Helm](installation/tools.html#helm)发出以下命令: - -``` -helm repo add gitlab https://charts.gitlab.io/ -helm search repo -l gitlab/gitlab -``` - -**注意**对于 Helm v2,搜索命令将为`helm search -l gitlab/gitlab` - -有关更多信息,请访问[版本映射 docs](installation/version_mappings.html) . - -### Contributing[](#contributing "Permalink") - -除了我们的[贡献准则](https://gitlab.com/gitlab-org/charts/gitlab/tree/master/CONTRIBUTING.md)之外,请参阅[开发者文档](development/index.html)以了解如何对 GitLab 图表[做出贡献](https://gitlab.com/gitlab-org/charts/gitlab/tree/master/CONTRIBUTING.md) . \ No newline at end of file diff --git a/docs/007.md b/docs/007.md deleted file mode 100644 index 1465da9585ee471ca3bd3eaed42a06e3ea53ff7d..0000000000000000000000000000000000000000 --- a/docs/007.md +++ /dev/null @@ -1,26 +0,0 @@ -# Install GitLab with Docker - -> 原文:[https://docs.gitlab.com/ee/install/docker.html](https://docs.gitlab.com/ee/install/docker.html) - -* [Omnibus GitLab based images](#omnibus-gitlab-based-images) -* [Cloud native images](#cloud-native-images) - -# Install GitLab with Docker[](#install-gitlab-with-docker "Permalink") - -在过去的几年中, [Docker](https://www.docker.com)和容器技术一直在改变软件世界. 它们将本地执行的性能和效率与虚拟化的抽象性,安全性和不变性结合在一起. - -GitLab 提供了官方的 Docker 映像,使您可以在操作 GitLab 实例时轻松利用容器化的优势. - -## Omnibus GitLab based images[](#omnibus-gitlab-based-images "Permalink") - -GitLab 基于我们的[Omnibus GitLab 软件包](https://docs.gitlab.com/omnibus/README.html)维护了一组[正式的 Docker 映像](https://hub.docker.com/u/gitlab) . 这些图像包括: - -* [GitLab Community Edition](https://hub.docker.com/r/gitlab/gitlab-ce/) -* [GitLab Enterprise Edition](https://hub.docker.com/r/gitlab/gitlab-ee/) -* [GitLab Runner](https://hub.docker.com/r/gitlab/gitlab-runner/) - -提供了有关这些映像的[完整用法指南](https://docs.gitlab.com/omnibus/docker/) ,以及[用于构建映像](https://gitlab.com/gitlab-org/omnibus-gitlab/tree/master/docker)的[Dockerfile](https://gitlab.com/gitlab-org/omnibus-gitlab/tree/master/docker) . - -## Cloud native images[](#cloud-native-images "Permalink") - -manbetx 客户端打不开也正在努力向[容器](https://docs.gitlab.com/charts/)的[云本机集,](https://docs.gitlab.com/charts/)每个组件服务具有单个映像. 我们打算将这些图像最终替换为[基于 Omnibus GitLab 的图像](#omnibus-gitlab-based-images) . \ No newline at end of file diff --git a/docs/008.md b/docs/008.md deleted file mode 100644 index 6d91a29ea7ca76107f3c10e1534839edf4189a68..0000000000000000000000000000000000000000 --- a/docs/008.md +++ /dev/null @@ -1,1010 +0,0 @@ -# Installation from source - -> 原文:[https://docs.gitlab.com/ee/install/installation.html](https://docs.gitlab.com/ee/install/installation.html) - -* [Consider the Omnibus package installation](#consider-the-omnibus-package-installation) -* [Select a version to install](#select-a-version-to-install) -* [GitLab directory structure](#gitlab-directory-structure) -* [Overview](#overview) -* [1\. Packages and dependencies](#1-packages-and-dependencies) -* [2\. Ruby](#2-ruby) -* [3\. Go](#3-go) -* [4\. Node](#4-node) -* [5\. System users](#5-system-users) -* [6\. Database](#6-database) -* [7\. Redis](#7-redis) -* [8\. GitLab](#8-gitlab) - * [Clone the Source](#clone-the-source) - * [Configure It](#configure-it) - * [Configure GitLab DB Settings](#configure-gitlab-db-settings) - * [Install Gems](#install-gems) - * [Install GitLab Shell](#install-gitlab-shell) - * [Install GitLab Workhorse](#install-gitlab-workhorse) - * [Install GitLab-Elasticsearch-indexer on Enterprise Edition](#install-gitlab-elasticsearch-indexer-on-enterprise-edition) - * [Install GitLab Pages](#install-gitlab-pages) - * [Install Gitaly](#install-gitaly) - * [Start Gitaly](#start-gitaly) - * [Initialize Database and Activate Advanced Features](#initialize-database-and-activate-advanced-features) - * [Secure secrets.yml](#secure-secretsyml) - * [Install Init Script](#install-init-script) - * [Set up Logrotate](#set-up-logrotate) - * [Check Application Status](#check-application-status) - * [Compile GetText PO files](#compile-gettext-po-files) - * [Compile Assets](#compile-assets) - * [Start Your GitLab Instance](#start-your-gitlab-instance) -* [9\. NGINX](#9-nginx) - * [Installation](#installation) - * [Site Configuration](#site-configuration) - * [Test Configuration](#test-configuration) - * [Restart](#restart) -* [Post-install](#post-install) - * [Double-check Application Status](#double-check-application-status) - * [Initial Login](#initial-login) -* [Advanced Setup Tips](#advanced-setup-tips) - * [Relative URL support](#relative-url-support) - * [Using HTTPS](#using-https) - * [Enable Reply by email](#enable-reply-by-email) - * [LDAP Authentication](#ldap-authentication) - * [Using Custom OmniAuth Providers](#using-custom-omniauth-providers) - * [Build your projects](#build-your-projects) - * [Adding your Trusted Proxies](#adding-your-trusted-proxies) - * [Custom Redis Connection](#custom-redis-connection) - * [Custom SSH Connection](#custom-ssh-connection) - * [Additional Markup Styles](#additional-markup-styles) - * [Using Unicorn](#using-unicorn) - * [Using Sidekiq instead of Sidekiq Cluster](#using-sidekiq-instead-of-sidekiq-cluster) -* [Troubleshooting](#troubleshooting) - * [“You appear to have cloned an empty repository.”](#you-appear-to-have-cloned-an-empty-repository) - * [`google-protobuf` “LoadError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14’ not found”](#google-protobuf-loaderror-libx86_64-linux-gnulibcso6-version-glibc_214-not-found) - -# Installation from source[](#installation-from-source "Permalink") - -这是使用源文件设置生产 GitLab 服务器的官方安装指南. 要设置**开发安装**或许多其他安装选项,请参见[主要安装页面](README.html) . 它是为**Debian / Ubuntu**操作系统创建并经过测试的. 有关硬件和操作系统[要求](requirements.html) ,请阅读 requirements.md. 如果要在 RHEL / CentOS 上安装,我们建议使用[Omnibus 软件包](https://about.gitlab.com/install/) . - -本指南之所以冗长,是因为它涵盖了许多情况,并且包括您需要的所有命令,这是[实际上可以立即使用的少数安装脚本之一](https://twitter.com/robinvdvleuten/status/424163226532986880) . 已知以下步骤有效. **偏离**本指南**时请多加注意** . 确保您没有违反任何有关 GitLab 对其环境的假设. 例如,许多人遇到权限问题,因为他们更改了目录的位置或以错误的用户身份运行服务. - -如果您在本指南中发现错误/错误, **请**按照[提供帮助的指南](https://gitlab.com/gitlab-org/gitlab/blob/master/CONTRIBUTING.md) **提交合并请求** . - -## Consider the Omnibus package installation[](#consider-the-omnibus-package-installation "Permalink") - -由于从源头进行安装需要大量工作并且容易出错,因此我们强烈建议您快速,可靠地[安装 Omnibus 软件包](https://about.gitlab.com/install/) (deb / rpm). - -Omnibus 软件包更可靠的原因之一是它使用 runit 来重新启动任何 GitLab 进程,以防万一崩溃. 在频繁使用的 GitLab 实例上,Sidekiq 后台工作程序的内存使用量会随着时间增长. - -Omnibus 软件包通过[使 Sidekiq](../administration/operations/sidekiq_memory_killer.html)在使用过多内存的情况下[正常终止来](../administration/operations/sidekiq_memory_killer.html)解决此问题. 在此终止后,runit 将检测到 Sidekiq 没有运行并启动它. 由于从源头进行的安装不使用 runit 进行过程监视,因此 Sidekiq 无法终止,并且其内存使用量会随着时间的推移而增长. - -## Select a version to install[](#select-a-version-to-install "Permalink") - -确保从您要安装的 GitLab 的分支(版本)中查看[此安装指南](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/install/installation.md) (例如`11-7-stable` ). 您可以在 GitLab 左上角的版本下拉菜单中选择分支(位于菜单栏下方). - -如果不清楚最高数目的稳定分支,请查看[GitLab 博客](https://about.gitlab.com/blog/)以获取版本信息. - -## GitLab directory structure[](#gitlab-directory-structure "Permalink") - -这是主要的目录结构,您将按照此页面的说明进行操作: - -``` -|-- home -| |-- git -| |-- .ssh -| |-- gitlab -| |-- gitlab-shell -| |-- repositories -``` - -* `/home/git/.ssh`包含 OpenSSH 设置. 具体来说,由 GitLab Shell 管理的`authorized_keys`文件. -* `/home/git/gitlab` -GitLab 核心软件. -* `/home/git/gitlab-shell` -GitLab 的核心附加组件. 维护 SSH 克隆和其他功能. -* `/home/git/repositories`按名称空间组织的所有项目的裸存储库. 这是为所有项目维护推/拉的 Git 存储库的地方. **该区域包含项目的关键数据.** **[保持备份](../raketasks/backup_restore.html) .** - -**注意:**可以在 GitLab 的`config/gitlab.yml`和 GitLab Shell 的`config.yml`中`config/gitlab.yml`存储库的默认位置. - -有关更深入的概述,请参阅[GitLab 体系结构文档](../development/architecture.html) . - -## Overview[](#overview "Permalink") - -GitLab 安装包括设置以下组件: - -1. [Packages and dependencies](#1-packages-and-dependencies). -2. [Ruby](#2-ruby). -3. [Go](#3-go). -4. [Node](#4-node). -5. [System users](#5-system-users). -6. [Database](#6-database). -7. [Redis](#7-redis). -8. [GitLab](#8-gitlab). -9. [NGINX](#9-nginx). - -## 1\. Packages and dependencies[](#1-packages-and-dependencies "Permalink") - -默认情况下,Debian 上未安装`sudo` . 确保您的系统是最新的并安装. - -``` -# run as root! -apt-get update -y -apt-get upgrade -y -apt-get install sudo -y -``` - -**注意:**在此安装过程中,将需要手动编辑某些文件. 如果您熟悉 vim,请使用以下命令将其设置为默认编辑器. 如果您不熟悉 vim,请跳过此步骤并继续使用默认编辑器. - -``` -# Install vim and set as default editor -sudo apt-get install -y vim -sudo update-alternatives --set editor /usr/bin/vim.basic -``` - -安装所需的软件包(需要编译 Ruby 和 Ruby gem 的本机扩展): - -``` -sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libre2-dev \ - libreadline-dev libncurses5-dev libffi-dev curl openssh-server checkinstall libxml2-dev \ - libxslt-dev libcurl4-openssl-dev libicu-dev logrotate rsync python-docutils pkg-config cmake \ - runit -``` - -Ubuntu 14.04(Trusty `libre2-dev` )没有可用的`libre2-dev`软件包,但您可以[手动安装 re2](https://github.com/google/re2/wiki/Install) . - -如果要使用 Kerberos 进行用户身份验证,请安装`libkrb5-dev` : - -``` -sudo apt-get install libkrb5-dev -``` - -**注意:**如果您不知道 Kerberos 是什么,则可以假定您不需要它. - -确保您安装了正确的 Git 版本: - -``` -# Install Git -sudo apt-get install -y git-core - -# Make sure Git is version 2.27.0 or higher (minimal supported version is 2.25.0) -git --version -``` - -从 GitLab 12.0 开始,需要使用`libpcre2`编译 Git. 找出是否是这种情况: - -``` -ldd $(command -v git) | grep pcre2 -``` - -输出应包含`libpcre2-8.so.0` . - -系统打包的 Git 是否过旧,或者未使用 pcre2 编译? 去掉它: - -``` -sudo apt-get remove git-core -``` - -在 Ubuntu 上, [从其官方 PPA](https://git-scm.com/download/linux)安装 Git: - -``` -# run as root! -add-apt-repository ppa:git-core/ppa -apt update -apt install git -# repeat libpcre2 check as above -``` - -在 Debian 上,使用以下编译说明: - -``` -# Install dependencies -sudo apt-get install -y libcurl4-openssl-dev libexpat1-dev gettext libz-dev libssl-dev build-essential - -# Download and compile pcre2 from source -curl --silent --show-error --location https://ftp.pcre.org/pub/pcre/pcre2-10.33.tar.gz --output pcre2.tar.gz -tar -xzf pcre2.tar.gz -cd pcre2-10.33 -chmod +x configure -./configure --prefix=/usr --enable-jit -make -sudo make install - -# Download and compile from source -cd /tmp -curl --remote-name --location --progress https://www.kernel.org/pub/software/scm/git/git-2.27.0.tar.gz -echo '77ded85cbe42b1ffdc2578b460a1ef5d23bcbc6683eabcafbb0d394dffe2e787 git-2.27.0.tar.gz' | shasum -a256 -c - && tar -xzf git-2.27.0.tar.gz -cd git-2.27.0/ -./configure --with-libpcre -make prefix=/usr/local all - -# Install into /usr/local/bin -sudo make prefix=/usr/local install - -# When editing config/gitlab.yml later, change the git -> bin_path to /usr/local/bin/git -``` - -为了使[自定义图标](../user/admin_area/appearance.html#favicon)能够正常工作,需要安装 GraphicsMagick. - -``` -sudo apt-get install -y graphicsmagick -``` - -**注意:**为了接收邮件通知,请确保安装邮件服务器. 默认情况下,Debian 随 exim4 一起提供,但这[会带来问题,](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/12754)而 Ubuntu 则没有. 推荐的邮件服务器是 postfix,您可以使用以下命令进行安装: - -``` -sudo apt-get install -y postfix -``` - -然后选择" Internet Site",然后按 Enter 确认主机名. - -[GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse#dependencies)需要使用`exiftool`才能从上传的图像中删除 EXIF 数据. - -``` -sudo apt-get install -y libimage-exiftool-perl -``` - -## 2\. Ruby[](#2-ruby "Permalink") - -运行 GitLab 需要使用 Ruby 解释器. - -**注意:**当前支持的 Ruby(MRI)版本是 2.6.x. GitLab 12.2 放弃了对 Ruby 2.5.x 的支持. - -在生产环境[中将](https://github.com/rbenv/rbenv) Ruby 版本管理器(如[RVM](https://rvm.io/) , [rbenv](https://github.com/rbenv/rbenv)或[chruby)](https://github.com/postmodern/chruby)与 GitLab [一起](https://github.com/postmodern/chruby)使用通常会导致难以诊断问题. 不支持版本管理器,我们强烈建议所有人按照以下说明使用系统 Ruby. - -Linux 发行版通常提供较旧版本的 Ruby,因此这些说明旨在从官方源代码安装 Ruby. - -删除旧的 Ruby 1.8(如果存在): - -``` -sudo apt-get remove ruby1.8 -``` - -下载 Ruby 并进行编译: - -``` -mkdir /tmp/ruby && cd /tmp/ruby -curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.6.tar.gz -echo '2d78048e293817f38d4ede4ebc7873013e97bb0b ruby-2.6.6.tar.gz' | shasum -c - && tar xzf ruby-2.6.6.tar.gz -cd ruby-2.6.6 - -./configure --disable-install-rdoc -make -sudo make install -``` - -然后安装 Bundler gem(低于 2.x 的版本): - -``` -sudo gem install bundler --no-document --version '< 2' -``` - -## 3\. Go[](#3-go "Permalink") - -从 GitLab 8.0 开始,GitLab 有几个用 Go 编写的守护程序. 要安装 GitLab,我们需要一个 Go 编译器. 以下说明假定您使用 64 位 Linux. 您可以在[Go 下载页面上](https://s0golang0org.icopy.site/dl)找到其他平台的[下载](https://s0golang0org.icopy.site/dl) . - -``` -# Remove former Go installation folder -sudo rm -rf /usr/local/go - -curl --remote-name --progress https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz -echo '512103d7ad296467814a6e3f635631bd35574cab3369a97a323c9a585ccaa569 go1.13.5.linux-amd64.tar.gz' | shasum -a256 -c - && \ - sudo tar -C /usr/local -xzf go1.13.5.linux-amd64.tar.gz -sudo ln -sf /usr/local/go/bin/{go,godoc,gofmt} /usr/local/bin/ -rm go1.13.5.linux-amd64.tar.gz -``` - -## 4\. Node[](#4-node "Permalink") - -从 GitLab 8.17 开始,GitLab 需要使用 Node 来编译 JavaScript 资产,并使用 Yarn 来管理 JavaScript 依赖项. 当前的最低要求是: - -* `node` > = v10.13.0\. (我们建议使用节点 12.x,因为它速度更快) -* `yarn` > = v1.10.0. - -在许多发行版中,官方软件包存储库提供的版本已经过时,因此我们需要通过以下命令进行安装: - -``` -# install node v12.x -curl --location https://deb.nodesource.com/setup_12.x | sudo bash - -sudo apt-get install -y nodejs - -curl --silent --show-error https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - -echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list -sudo apt-get update -sudo apt-get install yarn -``` - -如果您对这些步骤有任何疑问,请访问[node](https://s0nodejs0org.icopy.site/en/download/package-manager/)和[yarn](https://classic.yarnpkg.com/en/docs/install/)的官方网站. - -## 5\. System users[](#5-system-users "Permalink") - -为 GitLab 创建一个`git`用户: - -``` -sudo adduser --disabled-login --gecos 'GitLab' git -``` - -## 6\. Database[](#6-database "Permalink") - -**注意:**从 GitLab 12.1 开始,仅支持 PostgreSQL. 从 GitLab 13.0 开始,我们需要 PostgreSQL 11+. - -1. 安装数据库软件包: - - ``` - sudo apt-get install -y postgresql postgresql-client libpq-dev postgresql-contrib - ``` - -2. 启动 PostgreSQL 服务并确认该服务正在运行: - - ``` - sudo service postgresql start - sudo service postgresql status - ``` - -3. 为 GitLab 创建数据库用户: - - ``` - sudo -u postgres psql -d template1 -c "CREATE USER git CREATEDB;" - ``` - -4. 创建`pg_trgm`扩展(GitLab 8.6+必需): - - ``` - sudo -u postgres psql -d template1 -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;" - ``` - -5. 创建 GitLab 生产数据库并授予该数据库的所有特权: - - ``` - sudo -u postgres psql -d template1 -c "CREATE DATABASE gitlabhq_production OWNER git;" - ``` - -6. 尝试使用新用户连接到新数据库: - - ``` - sudo -u git -H psql -d gitlabhq_production - ``` - -7. 检查是否启用了`pg_trgm`扩展名: - - ``` - SELECT true AS enabled - FROM pg_available_extensions - WHERE name = 'pg_trgm' - AND installed_version IS NOT NULL; - ``` - - 如果启用了扩展名,将产生以下输出: - - ``` - enabled - --------- - t - (1 row) - ``` - -8. 退出数据库会话: - - ``` - gitlabhq_production> \q - ``` - -## 7\. Redis[](#7-redis "Permalink") - -GitLab 至少需要 Redis 5.0. - -如果您使用的是 Debian 10 或 Ubuntu 20.04 及更高版本,则可以使用以下命令安装 Redis 5.0: - -``` -sudo apt-get install redis-server -``` - -完成后,您可以配置 Redis: - -``` -# Configure redis to use sockets -sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.orig - -# Disable Redis listening on TCP by setting 'port' to 0 -sudo sed 's/^port .*/port 0/' /etc/redis/redis.conf.orig | sudo tee /etc/redis/redis.conf - -# Enable Redis socket for default Debian / Ubuntu path -echo 'unixsocket /var/run/redis/redis.sock' | sudo tee -a /etc/redis/redis.conf - -# Grant permission to the socket to all members of the redis group -echo 'unixsocketperm 770' | sudo tee -a /etc/redis/redis.conf - -# Create the directory which contains the socket -sudo mkdir -p /var/run/redis -sudo chown redis:redis /var/run/redis -sudo chmod 755 /var/run/redis - -# Persist the directory which contains the socket, if applicable -if [ -d /etc/tmpfiles.d ]; then echo 'd /var/run/redis 0755 redis redis 10d -' | sudo tee -a /etc/tmpfiles.d/redis.conf -fi - -# Activate the changes to redis.conf -sudo service redis-server restart - -# Add git to the redis group -sudo usermod -aG redis git -``` - -## 8\. GitLab[](#8-gitlab "Permalink") - -``` -# We'll install GitLab into the home directory of the user "git" -cd /home/git -``` - -### Clone the Source[](#clone-the-source "Permalink") - -克隆社区版: - -``` -# Clone GitLab repository -sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-foss.git -b X-Y-stable gitlab -``` - -克隆企业版: - -``` -# Clone GitLab repository -sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ee.git -b X-Y-stable gitlab -``` - -确保用与要安装的版本匹配的稳定分支替换`XY-stable` . 例如,如果要安装 11.8,则可以使用分支名称`11-8-stable` . - -**注意:**您可以更改`XY-stable` ,以`master` ,如果你想最*前沿*的版本,但从来没有安装`master`在生产服务器上! - -### Configure It[](#configure-it "Permalink") - -``` -# Go to GitLab installation folder -cd /home/git/gitlab - -# Copy the example GitLab config -sudo -u git -H cp config/gitlab.yml.example config/gitlab.yml - -# Update GitLab config file, follow the directions at top of the file -sudo -u git -H editor config/gitlab.yml - -# Copy the example secrets file -sudo -u git -H cp config/secrets.yml.example config/secrets.yml -sudo -u git -H chmod 0600 config/secrets.yml - -# Make sure GitLab can write to the log/ and tmp/ directories -sudo chown -R git log/ -sudo chown -R git tmp/ -sudo chmod -R u+rwX,go-w log/ -sudo chmod -R u+rwX tmp/ - -# Make sure GitLab can write to the tmp/pids/ and tmp/sockets/ directories -sudo chmod -R u+rwX tmp/pids/ -sudo chmod -R u+rwX tmp/sockets/ - -# Create the public/uploads/ directory -sudo -u git -H mkdir -p public/uploads/ - -# Make sure only the GitLab user has access to the public/uploads/ directory -# now that files in public/uploads are served by gitlab-workhorse -sudo chmod 0700 public/uploads - -# Change the permissions of the directory where CI job logs are stored -sudo chmod -R u+rwX builds/ - -# Change the permissions of the directory where CI artifacts are stored -sudo chmod -R u+rwX shared/artifacts/ - -# Change the permissions of the directory where GitLab Pages are stored -sudo chmod -R ug+rwX shared/pages/ - -# Copy the example Puma config -sudo -u git -H cp config/puma.rb.example config/puma.rb - -# Refer to https://github.com/puma/puma#configuration for more information. -# You should scale Puma workers and threads based on the number of CPU -# cores you have available. You can get that number via the `nproc` command. -sudo -u git -H editor config/puma.rb - -# Copy the example Rack attack config -sudo -u git -H cp config/initializers/rack_attack.rb.example config/initializers/rack_attack.rb - -# Configure Git global settings for git user -# 'autocrlf' is needed for the web editor -sudo -u git -H git config --global core.autocrlf input - -# Disable 'git gc --auto' because GitLab already runs 'git gc' when needed -sudo -u git -H git config --global gc.auto 0 - -# Enable packfile bitmaps -sudo -u git -H git config --global repack.writeBitmaps true - -# Enable push options -sudo -u git -H git config --global receive.advertisePushOptions true - -# Enable fsyncObjectFiles to reduce risk of repository corruption if the server crashes -sudo -u git -H git config --global core.fsyncObjectFiles true - -# Configure Redis connection settings -sudo -u git -H cp config/resque.yml.example config/resque.yml - -# Change the Redis socket path if you are not using the default Debian / Ubuntu configuration -sudo -u git -H editor config/resque.yml -``` - -**注意:**请确保同时编辑`gitlab.yml`和`puma.rb`以匹配您的设置. 如果要使用 Unicorn Web 服务器,请参阅" [使用 Unicorn"](#using-unicorn)以了解其他步骤.**注意:**如果要使用 HTTPS,请参阅" [使用 HTTPS"](#using-https)以了解其他步骤. - -### Configure GitLab DB Settings[](#configure-gitlab-db-settings "Permalink") - -``` -sudo -u git cp config/database.yml.postgresql config/database.yml - -# Remove host, username, and password lines from config/database.yml. -# Once modified, the `production` settings will be as follows: -# -# production: -# adapter: postgresql -# encoding: unicode -# database: gitlabhq_production -# pool: 10 -# -sudo -u git -H editor config/database.yml - -# Remote PostgreSQL only: -# Update username/password in config/database.yml. -# You only need to adapt the production settings (first part). -# If you followed the database guide then please do as follows: -# Change 'secure password' with the value you have given to $password -# You can keep the double quotes around the password -sudo -u git -H editor config/database.yml - -# Make config/database.yml readable to git only -sudo -u git -H chmod o-rwx config/database.yml -``` - -### Install Gems[](#install-gems "Permalink") - -**注意:**从 Bundler 1.5.2 开始,您可以调用`bundle install -jN` (其中`N`是您的处理器内核数)并享受并行 gem 的安装,其完成时间有可衡量的差异(快 60%). 使用`nproc`检查您的内核数. 有关更多信息,请参见这篇[文章](https://thoughtbot.com/blog/parallel-gem-installing-using-bundler) . - -确保您有`bundle` (运行`bundle -v` ): - -* `>= 1.5.2` ,因为某些[问题](https://devcenter.heroku.com/changelog-items/411)已在 1.5.2 中[修复](https://github.com/rubygems/bundler/pull/2817) . -* `< 2.x`. - -``` -sudo -u git -H bundle install --deployment --without development test mysql aws kerberos -``` - -**注意:**如果要使用 Kerberos 进行用户身份验证,请在上面的`--without`选项中省略`kerberos` . - -### Install GitLab Shell[](#install-gitlab-shell "Permalink") - -GitLab Shell 是专门为 GitLab 开发的 SSH 访问和存储库管理软件. - -``` -# Run the installation task for gitlab-shell: -sudo -u git -H bundle exec rake gitlab:shell:install RAILS_ENV=production - -# By default, the gitlab-shell config is generated from your main GitLab config. -# You can review (and modify) the gitlab-shell config as follows: -sudo -u git -H editor /home/git/gitlab-shell/config.yml -``` - -**注意:**如果要使用 HTTPS,请参阅" [使用 HTTPS"](#using-https)以了解其他步骤.**注意:**确保您的主机名可以通过正确的 DNS 记录或`/etc/hosts`的其他行(" 127.0.0.1 主机名")在计算机上解析. 例如,如果您在反向代理后面设置了 GitLab,则可能有必要. 如果无法解析主机名,则最终安装检查将失败,并具有`Check GitLab API access: FAILED. code: 401` `Check GitLab API access: FAILED. code: 401`和推送提交将通过`[remote rejected] master -> master (hook declined)` . - -### Install GitLab Workhorse[](#install-gitlab-workhorse "Permalink") - -GitLab-Workhorse 使用[GNU Make](https://www.gnu.org/software/make/) . 以下命令行将在建议的位置`/home/git/gitlab-workhorse`安装 GitLab-Workhorse. - -``` -sudo -u git -H bundle exec rake "gitlab:workhorse:install[/home/git/gitlab-workhorse]" RAILS_ENV=production -``` - -您可以通过提供其他参数来指定其他 Git 存储库: - -``` -sudo -u git -H bundle exec rake "gitlab:workhorse:install[/home/git/gitlab-workhorse,https://example.com/gitlab-workhorse.git]" RAILS_ENV=production -``` - -### Install GitLab-Elasticsearch-indexer on Enterprise Edition[](#install-gitlab-elasticsearch-indexer-on-enterprise-edition "Permalink") - -GitLab-Elasticsearch-Indexer 使用[GNU Make](https://www.gnu.org/software/make/) . 以下命令行将在推荐位置`/home/git/gitlab-elasticsearch-indexer`中安装 GitLab-Elasticsearch-Indexer. - -``` -sudo -u git -H bundle exec rake "gitlab:indexer:install[/home/git/gitlab-elasticsearch-indexer]" RAILS_ENV=production -``` - -您可以通过提供其他参数来指定其他 Git 存储库: - -``` -sudo -u git -H bundle exec rake "gitlab:indexer:install[/home/git/gitlab-elasticsearch-indexer,https://example.com/gitlab-elasticsearch-indexer.git]" RAILS_ENV=production -``` - -首先将源代码提取到第一个参数指定的路径. 然后,将在其`bin`目录下构建一个二进制文件. 然后,您将需要更新`gitlab.yml`的`production -> elasticsearch -> indexer_path`设置以指向该二进制文件. - -**注意:** Elasticsearch 是 GitLab 企业版的一项功能,不包含在 GitLab 社区版中. - -### Install GitLab Pages[](#install-gitlab-pages "Permalink") - -GitLab Pages 使用[GNU Make](https://www.gnu.org/software/make/) . 此步骤是可选的,仅当您希望在 GitLab 中托管静态站点时才需要. 以下命令将在`/home/git/gitlab-pages`安装 GitLab `/home/git/gitlab-pages` . 有关其他设置步骤,请查阅适用于您的 GitLab 版本的[管理指南](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/administration/pages/source.md) ,因为 GitLab Pages 守护程序可以通过几种不同的方式运行. - -``` -cd /home/git -sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-pages.git -cd gitlab-pages -sudo -u git -H git checkout v$(> $gitlab_path/log/gitaly.log 2>&1 &" -``` - -### Initialize Database and Activate Advanced Features[](#initialize-database-and-activate-advanced-features "Permalink") - -``` -cd /home/git/gitlab -sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production -# Type 'yes' to create the database tables. - -# or you can skip the question by adding force=yes -sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production force=yes - -# When done, you see 'Administrator account created:' -``` - -**注意:**您可以通过分别在环境变量`GITLAB_ROOT_PASSWORD`和`GITLAB_ROOT_EMAIL`提供管理员/ root 密码和电子邮件来设置它们,如下所示. 如果您未设置密码(并且密码已设置为默认密码),请等待 GitLab 暴露在公共互联网上,直到安装完成并且您已首次登录服务器. 首次登录时,将被迫更改默认密码. 通过在`GITLAB_LICENSE_FILE`环境变量中提供完整路径,此时也可以安装 Enterprise Edition 许可证. - -``` -sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production GITLAB_ROOT_PASSWORD=yourpassword GITLAB_ROOT_EMAIL=youremail GITLAB_LICENSE_FILE="/path/to/license" -``` - -### Secure secrets.yml[](#secure-secretsyml "Permalink") - -`secrets.yml`文件存储会话和安全变量的加密密钥. 备份`secrets.yml`安全保存,但是请不要将其与数据库备份存储在同一位置. 否则,如果其中一个备份遭到破坏,您的秘密就会暴露出来. - -### Install Init Script[](#install-init-script "Permalink") - -下载初始化脚本(将为`/etc/init.d/gitlab` ): - -``` -sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab -``` - -而且,如果要使用非默认文件夹或用户安装,请复制并编辑默认文件: - -``` -sudo cp lib/support/init.d/gitlab.default.example /etc/default/gitlab -``` - -如果将 GitLab 安装在其他目录中或以默认用户以外的用户身份安装,则应在`/etc/default/gitlab`更改这些设置. 不要编辑`/etc/init.d/gitlab`因为它将在升级时更改. - -使 GitLab 在启动时启动: - -``` -sudo update-rc.d gitlab defaults 21 -``` - -### Set up Logrotate[](#set-up-logrotate "Permalink") - -``` -sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab -``` - -### Check Application Status[](#check-application-status "Permalink") - -检查 GitLab 及其环境是否配置正确: - -``` -sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production -``` - -### Compile GetText PO files[](#compile-gettext-po-files "Permalink") - -``` -sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production -``` - -### Compile Assets[](#compile-assets "Permalink") - -``` -sudo -u git -H yarn install --production --pure-lockfile -sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production NODE_ENV=production -``` - -如果`rake`因`JavaScript heap out of memory`不足错误而失败,请尝试按如下所示设置`NODE_OPTIONS`来运行它. - -``` -sudo -u git -H bundle exec rake gitlab:assets:compile RAILS_ENV=production NODE_ENV=production NODE_OPTIONS="--max_old_space_size=4096" -``` - -### Start Your GitLab Instance[](#start-your-gitlab-instance "Permalink") - -``` -sudo service gitlab start -# or -sudo /etc/init.d/gitlab restart -``` - -## 9\. NGINX[](#9-nginx "Permalink") - -**注意:** NGINX 是 GitLab 官方支持的 Web 服务器. 如果您不能或不想将 NGINX 用作 Web 服务器,请参阅[GitLab 配方](https://gitlab.com/gitlab-org/gitlab-recipes/) . - -### Installation[](#installation "Permalink") - -``` -sudo apt-get install -y nginx -``` - -### Site Configuration[](#site-configuration "Permalink") - -复制示例站点配置: - -``` -sudo cp lib/support/nginx/gitlab /etc/nginx/sites-available/gitlab -sudo ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab -``` - -确保编辑配置文件以匹配您的设置. 另外,请确保您与 GitLab 的路径匹配,尤其是在为`git`用户以外的用户安装时: - -``` -# Change YOUR_SERVER_FQDN to the fully-qualified -# domain name of your host serving GitLab. -# -# Remember to match your paths to GitLab, especially -# if installing for a user other than 'git'. -# -# If using Ubuntu default nginx install: -# either remove the default_server from the listen line -# or else sudo rm -f /etc/nginx/sites-enabled/default -sudo editor /etc/nginx/sites-available/gitlab -``` - -如果您打算启用 GitLab 页面,则需要使用一个单独的 NGINX 配置. 在[GitLab 页面管理指南中](../administration/pages/index.html)阅读有关所需配置的所有信息. - -**注意:**如果要使用 HTTPS,请将`gitlab` NGINX 配置替换为`gitlab-ssl` . 有关 HTTPS 配置的详细信息,请参见[使用 HTTPS](#using-https) . - -### Test Configuration[](#test-configuration "Permalink") - -使用以下命令验证`gitlab`或`gitlab-ssl` NGINX 配置文件: - -``` -sudo nginx -t -``` - -您应该会收到`syntax is okay`并且`test is successful`消息. 如果收到错误,请按照给出的错误消息中的说明检查`gitlab`或`gitlab-ssl` NGINX 配置文件是否有错别字等. - -**注意:**通过运行`nginx -v`验证安装的版本是否大于 1.12.1\. 如果它较低,您可能会收到以下错误: `nginx: [emerg] unknown "start$temp=[filtered]$rest" variable nginx: configuration file /etc/nginx/nginx.conf test failed` - -### Restart[](#restart "Permalink") - -``` -sudo service nginx restart -``` - -## Post-install[](#post-install "Permalink") - -### Double-check Application Status[](#double-check-application-status "Permalink") - -为了确保您不会错过任何东西,请使用以下命令进行更彻底的检查: - -``` -sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production -``` - -如果所有项目均为绿色,则恭喜您成功安装了 GitLab! - -向`gitlab:check`提供`SANITIZE=true`环境变量,以从 check 命令的输出中省略项目名称. - -### Initial Login[](#initial-login "Permalink") - -在您的 Web 浏览器中访问 YOUR_SERVER 进行首次 GitLab 登录. - -如果[在设置过程中](#initialize-database-and-activate-advanced-features)未[提供 root 密码,](#initialize-database-and-activate-advanced-features)则将重定向到密码重置屏幕,以提供初始管理员帐户的密码. 输入所需的密码,您将被重定向回登录屏幕. - -默认帐户的用户名是**root** . 提供您先前创建的密码并登录. 登录后,您可以根据需要更改用户名. - -**Enjoy!** - -You can use `sudo service gitlab start` and `sudo service gitlab stop` to start and stop GitLab. - -## Advanced Setup Tips[](#advanced-setup-tips "Permalink") - -### Relative URL support[](#relative-url-support "Permalink") - -有关如何使用相对 URL 配置 GitLab 的更多信息,请参见[相对 URL 文档](relative_url.html) . - -### Using HTTPS[](#using-https "Permalink") - -要将 GitLab 与 HTTPS 一起使用: - -1. In `gitlab.yml`: - 1. 将第 1 节中的`port`选项设置为`443` . - 2. 将第 1 节中的`https`选项设置为`true` . -2. 在 GitLab Shell 的`config.yml`中: - 1. 将`gitlab_url`选项设置为 GitLab 的 HTTPS 端点(例如`https://git.example.com` ). - 2. 使用`ca_file`或`ca_path`选项设置证书. -3. 使用`gitlab-ssl` NGINX 示例配置,而不是`gitlab`配置. - 1. 更新`YOUR_SERVER_FQDN` . - 2. 更新`ssl_certificate`和`ssl_certificate_key` . - 3. 查看配置文件,并考虑应用其他安全性和性能增强功能. - -不鼓励使用自签名证书,但如果必须使用它,请遵循正常说明. 然后: - -1. 生成自签名 SSL 证书: - - ``` - mkdir -p /etc/nginx/ssl/ - cd /etc/nginx/ssl/ - sudo openssl req -newkey rsa:2048 -x509 -nodes -days 3560 -out gitlab.crt -keyout gitlab.key - sudo chmod o-r gitlab.key - ``` - -2. 在 GitLab Shell 的`config.yml` ,将`self_signed_cert`设置为`true` . - -### Enable Reply by email[](#enable-reply-by-email "Permalink") - -有关如何进行此设置的更多信息,请参见["通过电子邮件答复"文档](../administration/reply_by_email.html) . - -### LDAP Authentication[](#ldap-authentication "Permalink") - -您可以在`config/gitlab.yml`配置 LDAP 身份验证. 编辑此文件后,重新启动 GitLab. - -### Using Custom OmniAuth Providers[](#using-custom-omniauth-providers "Permalink") - -请参阅[OmniAuth 集成文档](../integration/omniauth.html) . - -### Build your projects[](#build-your-projects "Permalink") - -GitLab 可以构建您的项目. 要启用该功能,您需要 GitLab Runners 为您执行此操作. 请参阅[GitLab Runner 部分](https://about.gitlab.com/stages-devops-lifecycle/continuous-integration/#gitlab-runner)进行安装. - -### Adding your Trusted Proxies[](#adding-your-trusted-proxies "Permalink") - -如果要在单独的计算机上使用反向代理,则可能要将代理添加到"受信任的代理"列表中. 否则,用户将显示为从代理的 IP 地址登录. - -您可以通过自定义第 1 节中的`trusted_proxies`选项在`config/gitlab.yml`添加受信任的代理.保存文件并[重新配置 GitLab,](../administration/restart_gitlab.html)以使更改生效. - -### Custom Redis Connection[](#custom-redis-connection "Permalink") - -如果您想通过非标准端口或其他主机连接到 Redis 服务器,则可以通过`config/resque.yml`文件配置其连接字符串. - -``` -# example -production: - url: redis://redis.example.tld:6379 -``` - -如果要通过套接字连接 Redis 服务器,请使用" unix:" URL 方案以及`config/resque.yml`文件中 Redis 套接字文件的路径. - -``` -# example -production: - url: unix:/path/to/redis/socket -``` - -另外,您可以在`config/resque.yml`文件中使用环境变量: - -``` -# example -production: - url: <%= ENV.fetch('GITLAB_REDIS_URL') %> -``` - -### Custom SSH Connection[](#custom-ssh-connection "Permalink") - -如果您在非标准端口上运行 SSH,则必须更改 GitLab 用户的 SSH 配置. - -``` -# Add to /home/git/.ssh/config -host localhost # Give your setup a name (here: override localhost) - user git # Your remote git user - port 2222 # Your port number - hostname 127.0.0.1; # Your server name or IP -``` - -您还需要在`config\gitlab.yml`文件中更改相应的选项(例如`ssh_user` , `ssh_host` , `admin_uri` ). - -### Additional Markup Styles[](#additional-markup-styles "Permalink") - -除了始终支持的 Markdown 样式外,GitLab 还可以显示其他富文本文件. 但是您可能必须安装依赖项才能这样做. 有关更多信息,请参见[`github-markup` gem 自述文件](https://github.com/gitlabhq/markup#markups) . - -### Using Unicorn[](#using-unicorn "Permalink") - -从 GitLab 12.9 开始, [Puma](https://github.com/puma/puma)已取代 Unicorn 成为默认源安装 Web 服务器. 如果要切换回独角兽,请按照下列步骤操作: - -1. 完成 GitLab 设置,以使其启动并运行. -2. 将提供的示例 Unicorn 配置文件复制到位: - - ``` - cd /home/git/gitlab - - # Copy config file for the web server - sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb - ``` - -3. 编辑系统`init.d`脚本并设置`USE_WEB_SERVER="unicorn"` . 如果您有`/etc/default/gitlab` ,那么您应该对其进行编辑. -4. Restart GitLab. - -### Using Sidekiq instead of Sidekiq Cluster[](#using-sidekiq-instead-of-sidekiq-cluster "Permalink") - -从 GitLab 12.10 开始,Source 安装使用`bin/sidekiq-cluster`来管理 Sidekiq 进程. 在 14.0 之前,仍支持直接使用 Sidekiq. 因此,如果您遇到问题,请: - -1. 编辑系统`init.d`脚本以删除`SIDEKIQ_WORKERS`标志. 如果您有`/etc/default/gitlab` ,那么您应该对其进行编辑. -2. 重新启动 GitLab. -3. [创建一个](https://gitlab.com/gitlab-org/gitlab/-/issues/-/new)描述问题的问题. - -## Troubleshooting[](#troubleshooting "Permalink") - -### “You appear to have cloned an empty repository.”[](#you-appear-to-have-cloned-an-empty-repository "Permalink") - -如果在尝试克隆由 GitLab 托管的存储库时看到此消息,则可能是由于 NGINX 或 Apache 配置过时,或者缺少或配置了错误的 GitLab Workhorse 实例. 仔细检查您是否已[安装 Go](#3-go) , [已安装 GitLab Workhorse](#install-gitlab-workhorse)并已正确[配置 NGINX](#site-configuration) . - -### `google-protobuf` “LoadError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.14’ not found”[](#google-protobuf-loaderror-libx86_64-linux-gnulibcso6-version-glibc_214-not-found "Permalink") - -对于某些版本的`google-protobuf` gem,这可能会在某些平台上发生. 解决方法是安装此 gem 的仅源版本. - -首先,您必须找到 GitLab 安装所需的`google-protobuf`确切版本: - -``` -cd /home/git/gitlab - -# Only one of the following two commands will print something. It -# will look like: * google-protobuf (3.2.0) -bundle list | grep google-protobuf -bundle check | grep google-protobuf -``` - -下面以`3.2.0`为例. 将其替换为您在上面找到的版本号: - -``` -cd /home/git/gitlab -sudo -u git -H gem install google-protobuf --version 3.2.0 --platform ruby -``` - -最后,您可以测试`google-protobuf`是否正确加载. 以下应打印"确定". - -``` -sudo -u git -H bundle exec ruby -rgoogle/protobuf -e 'puts :OK' -``` - -如果`gem install`命令失败,则可能需要安装操作系统的开发人员工具. - -在 Debian / Ubuntu 上: - -``` -sudo apt-get install build-essential libgmp-dev -``` - -在 RedHat / CentOS 上: - -``` -sudo yum groupinstall 'Development Tools' -``` \ No newline at end of file diff --git a/docs/009.md b/docs/009.md deleted file mode 100644 index 9d598f33ac273490e9dbaa468678d3d7e6b46394..0000000000000000000000000000000000000000 --- a/docs/009.md +++ /dev/null @@ -1,345 +0,0 @@ -# Install GitLab on Microsoft Azure - -> 原文:[https://docs.gitlab.com/ee/install/azure/](https://docs.gitlab.com/ee/install/azure/) - -* [Getting started](#getting-started) -* [Working with Azure](#working-with-azure) -* [Create New VM](#create-new-vm) -* [Basics](#basics) -* [Size](#size) -* [Settings](#settings) -* [Purchase](#purchase) -* [Deployment](#deployment) -* [Set up a domain name](#set-up-a-domain-name) -* [Let’s open some ports](#lets-open-some-ports) - * [Which ports to open?](#which-ports-to-open) - * [Open HTTP on Port 80](#open-http-on-port-80) - * [Open SSH on Port 22](#open-ssh-on-port-22) -* [Connecting to GitLab](#connecting-to-gitlab) - * [Success?](#success) -* [Creating your first GitLab project](#creating-your-first-gitlab-project) -* [Maintaining your GitLab instance](#maintaining-your-gitlab-instance) - * [Checking our current version](#checking-our-current-version) - * [Connect via SSH](#connect-via-ssh) - * [SSH from the command-line](#ssh-from-the-command-line) - * [SSH from Windows (PuTTY)](#ssh-from-windows-putty) - * [Updating GitLab](#updating-gitlab) - * [Check out your updated GitLab](#check-out-your-updated-gitlab) -* [Conclusion](#conclusion) -* [Where to next?](#where-to-next) - * [Useful links](#useful-links) - -# Install GitLab on Microsoft Azure[](#install-gitlab-on-microsoft-azure "Permalink") - -Azure 是 Microsoft 的业务云,GitLab 是 Azure 市场上的预配置产品. 希望您不会惊讶地听到 Microsoft 和 Azure 接受了开源软件,例如 Ubuntu,Red Hat Enterprise Linux,当然还有 GitLab! 这意味着您可以启动预配置的 GitLab VM,并在 30 分钟左右启动并运行自己的私有 GitLab. 让我们开始吧. - -## Getting started[](#getting-started "Permalink") - -首先,您需要在 Azure 上拥有一个帐户. 有三种方法可以做到这一点: - -* 如果您的公司(或您)已经有一个帐户,那么您就可以开始了! -* 您还可以免费打开自己的 Azure 帐户. *在撰写本文时* ,您将获得 200 美元的信用额度,可用于 30 天的 Azure 服务支出. 您可以使用此信用额度试用付费的 Azure 服务,免费浏览 Microsoft 的云. 即使在开始的 30 天之后,您也无需支付任何费用,除非您决定转换为使用"按需付费" Azure 订阅的付费服务. 这是试用 Azure 和云计算的好方法,您可以[在其全面的 FAQ 中阅读更多内容](https://azure.microsoft.com/en-us/free/free-account-faq/) . -* 如果您具有 MSDN 订阅,则可以激活 Azure 订阅者权益. 您的 MSDN 订阅每月为您提供经常性的 Azure 信用,那么为什么不立即使用这些信用并尝试 GitLab 呢? - -## Working with Azure[](#working-with-azure "Permalink") - -Once you have an Azure account, you can get started. [Log in to Azure](https://portal.azure.com) and the first thing you will see is the Dashboard: - -[![Azure Dashboard](img/27f5db1ffe5c715ccd311bccf93665f2.png)](img/azure-dashboard.png) - -仪表板为您提供了 Azure 资源的快速概述,从这里您可以构建 VM,创建 SQL 数据库,创建网站以及执行许多其他云任务. - -## Create New VM[](#create-new-vm "Permalink") - -[Azure 市场](https://azuremarketplace.microsoft.com/en-us/marketplace/)是一个在线商店,用于存储预配置的应用程序和服务,这些软件和服务已由 GitLab 等软件供应商针对云进行了优化,可以在 Azure 市场上作为预配置的解决方案使用. 在本教程中,我们将安装 GitLab 社区版,但是对于 GitLab 企业版,您可以遵循相同的过程. - -要开始创建新的 GitLab VM,请单击**+新建**图标,在搜索框中键入" GitLab",然后单击**" GitLab Community Edition"**搜索结果: - -[![Azure - New - Search for 'GitLab'](img/3e0f74f35030a15b593a12090d5c0daf.png)](img/azure-new-search-gitlab.png) - -将会弹出一个新的"刀片"窗口,您可以在其中阅读有关 MIT Expat 许可免费提供的**" GitLab 社区版"**产品的更多信息: - -[![Azure - New - Select 'GitLab Community Edition'](img/0290c1013dba1b07f226f1548c8b6fd2.png)](img/azure-new-gitlab-ce.png) - -单击**"创建"** ,将显示"创建虚拟机"刀片: - -[![Azure - Create Virtual Machine - Basics](img/e4581843d51522e972a6bb6716aa4b05.png)](img/azure-create-virtual-machine-basics.png) - -## Basics[](#basics "Permalink") - -我们需要配置的第一项是基础虚拟机的基本设置: - -1. 输入虚拟机的`Name` -例如**" GitLab-CE"** -2. 选择一个`VM disk type` -无论是***HDD(**慢,成本更低)*或***SSD(**更快,更高成本)* -3. 输入`User name` -例如`gitlab-admin` -4. 选择一种`Authentication type` , **SSH 公钥**或**密码** : - - > **注意:**如果不确定要使用哪种身份验证类型,请选择**密码** - - 1. 如果您选择**SSH 公钥** -在提供的字段中输入`SSH public key` *(请阅读[SSH 文档,](../../ssh/README.html)以了解有关如何设置 SSH 公钥的更多信息)* - 2. 如果选择了**密码** -输入要使用*的密码(这是本教程后面将用于[SSH](https://en.wikipedia.org/wiki/Secure_Shell)到 VM 的密码,因此请确保它是一个强密码/密码)* -5. 为您的 Azure 帐户选择适当的`Subscription`层 -6. 选择一个现有的`Resource Group`或创建一个新的`Resource Group` -例如**" GitLab-CE-Azure"** - - > **注意:** "资源组"是一种将相关资源分组在一起以简化管理的方法. 我们选择了" GitLab-CE-Azure",但是您的资源组可以与 VM 具有相同的名称. - -7. 选择一个`Location` -如果不确定,请选择默认位置 - -这是我们使用的设置: - -[![Azure - Create Virtual Machine - Basics Completed](img/defc257dc0219b95ed3f3065afcaff94.png)](img/azure-create-virtual-machine-basics-password.png) - -检查您输入的设置,然后在准备好继续时单击**"确定"** . - -## Size[](#size "Permalink") - -接下来,您需要选择 VM 的大小-选择功能,例如 CPU 内核数,RAM 数量,存储大小(及其速度)等. - -> **注意:**与其他云供应商一样,Azure 运行资源/使用定价模型,即,VM 消耗的资源越多,运行成本就越高,因此请谨慎选择. 您会看到,Azure 提供了每个 VM 大小以下的*估计*每月费用,以帮助指导选择. - -默认大小-成本最低的**" DS1_V2 标准" VM-**满足运行测试和评估目的小型 GitLab 环境的最低系统要求,因此我们将继续选择该大小,但请选择大小最能满足您的要求: - -[![Azure - Create Virtual Machine - Size](img/f7bf9b7c134eb4ee2629082be8992d5a.png)](img/azure-create-virtual-machine-size.png) - -> **注意:请**注意,当您的 VM 处于活动状态(称为"已分配")时,将产生"计算费用",最终将向您收费. 因此,即使您使用的是免费试用版信用,您也可能想学习[如何正确关闭 Azure VM 以节省资金](https://build5nines.com/properly-shutdown-azure-vm-to-save-money/) . - -继续并单击您选择的大小,然后在准备进行下一步时单击**"选择"** . - -## Settings[](#settings "Permalink") - -在下一个刀片服务器上,要求您配置存储,网络和扩展设置. 我们保留了默认设置,因为它们足以进行 GitLab 的测试驾驶,但是请选择最能满足您自己要求的设置: - -[![Azure - Create Virtual Machine - Settings](img/e470cb0eb6198f35d2db011704471fce.png)](img/azure-create-virtual-machine-settings.png) - -检查设置,然后在准备好进行最后一步时单击**"确定"** . - -## Purchase[](#purchase "Permalink") - -"购买"页面是最后一步,在这里将为您显示新 VM 的每小时价格. 您只需要为 VM 本身付费(例如" Standard DS1 v2"),因为**" GitLab 社区版"**市场解决方案可以以 0 美元/小时的价格免费使用: - -[![Azure - Create Virtual Machine - Purchase](img/ed70f998a438f30a2762829a3cc5b5b6.png)](img/azure-create-virtual-machine-purchase.png) - -> **注意:**在此阶段,您可以查看和修改在之前所有步骤中所做的任何设置,只需单击四个步骤中的任何一个即可重新打开它们. - -阅读并同意使用条款并准备进行时,请单击**"购买"** . - -## Deployment[](#deployment "Permalink") - -此时,Azure 将开始部署您的新 VM. 部署过程将需要几分钟才能完成,进度显示在**"部署"**刀片上: - -[![Azure - Create Virtual Machine - Deployment](img/c9fb44f57074dc166ca07353bd7d31c7.png)](img/azure-create-virtual-machine-deployment.png) - -部署过程完成后,新的 VM 及其相关资源将显示在 Azure 仪表板上(您可能需要刷新页面): - -[![Azure - Dashboard - All resources](img/12208c7d040cd738d51605b7fcb55237.png)](img/azure-dashboard-running-resources.png) - -也可以通过单击 Azure Portal 侧栏导航菜单中的" `All resources`或" `Virtual machines`图标来访问新 VM. - -## Set up a domain name[](#set-up-a-domain-name "Permalink") - -该虚拟机将具有一个公共 IP 地址(默认情况下为静态),但是 Azure 允许我们为该虚拟机分配一个友好的 DNS 名称,所以让我们继续吧. - -在控制面板中,单击**" GitLab-CE"**图块以打开新 VM 的管理刀片. VM 使用的公共 IP 地址在"基本"部分中显示: - -[![Azure - VM - Management - Public IP Address](img/f08e838598cbf1f61321a510bb24c6a1.png)](img/azure-vm-management-public-ip.png) - -单击公共 IP 地址-这将打开**"公共 IP 地址-配置"**刀片,然后单击**"配置"** (在"设置"下). 现在,在" `DNS name label`字段中为您的实例输入一个友好的 DNS 名称: - -[![Azure - VM - Domain Name](img/bccfe6e36a18f67a038a8d90f2a6499f.png)](img/azure-vm-domain-name.png) - -In the screenshot above, you’ll see that we’ve set the `DNS name label` to `gitlab-ce-test`. This will make our VM accessible at `gitlab-ce-test.centralus.cloudapp.azure.com` *(当然,您自己的 VM 的完整域名将有所不同)*. - -单击**"保存"**以使更改生效. - -> **注意:**如果要使用自己的域名,则需要在域注册商处添加 DNS `A`记录, `A`记录指向 Azure VM 的公共 IP 地址. 如果这样做,则需要确保将 VM 配置为使用*静态的*公共 IP 地址(即不是*动态的* IP 地址),否则每次 Azure 重新为 VM 分配新的公共 IP 时,都必须重新配置 DNS `A`记录.地址. 阅读[公共 IP 地址](https://docs.microsoft.com/en-us/azure/virtual-network/public-ip-addresses)以了解更多信息. - -## Let’s open some ports[](#lets-open-some-ports "Permalink") - -在此阶段,您应该拥有一个正在运行且完全可运行的 VM. 但是,在您打开必要的端口以启用对这些服务的访问之前,将无法通过 Internet 公开访问 VM 上的任何服务(例如 GitLab). - -通过将*安全规则*添加到已分配了我们的 VM 的**"网络安全组"** (NSG),可以打开端口. 如果按照上述过程进行操作,则 Azure 将自动创建一个名为`GitLab-CE-nsg`的 NSG 并将`GitLab-CE` VM 分配给它. - -> **注意:**如果给虚拟机命名不同,则 Azure 自动创建的 NSG 也将具有不同的名称-您拥有虚拟机的名称,并附加`-nsg` . - -您可以通过 Azure 门户中的许多不同路径导航到 NSG 设置,但是最简单的方法之一是转到 Azure 仪表板,然后单击**"所有资源"**图块中列出的 Network Security 组: - -[![Azure - Dashboard - All resources - Network security group](img/c380b8ddd78f1d3281d0eeea7f19971c.png)](img/azure-dashboard-highlight-nsg.png) - -在打开**"网络安全组"**刀片的情况下,单击**"设置"**下的**"** **入站安全规则** **"** : - -[![Azure - Network security group - Inbound security rules](img/3b13f587681dd3391c82eb9b650ff6cf.png)](img/azure-nsg-inbound-sec-rules-highlight.png) - -接下来,点击**"添加"** : - -[![Azure - Network security group - Inbound security rules - Add](img/f6e26efd0e5206a2e9d1bf43865b9f4a.png)](img/azure-nsg-inbound-sec-rules-add-highlight.png) - -### Which ports to open?[](#which-ports-to-open "Permalink") - -像所有服务器一样,我们的 VM 将运行许多服务. 但是,我们要打开正确的端口,以使公共互联网特别能够访问两种服务: - -1. **HTTP** (端口 80)-打开端口 80 将使我们的 VM 能够响应 HTTP 请求,从而允许公众访问在我们的 VM 上运行的 GitLab 实例. -2. **SSH** (端口 22)-打开端口 22 将使我们的 VM 能够响应 SSH 连接请求,允许对远程终端会话进行公共访问(带有身份验证) *(您将[在本教程的后面部分](#maintaining-your-gitlab-instance)看到为什么我们需要对 VM 进行[SSH](https://en.wikipedia.org/wiki/Secure_Shell)访问)* - -### Open HTTP on Port 80[](#open-http-on-port-80 "Permalink") - -在**"添加入站安全规则"**刀片中,让我们打开端口 80,以便我们的 VM 可以接受 HTTP 连接: - -[![Azure - Add inbound security rules - HTTP](img/7d05273dffbd24f67285426b02a19ddc.png)](img/azure-add-inbound-sec-rule-http.png) - -1. 在`Name`字段中输入**" HTTP"** -2. 从`Service`下拉列表中的选项中选择**HTTP** -3. 确保将`Action`设置为**允许** -4. Click **“OK”** - -### Open SSH on Port 22[](#open-ssh-on-port-22 "Permalink") - -重复上述过程,添加第二个入站安全规则以打开端口 22,使我们的 VM 能够接受[SSH](https://en.wikipedia.org/wiki/Secure_Shell)连接: - -[![Azure - Add inbound security rules - SSH](img/fb8ded1bb07112b49dc42dff02fe01f7.png)](img/azure-add-inbound-sec-rule-ssh.png) - -1. 在" `Name`字段中输入**" SSH"** -2. 从`Service`下拉列表中的选项中选择**SSH** -3. 确保将`Action`设置为**允许** -4. Click **“OK”** - -Azure 将花一点时间来添加每个新的入站安全规则(您可能需要单击**"入站安全规则"**以刷新列表),但是一旦完成,您应该在列表中看到两个新规则: - -[![Azure - Inbound security rules - List](img/72431eb6b6fe2dd27e2f6f9be7d91672.png)](img/azure-inbound-sec-rules-list.png) - -## Connecting to GitLab[](#connecting-to-gitlab "Permalink") - -使用您先前设置的域名(或公共 IP 地址)在浏览器中访问新的 GitLab 实例. 如果一切都按计划进行,则应显示以下页面,要求您为 GitLab 自动创建的管理员帐户设置*新*密码: - -[![GitLab - Change Password](img/b786322ea49fe7840203db128b72a5e0.png)](img/gitlab-change-password.png) - -在两个表单字段中输入您的*新*密码,然后单击**"更改密码"** . - -更改密码后,您将被重定向到 GitLab 登录页面. 使用`root`作为用户名,输入在上一步中设置的新密码,然后单击**"登录"** : - -[![GitLab - Login](img/56b25600afa13ee05e76062ab09ee470.png)](img/gitlab-login.png) - -### Success?[](#success "Permalink") - -成功登录后,您应该看到 GitLab 项目页面显示**"欢迎使用 GitLab!".** 信息: - -[![GitLab - Projects Page](img/96c6ce839dca0e2ef2d69b8fbc0cff56.png)](img/gitlab-home.png) - -如果是这样,您现在可以在自己的私有 Azure VM 上拥有一个正常的 GitLab 实例. **恭喜你!** - -## Creating your first GitLab project[](#creating-your-first-gitlab-project "Permalink") - -如果您熟悉 Git 和 GitLab,则可以跳过本节. 否则,让我们创建第一个项目. 在"欢迎"页面上,单击**"新建项目"** . - -让我们给项目命名和描述,然后接受其他所有内容的默认值: - -1. 在`Project path`项目名称字段中输入**" demo"** -2. 输入`description` ,例如**"我的真棒演示项目!"** -3. Click **"创建项目"** - -[![GitLab - New Project](img/c7562ae46b8ec150661af0c88f1a5aad.png)](img/gitlab-new-project.png) - -一旦创建了新项目(只需要一点时间),您将被重定向到该项目的主页: - -[![GitLab - Empty Project](img/669c2de32e70a30ad93c28d4afd41491.png)](img/gitlab-project-home-empty.png) - -If you scroll further down the project’s home page, you’ll see some basic instructions on how to set up a local clone of your new repository and push and pull from it: - -[![GitLab - Empty Project - Basic Instructions](img/3281ef5fea53e2f0a57bb3c648aa7fa4.png)](img/gitlab-project-home-instructions.png) - -**而已! 现在,您已经在云中安装并运行了自己的私有 GitLab 环境!** - -## Maintaining your GitLab instance[](#maintaining-your-gitlab-instance "Permalink") - -保持最新的 GitLab 环境非常重要. GitLab 团队会不断进行增强,出于安全原因,有时您可能需要进行更新. 因此,让我们回顾一下如何更新 GitLab. - -### Checking our current version[](#checking-our-current-version "Permalink") - -要检查我们当前正在运行的 GitLab 版本,请单击"管理区域"链接-它是显示在搜索框旁边的右上角的扳手图标. - -在以下屏幕截图中,您可以在右上角看到**"尽快更新"**通知消息. 此特定消息表明存在可用的较新版本的 GitLab,其中包含一个或多个安全修复程序: - -[![GitLab - update asap](img/8465cc4b8bf68fad2a64c9fc838c7939.png)](img/gitlab-admin-area.png) - -在**"组件"**部分下,我们可以看到我们的 VM 当前正在运行 GitLab 的`8.6.5`版本. 这是 GitLab 的版本,包含在 Azure 市场**" GitLab 社区版"中,该**产品在编写本教程时曾用来构建 VM. - -> **注意:**您自己的 VM 实例中的 GitLab 版本可能会有所不同,但是更新过程仍然相同. - -### Connect via SSH[](#connect-via-ssh "Permalink") - -要执行更新,我们需要直接连接到我们的 Azure VM 实例并从终端运行一些命令. 我们的 Azure VM 实际上是运行 Linux(Ubuntu)的服务器,因此我们需要使用 SSH( [Secure Shell](https://en.wikipedia.org/wiki/Secure_Shell) )连接到它. - -如果您正在运行 Windows,则需要使用[PuTTY](https://www.putty.org)或等效的 Windows SSH 客户端进行连接. 如果您正在运行 Linux 或 macOS,则说明您已经安装了 SSH 客户端. - -> **Note:** -> -> * 请记住,您将需要使用[创建](#basics) Azure VM [时](#basics)指定的用户名和密码登录 -> * 如果需要重置虚拟机密码,请阅读[如何为 Azure VM 上的用户重置 SSH 凭据](https://docs.microsoft.com/en-us/azure/virtual-machines/troubleshooting/troubleshoot-ssh-connection) . - -#### SSH from the command-line[](#ssh-from-the-command-line "Permalink") - -如果您从命令行(终端)运行[SSH](https://en.wikipedia.org/wiki/Secure_Shell) ,则键入以下命令以连接到您的 VM,用`username`和`your-azure-domain-name.com`替换正确的值. - -再次提醒您,您的 Azure VM 域名将是您[先前在本教程中设置的](#set-up-a-domain-name)域名. 如果未为 VM 设置域名,则可以在以下命令中使用其 IP 地址: - -``` -ssh username@your-azure-domain-name.com -``` - -在提示时提供密码以进行身份​​验证. - -#### SSH from Windows (PuTTY)[](#ssh-from-windows-putty "Permalink") - -如果您将 Windows 中的[PuTTY](https://www.putty.org)用作[SSH](https://en.wikipedia.org/wiki/Secure_Shell)客户端,那么您可能想快速阅读[Windows 中的 PuTTY](https://mediatemple.net/community/products/dv/204404604/using-ssh-in-putty-) . - -### Updating GitLab[](#updating-gitlab "Permalink") - -通过 SSH 登录后,输入以下命令将 GitLab 更新到最新版本: - -``` -sudo apt-get update && sudo apt-get install gitlab-ce -``` - -此命令会将 GitLab 及其关联的组件更新为最新版本,因此需要一些时间才能完成. 您将在 SSH 终端窗口中看到各种更新任务正在完成: - -[![GitLab updating](img/dbae11f07630ae759b8156031d0c496d.png)](img/gitlab-ssh-update-in-progress.png) - -更新过程完成后,您将看到以下消息: - -``` -Upgrade complete! If your GitLab server is misbehaving try running - - sudo gitlab-ctl restart - -before anything else. -``` - -#### Check out your updated GitLab[](#check-out-your-updated-gitlab "Permalink") - -在浏览器中刷新您的 GitLab 实例,然后导航到"管理区域". 您现在应该具有最新的 GitLab 实例. - -在编写本教程时,我们的 Azure VM GitLab 实例在撰写本文时已更新为最新版本( `9.4.0` ). 您可以看到以前显示**" update asap"**的消息现在显示为**"最新"** : - -[![GitLab up to date](img/80a9fe0374f84134fa2b40172431604d.png)](img/gitlab-admin-area-9.4.0.png) - -## Conclusion[](#conclusion "Permalink") - -自然地,我们认为 GitLab 是一个很棒的 Git 存储库工具. 但是,GitLab 的功能远不止于此. GitLab 将问题,代码审查,CI 和 CD 统一到一个 UI 中,可帮助您从构思到生产更快地迁移,并且在本教程中,我们向您展示了在 Azure 上设置和运行自己的 GitLab 实例是多么快速和容易. ,微软的云服务. - -Azure 是尝试 GitLab 的好方法,如果您决定(如我们所愿)GitLab 适合您,则可以继续使用 Azure 作为您的安全,可扩展的云提供商,当然也可以在您选择的任何云服务上运行 GitLab. - -## Where to next?[](#where-to-next "Permalink") - -查看其他[技术文章](../../articles/index.html)或浏览[GitLab 文档](../../README.html)以了解有关 GitLab 的更多信息. - -### Useful links[](#useful-links "Permalink") - -* [GitLab Community Edition](https://about.gitlab.com/features/) -* [GitLab Enterprise Edition](https://about.gitlab.com/features/#ee-starter) -* [Microsoft Azure](https://azure.microsoft.com/en-us/) - * [Azure - Free Account FAQ](https://azure.microsoft.com/en-us/free/free-account-faq/) - * [Azure - Marketplace](https://azuremarketplace.microsoft.com/en-us/marketplace/) - * [Azure Portal](https://portal.azure.com) - * [Azure - Pricing Calculator](https://azure.microsoft.com/en-us/pricing/calculator/) - * [Azure - Troubleshoot SSH Connections to an Azure Linux VM](https://docs.microsoft.com/en-us/azure/virtual-machines/troubleshooting/troubleshoot-ssh-connection) - * [Azure - Properly Shutdown an Azure VM](https://build5nines.com/properly-shutdown-azure-vm-to-save-money/) -* [SSH](https://en.wikipedia.org/wiki/Secure_Shell), [PuTTY](https://www.putty.org) and [Using SSH in PuTTY](https://mediatemple.net/community/products/dv/204404604/using-ssh-in-putty-) \ No newline at end of file diff --git a/docs/010.md b/docs/010.md deleted file mode 100644 index f3fad8a66bd72e139804011598deb4618d1a8a71..0000000000000000000000000000000000000000 --- a/docs/010.md +++ /dev/null @@ -1,122 +0,0 @@ -# Installing GitLab on Google Cloud Platform - -> 原文:[https://docs.gitlab.com/ee/install/google_cloud_platform/](https://docs.gitlab.com/ee/install/google_cloud_platform/) - -* [Prerequisites](#prerequisites) -* [Creating the VM](#creating-the-vm) -* [Installing GitLab](#installing-gitlab) -* [Next steps](#next-steps) - * [Assigning a static IP](#assigning-a-static-ip) - * [Using a domain name](#using-a-domain-name) - * [Configuring HTTPS with the domain name](#configuring-https-with-the-domain-name) - * [Configuring the email SMTP settings](#configuring-the-email-smtp-settings) -* [Further reading](#further-reading) - -# Installing GitLab on Google Cloud Platform[](#installing-gitlab-on-google-cloud-platform "Permalink") - -本指南将帮助您在[Google Cloud Platform(GCP)](https://cloud.google.com/)实例上安装 GitLab. - -**替代安装方法:** Google 提供了一份白皮书,用于[在 Google Kubernetes Engine 上部署可投入生产的 GitLab](https://cloud.google.com/solutions/deploying-production-ready-gitlab-on-gke) ,包括所有步骤和外部资源配置. 这些是使用 GCP VM 的替代方法,并使用[Cloud native GitLab Helm chart](https://docs.gitlab.com/charts/) . - -## Prerequisites[](#prerequisites "Permalink") - -在 GCP 上安装 GitLab 的前提条件只有两个: - -1. 您需要有一个 Google 帐户. -2. 您需要注册 GCP 计划. 如果您是第一次,Google 会为您提供[$ 300 的信用额,](https://console.cloud.google.com/freetrial)可在 60 天内[免费](https://console.cloud.google.com/freetrial)使用. - -完成这两个步骤后,就可以[创建 VM 了](#creating-the-vm) . - -## Creating the VM[](#creating-the-vm "Permalink") - -要在 GCP 上部署 GitLab,您首先需要创建一个虚拟机: - -1. 转到[https://console.cloud.google.com/compute/instances](https://console.cloud.google.com/compute/instances)并使用您的 Google 凭据登录. -2. 点击**创建** - - [![Search for GitLab](img/9f6f0b27f8e7df6c95a3262de502b39f.png)](img/launch_vm.png) - -3. On the next page, you can select the type of VM as well as the estimated costs. Provide the name of the instance, desired datacenter, and machine type. Note our [hardware requirements for different user base sizes](../requirements.html#hardware-requirements). - - [![Launch on Compute Engine](img/d345ea7938f401127d9471442b27eb27.png)](img/vm_details.png) - -4. 要选择大小,类型和所需的[操作系统](../requirements.html#supported-linux-distributions) ,请在" `Boot disk` **"**下单击" **更改** ". 完成后单击" **选择"** . - -5. 最后,允许 HTTP 和 HTTPS 通信,然后点击**创建** . 该过程将在几秒钟内完成. - -## Installing GitLab[](#installing-gitlab "Permalink") - -几秒钟后,实例将被创建并可以登录.下一步是将 GitLab 安装到实例上. - -[![Deploy settings](img/ad33446e7ba7897d31835424ce5e1feb.png)](img/vm_created.png) - -1. 记下实例的 IP 地址,因为在后续步骤中将需要使用该 IP 地址. -2. 单击 SSH 按钮以连接到实例. -3. 登录到实例后,将出现一个新窗口. - - [![GitLab first sign in](img/e2a52ca7a089fcbd9b17f94875cba0ca.png)](img/ssh_terminal.png) - -4. 接下来,在[https://about.gitlab.com/install/上](https://about.gitlab.com/install/)按照说明为您选择的操作系统安装 GitLab. 您可以将上述步骤中的 IP 地址用作主机名. - -5. 恭喜你! GitLab 现在已安装,您可以通过浏览器访问它. 要完成安装,请在浏览器中打开 URL 并提供初始管理员密码. 该帐户的用户名是`root` . - - [![GitLab first sign in](img/279650b9e9c3ec26a7d6f0493bd5af7c.png)](img/first_signin.png) - -## Next steps[](#next-steps "Permalink") - -这些是首次安装 GitLab 之后要执行的最重要的后续步骤. - -### Assigning a static IP[](#assigning-a-static-ip "Permalink") - -默认情况下,Google 会为您的实例分配一个临时 IP. 如果您要在生产中使用 GitLab 并使用域名,则强烈建议分配一个静态 IP,如下所示. - -阅读 Google 有关如何[提升临时 IP 地址](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip)的文档. - -### Using a domain name[](#using-a-domain-name "Permalink") - -假设您拥有一个域名,并且已正确设置 DNS 以指向在上一步中配置的静态 IP,则可以通过以下方法配置 GitLab 以了解更改: - -1. SSH 进入虚拟机. 您可以轻松使用 Google 控制台中的**SSH**按钮,然后会弹出一个新窗口. - - [![SSH button](img/ad33446e7ba7897d31835424ce5e1feb.png)](img/vm_created.png) - - 将来,您可能想设置[使用 SSH 密钥的连接](https://cloud.google.com/compute/docs/instances/connecting-to-instance) . - -2. 使用您喜欢的文本编辑器编辑 Omnibus GitLab 的配置文件: - - ``` - sudo vim /etc/gitlab/gitlab.rb - ``` - -3. 将`external_url`值设置为您希望 GitLab 在**不使用** `https` **情况下**拥有的域名: - - ``` - external_url 'http://gitlab.example.com' - ``` - - 我们将在下一步中设置 HTTPS,而现在无需这样做. - -4. 重新配置 GitLab,以使更改生效: - - ``` - sudo gitlab-ctl reconfigure - ``` - -5. 您现在可以使用域名访问 GitLab. - -### Configuring HTTPS with the domain name[](#configuring-https-with-the-domain-name "Permalink") - -尽管不需要,但强烈建议使用 TLS 证书保护 GitLab. 请遵循[Omnibus 文档中](https://docs.gitlab.com/omnibus/settings/nginx.html)的步骤. - -### Configuring the email SMTP settings[](#configuring-the-email-smtp-settings "Permalink") - -您需要正确配置电子邮件 SMTP 设置,否则 GitLab 将无法发送通知电子邮件,例如注释和密码更改. 检查[Omnibus 文档的](https://docs.gitlab.com/omnibus/settings/smtp.html)操作方法. - -## Further reading[](#further-reading "Permalink") - -可以将 GitLab 配置为与其他 OAuth 提供程序,LDAP,SAML,Kerberos 等进行身份验证.以下是您可能感兴趣阅读的一些文档: - -* [Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/) -* [Integration documentation](../../integration/README.html) -* [GitLab Pages configuration](../../administration/pages/index.html) -* [GitLab Container Registry configuration](../../administration/packages/container_registry.html) \ No newline at end of file diff --git a/docs/011.md b/docs/011.md deleted file mode 100644 index 97920a2c475f285239d9eb4f496cf2ab0b5256cc..0000000000000000000000000000000000000000 --- a/docs/011.md +++ /dev/null @@ -1,754 +0,0 @@ -# Installing GitLab on Amazon Web Services (AWS) - -> 原文:[https://docs.gitlab.com/ee/install/aws/](https://docs.gitlab.com/ee/install/aws/) - -* [Introduction](#introduction) -* [Requirements](#requirements) -* [Architecture](#architecture) -* [AWS costs](#aws-costs) -* [Create an IAM EC2 instance role and profile](#create-an-iam-ec2-instance-role-and-profile) - * [Create an IAM Policy](#create-an-iam-policy) - * [Create an IAM Role](#create-an-iam-role) -* [Configuring the network](#configuring-the-network) - * [Creating the Virtual Private Cloud (VPC)](#creating-the-virtual-private-cloud-vpc) - * [Subnets](#subnets) - * [Internet Gateway](#internet-gateway) - * [Create NAT Gateways](#create-nat-gateways) - * [Route Tables](#route-tables) - * [Public Route Table](#public-route-table) - * [Private Route Tables](#private-route-tables) -* [Load Balancer](#load-balancer) - * [Configure DNS for Load Balancer](#configure-dns-for-load-balancer) -* [PostgreSQL with RDS](#postgresql-with-rds) - * [RDS Security Group](#rds-security-group) - * [RDS Subnet Group](#rds-subnet-group) - * [Create the database](#create-the-database) -* [Redis with ElastiCache](#redis-with-elasticache) - * [Create a Redis Security Group](#create-a-redis-security-group) - * [Redis Subnet Group](#redis-subnet-group) - * [Create the Redis Cluster](#create-the-redis-cluster) -* [Setting up Bastion Hosts](#setting-up-bastion-hosts) - * [Create Bastion Host A](#create-bastion-host-a) - * [Create Bastion Host B](#create-bastion-host-b) - * [Use SSH Agent Forwarding](#use-ssh-agent-forwarding) -* [Install GitLab and create custom AMI](#install-gitlab-and-create-custom-ami) - * [Install GitLab](#install-gitlab) - * [Add custom configuration](#add-custom-configuration) - * [Disable Let’s Encrypt](#disable-lets-encrypt) - * [Install the `pg_trgm` extension for PostgreSQL](#install-the-pg_trgm-extension-for-postgresql) - * [Configure GitLab to connect to PostgreSQL and Redis](#configure-gitlab-to-connect-to-postgresql-and-redis) - * [Set up Gitaly](#set-up-gitaly) - * [Add Support for Proxied SSL](#add-support-for-proxied-ssl) - * [Fast lookup of authorized SSH keys](#fast-lookup-of-authorized-ssh-keys) - * [Configure host keys](#configure-host-keys) - * [Amazon S3 object storage](#amazon-s3-object-storage) - * [Create custom AMI](#create-custom-ami) -* [Deploy GitLab inside an auto scaling group](#deploy-gitlab-inside-an-auto-scaling-group) - * [Create a launch configuration](#create-a-launch-configuration) - * [Create an auto scaling group](#create-an-auto-scaling-group) - * [Log in for the first time](#log-in-for-the-first-time) -* [Health check and monitoring with Prometheus](#health-check-and-monitoring-with-prometheus) -* [GitLab Runners](#gitlab-runners) -* [Backup and restore](#backup-and-restore) - * [Backing up GitLab](#backing-up-gitlab) - * [Restoring GitLab from a backup](#restoring-gitlab-from-a-backup) -* [Updating GitLab](#updating-gitlab) -* [Conclusion](#conclusion) -* [Troubleshooting](#troubleshooting) - * [Instances are failing health checks](#instances-are-failing-health-checks) - * [“The change you requested was rejected (422)”](#the-change-you-requested-was-rejected-422) - -# Installing GitLab on Amazon Web Services (AWS)[](#installing-gitlab-on-amazon-web-services-aws "Permalink") - -该页面提供了 AWS 上 GitLab 通用配置的演练. 您应该对其进行自定义以满足您的需求. - -**注意:**对于拥有 1,000 个或更少用户的组织,建议的 AWS 安装方法是启动 EC2 单框[Omnibus 安装](https://about.gitlab.com/install/)并实施快照策略以备份数据. 有关更多信息,请参见[1,000 个用户参考体系结构](../../administration/reference_architectures/1k_users.html) . - -## Introduction[](#introduction "Permalink") - -在大多数情况下,我们将在我们的设置中使用 Omnibus GitLab,但我们还将利用本机 AWS 服务. 代替使用 Omnibus 捆绑的 PostgreSQL 和 Redis,我们将使用 AWS RDS 和 ElastiCache. - -在本指南中,我们将进行多节点设置,首先将配置虚拟私有云和子网,以稍后集成服务(例如用于数据库服务器的 RDS 和作为 Redis 集群的 ElastiCache)以最终在一个具有自定义缩放策略的自动缩放组. - -## Requirements[](#requirements "Permalink") - -除了基本了解[AWS](https://docs.aws.amazon.com/)和[Amazon EC2 之外](https://docs.aws.amazon.com/ec2/) ,您还需要: - -* [An AWS account](https://console.aws.amazon.com/console/home) -* [To create or upload an SSH key](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html) to connect to the instance via SSH -* GitLab 实例的域名 -* SSL / TLS 证书以保护您的域. 如果您还不拥有该证书,则可以通过[AWS Certificate Manager](https://aws.amazon.com/certificate-manager/) (ACM)设置免费的公共 SSL / TLS 证书,以与我们将创建的[Elastic Load Balancer](#load-balancer)一起使用. - -**注意:**验证通过 ACM 设置的证书可能需要几个小时. 为避免以后出现延迟,请尽快申请您的证书. - -## Architecture[](#architecture "Permalink") - -下面是推荐架构的示意图. - -[![AWS architecture diagram](img/20bba5f798131b98df30aaa9202ccfd5.png)](img/aws_ha_architecture_diagram.png) - -## AWS costs[](#aws-costs "Permalink") - -以下是我们将使用的 AWS 服务的列表,以及指向定价信息的链接: - -* **EC2** :GitLab 将部署在共享硬件上,这意味着将[按需定价](https://aws.amazon.com/ec2/pricing/on-demand/) . 如果要在专用或保留实例上运行它,请参阅[EC2 定价页面](https://aws.amazon.com/ec2/pricing/)以获取有关费用的更多信息. -* **S3** :我们将使用 S3 来存储备份,工件,LFS 对象等.请参阅[Amazon S3 定价](https://aws.amazon.com/s3/pricing/) . -* **ELB** :经典负载均衡器将用于将请求路由到 GitLab 实例. 请参阅[Amazon ELB 定价](https://aws.amazon.com/elasticloadbalancing/pricing/) . -* **RDS** :将使用使用 PostgreSQL 的 Amazon Relational Database Service. 请参阅[Amazon RDS 定价](https://aws.amazon.com/rds/postgresql/pricing/) . -* **ElastiCache** :内存缓存环境将用于提供 Redis 配置. 请参阅[Amazon ElastiCache 定价](https://aws.amazon.com/elasticache/pricing/) . - -## Create an IAM EC2 instance role and profile[](#create-an-iam-ec2-instance-role-and-profile "Permalink") - -由于我们将使用[Amazon S3 对象存储](#amazon-s3-object-storage) ,因此我们的 EC2 实例需要具有对 S3 存储桶的读取,写入和列出权限. 为了避免将 AWS Key 嵌入我们的 GitLab 配置中,我们将利用[IAM 角色](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html)允许 GitLab 实例具有此访问权限. 我们需要创建一个 IAM 策略以附加到我们的 IAM 角色: - -### Create an IAM Policy[](#create-an-iam-policy "Permalink") - -1. 导航到 IAM 仪表板,然后单击左侧菜单中的" **策略** ". -2. 单击**创建策略** ,选择`JSON`选项卡,然后添加策略. 我们希望[遵循安全最佳实践并授予*最少的特权*](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege) ,仅向我们的角色授予执行所需操作所需的权限. - 1. 假设如图所示,在 S3 存储桶名称前添加`gl-`作为前缀,请添加以下策略: - -``` -{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:AbortMultipartUpload", "s3:CompleteMultipartUpload", "s3:ListBucket", "s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:PutObjectAcl" ], "Resource": [ "arn:aws:s3:::gl-*/*" ] } ] } -``` - -1. 点击**审核政策** ,为您的政策命名(我们将使用`gl-s3-policy` ),然后点击**创建政策** . - -### Create an IAM Role[](#create-an-iam-role "Permalink") - -1. 仍在 IAM 仪表板上,单击左侧菜单中的**角色** ,然后单击**创建角色** . -2. 通过选择**AWS 服务> EC2**来创建新角色,然后单击**下一步:权限** . -3. 在策略过滤器中,搜索我们在上面创建的`gl-s3-policy` ,选择它,然后点击**标签** . -4. 根据需要添加标签,然后单击" **查看"** . -5. 为角色命名(我们将使用`GitLabS3Access` ),然后点击**创建角色** . - -稍后[创建启动配置](#create-a-launch-configuration)时,将使用此角色. - -## Configuring the network[](#configuring-the-network "Permalink") - -我们将从为 GitLab 云基础架构创建 VPC 开始,然后我们可以创建子网以在至少两个[可用区(AZ)中](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html)具有公共实例和私有实例. 公共子网将需要保留路由表和关联的 Internet 网关. - -### Creating the Virtual Private Cloud (VPC)[](#creating-the-virtual-private-cloud-vpc "Permalink") - -现在,我们将创建一个 VPC,一个您可以控制的虚拟网络环境: - -1. 导航至[https://console.aws.amazon.com/vpc/home](https://console.aws.amazon.com/vpc/home) . -2. 从左侧菜单中选择**您的 VPC** ,然后单击**创建 VPC** . 在"名称标签"中输入`gitlab-vpc` ,在" IPv4 CIDR 块"中输入`10.0.0.0/16` . 如果不需要专用硬件,则可以将" Tenancy"保留为默认设置. 单击**是,**准备好后**创建** . - - [![Create VPC](img/7cfe14b5f606095866af7260c844d4e2.png)](img/create_vpc.png) - -3. 选择 VPC,单击" **操作"** ,单击" **编辑 DNS 解析"** ,然后启用 DNS 解析. 完成后点击**保存** . - -### Subnets[](#subnets "Permalink") - -现在,让我们在不同的可用区中创建一些子网. 确保每个子网都与我们刚刚创建的 VPC 相关联,并且 CIDR 块不会重叠. 这也将使我们能够启用多可用区以实现冗余. - -我们还将创建专用和公用子网以匹配负载均衡器和 RDS 实例: - -1. 从左侧菜单中选择**子网** . -2. 单击**创建子网** . 给它一个基于 IP 的描述性名称标签,例如`gitlab-public-10.0.0.0` ,选择我们之前创建的 VPC,选择一个可用区(我们将使用`us-west-2a` ),并在 IPv4 CIDR 块上让我们给它一个 24 个子网`10.0.0.0/24` : - - [![Create subnet](img/48482b1410caf250f0257d772e55c544.png)](img/create_subnet.png) - -3. 请按照相同的步骤创建所有子网: - - | 名称标签 | Type | 可用区 | CIDR 块 | - | --- | --- | --- | --- | - | `gitlab-public-10.0.0.0` | public | `us-west-2a` | `10.0.0.0/24` | - | `gitlab-private-10.0.1.0` | private | `us-west-2a` | `10.0.1.0/24` | - | `gitlab-public-10.0.2.0` | public | `us-west-2b` | `10.0.2.0/24` | - | `gitlab-private-10.0.3.0` | private | `us-west-2b` | `10.0.3.0/24` | - -4. 创建所有子网后,请为两个公共子网启用**自动分配 IPv4** : - 1. 依次选择每个公共子网,单击" **操作"** ,然后单击" **修改自动分配 IP 设置"** . 启用该选项并保存. - -### Internet Gateway[](#internet-gateway "Permalink") - -现在,仍然在同一仪表板上,转到 Internet 网关并创建一个新的网关: - -1. 从左侧菜单中选择" **Internet 网关** ". -2. 单击**创建互联网网关** ,为其命名为`gitlab-gateway` ,然后单击**创建** . -3. 从表中选择它,然后在" **操作"**下拉菜单下选择"附加到 VPC". - - [![Create gateway](img/104374dd85800b346ef75734f6fd0b38.png)](img/create_gateway.png) - -4. 从列表中选择`gitlab-vpc` ,然后点击**Attach** . - -### Create NAT Gateways[](#create-nat-gateways "Permalink") - -部署在我们专用子网中的实例需要连接到 Internet 进行更新,但不能从公共 Internet 到达. 为此,我们将利用部署在每个公共子网中的[NAT 网关](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html) : - -1. 导航到 VPC 仪表板,然后单击左侧菜单栏中的**NAT 网关** . -2. 单击**创建 NAT 网关,**然后完成以下操作: - 1. **子网** :从下拉列表中选择`gitlab-public-10.0.0.0` . - 2. **弹性 IP 分配 ID** :输入现有的弹性 IP 或单击**分配弹性 IP 地址,**以将新 IP 分配给您的 NAT 网关. - 3. 如果需要,添加标签. - 4. 单击**创建 NAT 网关** . - -创建第二个 NAT 网关,但这一次将其放置在第二个公共子网`gitlab-public-10.0.2.0` . - -### Route Tables[](#route-tables "Permalink") - -#### Public Route Table[](#public-route-table "Permalink") - -我们需要为公共子网创建路由表,以通过上一步中创建的 Internet 网关访问 Internet. - -在 VPC 仪表板上: - -1. 从左侧菜单中选择**路由表** . -2. Click **创建路由表**. -3. 在"名称标签"中,输入`gitlab-public` , `gitlab-vpc`在" VPC"下选择`gitlab-vpc` . -4. Click **Create**. - -现在,我们需要将我们的 Internet 网关添加为新目标,并使其接收来自任何目的地的流量. - -1. 从左侧菜单中选择" **路由表"** ,然后选择`gitlab-public`路由以在底部显示选项. -2. 选择" **路线"**选项卡,单击" **编辑路线">"添加路线",**然后将`0.0.0.0/0`设置为目的地. 在目标列中,选择我们之前创建的`gitlab-gateway` . 完成后,点击**保存路线** . - -接下来,我们必须将**公共**子网关联到路由表: - -1. Select the **子网关联** tab and click **编辑子网关联**. -2. 仅检查公共子网,然后单击" **保存"** . - -#### Private Route Tables[](#private-route-tables "Permalink") - -我们还需要创建两个私有路由表,以便每个私有子网中的实例都可以通过同一可用性区域中相应公共子网中的 NAT 网关到达 Internet. - -1. 请按照与上述相同的步骤创建两个专用路由表. 将它们`gitlab-private-a`命名为`gitlab-private-a`和`gitlab-private-b` . -2. Next, add a new route to each of the private route tables where the destination is `0.0.0.0/0` and the target is one of the NAT gateways we created earlier. - 1. 将我们在`gitlab-public-10.0.0.0`创建的 NAT 网关添加为`gitlab-private-a`路由表中新路由的目标. - 2. 同样,在`gitlab-public-10.0.2.0`添加 NAT 网关作为`gitlab-private-b`新路由的目标. -3. 最后,将每个专用子网与专用路由表相关联. - 1. 将`gitlab-private-10.0.1.0` `gitlab-private-a`与`gitlab-private-a` . - 2. 将`gitlab-private-10.0.3.0`与`gitlab-private-b` . - -## Load Balancer[](#load-balancer "Permalink") - -我们将创建一个负载平衡器,以在我们的 GitLab 应用程序服务器之间平均分配端口`80`和`443`上的入站流量. 根据我们稍后将创建的[扩展策略](#create-an-auto-scaling-group) ,实例将根据需要添加到负载均衡器中或从负载均衡器中删除. 此外,负载平衡将对我们的实例执行运行状况检查. - -在 EC2 仪表板上,在左侧导航栏中查找 Load Balancer: - -1. 单击**创建负载均衡器**按钮. - 1. 选择**经典负载均衡器** . - 2. 给它`gitlab-loadbalancer` (我们将使用`gitlab-loadbalancer` ),并在**Create LB Inside**选项中,从下拉菜单中选择`gitlab-vpc` . - 3. 在" **侦听器"**部分中,设置以下侦听器: - * 负载均衡器和实例协议以及端口的 HTTP 端口 80 - * 负载均衡器和实例协议以及端口的 TCP 端口 22 - * HTTPS 端口 443(用于负载均衡器协议和端口),转发到实例上的 HTTP 端口 80(我们将[在指南](#add-support-for-proxied-ssl)中将 GitLab 配置为侦听端口 80) - 4. 在" **选择子网"**部分中,从列表中选择两个公共子网,以便负载均衡器可以将流量路由到两个可用区域. -2. 我们将为负载均衡器添加一个安全组,以充当防火墙来控制允许通过的流量. 单击**分配安全组,**然后选择**创建新的安全组** ,为其命名(我们将使用`gitlab-loadbalancer-sec-group` )和说明,并允许来自任何地方的 HTTP 和 HTTPS 通信( `0.0.0.0/0, ::/0` ). 还允许 SSH 流量,选择自定义来源,并以 CIDR 表示法添加单个受信任的 IP 地址或 IP 地址范围. 这将允许用户通过 SSH 执行 Git 操作. -3. 单击**配置安全设置,**然后进行以下设置: - 1. 从 ACM 中选择一个 SSL / TLS 证书或将一个证书上传到 IAM. - 2. 在" **选择密码"下** ,从下拉列表中选择预定义的安全策略. 您可以在 AWS 文档中[查看 Classic Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html)的[预定义 SSL 安全策略](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html)明细. 检查 GitLab 代码库以获取[受支持的 SSL 密码和协议](https://gitlab.com/gitlab-org/gitlab/-/blob/9ee7ad433269b37251e0dd5b5e00a0f00d8126b4/lib/support/nginx/gitlab-ssl#L97-99)的列表. -4. 单击" **配置**运行状况检查",然后为您的 EC2 实例设置运行状况检查. - 1. 对于" **Ping 协议"** ,选择" HTTP". - 2. 对于**Ping 端口** ,输入 80\. - 3. 对于**Ping Path** ,输入`/users/sign_in` . (我们使用`/users/sign_in`因为它是不需要授权的公共端点.) - 4. 保留默认的" **高级详细信息"**或根据需要进行调整. -5. 单击**添加 EC2 实例** -不要添加任何内容,因为稍后我们将创建一个 Auto Scaling 组来为我们管理实例. -6. 单击**添加标签,**然后添加您需要的任何标签. -7. 单击" **查看并创建"** ,查看所有设置,如果满意,请单击" **创建"** . - -在负载均衡器启动并运行后,您可以重新访问安全组以仅通过 ELB 和您可能具有的任何其他要求来完善访问. - -### Configure DNS for Load Balancer[](#configure-dns-for-load-balancer "Permalink") - -在 Route 53 仪表板上,单击左侧导航栏中的" **托管区域** ": - -1. 选择一个现有的托管区域,或者,如果您的域还没有一个,请单击**创建托管区域** ,输入您的域名,然后单击**创建** . -2. 单击**创建记录集,**并提供以下值: - 1. **名称:**使用域名(默认值)或输入一个子域. - 2. **类型:**选择**A-IPv4 地址** . - 3. **别名:**默认为**No.** 选择**是** . - 4. **别名目标:**找到" **ELB 经典负载均衡器"**部分,然后选择我们之前创建的经典负载均衡器. - 5. **路由策略:**我们将使用" **简单",**但您可以根据用例选择其他策略. - 6. **评估目标健康状况:**我们将其设置为" **否",**但是您可以选择让负载均衡器根据目标健康状况来路由流量. - 7. 点击**创建** . -3. 如果您通过 Route 53 注册了域,那么您就完成了. 如果您使用了其他域名注册商,则需要使用域名注册商更新 DNS 记录. 您需要: - 1. 单击**托管区域,**然后选择您在上面添加的域. - 2. 您将看到`NS`记录列表. 在您的域名注册商的管理面板中,将每一个作为`NS`记录添加到您域的 DNS 记录中. 这些步骤在域注册商之间可能会有所不同. 如果您陷入困境,则 Google **"您的注册商名称"会添加 dns 记录** ,您应该会找到针对您的域名注册商的帮助文章. - -根据您使用的注册商的不同,执行此操作的步骤也有所不同,这超出了本指南的范围. - -## PostgreSQL with RDS[](#postgresql-with-rds "Permalink") - -对于我们的数据库服务器,我们将使用提供多可用区以实现冗余的 Amazon RDS. 首先,我们将创建一个安全组和子网组,然后将创建实际的 RDS 实例. - -### RDS Security Group[](#rds-security-group "Permalink") - -我们需要一个用于数据库的安全组,该安全组将允许稍后将在`gitlab-loadbalancer-sec-group`部署的实例的入站流量: - -1. 在 EC2 仪表板中,从左侧菜单栏中选择" **安全组** ". -2. Click **创建安全组**. -3. 给它起一个名字(我们将使用`gitlab-rds-sec-group` ),一个描述,并从**VPC**下拉列表中选择`gitlab-vpc` . -4. 在" **入站规则"**部分中,单击" **添加规则"**并进行以下设置: - 1. **键入:**搜索并选择**PostgreSQL**规则. - 2. **来源类型:**设置为"自定义". - 3. **来源:**选择我们之前创建的`gitlab-loadbalancer-sec-group` . -5. 完成后,点击**创建安全组** . - -### RDS Subnet Group[](#rds-subnet-group "Permalink") - -1. 导航到 RDS 仪表板,然后从左侧菜单中选择" **子网组** ". -2. 单击**创建数据库子网组** . -3. 在" **子网组详细信息"下** ,输入名称(我们将使用`gitlab-rds-group` ),描述,然后从 VPC 下拉列表中选择`gitlab-vpc` . -4. 从" **可用区"**下拉列表中,选择包括您已配置的子网的可用区. 在本例中,我们将添加`eu-west-2a`和`eu-west-2b` . -5. 从**子网**下拉列表中,选择两个专用子网( `10.0.1.0/24`和`10.0.3.0/24` ,因为我们在定义它们) [的子网部分](#subnets) . -6. 准备好后,单击**创建** . - -### Create the database[](#create-the-database "Permalink") - -**危险:**避免对数据库使用易爆实例(t 类实例),因为由于 CPU 信用在持续的高负载期间用尽而可能导致性能问题. - -现在,该创建数据库了: - -1. 导航到 RDS 仪表板,从左侧菜单中选择" **数据库** ",然后单击" **创建数据库"** . -2. 选择**标准创建**作为数据库创建方法. -3. 选择**PostgreSQL**作为数据库引擎,然后选择在[数据库要求中](../../install/requirements.html#postgresql-requirements)为您的 GitLab 版本定义的最低 PostgreSQL 版本. -4. 由于这是生产服务器,因此我们从" **模板"**部分中选择" **生产** ". -5. 在**"设置"下** ,设置数据库实例标识符,主用户名和主密码. 我们将分别使用`gitlab-db-ha` , `gitlab`和一个非常安全的密码. 记下这些内容,稍后我们将需要它们. -6. 对于数据库实例大小,请选择" **标准类",**然后从下拉菜单中选择一个满足您要求的实例大小. 我们将使用`db.m4.large`实例. -7. 在" **存储"下** ,配置以下内容: - 1. 从存储类型下拉菜单中选择" **Provisioned IOPS(SSD)** ". 预置 IOPS(SSD)存储最适合此用途(尽管您可以选择 General Purpose(SSD)来降低成本). 在[Amazon RDS 的存储中](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Storage.html)阅读有关它的更多信息. - 2. 分配存储并设置预配置的 IOPS. 我们将分别使用最小值`100`和`1000` . - 3. 启用存储自动缩放(可选)并设置最大存储阈值. -8. 在" **可用性和持久性"下** ,选择" **创建备用实例"**以在另一个可用[区中](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.MultiAZ.html)配置备用 RDS 实例. -9. 在" **连接性"下** ,配置以下内容: - 1. 从**虚拟私有云(VPC)**下拉菜单中选择我们之前创建的 VPC( `gitlab-vpc` ). - 2. 展开**其他连接配置**部分,然后选择我们之前创建的子网组( `gitlab-rds-group` ). - 3. 设置公众了解**没有** . - 4. 在**VPC 安全组下** ,选择**选择现有,**然后从下拉列表中选择我们在上面创建的`gitlab-rds-sec-group` . - 5. 将数据库端口保留为默认值`5432` . -10. 对于**数据库身份验证** ,选择**密码身份验证** . -11. 展开**其他配置**部分,并完成以下操作: - 1. 初始数据库名称. 我们将使用`gitlabhq_production` . - 2. 配置您的首选备份设置. - 3. 我们将在此处进行的唯一其他更改是禁用" **维护"**下的自动次要版本更新. - 4. 保留所有其他设置不变或根据需要进行调整. - 5. 满意后,点击**创建数据库** . - -现在已经创建了数据库,让我们继续使用 ElastiCache 设置 Redis. - -## Redis with ElastiCache[](#redis-with-elasticache "Permalink") - -ElastiCache 是​​一个内存托管的缓存解决方案. Redis 保持其自身的持久性,并用于为 GitLab 应用程序存储会话数据,临时缓存信息和后台作业队列. - -### Create a Redis Security Group[](#create-a-redis-security-group "Permalink") - -1. 导航到 EC2 仪表板. -2. 从左侧菜单中选择" **安全组** ". -3. 单击**创建安全组,**然后填写详细信息. 给它`gitlab-redis-sec-group` (我们将使用`gitlab-redis-sec-group` ),添加描述,然后选择我们之前创建的 VPC -4. 在" **入站规则"**部分中,单击" **添加规则"**并添加一个" **自定义 TCP"**规则,设置端口`6379` ,并将"自定义"源设置为我们之前创建的`gitlab-loadbalancer-sec-group` . -5. 完成后,点击**创建安全组** . - -### Redis Subnet Group[](#redis-subnet-group "Permalink") - -1. 从您的 AWS 控制台导航到 ElastiCache 仪表板. -2. 转到左侧菜单中的" **子网组** ",然后创建一个新的子网组(我们将其命名为`gitlab-redis-group` ). 确保选择我们的 VPC 及其[专用子网](#subnets) . 准备好后,单击**创建** . - - [![ElastiCache subnet](img/98f7e80b6f738f9886082aeec3955fd5.png)](img/ec_subnet.png) - -### Create the Redis Cluster[](#create-the-redis-cluster "Permalink") - -1. 导航回到 ElastiCache 仪表板. -2. 在左侧菜单上选择**Redis** ,然后单击**创建**以创建新的 Redis 集群. 不要启用**集群模式,**因为它[不受支持](../../administration/redis/replication_and_failover_external.html#requirements) . 即使没有启用群集模式,您仍然有机会在多个可用性区域中部署 Redis. -3. 在设置部分: - 1. 为集群命名( `gitlab-redis` )和描述. - 2. 对于版本,选择最新的`5.0`系列(例如`5.0.6` ). - 3. 将端口保留为`6379`因为这是我们在上面的 Redis 安全组中使用的端口. - 4. 选择节点类型(至少为`cache.t3.medium` ,但根据需要进行调整)和副本数. -4. 在高级设置部分: - 1. 选择多可用区自动故障转移选项. - 2. 选择我们之前创建的子网组. - 3. 手动选择首选的可用区域,然后在"副本 2"下选择与其他两个区域不同的区域. - - [![Redis 可用区](img/38ef5bf427869fe9b1050db6eacd2972.png)](img/ec_az.png) - -5. 在安全设置中,编辑安全组,然后选择我们之前创建的`gitlab-redis-sec-group` . -6. 将其余设置保留为默认值,或根据自己的喜好进行编辑. -7. 完成后,点击**创建** . - -## Setting up Bastion Hosts[](#setting-up-bastion-hosts "Permalink") - -由于我们的 GitLab 实例将位于专用子网中,因此我们需要一种通过 SSH 连接到这些实例以进行配置更改,执行升级等的方法.一种方法是通过[堡垒主机](https://en.wikipedia.org/wiki/Bastion_host) ,有时也称为跳转框. - -**提示:**如果您不想维护堡垒主机,则可以设置[AWS Systems Manager Session Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager.html)来访问实例. 这超出了本文档的范围. - -### Create Bastion Host A[](#create-bastion-host-a "Permalink") - -1. 导航到 EC2 仪表板,然后单击**Launch instance** . -2. 选择**Ubuntu Server 18.04 LTS(HVM)** AMI. -3. 选择一个实例类型. 我们将使用`t2.micro`因为我们仅使用堡垒主机将 SSH SSH 到我们的其他实例中. -4. Click **配置实例详细信息**. - 1. 在" **网络"下** ,从下拉菜单中选择`gitlab-vpc` . - 2. 在" **子网"下** ,选择我们之前创建的公共子网( `gitlab-public-10.0.0.0` ). - 3. 仔细检查是否在" **自动分配公用 IP"下**选择了" **使用子网设置"("启用")** . - 4. 将其他所有内容保留为默认值,然后单击" **添加存储"** . -5. 对于存储,我们将所有内容保留为默认设置,仅添加 8GB 根卷. 我们不会在此实例上存储任何内容. -6. 单击**添加标签** ,然后在下一个屏幕上单击**添加标签** . - 1. 我们只设置`Key: Name`和`Value: Bastion Host A` -7. Click **配置安全组**. - 1. 选择**创建新的安全组** ,输入**安全组名称** (我们将使用`bastion-sec-group` ),然后添加描述. - 2. 我们将从任何地方( `0.0.0.0/0` )启用 SSH 访问. 如果需要更严格的安全性,请以 CIDR 表示法指定单个 IP 地址或 IP 地址范围. - 3. Click **审查并启动** -8. Review all your settings and, if you’re happy, click **Launch**. -9. 确认您有权访问现有的密钥对或创建一个新的密钥对. 单击**启动实例** . - -确认您可以通过 SSH 进入实例: - -1. 在 EC2 仪表板上,单击左侧菜单中的**Instances** . -2. 从实例列表中选择**Bastion HostA** . -3. 单击**连接,**然后按照连接说明进行操作. -4. 如果能够成功连接,让我们继续设置第二个堡垒主机以实现冗余. - -### Create Bastion Host B[](#create-bastion-host-b "Permalink") - -1. 按照与上述相同的步骤创建 EC2 实例,并进行以下更改: - 1. 对于**Subnet** ,选择我们之前创建的第二个公共子网( `gitlab-public-10.0.2.0` ). - 2. 在" **添加标签"**部分下,我们将设置" `Key: Name`和`Value: Bastion Host B`以便我们可以轻松识别两个实例. - 3. 对于安全组,选择我们上面创建的现有`bastion-sec-group` . - -### Use SSH Agent Forwarding[](#use-ssh-agent-forwarding "Permalink") - -运行 Linux 的 EC2 实例使用私钥文件进行 SSH 身份验证. 您将使用 SSH 客户端和存储在客户端上的私钥文件连接到堡垒主机. 由于私有密钥文件不存在于堡垒主机上,因此您将无法连接到私有子网中的实例. - -在堡垒主机上存储私钥文件是一个坏主意. 要解决此问题,请在客户端上使用 SSH 代理转发. 有关如何使用 SSH 代理转发的分步指南,请参阅[安全连接到在私有 Amazon VPC 中运行的 Linux 实例](https://aws.amazon.com/blogs/security/securely-connect-to-linux-instances-running-in-a-private-amazon-vpc/) . - -## Install GitLab and create custom AMI[](#install-gitlab-and-create-custom-ami "Permalink") - -我们将需要预先配置的自定义 GitLab AMI,以便稍后在我们的启动配置中使用. 首先,我们将使用官方的 GitLab AMI 创建 GitLab 实例. 然后,我们将为 PostgreSQL,Redis 和 Gitaly 添加自定义配置. 如果愿意,您也可以使用自己选择的 EC2 实例启动并[手动安装 GitLab](https://about.gitlab.com/install/) ,而不是使用官方的 GitLab AMI. - -### Install GitLab[](#install-gitlab "Permalink") - -从 EC2 仪表板: - -1. 单击**启动实例,**然后从左侧菜单中选择**社区 AMI** . -2. 在搜索栏中,搜索`GitLab EE ` ,其中``是[发行页面](https://about.gitlab.com/releases/)上显示的最新版本. 选择最新的补丁程序版本,例如`GitLab EE 12.9.2` . -3. 根据您的工作量选择一个实例类型. 请查阅[硬件要求,](../../install/requirements.html#hardware-requirements)以选择适合您需求的[硬件](../../install/requirements.html#hardware-requirements) (至少`c5.xlarge` ,足以容纳 100 位用户). -4. Click **配置实例详细信息**: - 1. 在" **网络"**下拉列表中,选择`gitlab-vpc` ,这是我们之前创建的 VPC. - 2. 在" **子网"**下拉列表中,从我们先前创建的**子网**列表中选择`gitlab-private-10.0.1.0` . - 3. 仔细检查是否将" **自动分配公用 IP"**设置为" `Use subnet setting (Disable)` . - 4. Click **添加存储**. - 5. 默认情况下,根卷为 8GiB,并且在我们不会在其中存储任何数据的情况下,根卷应该足够. -5. 单击**添加标签,**然后添加您可能需要的任何标签. 在本例中,我们将仅设置`Key: Name`和`Value: GitLab` . -6. 单击**配置安全组** . 选中**选择现有安全组,**然后选择我们之前创建的`gitlab-loadbalancer-sec-group` . -7. 如果对设置满意,请单击**查看并启动,**然后单击**启动** . -8. 最后,确认您有权访问所选的私钥文件或创建一个新的私钥文件. 单击**启动实例** . - -### Add custom configuration[](#add-custom-configuration "Permalink") - -使用[SSH 代理转发](#use-ssh-agent-forwarding)通过**Bastion Host A**连接到您的 GitLab 实例. 连接后,添加以下自定义配置: - -#### Disable Let’s Encrypt[](#disable-lets-encrypt "Permalink") - -由于我们要在负载均衡器中添加 SSL 证书,因此我们不需要 GitLab 对 Let's Encrypt 的内置支持. 自 GitLab 10.7 起,使用`https`域时[,默认情况下启用](https://docs.gitlab.com/omnibus/settings/ssl.html)加密[功能](https://docs.gitlab.com/omnibus/settings/ssl.html) ,因此我们需要显式禁用它: - -1. 打开`/etc/gitlab/gitlab.rb`并禁用它: - - ``` - letsencrypt['enable'] = false - ``` - -2. 保存文件并重新配置以使更改生效: - - ``` - sudo gitlab-ctl reconfigure - ``` - -#### Install the `pg_trgm` extension for PostgreSQL[](#install-the-pg_trgm-extension-for-postgresql "Permalink") - -在您的 GitLab 实例中,连接到 RDS 实例以验证访问权限并安装所需的`pg_trgm`扩展. - -要查找主机或终端节点,请导航至**Amazon RDS>数据库** ,然后单击您之前创建的数据库. 在" **连接性和安全性"**选项卡下查找端点. - -不要包括冒号和端口号: - -``` -sudo /opt/gitlab/embedded/bin/psql -U gitlab -h -d gitlabhq_production -``` - -在`psql`提示符下,创建扩展,然后退出会话: - -``` -psql (10.9) -Type "help" for help. - -gitlab=# CREATE EXTENSION pg_trgm; -gitlab=# \q -``` - -#### Configure GitLab to connect to PostgreSQL and Redis[](#configure-gitlab-to-connect-to-postgresql-and-redis "Permalink") - -1. 编辑`/etc/gitlab/gitlab.rb` ,找到`external_url 'http://'`选项并将其更改为您将使用的`https`域. - -2. 查找 GitLab 数据库设置,并根据需要取消注释. 在当前情况下,我们将指定数据库适配器,编码,主机,名称,用户名和密码: - - ``` - # Disable the built-in Postgres - postgresql['enable'] = false - - # Fill in the connection details - gitlab_rails['db_adapter'] = "postgresql" - gitlab_rails['db_encoding'] = "unicode" - gitlab_rails['db_database'] = "gitlabhq_production" - gitlab_rails['db_username'] = "gitlab" - gitlab_rails['db_password'] = "mypassword" - gitlab_rails['db_host'] = "" - ``` - -3. 接下来,我们需要通过添加主机并取消注释端口来配置 Redis 部分: - - ``` - # Disable the built-in Redis - redis['enable'] = false - - # Fill in the connection details - gitlab_rails['redis_host'] = "" - gitlab_rails['redis_port'] = 6379 - ``` - -4. 最后,重新配置 GitLab 以使更改生效: - - ``` - sudo gitlab-ctl reconfigure - ``` - -5. 您可能还会发现运行检查和服务状态以确保一切均已正确设置很有用: - - ``` - sudo gitlab-rake gitlab:check - sudo gitlab-ctl status - ``` - -#### Set up Gitaly[](#set-up-gitaly "Permalink") - -**注意:**在这种体系结构中,只有一台 Gitaly 服务器会造成单点故障. 使用[Gitaly Cluster](../../administration/gitaly/praefect.html)可以消除此限制. - -Gitaly 是一项服务,它提供对 Git 存储库的高级 RPC 访问. 应该在我们之前配置的[专用子网](#subnets)之一中的单独 EC2 实例上启用和配置它. - -让我们创建一个安装 Gitaly 的 EC2 实例: - -1. 在 EC2 仪表板中,单击**启动实例** . -2. 选择一个 AMI. 在此示例中,我们将选择**Ubuntu Server 18.04 LTS(HVM),SSD Volume Type** . -3. Choose an instance type. We’ll pick a **c5.xlarge**. -4. Click **配置实例详细信息**. - 1. 在" **网络"**下拉列表中,选择`gitlab-vpc` ,这是我们之前创建的 VPC. - 2. 在" **子网"**下拉列表中,从我们先前创建的**子网**列表中选择`gitlab-private-10.0.1.0` . - 3. 仔细检查是否将" **自动分配公用 IP"**设置为" `Use subnet setting (Disable)` . - 4. Click **添加存储**. -5. 将根卷大小增加到`20 GiB` ,并将**卷类型**更改为`Provisoned IOPS SSD (io1)` . (这是一个任意大小.创建一个足以满足您的存储库存储需求的卷.) - 1. 对于**IOPS**设置`1000` (20 GiB x 50 IOPS). 每个 GiB 最多可以配置 50 IOPS. 如果选择更大的音量,请相应地增加 IOPS. 以串行方式写入许多小文件的工作负载(如`git` )需要高性能的存储,因此选择`Provisoned IOPS SSD (io1)` . -6. 单击**添加标签**并添加您的标签. 在本例中,我们将仅设置`Key: Name`和`Value: Gitaly` . -7. 单击" **配置安全组",**然后**创建一个新的安全组** . - 1. 给您的安全组一个名称和描述. 我们将同时使用`gitlab-gitaly-sec-group` . - 2. 创建一个**自定义 TCP**规则,并将端口`8075`添加到" **端口范围"中** . 对于**Source** ,选择`gitlab-loadbalancer-sec-group` . - 3. 还要从`bastion-sec-group`添加 SSH 的入站规则,以便我们可以使用来自堡垒主机的[SSH 代理转发](#use-ssh-agent-forwarding)进行连接. -8. 如果对设置满意,请单击**查看并启动,**然后单击**启动** . -9. 最后,确认您有权访问所选的私钥文件或创建一个新的私钥文件. 单击**启动实例** . - -**注意:**除了将配置*和*存储库数据存储在根卷上之外,您还可以选择添加其他 EBS 卷用于存储库存储. 请遵循上述相同的指导. 请参阅[Amazon EBS 定价](https://aws.amazon.com/ebs/pricing/) . 我们不建议使用 EFS,因为它可能会对 GitLab 的性能产生负面影响. 您可以查看[相关文档](../../administration/high_availability/nfs.html#avoid-using-awss-elastic-file-system-efs)以了解更多详细信息. - -现在我们已经准备好我们的 EC2 实例,请按照[文档安装 GitLab 并在其自己的服务器上设置 Gitaly](../../administration/gitaly/index.html#run-gitaly-on-its-own-server) . 在[我们](#install-gitlab)上面[创建](#install-gitlab)的[GitLab 实例](#install-gitlab)上,从该文档执行客户端设置步骤. - -#### Add Support for Proxied SSL[](#add-support-for-proxied-ssl "Permalink") - -当我们在[负载均衡器](#load-balancer)处终止 SSL 时,请按照[支持代理的 SSL 中](https://docs.gitlab.com/omnibus/settings/nginx.html)的步骤在`/etc/gitlab/gitlab.rb`进行配置. - -将更改保存到`gitlab.rb`文件后,切记要运行`sudo gitlab-ctl reconfigure` . - -#### Fast lookup of authorized SSH keys[](#fast-lookup-of-authorized-ssh-keys "Permalink") - -允许访问 GitLab 的用户的公共 SSH 密钥存储在`/var/opt/gitlab/.ssh/authorized_keys` . 通常,我们会使用共享存储,以便当用户通过 SSH 执行 Git 操作时,所有实例都能够访问该文件. 由于我们的设置中没有共享存储,因此我们将更新配置,以通过 GitLab 数据库中的索引查找来授权 SSH 用户. - -按照[通过 GitLab Shell 设置快速查找中](../../administration/operations/fast_ssh_key_lookup.html#setting-up-fast-lookup-via-gitlab-shell)的说明,从使用`authorized_keys`文件切换到数据库. - -如果不配置快速查找,则通过 SSH 进行的 Git 操作将导致以下错误: - -``` -Permission denied (publickey). -fatal: Could not read from remote repository. - -Please make sure you have the correct access rights -and the repository exists. -``` - -#### Configure host keys[](#configure-host-keys "Permalink") - -通常,我们将手动将主应用程序服务器上`/etc/ssh/`的内容(主密钥和公共密钥)复制到所有辅助服务器上的`/etc/ssh` . 这样可以防止在访问负载均衡器后面的群集中的服务器时出现虚假的中间人攻击警报. - -我们将通过创建静态主机密钥作为自定义 AMI 的一部分来自动执行此操作. 由于每次 EC2 实例启动时也会旋转这些主机密钥,因此将它们"硬编码"到我们的自定义 AMI 中是一种方便的解决方法. - -在您的 GitLab 实例上运行以下命令: - -``` -sudo mkdir /etc/ssh_static -sudo cp -R /etc/ssh/* /etc/ssh_static -``` - -在`/etc/ssh/sshd_config`更新以下内容: - -``` -# HostKeys for protocol version 2 -HostKey /etc/ssh_static/ssh_host_rsa_key -HostKey /etc/ssh_static/ssh_host_dsa_key -HostKey /etc/ssh_static/ssh_host_ecdsa_key -HostKey /etc/ssh_static/ssh_host_ed25519_key -``` - -#### Amazon S3 object storage[](#amazon-s3-object-storage "Permalink") - -由于我们不使用 NFS 进行共享存储,因此我们将使用[Amazon S3](https://aws.amazon.com/s3/)存储桶来存储备份,工件,LFS 对象,上传,合并请求差异,容器注册表映像等等. 我们的文档包括[有关如何](../../administration/object_storage.html)为每种数据类型[配置对象存储的说明](../../administration/object_storage.html) ,以及有关在 GitLab 中使用对象存储的其他信息. - -**注意:**由于我们使用的是之前创建的[AWS IAM 配置文件](#create-an-iam-role) ,因此在配置对象存储时,请确保省略 AWS 访问密钥和秘密访问密钥/值对. 而是在您的配置中使用`'use_iam_profile' => true` ,如上面链接的对象存储文档中所示. - -将更改保存到`gitlab.rb`文件后,切记要运行`sudo gitlab-ctl reconfigure` . - -**注意:** GitLab 的当前一项功能仍需要共享目录(NFS),即[GitLab Pages](../../user/project/pages/index.html) . 目前[正在进行的工作](https://gitlab.com/gitlab-org/gitlab-pages/-/issues/196) ,以消除支持 GitLab 页面需要 NFS. - -* * * - -到此,我们的 GitLab 实例的配置更改结束了. 接下来,我们将基于该实例创建自定义 AMI,以用于我们的启动配置和自动缩放组. - -### Create custom AMI[](#create-custom-ami "Permalink") - -在 EC2 仪表板上: - -1. 选择我们[之前创建](#install-gitlab)的`GitLab`实例. -2. 单击" **操作"** ,向下滚动到" **图像"** ,然后单击" **创建图像"** . -3. 给您的图像起一个名称和描述(我们将同时使用`GitLab-Source` ). -4. 将其他所有内容保留为默认值,然后单击**创建图像** - -现在,我们有了一个定制的 AMI,将用于下一步创建启动配置. - -## Deploy GitLab inside an auto scaling group[](#deploy-gitlab-inside-an-auto-scaling-group "Permalink") - -### Create a launch configuration[](#create-a-launch-configuration "Permalink") - -从 EC2 仪表板: - -1. 从左侧菜单中选择**启动配置** ,然后单击**创建启动配置** . -2. 从左侧菜单中选择**我的 AMI** ,然后选择我们在上面创建的`GitLab`自定义 AMI. -3. 选择最适合您需求的实例类型(至少为`c5.xlarge` ),然后单击**配置详细信息** . -4. 输入启动配置的名称(我们将使用`gitlab-ha-launch-config` ). -5. **不要** check **请求竞价型实例**. -6. 从**IAM 角色**下拉列表中,选择我们[之前创建](#create-an-iam-ec2-instance-role-and-profile)的`GitLabAdmin`实例角色. -7. 将其余的保留为默认值,然后单击" **添加存储"** . -8. 默认情况下,根卷为 8GiB,并且在我们不会在其中存储任何数据的情况下,根卷应该足够. 单击**配置安全组** . -9. 选中**选择和现有安全组,**然后选择我们之前创建的`gitlab-loadbalancer-sec-group` . -10. 点击**查看** ,查看您的更改,然后点击**创建启动配置** . -11. 确认您有权访问私钥或创建一个新私钥. 单击**创建启动配置** . - -### Create an auto scaling group[](#create-an-auto-scaling-group "Permalink") - -1. 创建启动配置后,您将看到一个**使用此启动配置创建 Auto Scaling 组**的选项. 单击以开始创建自动缩放组. -2. 输入一个**组名** (我们将使用`gitlab-auto-scaling-group` ). -3. 对于**Group size** ,输入您要开始的实例数(我们将输入`2` ). -4. 从" **网络"**下拉列表中选择`gitlab-vpc` . -5. 添加[我们先前创建的](#subnets)两个专用[子网](#subnets) . -6. 展开" **高级详细信息"**部分,然后选中" **从一个或多个负载平衡器接收流量"**选项. -7. 从**经典负载均衡器**下拉列表中,选择我们之前创建的负载均衡器. -8. For **健康检查类型**, select **ELB**. -9. 我们将" **健康检查宽限期"**保留为默认的`300`秒. 单击" **配置扩展策略"** . -10. Check **使用扩展策略来调整该组的容量**. -11. 对于该组,我们将在 2 到 4 个实例之间扩展,如果 CPU 利用率大于 60%将添加一个实例,如果 CPU 利用率小于 45%则删除一个实例. - -[![Auto scaling group policies](img/36aa502eb297ed552d82e3b015053e9e.png)](img/policies.png) - -1. 最后,根据需要配置通知和标签,查看更改并创建自动缩放组. - -创建自动伸缩组后,您将在 EC2 仪表板中看到新实例. 您还将看到新实例添加到您的负载均衡器. 一旦实例通过健康检查,它们就准备开始从负载平衡器接收流量. - -由于我们的实例是由自动缩放组创建的,因此请返回您的实例并终止[我们在上面手动创建](#install-gitlab)的[实例](#install-gitlab) . 我们只需要该实例即可创建我们的自定义 AMI. - -### Log in for the first time[](#log-in-for-the-first-time "Permalink") - -现在,使用[为负载均衡器](#configure-dns-for-load-balancer)设置[DNS](#configure-dns-for-load-balancer)时使用的域名,您现在应该能够在浏览器中访问 GitLab. 首次要求您为在 GitLab 实例上具有管理员权限的`root`用户设置密码. - -设置后,使用用户名`root`和新创建的密码登录. - -## Health check and monitoring with Prometheus[](#health-check-and-monitoring-with-prometheus "Permalink") - -除了可以在各种服务上启用的 Amazon Cloudwatch 之外,GitLab 还提供了自己的基于 Prometheus 的集成监控解决方案. 有关如何设置的更多信息,请访问[GitLab Prometheus 文档.](../../administration/monitoring/prometheus/index.html) - -GitLab 还具有各种[运行状况检查端点](../../user/admin_area/monitoring/health_check.html) ,您可以对其进行 ping 操作并获取报告. - -## GitLab Runners[](#gitlab-runners "Permalink") - -如果要利用[GitLab CI / CD](../../ci/README.html) ,则必须至少设置一个[GitLab Runner](https://docs.gitlab.com/runner/) . - -阅读有关[在 AWS](https://docs.gitlab.com/runner/configuration/runner_autoscale_aws/)上配置[自动缩放 GitLab Runner 的](https://docs.gitlab.com/runner/configuration/runner_autoscale_aws/)更多信息. - -## Backup and restore[](#backup-and-restore "Permalink") - -GitLab 提供[了一个备份](../../raketasks/backup_restore.html#back-up-gitlab)和还原其 Git 数据,数据库,附件,LFS 对象等的工具. - -一些重要的事情要知道: - -* 备份/还原工具**不**存储某些配置文件,例如机密. 您需要[自己配置](../../raketasks/backup_restore.html#storing-configuration-files) . -* 默认情况下,备份文件存储在本地,但是您可以[使用 S3 备份 GitLab](../../raketasks/backup_restore.html#using-amazon-s3) . -* 您可以[从备份中排除特定目录](../../raketasks/backup_restore.html#excluding-specific-directories-from-the-backup) . - -### Backing up GitLab[](#backing-up-gitlab "Permalink") - -备份 GitLab: - -1. SSH 进入您的实例. -2. 备份: - - ``` - sudo gitlab-backup create - ``` - -**注意:**对于 GitLab 12.1 和更早版本,请使用`gitlab-rake gitlab:backup:create` . - -### Restoring GitLab from a backup[](#restoring-gitlab-from-a-backup "Permalink") - -To restore GitLab, first review the [restore documentation](../../raketasks/backup_restore.html#restore-gitlab), and primarily the restore prerequisites. Then, follow the steps under the [Omnibus installations section](../../raketasks/backup_restore.html#restore-for-omnibus-gitlab-installations). - -## Updating GitLab[](#updating-gitlab "Permalink") - -GitLab 于 22 日每月发布一个新版本. 每当发布新版本时,您都可以更新您的 GitLab 实例: - -1. SSH 进入您的实例 -2. 备份: - - ``` - sudo gitlab-backup create - ``` - -**注意:**对于 GitLab 12.1 和更早版本,请使用`gitlab-rake gitlab:backup:create` . - -1. 更新存储库并安装 GitLab: - - ``` - sudo apt update - sudo apt install gitlab-ee - ``` - -几分钟后,新版本应已启动并正在运行. - -## Conclusion[](#conclusion "Permalink") - -在本指南中,我们主要进行了缩放和一些冗余选项,您的里程可能会有所不同. - -请记住,所有解决方案都需要在成本/复杂性和正常运行时间之间进行权衡. 您想要的正常运行时间越长,解决方案就越复杂. 解决方案越复杂,设置和维护该解决方案所涉及的工作就越多. - -通读以下其他资源,并随时[提出问题](https://gitlab.com/gitlab-org/gitlab/-/issues/new)以请求其他材料: - -* [扩展 GitLab](../../administration/reference_architectures/index.html) :GitLab 支持几种不同类型的集群. -* [Geo 复制](../../administration/geo/replication/index.html) :Geo 是面向广泛分布的开发团队的解决方案. -* [Omnibus GitLab-](https://docs.gitlab.com/omnibus/)您需要了解的有关管理 GitLab 实例的所有信息. -* [上载许可证](../../user/admin_area/license.html) : [使用许可证](../../user/admin_area/license.html)激活所有的 GitLab Enterprise Edition 功能. -* [定价](https://about.gitlab.com/pricing/) :不同层级的定价. - -## Troubleshooting[](#troubleshooting "Permalink") - -### Instances are failing health checks[](#instances-are-failing-health-checks "Permalink") - -如果您的实例未通过负载均衡器的运行状况检查,请验证它们是否从我们之前配置的运行状况检查终结点返回状态`200` . 任何其他状态,包括重定向(例如状态`302` ),都会导致运行状况检查失败. - -您可能必须在`root`用户上设置密码,以防止在运行状况检查通过之前在登录端点上进行自动重定向. - -### “The change you requested was rejected (422)”[](#the-change-you-requested-was-rejected-422 "Permalink") - -如果你看到这个页面,试图设置通过网络界面输入密码时,请确保`external_url`在`gitlab.rb`你正在从一个请求域,并运行匹配`sudo gitlab-ctl reconfigure`进行任何更改之后. \ No newline at end of file diff --git a/docs/012.md b/docs/012.md deleted file mode 100644 index a2446ee93c4059a4196535aa608014b207485b1b..0000000000000000000000000000000000000000 --- a/docs/012.md +++ /dev/null @@ -1,40 +0,0 @@ -# Analytics - -> 原文:[https://docs.gitlab.com/ee/user/analytics/](https://docs.gitlab.com/ee/user/analytics/) - -* [Analytics workspace](#analytics-workspace) -* [Group-level analytics](#group-level-analytics) -* [Project-level analytics](#project-level-analytics) - -# Analytics[](#analytics "Permalink") - -## Analytics workspace[](#analytics-workspace "Permalink") - -在 GitLab 12.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/12077) . - -通过 Analytics(分析)工作区,可以跨 GitLab 汇总分析,以便用户可以在一个地方查看多个项目和组中的信息. - -要访问 Google Analytics(分析)工作区,请单击顶部导航栏中的**更多>分析** . - -## Group-level analytics[](#group-level-analytics "Permalink") - -在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/195979) . - -在组级别可以使用以下分析功能: - -* [Contribution](../group/contribution_analytics/index.html). -* [Insights](../group/insights/index.html). -* [Issues](../group/issues_analytics/index.html). -* [生产力](productivity_analytics.html) (通过`productivity_analytics` [功能标记](../../development/feature_flags/development.html#enabling-a-feature-flag-in-development)启用). -* [值流](value_stream_analytics.html) ,通过`cycle_analytics` [功能标记](../../development/feature_flags/development.html#enabling-a-feature-flag-in-development)启用. - -## Project-level analytics[](#project-level-analytics "Permalink") - -在项目级别可以使用以下分析功能: - -* [CI/CD](../../ci/pipelines/index.html#pipeline-success-and-duration-charts). -* [Code Review](code_review_analytics.html). -* [Insights](../group/insights/index.html). -* [Issues](../group/issues_analytics/index.html). -* [Repository](repository_analytics.html). -* [值流](value_stream_analytics.html) ,通过`cycle_analytics` [功能标记](../../development/feature_flags/development.html#enabling-a-feature-flag-in-development)启用. \ No newline at end of file diff --git a/docs/013.md b/docs/013.md deleted file mode 100644 index 8743ce152e598a049b28436eb559af5e5cd70437..0000000000000000000000000000000000000000 --- a/docs/013.md +++ /dev/null @@ -1,49 +0,0 @@ -# Code Review Analytics - -> 原文:[https://docs.gitlab.com/ee/user/analytics/code_review_analytics.html](https://docs.gitlab.com/ee/user/analytics/code_review_analytics.html) - -* [Overview](#overview) -* [Use cases](#use-cases) -* [Permissions](#permissions) - -# Code Review Analytics[](#code-review-analytics-starter "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/38062) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.7. - -通过 Code Review Analytics,可以轻松地查看打开的合并请求中运行时间最长的审查,从而使您可以对单个合并请求采取措施,并缩短总体周期. - -**注意:**最初,不会显示任何数据. 用户在打开的合并请求中发表评论时,将填充数据. - -## Overview[](#overview "Permalink") - -Code Review Analytics 显示一个打开的合并请求表,该请求至少具有一个非作者注释. 审阅时间从提交第一个非作者评论的时间开始计算. 合并请求的代码审阅时间自动标识为自第一个非作者评论以来的时间. - -要访问 Code Review Analytics,请从您项目的菜单中转到 **项目分析>代码审查** . - -[![Code Review Analytics](img/0124687ca256ab68d34dd0918f1e1a8d.png "List of code reviews; oldest review first.")](img/code_review_analytics_v12_8.png) - -* 该表格按评论时长排序,可帮助您快速找到运行时间最长的评论,这可能需要干预或分解成较小的部分. -* 您可以按里程碑和标签过滤 MR 列表. -* 用于显示作者,批准者,评论数和行更改(-/ +)数的列. - -## Use cases[](#use-cases "Permalink") - -此功能专为[开发团队负责](https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/#delaney-development-team-lead)人和其他想了解广泛的代码审查动态并确定模式以对其进行解释的人员而设计. - -您可以使用 Code Review Analytics 通过代码审查来揭露团队的独特挑战,并确定可能会大大加快开发周期的改进. - -在以下情况下可以使用代码审查分析: - -* 您的团队同意代码审查进度太慢. -* [价值流分析功能](value_stream_analytics.html)表明,审核是您团队最耗时的步骤. - -您可以使用 Code Review Analytics 查看当前运行最慢的工作类型,并分析它们之间的模式和趋势. 例如: - -* 很多评论或承诺? 也许代码太复杂了. -* 涉及特定作者吗? 也许需要更多的培训. -* 评论和批准者很少? 也许您的团队人手不足. - -## Permissions[](#permissions "Permalink") - -* 在[简化版或青铜级](https://about.gitlab.com/pricing/)上. -* 由具有 Reporter 访问权限及以上权限的用户组成. \ No newline at end of file diff --git a/docs/014.md b/docs/014.md deleted file mode 100644 index 1c80f2ec3f6019d2b886758914547fdc914c5fbd..0000000000000000000000000000000000000000 --- a/docs/014.md +++ /dev/null @@ -1,91 +0,0 @@ -# Productivity Analytics - -> 原文:[https://docs.gitlab.com/ee/user/analytics/productivity_analytics.html](https://docs.gitlab.com/ee/user/analytics/productivity_analytics.html) - -* [Supported features](#supported-features) -* [Accessing metrics and visualizations](#accessing-metrics-and-visualizations) -* [Date ranges](#date-ranges) -* [Permissions](#permissions) -* [Enabling and disabling using feature flags](#enabling-and-disabling-using-feature-flags) - -# Productivity Analytics[](#productivity-analytics-premium "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12079) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.3. - -使用 Productivity Analytics 追踪发展速度. - -For many companies, the development cycle is a black box and getting an estimate of how long, on average, it takes to deliver features is an enormous endeavor. - -虽然[价值流分析](../project/cycle_analytics.html)专注于整个软件开发生命周期(SDLC)流程,但生产力分析为工程管理提供了一种以系统的方式向下钻取的方法,以揭示在个人,项目或团队级别上的模式以及成败的原因. - -生产力降低的原因很多,从降低代码库到快速成长的团队. 为了进行调查,部门或团队负责人可以从可视化合并请求所花费的时间开始. - -## Supported features[](#supported-features "Permalink") - -生产力分析允许 GitLab 用户执行以下操作: - -* 可视化典型的合并请求(MR)生存期和统计信息. 使用直方图显示创建和合并合并请求之间经过的时间分布. -* 深入研究最耗时的合并请求,选择一些异常值,然后筛选所有后续图表以调查潜在原因. -* 按组,项目,作者,标签,里程碑或特定日期范围过滤. 例如,在里程碑或特定日期范围内,筛选出组或项目中特定作者的合并请求. -* 测量随时间变化的速度. 随时间推移可视化以上图表中每个指标的趋势,以观察进度. 如果发现异常值,请放大特定的日期范围. - -## Accessing metrics and visualizations[](#accessing-metrics-and-visualizations "Permalink") - -要访问该图表,请导航至组的侧边栏,然后选择**Analytics(分析)> Productivity Analytics(生产力分析)** . - -以下度量标准和可视化在项目或组级别可用-当前仅涵盖**合并的**合并请求: - -* 直方图,显示创建后经过指定天数进行合并的合并请求数. 选择一个特定的列以筛选后续的图表. -* 直方图显示了合并合并请求所花费的时间(以小时为单位)的细目. 可以使用以下间隔: - * 从第一次提交到第一次评论的时间. - * 从第一次评论到最后一次提交的时间. - * 从上次提交到合并的时间. -* 使用以下内容显示合并请求的大小或复杂度的直方图: - * 每个合并请求的提交数. - * 每次提交的代码行数. - * 触摸的文件数. -* 散点图显示所有 MR 在特定日期合并,以及完成操作所需的天数和 30 天的滚动中位数. -* 该表显示了合并请求的列表及其各自的持续时间指标. - * 用户可以按上述任何指标进行排序. - -## Date ranges[](#date-ranges "Permalink") - -在 GitLab 12.4 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/13188) . - -GitLab 能够根据日期范围过滤分析. 要过滤结果: - -1. 选择一个组. -2. (可选)选择一个项目. -3. 使用可用的日期选择器选择日期范围. - -## Permissions[](#permissions "Permalink") - -只能访问**Productivity Analytics**仪表板: - -* 在[高级或银级](https://about.gitlab.com/pricing/)以上. -* 由具有[Reporter 访问权限](../permissions.html)及以上[权限的](../permissions.html)用户组成. - -## Enabling and disabling using feature flags[](#enabling-and-disabling-using-feature-flags "Permalink") - -生产力分析是: - -* [默认情况下](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18754)从 GitLab 12.4 [启用](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18754) ,但可以使用以下功能标志禁用: - * `productivity_analytics` . - * `productivity_analytics_scatterplot_enabled` . -* 在 GitLab 12.3 中默认为禁用,但可以使用以下功能标志启用: - * `productivity_analytics` . - -GitLab 管理员可以: - -* 通过在 Rails 控制台中运行以下命令,从 GitLab 12.4 禁用此功能: - - ``` - Feature.disable(:productivity_analytics) - Feature.disable(:productivity_analytics_scatterplot_enabled) - ``` - -* 通过在 Rails 控制台中运行以下命令,在 GitLab 12.3 中启用此功能: - - ``` - Feature.enable(:productivity_analytics) - ``` \ No newline at end of file diff --git a/docs/015.md b/docs/015.md deleted file mode 100644 index 571c1984e5848d74a125a4302a5f3284f97814bd..0000000000000000000000000000000000000000 --- a/docs/015.md +++ /dev/null @@ -1,298 +0,0 @@ -# Value Stream Analytics - -> 原文:[https://docs.gitlab.com/ee/user/analytics/value_stream_analytics.html](https://docs.gitlab.com/ee/user/analytics/value_stream_analytics.html) - -* [Overview](#overview) -* [Date ranges](#date-ranges) -* [How Time metrics are measured](#how-time-metrics-are-measured) -* [How the stages are measured](#how-the-stages-are-measured) -* [Example workflow](#example-workflow) -* [Customizable Value Stream Analytics](#customizable-value-stream-analytics) - * [Stage path](#stage-path) - * [Adding a stage](#adding-a-stage) - * [Re-ordering stages](#re-ordering-stages) - * [Label based stages](#label-based-stages) - * [Hiding unused stages](#hiding-unused-stages) -* [Days to completion chart](#days-to-completion-chart) - * [Chart median line](#chart-median-line) - * [Disabling chart](#disabling-chart) - * [Disabling chart median line](#disabling-chart-median-line) -* [Type of work - Tasks by type chart](#type-of-work---tasks-by-type-chart) -* [Permissions](#permissions) -* [More resources](#more-resources) - -# Value Stream Analytics[](#value-stream-analytics "Permalink") - -版本历史 - -* 在项目级别在 GitLab 12.3 之前作为 Cycle Analytics 引入. -* 在小组级别的[GitLab Premium](https://about.gitlab.com/pricing/) 12.3 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/12077) . -* 在 GitLab 12.8 中从 Cycle Analytics [重命名](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23427)为 Value Stream Analytics. - -Value Stream Analytics measures the time spent to go from an [idea to production](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#from-idea-to-production-with-gitlab) (also known as cycle time) for each of your projects. Value Stream Analytics displays the median time spent in each stage defined in the process. - -有关如何为 Value Stream Analytics 的发展做出贡献的信息,请参阅我们的[贡献者文档](../../development/value_stream_analytics.html) . - -值流分析有助于快速确定给定项目的速度. 它指出了开发过程中的瓶颈,从而使管理层能够发现,分类和识别软件开发生命周期中速度下降的根本原因. - -Value Stream Analytics 与[GitLab 流程](../../topics/gitlab_flow.html)紧密结合,并为每个阶段计算单独的中位数. - -## Overview[](#overview "Permalink") - -价值流分析可用: - -* 在 GitLab 12.9 中,通过**组>分析>值流**在组级别. -* 在项目级别,通过" **项目">"分析">"价值流"** . - -作为"价值流分析"计算的一部分,将跟踪七个阶段. - -* **Issue** (Tracker) - * 安排问题的时间(按里程碑或通过将其添加到问题板) -* **Plan** (Board) - * 第一次提交的时间 -* **Code** (IDE) - * 是时候创建合并请求了 -* **Test** (CI) - * GitLab CI / CD 测试代码所需的时间 -* **审核** (合并请求/ MR) - * 花在代码审查上的时间 -* **暂存** (连续部署) - * 合并和部署到生产之间的时间 -* **Total** (Total) - * 总生命周期时间. 也就是说,项目或团队的速度. [以前称为](https://gitlab.com/gitlab-org/gitlab/-/issues/38317) **Production** . - -## Date ranges[](#date-ranges "Permalink") - -在 GitLab 12.4 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/13216) . - -GitLab 提供了根据日期范围过滤分析的功能. 要过滤结果: - -1. 选择一个组. -2. (可选)选择一个项目. -3. 使用可用的日期选择器选择日期范围. - -## How Time metrics are measured[](#how-time-metrics-are-measured "Permalink") - -页面顶部附近的"时间"指标的测量方法如下: - -* **提前期** :从创建问题到关闭问题的平均时间. -* **周期时间** :从第一次提交到发布完成的中值时间. - -注意:通过在提交消息中进行[交联](../project/issues/crosslinking_issues.html)或通过手动链接包含提交的合并请求,将提交与问题相关[联](../project/issues/crosslinking_issues.html) . - -[![Value stream analytics time metrics](img/f7050ce0aa3559c639befc2fe3d7aacb.png "Time metrics for value stream analytics")](img/vsa_time_metrics_v13_0.png) - -## How the stages are measured[](#how-the-stages-are-measured "Permalink") - -Value Stream Analytics 根据项目问题记录阶段时间和数据,但阶段和总阶段除外,在阶段和总阶段中,仅测量部署到生产中的数据. - -具体而言,如果未设置 CI 且尚未定义`production`或`production/*` [环境](../../ci/yaml/README.html#environment) ,则此阶段将没有任何数据. - -下表进一步描述了价值流分析的每个阶段. - -| **Stage** | **Description** | -| --- | --- | -| Issue | 通过标记问题或将其添加到里程碑中,以先发生的为准,来衡量从创建问题到采取行动解决问题之间的平均时间. 仅在标签已经为其创建了[发行委员会列表的](../project/issue_board.html)情况下,才会跟踪该标签. | -| Plan | 测量您在上一阶段采取的操作与将第一次提交推入分支之间的平均时间. 分支的第一个提交是触发**计划**和**代码**之间分离的提交,并且分支中的至少一个提交需要包含相关的发行编号(例如`#42` ). 如果分支中的所有提交都未提及相关的发行号,则不会考虑该阶段的度量时间. | -| Code | 测量推入第一个提交(上一阶段)与创建与该提交相关的合并请求(MR)之间的平均时间. 保持流程跟踪的关键是在合并请求的描述中包括[问题关闭模式](../project/issues/managing_issues.html#closing-issues-automatically) (例如, `Closes #xxx` ,其中`xxx`是与此合并请求相关的问题编号). 如果合并请求描述中不存在问题结束模式,则不会将 MR 视为平台的测量时间. | -| Test | 测量运行该项目的整个管道的中值时间. 这与 GitLab CI / CD 为推送到上一阶段中定义的合并请求的提交运行每个作业所花费的时间有关. 基本上,这是所有管道的开始->完成时间. | -| Review | 测量从创建到合并之间,审核具有结束问题模式的合并请求所需的平均时间. | -| Staging | 测量从合并合并请求到结束发布模式到首次部署到生产之间的平均时间. 在您的 GitLab CI / CD 配置中,通过设置为`production`或匹配`production/*` (区分大小写, `Production`将不起作用)的环境进行跟踪. 如果没有生产环境,则不会进行跟踪. | -| Total | 从问题创建到将代码部署到生产中,运行整个过程所需的所有时间(中位数)之和. [以前称为](https://gitlab.com/gitlab-org/gitlab/-/issues/38317) **Production** . | - -幕后工作原理: - -1. 问题和合并请求成对地分组在一起,这样对于每个``对,合并请求都具有对应问题的[问题关闭模式](../project/issues/managing_issues.html#closing-issues-automatically) . **不**考虑所有其他问题和合并请求. -2. 然后,在最近的 XX 天(由 UI 指定-默认为 90 天)中过滤出``对. 因此,它禁止考虑这些对. -3. 对于其余的``对,我们检查阶段所需的信息,例如发行日期,合并请求合并时间等. - -综上所述,不会跟踪任何未遵循[GitLab 流程的](../../workflow/gitlab_flow.html)内容,并且 Value Stream Analytics 仪表板将不会显示以下任何数据: - -* 合并不会解决问题的请求. -* 未在发行委员会中贴有标签的问题或未分配里程碑的问题. -* 如果项目没有`production`或`production/*`环境,则为阶段和生产阶段. - -## Example workflow[](#example-workflow "Permalink") - -以下是一个简单的虚拟周期工作流,它在一天中经历了所有七个阶段后,才发生. 请注意,如果一个阶段没有开始和结束标记,则不会对其进行测量,因此不会在中位时间中进行计算. 假定已创建里程碑并配置了用于测试和设置环境的 CI. - -1. 在 09:00( **发行**阶段开始)创建**发行** . -2. 在 11:00( **发行**阶段停止/ **计划**阶段开始)将发行添加到里程碑. -3. 开始解决此问题,在本地创建一个分支,并在 12:00 提交一次. -4. 对分支进行第二次提交,该分支在 12.30( **计划**阶段的停止/ **代码**阶段的开始)中提及发行号. -5. 推送分支并创建一个合并请求,该请求的描述在 14:00( **代码**阶段停止/ **测试**和**复审**阶段开始)中包含[问题关闭模式](../project/issues/managing_issues.html#closing-issues-automatically) . -6. CI 将开始运行您在[`.gitlab-ci.yml`](../../ci/yaml/README.html)定义的脚本,并需要 5 分钟( **测试**阶段停止). -7. 查看合并请求,确保一切正常,然后在 19:00 合并合并请求. ( **复习**阶段的停止/启动**分期**阶段). -8. 现在,合并请求合并,部署到`production`环境中开始和结束日 19:30( **分期**阶段停止). -9. 循环完成,并且先前阶段的中位数时间总和记录到" **总计"**阶段. 这是从创建问题到将其相关合并请求部署到生产之间的时间. - -从上面的示例中,您可以得出每个阶段完成所需的时间,只要达到其总时间即可: - -* **问题** :2 小时(11:00-09:00) -* **计划** :1 小时(12:00-11:00) -* **编码** :2h(14:00-12:00) -* **测试时间** :5 分钟 -* **评论** :5 小时(19:00-14:00) -* **演出时间** :30 分钟(19:30-19:00) -* **总计** :由于此阶段测量的是之前所有阶段的中位时间之和,因此如果我们不知道之前各阶段的状态,则无法计算. 如果这是项目中运行的第一个周期,则**总**时间为 10h 30min(19:30-09:00) - -一些注意事项: - -* 在上面的示例中,我们演示了您的第一次提交没有提到发行号也没关系,您可以稍后在正在处理的分支的任何提交中进行此操作. -* 您可以看到,由于未将" **测试"**阶段计算为整个周期的时间,因此" **检查"**阶段已包含在" **审查"**过程中(应测试每个 MR). -* 上面的示例只是七个阶段中的**一个循环** . 添加多个周期,计算它们的中值时间,结果就是 Value Stream Analytics 仪表板显示的内容. - -## Customizable Value Stream Analytics[](#customizable-value-stream-analytics "Permalink") - -在 GitLab 12.9 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/12196) . - -默认阶段旨在直接使用,但是可能并不适合所有团队. 不同的团队使用不同的方法来构建软件,因此一些团队可能想要自定义其 Value Stream Analytics. - -GitLab 允许用户隐藏默认阶段并创建自定义阶段,使其更适合其开发工作流程. - -**注意:**自定义性[仅适用于组级别的](https://gitlab.com/gitlab-org/gitlab/-/issues/35823#note_272558950)价值流分析. - -### Stage path[](#stage-path "Permalink") - -在 GitLab 13.0 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/210315) . - -从视觉上将阶段描绘为水平过程流. 选择一个阶段将更新值流下方的内容. - -默认情况下禁用. 如果您具有自我管理的实例,则管理员可以[打开 Rails 控制台](../../administration/troubleshooting/navigating_gitlab_via_rails_console.html)并使用以下命令启用它: - -``` -Feature.enable(:value_stream_analytics_path_navigation) -``` - -### Adding a stage[](#adding-a-stage "Permalink") - -在下面的示例中,我们将创建一个新阶段,该阶段可以衡量和跟踪从创建到关闭的所有问题. - -1. 导航到您组的" **分析">"价值流"** . -2. 单击**添加阶段**按钮. -3. 填写新的舞台表格: - * 名称:问题开始完成. - * 开始事件:已创建问题. - * 结束事件:问题已关闭. -4. 单击**添加阶段**按钮. - -[![New Value Stream Analytics Stage](img/d1c47110b6092ce9cec04ff22addfaa4.png "Form for creating a new stage")](img/new_vsm_stage_v12_9.png) - -新阶段将保持不变,并将始终显示在您组的"价值流分析"页面上. - -如果要更改或删除阶段,可以通过以下方法轻松地针对自定义阶段进行操作: - -1. Hovering over the stage. -2. 单击垂直省略号( )出现的按钮. - -[![Value Stream Analytics Stages](img/d277485e75207494ed3529dfcc7a6395.png)](img/vsm_stage_list_v12_9.png) - -创建自定义阶段需要指定两个事件: - -* 开始. -* 结束. - -请小心选择*在*结束事件*之前*发生的开始事件. 例如,考虑一个阶段: - -* 在将问题添加到板上时开始. -* 创建问题时结束. - -此阶段将不起作用,因为开始事件发生时,结束事件已经发生. 为防止此类无效阶段,UI 禁止出现不兼容的开始和结束事件. 选择开始事件后,停止事件下拉列表将仅列出兼容事件. - -### Re-ordering stages[](#re-ordering-stages "Permalink") - -在 GitLab 12.10 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/196698) . - -添加自定义阶段后,您可以"拖放"阶段以重新排列其顺序. 这些更改将自动保存到系统中. - -### Label based stages[](#label-based-stages "Permalink") - -预定义的开始和结束事件可以涵盖涉及问题和合并请求的许多用例. - -为了支持更复杂的工作流程,请使用基于组标签的阶段. 这些事件基于添加或删除的标签. 特别是, [范围标签](../project/labels.html#scoped-labels-premium)对于复杂的工作流程很有用. - -在此示例中,我们希望测量更准确的代码检查时间. 工作流程如下: - -* 代码审阅开始时,审阅者将`workflow::code_review_start`标签添加到合并请求中. -* 代码检查完成后,检查者将`workflow::code_review_complete`标签添加到合并请求中. - -创建一个称为"代码审查"的新阶段: - -[![New Label Based Value Stream Analytics Stage](img/ea01744c06eb8853392bfd840dc1517d.png "Creating a label based Value Stream Analytics Stage")](img/label_based_stage_vsm_v12_9.png) - -### Hiding unused stages[](#hiding-unused-stages "Permalink") - -有时某些默认阶段与团队无关. 在这种情况下,您可以轻松隐藏阶段,使它们不再出现在列表中. 隐藏阶段: - -1. 添加定制阶段以激活可定制性. -2. 将鼠标悬停在要隐藏的默认阶段上. -3. 单击垂直省略号( )按钮出现,然后选择" **隐藏舞台"** . - -要恢复以前隐藏的默认阶段: - -1. Click **添加一个阶段** button. -2. 在右上角打开" **恢复隐藏的阶段"**下拉列表. -3. 选择一个阶段. - -## Days to completion chart[](#days-to-completion-chart "Permalink") - -在 GitLab 12.6 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21631) . - -该图表直观地描述了完成周期所需的总天数. - -该图表使用全局页面过滤器来基于选定的组,项目和时间范围显示数据. 此外,可以从图表本身内选择特定阶段. - -### Chart median line[](#chart-median-line "Permalink") - -在 GitLab 12.7 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/36675) . - -图表上的中间线显示的数据偏移了所选的天数. 例如,如果选择了 30 天的数据(例如 2019-12-16 至 2020-01-15),则中线将代表前 30 天的数据(2019-11-16 至 2019-12 -16)作为要比较的指标. - -### Disabling chart[](#disabling-chart "Permalink") - -This chart is enabled by default. If you have a self-managed instance, an administrator can open a Rails console and disable it with the following command: - -``` -Feature.disable(:cycle_analytics_scatterplot_enabled) -``` - -### Disabling chart median line[](#disabling-chart-median-line "Permalink") - -默认情况下,此图表的中线是启用的. 如果您具有自我管理的实例,则管理员可以打开 Rails 控制台并使用以下命令将其禁用: - -``` -Feature.disable(:cycle_analytics_scatterplot_median_enabled) -``` - -## Type of work - Tasks by type chart[](#type-of-work---tasks-by-type-chart "Permalink") - -在 GitLab 12.10 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/32421) . - -此图表显示每天的问题和合并请求的累积计数. - -该图表使用全局页面过滤器来基于选定的组,项目和时间范围显示数据. 该图表默认为显示问题计数,但可以切换为显示合并请求数据,并进一步细化为特定的组级标签. - -默认情况下,预先选择了最高的组级别标签(最多 10 个),最多可以选择 15 个标签. - -## Permissions[](#permissions "Permalink") - -Project Value Stream Analytics 仪表板上的当前权限为: - -* 公共项目-任何人都可以访问. -* 内部项目-任何经过身份验证的用户都可以访问. -* 私人项目-访客及以上的任何成员都可以访问. - -您通常可以[阅读有关权限的更多信息](../../ci/yaml/README.html) . - -对于 GitLab 12.3 和更高版本中引入的 Value Stream Analytics 功能: - -* 用户必须具有 Reporter 或更高权限. -* 仅在[Premium 或 Silver 等级](https://about.gitlab.com/pricing/)及更高[级别](https://about.gitlab.com/pricing/)上可用. - -## More resources[](#more-resources "Permalink") - -Learn more about Value Stream Analytics in the following resources: - -* [Value Stream Analytics feature page](https://about.gitlab.com/stages-devops-lifecycle/value-stream-analytics/). -* [Value Stream Analytics feature preview](https://about.gitlab.com/blog/2016/09/16/feature-preview-introducing-cycle-analytics/). -* [Value Stream Analytics feature highlight](https://about.gitlab.com/blog/2016/09/21/cycle-analytics-feature-highlight/). \ No newline at end of file diff --git a/docs/016.md b/docs/016.md deleted file mode 100644 index 4ce588b0d0e27519d83261314aa935773d7e0fea..0000000000000000000000000000000000000000 --- a/docs/016.md +++ /dev/null @@ -1,309 +0,0 @@ -# Kubernetes clusters - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/](https://docs.gitlab.com/ee/user/project/clusters/) - -* [Overview](#overview) -* [Setting up](#setting-up) - * [Supported cluster versions](#supported-cluster-versions) - * [Adding and removing clusters](#adding-and-removing-clusters) - * [Multiple Kubernetes clusters](#multiple-kubernetes-clusters) - * [Setting the environment scope](#setting-the-environment-scope-premium) -* [Configuring your Kubernetes cluster](#configuring-your-kubernetes-cluster) - * [Security implications](#security-implications) - * [GitLab-managed clusters](#gitlab-managed-clusters) - * [Important notes](#important-notes) - * [Clearing the cluster cache](#clearing-the-cluster-cache) - * [Base domain](#base-domain) -* [Installing applications](#installing-applications) -* [Auto DevOps](#auto-devops) -* [Deploying to a Kubernetes cluster](#deploying-to-a-kubernetes-cluster) - * [Deployment variables](#deployment-variables) - * [Custom namespace](#custom-namespace) - * [Integrations](#integrations) - * [Canary Deployments](#canary-deployments-premium) - * [Deploy Boards](#deploy-boards-premium) - * [Viewing pod logs](#viewing-pod-logs) - * [Web terminals](#web-terminals) - * [Troubleshooting](#troubleshooting) -* [Monitoring your Kubernetes cluster](#monitoring-your-kubernetes-cluster) - * [Visualizing cluster health](#visualizing-cluster-health) - -# Kubernetes clusters[](#kubernetes-clusters "Permalink") - -版本历史 - -* 在项目的 GitLab 10.1 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/35954) . -* 在 GitLab 11.6 中针对[组](../../group/clusters/index.html) [引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/34758) . -* 在 GitLab 11.11 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/39840)了[实例](../../instance/clusters/index.html) . - -## Overview[](#overview "Permalink") - -使用 GitLab 项目 Kubernetes 集成,您可以: - -* Use [Review Apps](../../../ci/review_apps/index.html). -* Run [pipelines](../../../ci/pipelines/index.html). -* [部署](#deploying-to-a-kubernetes-cluster)您的应用程序. -* 检测和[监控 Kubernetes](#monitoring-your-kubernetes-cluster) . -* 与[Auto DevOps](#auto-devops)一起使用. -* Use [Web terminals](#web-terminals). -* Use [Deploy Boards](#deploy-boards-premium). -* Use [Canary Deployments](#canary-deployments-premium). -* View [Logs](#viewing-pod-logs). -* [使用 Knative](serverless/index.html)在[Kubernetes 上](serverless/index.html)运行无服务器工作负载. - -除了在项目级别进行集成之外,Kubernetes 集群还可以在[组级别](../../group/clusters/index.html)或[GitLab 实例级别](../../instance/clusters/index.html)进行集成. - -## Setting up[](#setting-up "Permalink") - -### Supported cluster versions[](#supported-cluster-versions "Permalink") - -GitLab 承诺在任何给定时间至少支持两个生产就绪的 Kubernetes 次要版本. 我们会定期审查我们支持的版本,并提供四个月的弃用期,然后再删除特定版本的支持. 支持的版本范围基于以下方面的评估: - -* 我们自己的需求. -* 主要托管 Kubernetes 提供商支持的版本. -* [Kubernetes 社区支持](https://kubernetes.io/docs/setup/release/version-skew-policy/#supported-versions)的版本. - -当前,GitLab 支持以下 Kubernetes 版本: - -* 1.16 -* 1.15 -* 1.14 -* 1.13(不建议使用,支持终止于 2020 年 11 月 22 日) -* 1.12(不建议使用,支持终止于 2020 年 9 月 22 日) - -**注意:**某些 GitLab 功能可能支持此处提供的范围之外的版本. - -### Adding and removing clusters[](#adding-and-removing-clusters "Permalink") - -有关如何执行以下操作的详细信息,请参见[添加和删​​除 Kubernetes 集群](add_remove_clusters.html) : - -* 使用 GitLab 的 UI 在 Google Cloud Platform(GCP)或 Amazon Elastic Kubernetes Service(EKS)中创建集群. -* 从任何 Kubernetes 平台向现有集群添加集成. - -### Multiple Kubernetes clusters[](#multiple-kubernetes-clusters "Permalink") - -版本历史 - -* 在[GitLab Premium](https://about.gitlab.com/pricing/) 10.3 中引入 -* 在 13.2 中[移至](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35094) GitLab 核心. - -您可以将多个 Kubernetes 集群关联到您的项目. 这样,您可以为不同的环境(例如开发,登台,生产等)使用不同的集群. - -就像您第一次一样,只需添加另一个集群,并确保[设置一个环境范围即可](#setting-the-environment-scope-premium)将新集群与其他集群区分开. - -#### Setting the environment scope[](#setting-the-environment-scope-premium "Permalink") - -将多个 Kubernetes 集群添加到您的项目时,您需要通过环境范围来区分它们. 环境范围将群集与[环境](../../../ci/environments/index.html)相关联,类似于[特定](../../../ci/variables/README.html#limit-the-environment-scopes-of-environment-variables)于[环境的变量的](../../../ci/variables/README.html#limit-the-environment-scopes-of-environment-variables)工作方式. - -默认环境范围是`*` ,这意味着所有作业,无论其环境如何,都将使用该群集. 每个作用域只能由项目中的单个群集使用,否则将发生验证错误. 另外,没有设置环境关键字的作业将无法访问任何群集. - -例如,假设项目中存在以下 Kubernetes 集群: - -| Cluster | 环境范围 | -| --- | --- | -| Development | `*` | -| Production | `production` | - -[`.gitlab-ci.yml`](../../../ci/yaml/README.html)中设置了以下环境: - -``` -stages: - - test - - deploy - -test: - stage: test - script: sh test - -deploy to staging: - stage: deploy - script: make deploy - environment: - name: staging - url: https://staging.example.com/ - -deploy to production: - stage: deploy - script: make deploy - environment: - name: production - url: https://example.com/ -``` - -结果将是: - -* The Development cluster details will be available in the `deploy to staging` job. -* 生产集群详细信息将在`deploy to production`作业中提供. -* `test`作业中没有可用的群集详细信息,因为它没有定义任何环境. - -## Configuring your Kubernetes cluster[](#configuring-your-kubernetes-cluster "Permalink") - -[将 Kubernetes 群集添加](add_remove_clusters.html)到 GitLab 之后,请阅读本节,其中涵盖了使用 GitLab 配置 Kubernetes 群集的重要注意事项. - -### Security implications[](#security-implications "Permalink") - -**Important:** The whole cluster security is based on a model where [developers](../../permissions.html) are trusted, so **仅允许受信任的用户控制您的集群**. - -默认的群集配置授予对成功构建和部署容器化应用程序所需的广泛功能的访问权限. 请记住,群集上运行的所有应用程序都使用相同的凭据. - -### GitLab-managed clusters[](#gitlab-managed-clusters "Permalink") - -版本历史 - -* 在 GitLab 11.5 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22011) . -* 在 GitLab 11.11 中成为[可选](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/26565) . - -您可以选择允许 GitLab 为您管理集群. 如果您的集群由 GitLab 管理,则将自动创建项目资源. 有关创建哪些资源的详细信息,请参见" [访问控制"](add_remove_clusters.html#access-controls)部分. - -如果选择管理自己的群集,则不会自动创建特定于项目的资源. 如果使用的是[Auto DevOps](../../../topics/autodevops/index.html) ,则需要显式提供部署作业将使用的`KUBE_NAMESPACE` [部署变量](#deployment-variables) ,否则将为您创建一个名称空间. - -#### Important notes[](#important-notes "Permalink") - -在 GitLab 和集群上注意以下几点: - -* 如果您在群集上[安装应用程序](#installing-applications) ,即使您选择管理自己的群集,GitLab 也会创建运行这些资源所需的资源. -* 请注意,手动管理由 GitLab 创建的资源(例如名称空间和服务帐户)可能会导致意外错误. 如果发生这种情况,请尝试[清除集群缓存](#clearing-the-cluster-cache) . - -#### Clearing the cluster cache[](#clearing-the-cluster-cache "Permalink") - -在 GitLab 12.6 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/31759) . - -如果您选择允许 GitLab 为您管理集群,则 GitLab 将存储它为项目创建的名称空间和服务帐户的缓存版本. 如果在群集中手动修改这些资源,则此缓存可能与群集不同步,这可能导致部署作业失败. - -清除缓存: - -1. 导航到项目的" **操作">" Kubernetes"**页面,然后选择您的集群. -2. 展开**高级设置**部分. -3. Click **Clear cluster cache**. - -### Base domain[](#base-domain "Permalink") - -在 GitLab 11.8 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24580) . - -**注意:**使用 GitLab Serverless 时,无需在群集设置上指定基本域. 在这种情况下,域将被指定为 Knative 安装的一部分. 请参阅[安装应用程序](#installing-applications) . - -指定基本域将自动将`KUBE_INGRESS_BASE_DOMAIN`设置为环境变量. 如果您使用的是[Auto DevOps](../../../topics/autodevops/index.html) ,则此域将用于不同的阶段. 例如,"自动查看应用程序"和"自动部署". - -该域应将通配符 DNS 配置为入口 IP 地址. 安装 Ingress 之后(请参阅[安装应用程序](#installing-applications) ),您可以: - -* 创建一个指向您的域提供商指向入口 IP 地址的`A`记录. -* 使用 nip.io 或 xip.io 之类的服务输入通配符 DNS 地址. 例如, `192.168.1.1.xip.io` . - -## Installing applications[](#installing-applications "Permalink") - -GitLab 可以在项目级集群中安装和管理一些应用程序,例如 Helm,GitLab Runner,Ingress,Prometheus 等. 有关为项目集群安装,升级,卸载和故障排除应用程序的更多信息,请参阅[GitLab 托管应用程序](../../clusters/applications.html) . - -## Auto DevOps[](#auto-devops "Permalink") - -Auto DevOps 自动检测,构建,测试,部署和监视您的应用程序. - -要充分利用 Auto DevOps(自动部署,自动查看应用程序和自动监控),您需要启用 Kubernetes 项目集成. - -[Read more about Auto DevOps](../../../topics/autodevops/index.html) - -**注意** Kubernetes 群集可以在没有 Auto DevOps 的情况下使用. - -## Deploying to a Kubernetes cluster[](#deploying-to-a-kubernetes-cluster "Permalink") - -Kubernetes 集群可以作为部署作业的目标. 如果 - -* 该集群与 GitLab 集成在一起,特殊的[部署变量](#deployment-variables)可用于您的工作,并且不需要配置. 您可以使用诸如`kubectl`或`helm`工具立即开始从作业中与集群进行交互. -* 您无需使用 GitLab 的集群集成,仍然可以将其部署到集群中. 但是,您需要自己使用[环境变量](../../../ci/variables/README.html#custom-environment-variables)配置 Kubernetes 工具,然后才能通过作业与集群进行交互. - -### Deployment variables[](#deployment-variables "Permalink") - -Kubernetes 集群集成在 GitLab CI / CD 构建环境中公开了以下[部署变量](../../../ci/variables/README.html#deployment-environment-variables) . - -| Variable | Description | -| --- | --- | -| `KUBE_URL` | 等于 API URL. | -| `KUBE_TOKEN` | [环境服务帐户](add_remove_clusters.html#access-controls)的 Kubernetes 令牌. | -| `KUBE_NAMESPACE` | 与项目的部署服务帐户关联的名称空间. 格式为`--` . 对于由 GitLab 管理的集群,GitLab 会在集群中自动创建一个匹配的名称空间. | -| `KUBE_CA_PEM_FILE` | 包含 PEM 数据的文件的路径. 仅当指定了自定义 CA 捆绑包时才存在. | -| `KUBE_CA_PEM` | ( **已弃用** )原始 PEM 数据. 仅当指定了自定义 CA 捆绑包时. | -| `KUBECONFIG` | 包含用于此部署的`kubeconfig`的文件的路径. 如果指定,则将嵌入 CA 捆绑软件. 此配置还嵌入了在`KUBE_TOKEN`定义的相同令牌,因此您可能只需要此变量. 该变量名也会由`kubectl`自动选择,因此,如果使用`kubectl`则实际上不需要显式引用它. | -| `KUBE_INGRESS_BASE_DOMAIN` | 从 GitLab 11.8 开始,此变量可用于为每个群集设置一个域. 有关更多信息,请参见[群集域](#base-domain) . | - -**注意:**在 GitLab 11.5 之前, `KUBE_TOKEN`是集群集成的主要服务帐户的 Kubernetes 令牌.**注意:**如果您的集群是在 GitLab 12.2 之前创建的,则默认`KUBE_NAMESPACE`将设置为`-` . - -### Custom namespace[](#custom-namespace "Permalink") - -在 GitLab 12.6 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/27630) . - -Kubernetes 集成默认为格式为`--`的特定于项目环境的名称空间(请参阅[部署变量](#deployment-variables) ). - -对于**非** GitLab 管理的集群,可以使用`.gitlab-ci.yml` [`environment:kubernetes:namespace`](../../../ci/environments/index.html#configuring-kubernetes-deployments)来定制[`environment:kubernetes:namespace`](../../../ci/environments/index.html#configuring-kubernetes-deployments) . - -**注意:**使用[GitLab 管理的集群时](#gitlab-managed-clusters) ,名称空间是在部署之前自动创建的, [无法自定义](https://gitlab.com/gitlab-org/gitlab/-/issues/38054) . - -### Integrations[](#integrations "Permalink") - -#### Canary Deployments[](#canary-deployments-premium "Permalink") - -利用[Kubernetes 的 Canary 部署,](https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments)并在部署板内部可视化您的 Canary 部署,而无需离开 GitLab. - -[Read more about Canary Deployments](../canary_deployments.html) - -#### Deploy Boards[](#deploy-boards-premium "Permalink") - -GitLab 的部署板提供了 Kubernetes 上运行的每个 CI [环境](../../../ci/environments/index.html)的当前运行状况和状态的合并视图,显示了部署中 Pod 的状态. 开发人员和其他团队成员可以在已经使用的工作流程中逐个窗格地查看发布的进度和状态,而无需访问 Kubernetes. - -[Read more about Deploy Boards](../deploy_boards.html) - -#### Viewing pod logs[](#viewing-pod-logs "Permalink") - -使用 GitLab 可以轻松查看连接的 Kubernetes 集群中正在运行的 Pod 的日志. 通过直接在 GitLab 中显示日志,开发人员可以避免管理控制台工具或跳转到其他界面. - -[Read more about Kubernetes logs](kubernetes_pod_logs.html) - -#### Web terminals[](#web-terminals "Permalink") - -在 GitLab 8.15 中引入. - -启用后,Kubernetes 集成将为您的[环境](../../../ci/environments/index.html)添加[Web 终端](../../../ci/environments/index.html#web-terminals)支持. 这基于 Docker 和 Kubernetes 中的`exec`功能,因此您可以在现有容器中获得一个新的 Shell 会话. 要使用此集成,您应该使用上面的部署变量将其部署到 Kubernetes,并确保对所有部署,副本集和 Pod 进行注释: - -* `app.gitlab.com/env: $CI_ENVIRONMENT_SLUG` -* `app.gitlab.com/app: $CI_PROJECT_PATH_SLUG` - -`$CI_ENVIRONMENT_SLUG`和`$CI_PROJECT_PATH_SLUG`是 CI 变量的值. - -您必须是项目所有者或拥有`maintainer`权限才能使用终端. 支持仅限于环境中第一个容器中的第一个容器. - -### Troubleshooting[](#troubleshooting "Permalink") - -在开始部署作业之前,GitLab 将为部署作业专门创建以下内容: - -* 命名空间. -* A service account. - -但是,有时 GitLab 无法创建它们. 在这种情况下,您的工作将失败,并显示以下消息: - -``` -This job failed because the necessary resources were not successfully created. -``` - -要在创建名称空间和服务帐户时查找导致此错误的原因,请检查[日志](../../../administration/logs.html#kuberneteslog) . - -失败的原因包括: - -* 您为 GitLab 提供的令牌没有 GitLab 所需的[`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)特权. -* 缺少`KUBECONFIG`或`KUBE_TOKEN`变量. 要传递给您的工作,他们必须具有匹配的[`environment:name`](../../../ci/environments/index.html#defining-environments) . 如果您的作业没有设置`environment:name` ,则不会通过 Kubernetes 凭据. - -**注意:**从 GitLab 12.0 或更早版本升级的项目级群集可能以导致此错误的方式进行配置. 如果要自己管理名称空间和服务帐户,请确保取消选择由[GitLab 管理的群集](#gitlab-managed-clusters)选项. - -## Monitoring your Kubernetes cluster[](#monitoring-your-kubernetes-cluster "Permalink") - -自动检测和监控 Kubernetes 指标. 还支持[NGINX Ingress 的](../integrations/prometheus_library/nginx.html)自动监视. - -[Read more about Kubernetes monitoring](../integrations/prometheus_library/kubernetes.html) - -### Visualizing cluster health[](#visualizing-cluster-health "Permalink") - -版本历史 - -* 在[GitLab Ultimate](https://about.gitlab.com/pricing/) 10.6 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4701) . -* 在 13.2 中[移至](https://gitlab.com/gitlab-org/gitlab/-/issues/208224) GitLab 核心. - -[部署 Prometheus 后](#installing-applications) ,GitLab 将自动监视群集的运行状况. 在群集设置页面的顶部,显示 CPU 和内存利用率以及可用总量. 如果群集的内存不足,则监视群集资源可能很重要,可能会关闭或无法启动. - -[![Cluster Monitoring](img/0e27f7f7b1dd7b6748365d5ea985238a.png)](img/k8s_cluster_monitoring.png) \ No newline at end of file diff --git a/docs/017.md b/docs/017.md deleted file mode 100644 index 44149203201a8e84ffd6b29e0d80e99ab486a7da..0000000000000000000000000000000000000000 --- a/docs/017.md +++ /dev/null @@ -1,256 +0,0 @@ -# Adding and removing Kubernetes clusters - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/add_remove_clusters.html](https://docs.gitlab.com/ee/user/project/clusters/add_remove_clusters.html) - -* [Before you begin](#before-you-begin) -* [Access controls](#access-controls) - * [Important notes](#important-notes) - * [RBAC cluster resources](#rbac-cluster-resources) - * [ABAC cluster resources](#abac-cluster-resources) - * [Security of GitLab Runners](#security-of-gitlab-runners) -* [Create new cluster](#create-new-cluster) -* [Add existing cluster](#add-existing-cluster) - * [Existing Kubernetes cluster](#existing-kubernetes-cluster) - * [Disable Role-Based Access Control (RBAC) (optional)](#disable-role-based-access-control-rbac-optional) -* [Enabling or disabling integration](#enabling-or-disabling-integration) -* [Removing integration](#removing-integration) -* [Learn more](#learn-more) - -# Adding and removing Kubernetes clusters[](#adding-and-removing-kubernetes-clusters "Permalink") - -GitLab 为以下 Kubernetes 提供者提供了集成的集群创建功能: - -* Google Kubernetes 引擎(GKE). -* Amazon Elastic Kubernetes 服务(EKS). - -GitLab 还可以与本地或托管的任何标准 Kubernetes 提供程序集成. - -**注意:**观看[使用 GitLab 和 Google Cloud Platform 进行](https://about.gitlab.com/webcast/scalable-app-deploy/)的网络广播[可扩展应用程序部署,](https://about.gitlab.com/webcast/scalable-app-deploy/)并了解如何通过单击几下加速由 Google Cloud Platform(GCP)管理的 Kubernetes 集群.**提示:**每个新的 Google Cloud Platform(GCP)帐户[在注册后](https://console.cloud.google.com/freetrial)都会获得[$ 300 的信用额](https://console.cloud.google.com/freetrial) ,并且与 Google 合作,GitLab 能够为新的 GCP 帐户提供额外的$ 200,以开始使用 GitLab 的 Google Kubernetes Engine Integration. 您所要做的就是[点击此链接](https://cloud.google.com/partners/partnercredit/?pcn_code=0014M00001h35gDQAQ#contact-form)并申请信贷. - -## Before you begin[](#before-you-begin "Permalink") - -在使用 GitLab [添加 Kubernetes 集群](#create-new-cluster)之前,您需要: - -* GitLab 本身. 要么: - * 一个[GitLab.com 帐户](https://about.gitlab.com/pricing/#gitlab-com) . - * 使用 GitLab 12.5 或更高版本的[自我管理安装](https://about.gitlab.com/pricing/#self-managed) . 这将确保 GitLab UI 可用于创建集群. -* 以下 GitLab 访问: - * [维护者](../../permissions.html#project-members-permissions)对项目级集群的项目[访问](../../permissions.html#project-members-permissions) . - * [维护者](../../permissions.html#group-members-permissions)对组级别集群的[访问权限](../../permissions.html#group-members-permissions) . - * 自我管理的实例级别群集的管理[区域访问](../../admin_area/index.html) . - -## Access controls[](#access-controls "Permalink") - -在 GitLab 中创建集群时,系统会询问您是否要创建以下任一集群: - -* A [Role-based access control (RBAC)](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) cluster. -* An [Attribute-based access control (ABAC)](https://kubernetes.io/docs/reference/access-authn-authz/abac/) cluster. - -**注意:**建议使用[RBAC](#rbac-cluster-resources) ,GitLab 为默认值. - -GitLab 创建必要的服务帐户和特权,以安装和运行[GitLab 托管的应用程序](index.html#installing-applications) . 当 GitLab 创建集群时,将在`default`名称空间中创建具有`cluster-admin`特权的`gitlab`服务帐户,以管理新创建的集群. - -**注意:**用于部署的受限服务帐户是在 GitLab 11.5 中[引入的](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/51716) . - -The first time you install an application into your cluster, the `tiller` service account is created with `cluster-admin` privileges in the `gitlab-managed-apps` namespace. This service account will be used by Helm to install and run [GitLab managed applications](index.html#installing-applications). - -Helm 还将为每个已安装的应用程序创建其他服务帐户和其他资源. 有关每个应用程序,请查阅 Helm 图表的文档. - -如果要[添加现有的 Kubernetes 集群](add_remove_clusters.html#add-existing-cluster) ,请确保该帐户的令牌具有该集群的管理员特权. - -GitLab 创建的资源取决于集群的类型. - -### Important notes[](#important-notes "Permalink") - -请注意以下有关访问控制的内容: - -* 仅当集群[由 GitLab 管理时,](index.html#gitlab-managed-clusters)才会创建特定于环境的资源. -* 如果您的集群是在 GitLab 12.2 之前创建的,它将为所有项目环境使用单个名称空间. - -### RBAC cluster resources[](#rbac-cluster-resources "Permalink") - -GitLab 为 RBAC 集群创建以下资源. - -| Name | Type | Details | 创建时间 | -| --- | --- | --- | --- | -| `gitlab` | `ServiceAccount` | `default` namespace | 创建一个新集群 | -| `gitlab-admin` | `ClusterRoleBinding` | [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | 创建一个新集群 | -| `gitlab-token` | `Secret` | `gitlab` ServiceAccount 的令牌 | 创建一个新集群 | -| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | 安装舵图 | -| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | 安装舵图 | -| 环境名称空间 | `Namespace` | 包含所有特定于环境的资源 | 部署到集群 | -| 环境名称空间 | `ServiceAccount` | 使用环境的名称空间 | 部署到集群 | -| 环境名称空间 | `Secret` | 环境 ServiceAccount 的令牌 | 部署到集群 | -| 环境名称空间 | `RoleBinding` | [`edit`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) roleRef | 部署到集群 | - -### ABAC cluster resources[](#abac-cluster-resources "Permalink") - -GitLab 为 ABAC 群集创建以下资源. - -| Name | Type | Details | 创建时间 | -| --- | --- | --- | --- | -| `gitlab` | `ServiceAccount` | `default` namespace | 创建一个新集群 | -| `gitlab-token` | `Secret` | `gitlab` ServiceAccount 的令牌 | 创建一个新集群 | -| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | 安装舵图 | -| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | 安装舵图 | -| 环境名称空间 | `Namespace` | 包含所有特定于环境的资源 | 部署到集群 | -| 环境名称空间 | `ServiceAccount` | 使用环境的名称空间 | 部署到集群 | -| 环境名称空间 | `Secret` | 环境 ServiceAccount 的令牌 | 部署到集群 | - -### Security of GitLab Runners[](#security-of-gitlab-runners "Permalink") - -GitLab Runners 默认情况[下](https://docs.gitlab.com/runner/executors/docker.html)启用了[特权模式](https://docs.gitlab.com/runner/executors/docker.html) ,这使他们可以执行特殊命令并在 Docker 中运行 Docker. 运行某些[Auto DevOps](../../../topics/autodevops/index.html)作业需要此功能. 这意味着容器正在特权模式下运行,因此,您应该注意一些重要的细节. - -特权标志为正在运行的容器提供了所有功能,而容器又可以执行主机可以执行的几乎所有操作. 请注意与对任意映像执行`docker run`操作相关的固有安全风险,因为它们有效地具有 root 用户访问权限. - -如果您不想在特权模式下使用 GitLab Runner,请执行以下任一操作: - -* 在 GitLab.com 上使用共享的跑步者. 他们没有这个安全问题. -* 使用[Shared Runners 中](../../gitlab_com/index.html#shared-runners)描述的配置来设置自己的[Runners](../../gitlab_com/index.html#shared-runners) . 这涉及: - 1. 确保您没有通过[应用程序](index.html#installing-applications)安装它. - 2. [使用`docker+machine`](https://docs.gitlab.com/runner/executors/docker_machine.html)安装 Runner. - -## Create new cluster[](#create-new-cluster "Permalink") - -可以使用 Google Kubernetes Engine(GKE)上的 GitLab 或 Amazon Elastic Kubernetes Service(EKS)在项目,组或实例级别上创建新集群: - -1. 导航到您的: - * 项目的 **操作> Kubernetes**页面,用于项目级集群. - * 组的 **Kubernetes**页面,用于组级别集群. - * **管理区>** **Kubernetes**页面,用于实例级集群. -2. Click **添加 Kubernetes 集群**. -3. 单击**创建新集群**选项卡. -4. 单击**Amazon EKS**或**Google GKE** ,然后按照说明提供所需的服务: - * [亚马逊 EKS](add_eks_clusters.html#new-eks-cluster) . - * [Google GKE](add_gke_clusters.html#creating-the-cluster-on-gke) . - -## Add existing cluster[](#add-existing-cluster "Permalink") - -如果您已有 Kubernetes 集群,则可以将其添加到项目,组或实例中. - -**注意:** arm64 集群不支持 Kubernetes 集成. 有关详细信息,请参阅问题[Helm Tiller 无法在 arm64 群集上安装](https://gitlab.com/gitlab-org/gitlab/-/issues/29838) . - -### Existing Kubernetes cluster[](#existing-kubernetes-cluster "Permalink") - -要将 Kubernetes 集群添加到您的项目,组或实例: - -1. 导航到您的: - 1. 项目的 **操作> Kubernetes**页面,用于项目级集群. - 2. 组的 **Kubernetes**页面,用于组级别集群. - 3. **管理区>** **Kubernetes**页面,用于实例级集群. -2. Click **添加 Kubernetes 集群**. -3. 单击**添加现有集群**选项卡,然后填写详细信息: - 1. **Kubernetes 集群名称** (必填)-您希望为**集群指定**的名称. - 2. **环境范围** (必需)- [与](index.html#setting-the-environment-scope-premium)此集群[相关的环境](index.html#setting-the-environment-scope-premium) . - 3. **API URL** (必填)-这是 GitLab 用于访问 Kubernetes API 的 URL. Kubernetes 公开了几个 API,我们想要所有这些 API 通用的"基本" URL. 例如, `https://kubernetes.example.com`而不是`https://kubernetes.example.com/api/v1` . - - 通过运行以下命令获取 API URL: - - ``` - kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}' - ``` - - 4. **CA 证书** (必需)-需要有效的 Kubernetes 证书才能对集群进行身份验证. 我们将使用默认创建的证书. - 1. 列出带有`kubectl get secrets` ,并且应将其命名类似于`default-token-xxxxx` . 复制该令牌名称以在下面使用. - 2. 通过运行以下命令获取证书: - - ``` - kubectl get secret -o jsonpath = "{['data']['ca \. crt']}" | base64 --decode - ``` - - **注意:**如果命令返回整个证书链,则需要在证书链的底部复制*根 ca*证书. - 5. **令牌** -GitLab 使用服务令牌对 Kubernetes 进行身份验证,服务令牌的作用域是特定的`namespace` . **使用的令牌应属于具有[`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)特权的服务帐户.** 要创建此服务帐户: - 1. 创建一个名为`gitlab-admin-service-account.yaml` ,其内容为: - - ``` - apiVersion : v1 kind : ServiceAccount metadata : name : gitlab-admin namespace : kube-system --- apiVersion : rbac.authorization.k8s.io/v1beta1 kind : ClusterRoleBinding metadata : name : gitlab-admin roleRef : apiGroup : rbac.authorization.k8s.io kind : ClusterRole name : cluster-admin subjects : - kind : ServiceAccount name : gitlab-admin namespace : kube-system - ``` - - 2. 将服务帐户和群集角色绑定应用于您的群集: - - ``` - kubectl apply -f gitlab-admin-service-account.yaml - ``` - - 您将需要`container.clusterRoleBindings.create`权限来创建集群级角色. 如果您没有此权限,则可以选择启用基本身份验证,然后以管理员身份运行`kubectl apply`命令: - - ``` - kubectl apply -f gitlab-admin-service-account.yaml --username = admin --password = - ``` - - **注意:**可以打开基本身份验证,并可以使用 Google Cloud Console 获取密码凭据. - - 输出: - - ``` - serviceaccount "gitlab-admin" created clusterrolebinding "gitlab-admin" created - ``` - - 3. 检索`gitlab-admin`服务帐户的令牌: - - ``` - kubectl -n kube-system describe secret $( kubectl -n kube-system get secret | grep gitlab-admin | awk '{print $1}' ) - ``` - - 从输出中复制``值: - - ``` - Name : gitlab-admin-token-b5zv4 Namespace : kube-system Labels : Annotations : kubernetes.io/service-account.name=gitlab-admin kubernetes.io/service-account.uid=bcfe66ac-39be-11e8-97e8-026dce96b6e8 Type : kubernetes.io/service-account-token Data ==== ca.crt : 1025 bytes namespace : 11 bytes token : - ``` - - **注意:**对于 GKE 群集,您将需要`container.clusterRoleBindings.create`权限来创建群集角色绑定. 您可以按照[Google Cloud 文档](https://cloud.google.com/iam/docs/granting-changing-revoking-access)授予访问权限. - 6. **由 GitLab 管理的群集** -如果要让 GitLab 管理该群集的名称空间和服务帐户,请选中此复选框. 有关更多信息,请参见[托管集群部分](index.html#gitlab-managed-clusters) . - 7. **项目名称空间** (可选)-您不必填写它; 将其保留为空白,GitLab 将为您创建一个. 也: - * 每个项目应具有唯一的名称空间. - * 如果您正在使用具有更广泛权限的机密(例如`default`的机密),则项目名称空间不一定是机密的名称空间. - * 你**不**应该使用`default`为项目命名空间. - * 如果您或某人为项目专门创建了一个秘密(通常具有有限的权限),则该秘密的名称空间和项目名称空间可能是相同的. -4. 最后,单击**创建 Kubernetes 集群**按钮. - -几分钟后,您的集群将准备就绪. 现在,您可以继续安装一些[预定义的应用程序](index.html#installing-applications) . - -#### Disable Role-Based Access Control (RBAC) (optional)[](#disable-role-based-access-control-rbac-optional "Permalink") - -通过 GitLab 集成连接集群时,您可以指定集群是否支持 RBAC. 这将影响 GitLab 如何与集群进行某些操作的交互. 如果您在创建时*未*选中**启用 RBAC 的群集**复选框,则 GitLab 将假定与群集进行交互时禁用了 RBAC. 如果是这样,则必须在群集上禁用 RBAC 才能使集成正常工作. - -[![rbac](img/9d9a196fe723b5afc79e2d7b29fd0f4d.png)](img/rbac_v13_1.png) - -**注意:**禁用 RBAC 意味着群集中运行的任何应用程序或可以向群集进行身份验证的用户都具有完全的 API 访问权限. 这是一个[安全问题](index.html#security-implications) ,可能不是所希望的. - -为了有效地禁用 RBAC,可以应用全局权限来授予完全访问权限: - -``` -kubectl create clusterrolebinding permissive-binding \ - --clusterrole=cluster-admin \ - --user=admin \ - --user=kubelet \ - --group=system:serviceaccounts -``` - -## Enabling or disabling integration[](#enabling-or-disabling-integration "Permalink") - -成功创建新集群或添加现有集群后,即可启用 Kubernetes 集群集成. 要禁用 Kubernetes 集群集成: - -1. 导航到您的: - * 项目的 **操作> Kubernetes**页面,用于项目级集群. - * 组的 **Kubernetes**页面,用于组级别集群. - * **管理区>** **Kubernetes**页面,用于实例级集群. -2. 单击群集的名称. -3. 单击**GitLab 集成**切换. -4. Click **保存更改**. - -## Removing integration[](#removing-integration "Permalink") - -要从您的项目中删除 Kubernetes 集群集成,请首先导航到集群详细信息页面的**Advanced Settings**选项卡,然后执行以下任一操作: - -* 选择**删除集成** ,仅删除 Kubernetes 集成. -* [从 GitLab 12.6 中](https://gitlab.com/gitlab-org/gitlab/-/issues/26815) ,选择**删除集成和资源** ,以在**删除集成时**也删除所有相关的 GitLab 集群资源(例如,名称空间,角色和绑定). - -删除集群集成时,请注意: - -* 您需要具有维护人员及以上[权限](../../permissions.html)才能删除 Kubernetes 集群集成. -* 删除集群时,只删除其与 GitLab 的关系,而不删除集群本身. 要删除集群,可以通过访问 GKE 或 EKS 仪表板或使用`kubectl`来`kubectl` . - -## Learn more[](#learn-more "Permalink") - -要了解有关自动部署应用程序的更多信息,请阅读有关[Auto DevOps](../../../topics/autodevops/index.html) . \ No newline at end of file diff --git a/docs/018.md b/docs/018.md deleted file mode 100644 index ed361cb7d4b5f8794d573c41a2c6ff1ffa94548e..0000000000000000000000000000000000000000 --- a/docs/018.md +++ /dev/null @@ -1,190 +0,0 @@ -# Adding EKS clusters - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/add_eks_clusters.html](https://docs.gitlab.com/ee/user/project/clusters/add_eks_clusters.html) - -* [EKS requirements](#eks-requirements) - * [Additional requirements for self-managed instances](#additional-requirements-for-self-managed-instances-core-only) -* [New EKS cluster](#new-eks-cluster) - * [Troubleshooting creating a new cluster](#troubleshooting-creating-a-new-cluster) - * [Error: Request failed with status code 422](#error-request-failed-with-status-code-422) - * [Could not load Security Groups for this VPC](#could-not-load-security-groups-for-this-vpc) - * [`ROLLBACK_FAILED` during cluster creation](#rollback_failed-during-cluster-creation) -* [Existing EKS cluster](#existing-eks-cluster) - * [Create a default Storage Class](#create-a-default-storage-class) - * [Deploy the app to EKS](#deploy-the-app-to-eks) - -# Adding EKS clusters[](#adding-eks-clusters "Permalink") - -GitLab 支持添加新的和现有的 EKS 集群. - -## EKS requirements[](#eks-requirements "Permalink") - -在通过 GitLab 集成在 Amazon EKS 上创建第一个集群之前,请确保满足以下要求: - -* 设置了[Amazon Web Services](https://aws.amazon.com/)帐户,您就可以登录. -* 您有权管理 IAM 资源. -* 如果要使用[现有的 EKS 集群](#existing-eks-cluster) : - * 已正确配置工作节点的 Amazon EKS 集群. - * [安装并配置](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html#get-started-kubectl)了`kubectl`以访问 EKS 集群. - -### Additional requirements for self-managed instances[](#additional-requirements-for-self-managed-instances-core-only "Permalink") - -如果您使用自我管理的 GitLab 实例,则必须首先使用一组 Amazon 凭证配置 GitLab. 这些凭证将用于承担创建集群的用户提供的 Amazon IAM 角色. 创建一个 IAM 用户,并确保其有权承担您的用户将用来创建 EKS 群集的角色. - -例如,以下策略文档允许在帐户`123456789012`假设一个角色的名称以`gitlab-eks-` : - -``` -{ "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::123456789012:role/gitlab-eks-*" } } -``` - -为 IAM 用户生成访问密钥,并使用凭据配置 GitLab: - -1. 导航至**管理区域>设置>集成,**然后展开**Amazon EKS**部分. -2. Check **启用 Amazon EKS 集成**. -3. 在相应的`Account ID` , `Access key ID`和`Secret access key`字段中输入帐户 ID 和访问密钥凭据. -4. Click **保存更改**. - -## New EKS cluster[](#new-eks-cluster "Permalink") - -在 GitLab 12.5 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/22392) . - -要创建新的 Kubernetes 集群并将其添加到您的项目,组或实例: - -1. 导航到您的: - * 项目的 **操作> Kubernetes**页面,用于项目级集群. - * 组的 **Kubernetes**页面,用于组级别集群. - * **管理区>** **Kubernetes** ,用于实例级集群. -2. Click **添加 Kubernetes 集群**. -3. 在" **创建新集群"**选项卡下,单击**Amazon EKS** . 将为您提供一个`Account ID`和`External ID` ,供下一步使用. -4. 在[IAM 管理控制台中](https://console.aws.amazon.com/iam/home) ,创建一个 IAM 角色: - 1. 在左侧面板中,选择**角色** . - 2. 单击**创建角色** . - 3. 在`Select type of trusted entity` ,选择**另一个 AWS 账户** . - 4. 在 GitLab 中的`Account ID`字段中输入`Account ID` . - 5. 选中**需要外部 ID** . - 6. 在 GitLab 中将`External ID`输入到`External ID`字段中. - 7. 单击**下一步:权限** . - 8. 点击**创建策略** ,这将打开一个新窗口. - 9. 选择**JSON**标签,然后粘贴以下代码段代替现有内容: - - ``` - { - "Version" : "2012-10-17" , - "Statement" : [ - { - "Effect" : "Allow" , - "Action" : [ - "autoscaling:CreateAutoScalingGroup" , - "autoscaling:DescribeAutoScalingGroups" , - "autoscaling:DescribeScalingActivities" , - "autoscaling:UpdateAutoScalingGroup" , - "autoscaling:CreateLaunchConfiguration" , - "autoscaling:DescribeLaunchConfigurations" , - "cloudformation:CreateStack" , - "cloudformation:DescribeStacks" , - "ec2:AuthorizeSecurityGroupEgress" , - "ec2:AuthorizeSecurityGroupIngress" , - "ec2:RevokeSecurityGroupEgress" , - "ec2:RevokeSecurityGroupIngress" , - "ec2:CreateSecurityGroup" , - "ec2:createTags" , - "ec2:DescribeImages" , - "ec2:DescribeKeyPairs" , - "ec2:DescribeRegions" , - "ec2:DescribeSecurityGroups" , - "ec2:DescribeSubnets" , - "ec2:DescribeVpcs" , - "eks:CreateCluster" , - "eks:DescribeCluster" , - "iam:AddRoleToInstanceProfile" , - "iam:AttachRolePolicy" , - "iam:CreateRole" , - "iam:CreateInstanceProfile" , - "iam:CreateServiceLinkedRole" , - "iam:GetRole" , - "iam:ListRoles" , - "iam:PassRole" , - "ssm:GetParameters" - ], - "Resource" : "*" - } - ] - } - ``` - - **注意:**这些权限使 GitLab 能够创建资源,但不能删除它们. 这意味着,如果在创建过程中遇到错误,更改将不会回滚,您必须手动删除资源. 您可以通过删除相关的[CloudFormation 堆栈](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-delete-stack.html)来做到这一点 - 10. 点击**审核政策** . - 11. 为此策略输入合适的名称,然后点击**创建策略** . 您现在可以关闭此窗口. - 12. 切换回"创建角色"窗口,然后选择刚创建的策略. - 13. 单击**下一步:标签** ,并选择输入您希望与此角色关联的任何标签. - 14. 单击**下一步:查看** . - 15. 在提供的字段中输入角色名称和可选描述. - 16. 点击**创建角色** ,新角色名称将显示在顶部. 单击其名称,然后从新创建的角色复制`Role ARN` . -5. 在 GitLab 中,将复制的角色 ARN 输入到`Role ARN`字段中. -6. Click **使用 AWS 进行身份验证**. -7. 选择集群的设置: - * **Kubernetes 集群名称** -您希望赋予集群的名称. - * **环境范围** -该集群的[关联环境](index.html#setting-the-environment-scope-premium) . - * **Kubernetes 版本** -要使用的 Kubernetes 版本. 当前唯一支持的版本是 1.14\. - * **角色名称** -选择[IAM 角色](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html)以允许 Amazon EKS 和 Kubernetes 控制平面代表您管理 AWS 资源. 此 IAM 角色与上面创建的 IAM 角色是分开的,如果尚不存在,则需要创建它. - * **区域** -将在其中创建群集的[区域](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html) . - * **密钥对名称** -如果需要,选择可用于连接到工作节点的[密钥对](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html) . - * **VPC-**选择要用于 EKS 群集资源的[VPC](https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html) . - * **子网** -在您的 VPC 中选择运行工作节点的[子网](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Subnets.html) . 您必须至少选择两个. - * **安全组** -选择[安全组](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html)以应用到在工作节点子网中创建的 EKS 管理的弹性网络接口. - * **实例类型** -工作节点的[实例类型](https://aws.amazon.com/ec2/instance-types/) . - * **节点数** -工作节点数. - * **由 GitLab 管理的群集** -如果要让 GitLab 管理该群集的名称空间和服务帐户,请选中此复选框. 有关更多信息,请参见[托管集群部分](index.html#gitlab-managed-clusters) . -8. 最后,单击**创建 Kubernetes 集群**按钮. - -大约 10 分钟后,您的集群便可以使用了. 现在,您可以继续安装一些[预定义的应用程序](index.html#installing-applications) . - -**注意:**您需要将 AWS 外部 ID 添加到[AWS CLI 中](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html#cli-configure-role-xaccount)的[IAM 角色,](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html#cli-configure-role-xaccount)才能使用`kubectl`管理集群. - -### Troubleshooting creating a new cluster[](#troubleshooting-creating-a-new-cluster "Permalink") - -创建新集群时,通常会遇到以下错误. - -#### Error: Request failed with status code 422[](#error-request-failed-with-status-code-422 "Permalink") - -提交初始身份验证表单时,如果无法确定您提供的角色,则 GitLab 会返回状态码 422 错误. 确保已使用 GitLab 提供的**帐户 ID**和**外部 ID**正确配置了角色. 在 GitLab 中,确保输入正确的**Role ARN** . - -#### Could not load Security Groups for this VPC[](#could-not-load-security-groups-for-this-vpc "Permalink") - -当在配置表单中填充选项时,GitLab 将返回此错误,因为 GitLab 已成功承担了您提供的角色,但是该角色没有足够的权限来检索表单所需的资源. 确保已为角色分配了正确的权限. - -#### `ROLLBACK_FAILED` during cluster creation[](#rollback_failed-during-cluster-creation "Permalink") - -由于 GitLab 在创建一个或多个资源时遇到错误,因此创建过程停止. 您可以检查关联的[CloudFormation 堆栈](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-view-stack-data-resources.html)以查找创建失败的特定资源. - -如果`Cluster`资源因错误`The provided role doesn't have the Amazon EKS Managed Policies associated with it.`失败,则`The provided role doesn't have the Amazon EKS Managed Policies associated with it.` , **角色名称**中指定的**角色**配置不正确. - -**注意:**此角色不应与上面创建的角色相同. 如果您没有现有的[EKS 群集 IAM 角色](https://docs.aws.amazon.com/eks/latest/userguide/service_IAM_role.html) ,则必须创建一个. - -## Existing EKS cluster[](#existing-eks-cluster "Permalink") - -有关添加现有 EKS 群集的信息,请参阅" [现有 Kubernetes 群集"](add_remove_clusters.html#existing-kubernetes-cluster) . - -### Create a default Storage Class[](#create-a-default-storage-class "Permalink") - -Amazon EKS 没有开箱即用的默认存储类,这意味着对持久卷的请求将不会自动满足. 作为 Auto DevOps 的一部分,已部署的 PostgreSQL 实例将请求持久存储,并且如果没有默认存储类,它将无法启动. - -如果默认的存储类尚不存在并且需要使用,请按照 Amazon 的[存储类指南](https://docs.aws.amazon.com/eks/latest/userguide/storage-classes.html)创建一个. - -或者,通过将项目变量[`POSTGRES_ENABLED`](../../../topics/autodevops/customize.html#environment-variables)设置为`false`来禁用 PostgreSQL. - -### Deploy the app to EKS[](#deploy-the-app-to-eks "Permalink") - -在禁用 RBAC 和部署服务的情况下,现在可以利用[Auto DevOps](../../../topics/autodevops/index.html)构建,测试和部署应用程序. - -如果尚未启用,则[启用 Auto DevOps](../../../topics/autodevops/index.html#at-the-project-level) . 如果创建了通配符 DNS 条目以解析到负载均衡器,请在"自动 DevOps"设置下的" `domain`字段中输入它. 否则,已部署的应用程序将无法在群集外部从外部获得. - -[![Deploy Pipeline](img/de608fa9aefa963f38d0d95043413679.png)](img/pipeline.png) - -将自动创建一个新管道,该管道将开始构建,测试和部署该应用程序. - -管道完成后,您的应用将在 EKS 中运行,并可供用户使用. 单击**CI / CD>环境** . - -[![Deployed Environment](img/dc47374cec4da1de3e6476346ecf738e.png)](img/environment.png) - -您将看到环境及其部署状态的列表,以及浏览到应用程序,查看监视指标甚至访问正在运行的 Pod 上的 Shell 的选项. \ No newline at end of file diff --git a/docs/019.md b/docs/019.md deleted file mode 100644 index fa763920987d9effd3c7fdadfe55e25f7149dc67..0000000000000000000000000000000000000000 --- a/docs/019.md +++ /dev/null @@ -1,65 +0,0 @@ -# Adding GKE clusters - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/add_gke_clusters.html](https://docs.gitlab.com/ee/user/project/clusters/add_gke_clusters.html) - -* [GKE requirements](#gke-requirements) -* [New GKE cluster](#new-gke-cluster) - * [Creating the cluster on GKE](#creating-the-cluster-on-gke) - * [Cloud Run for Anthos](#cloud-run-for-anthos) -* [Existing GKE cluster](#existing-gke-cluster) - -# Adding GKE clusters[](#adding-gke-clusters "Permalink") - -GitLab 支持添加新的和现有的 GKE 集群. - -## GKE requirements[](#gke-requirements "Permalink") - -在通过 GitLab 集成在 Google GKE 上创建第一个集群之前,请确保满足以下要求: - -* 设置了具有访问权限的[结算帐户](https://cloud.google.com/billing/docs/how-to/manage-billing-account) . -* 启用了 Kubernetes Engine API 和相关服务. 它应该可以立即工作,但是创建项目后最多可能需要 10 分钟. 有关更多信息,请参见[Kubernetes Engine 文档](https://cloud.google.com/kubernetes-engine/docs/quickstart#before-you-begin)的["开始之前"部分](https://cloud.google.com/kubernetes-engine/docs/quickstart#before-you-begin) . - -## New GKE cluster[](#new-gke-cluster "Permalink") - -从[GitLab 12.4](https://gitlab.com/gitlab-org/gitlab/-/issues/25925)开始, [GitLab](https://gitlab.com/gitlab-org/gitlab/-/issues/25925)提供的所有 GKE 群集均为[VPC 本地的](https://cloud.google.com/kubernetes-engine/docs/how-to/alias-ips) . - -请注意以下几点: - -* 必须在实例级别的 GitLab 中启用[Google 身份验证集成](../../../integration/google.html) . 如果不是这种情况,请要求您的 GitLab 管理员启用它. 在 GitLab.com 上启用了此功能. -* 从[GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/55902)开始,由[GitLab](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/55902)创建的所有 GKE 集群都启用了 RBAC. 请参阅[RBAC 部分](add_remove_clusters.html#rbac-cluster-resources)以获取更多信息. -* 从[GitLab 12.5](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18341)开始,群集的 Pod 地址 IP 范围将设置为/ 16,而不是常规的/ 14\. / 16 是 CIDR 表示法. -* GitLab 要求启用基本身份验证并为集群颁发客户端证书,以设置[初始服务帐户](add_remove_clusters.html#access-controls) . 在[GitLab 11.10 及更高版本中](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/58208) ,集群创建过程明确要求 GKE 创建启用了基本身份验证和客户端证书的集群. - -### Creating the cluster on GKE[](#creating-the-cluster-on-gke "Permalink") - -要创建新的 Kubernetes 集群并将其添加到您的项目,组或实例: - -1. 导航到您的: - * 项目的 **操作> Kubernetes**页面,用于项目级集群. - * 组的 **Kubernetes**页面,用于组级别集群. - * **管理区>** **Kubernetes**页面,用于实例级集群. -2. Click **添加 Kubernetes 集群**. -3. 在[ **建立新丛集]**标签下,按一下[ **Google GKE]** . -4. 如果尚未连接 Google 帐户,请单击" **使用 Google 登录"**按钮. -5. 选择集群的设置: - * **Kubernetes 集群名称** -您希望赋予集群的名称. - * **环境范围** -该集群的[关联环境](index.html#setting-the-environment-scope-premium) . - * **Google Cloud Platform 项目** -选择您在 GCP 控制台中创建的将托管 Kubernetes 集群的项目. 了解有关[Google Cloud Platform 项目的](https://cloud.google.com/resource-manager/docs/creating-managing-projects)更多信息. - * **区域** -选择将在其下创建群集的[区域区域](https://cloud.google.com/compute/docs/regions-zones/) . - * **节点数** -输入希望群集具有的节点数. - * **计算机类型** -群集将基于的虚拟机实例的[计算机类型](https://cloud.google.com/compute/docs/machine-types) . - * **为 Anthos 启用 Cloud Run-**如果要对此集群使用 Cloud Run for Anthos,请选中此复选框. 有关更多信息,请参见[Anthos](#cloud-run-for-anthos)的[Cloud Run 部分](#cloud-run-for-anthos) . - * **由 GitLab 管理的群集** -如果要让 GitLab 管理该群集的名称空间和服务帐户,请选中此复选框. 有关更多信息,请参见[托管集群部分](index.html#gitlab-managed-clusters) . -6. 最后,单击**创建 Kubernetes 集群**按钮. - -几分钟后,您的集群将准备就绪. 现在,您可以继续安装一些[预定义的应用程序](index.html#installing-applications) . - -### Cloud Run for Anthos[](#cloud-run-for-anthos "Permalink") - -在 GitLab 12.4 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/16566) . - -创建群集后,可以选择使用 Cloud Run for Anthos 代替分别安装 Knative 和 Istio. 这意味着将在创建时在集群上启用 Cloud Run(Knative),Istio 和 HTTP Load Balancing,并且不能单独[安装或卸载](../../clusters/applications.html) . - -## Existing GKE cluster[](#existing-gke-cluster "Permalink") - -有关添加现有 GKE 群集的信息,请参阅" [现有 Kubernetes 群集"](add_remove_clusters.html#existing-kubernetes-cluster) . \ No newline at end of file diff --git a/docs/020.md b/docs/020.md deleted file mode 100644 index e00a05647fd42a90e2515b47ea7136bf641168d0..0000000000000000000000000000000000000000 --- a/docs/020.md +++ /dev/null @@ -1,144 +0,0 @@ -# Group-level Kubernetes clusters - -> 原文:[https://docs.gitlab.com/ee/user/group/clusters/](https://docs.gitlab.com/ee/user/group/clusters/) - -* [Installing applications](#installing-applications) -* [RBAC compatibility](#rbac-compatibility) -* [Cluster precedence](#cluster-precedence) -* [Multiple Kubernetes clusters](#multiple-kubernetes-clusters) -* [GitLab-managed clusters](#gitlab-managed-clusters) - * [Clearing the cluster cache](#clearing-the-cluster-cache) -* [Base domain](#base-domain) -* [Environment scopes](#environment-scopes-premium) -* [Cluster environments](#cluster-environments-premium) -* [Security of Runners](#security-of-runners) -* [More information](#more-information) - -# Group-level Kubernetes clusters[](#group-level-kubernetes-clusters "Permalink") - -在 GitLab 11.6 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/34758) . - -与[项目级](../../project/clusters/index.html)和[实例级](../../instance/clusters/index.html) Kubernetes 集群类似,组级 Kubernetes 集群允许您将 Kubernetes 集群连接到您的组,从而使您可以在多个项目中使用同一集群. - -## Installing applications[](#installing-applications "Permalink") - -GitLab 可以在您的组级别集群中安装和管理某些应用程序. 有关为您的组集群安装,升级,卸载和故障排除应用程序的更多信息,请参阅[GitLab 托管应用程序](../../clusters/applications.html) . - -## RBAC compatibility[](#rbac-compatibility "Permalink") - -版本历史 - -* 在 GitLab 11.4 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/29398) . -* [项目名称空间限制](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/51716)是在 GitLab 11.5 中引入的. - -对于具有 Kubernetes 集群的组中的每个项目,GitLab 都会在项目名称空间中创建具有[`edit`权限](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)的受限服务帐户. - -## Cluster precedence[](#cluster-precedence "Permalink") - -如果项目的群集可用且未禁用,则 GitLab 在使用属于包含该项目的组的任何群集之前,先使用项目的群集. 对于子组,如果未禁用该组,则 GitLab 将使用与项目最接近的祖先组的集群. - -## Multiple Kubernetes clusters[](#multiple-kubernetes-clusters "Permalink") - -版本历史 - -* 在 13.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35094)了 GitLab Core. - -您可以将多个 Kubernetes 集群关联到您的组,并为不同的环境(例如开发,登台和生产)维护不同的集群. - -添加另一个群集时,请[设置环境范围](#environment-scopes-premium)以帮助区分新群集和其他群集. - -## GitLab-managed clusters[](#gitlab-managed-clusters "Permalink") - -版本历史 - -* 在 GitLab 11.5 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22011) . -* 在 GitLab 11.11 中成为[可选](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/26565) . - -You can choose to allow GitLab to manage your cluster for you. If GitLab manages your cluster, resources for your projects will be automatically created. See the [Access controls](../../project/clusters/add_remove_clusters.html#access-controls) section for details on which resources GitLab creates for you. - -对于不受 GitLab 管理的集群,将不会自动创建特定于项目的资源. 如果将[Auto DevOps](../../../topics/autodevops/index.html)用于具有不受 GitLab 管理的群集的部署,则必须确保: - -* 项目的部署服务帐户有权部署到[`KUBE_NAMESPACE`](../../project/clusters/index.html#deployment-variables) . -* `KUBECONFIG`正确反映了对`KUBE_NAMESPACE`任何更改(这[不是自动的](https://gitlab.com/gitlab-org/gitlab/-/issues/31519) ). 不建议直接编辑`KUBE_NAMESPACE` . - -**注意:**如果您在群集上[安装应用程序](#installing-applications) ,即使您选择管理自己的群集,GitLab 也会创建运行它们所需的资源. - -### Clearing the cluster cache[](#clearing-the-cluster-cache "Permalink") - -在 GitLab 12.6 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/31759) . - -如果您选择允许 GitLab 为您管理集群,则 GitLab 将存储它为项目创建的名称空间和服务帐户的缓存版本. 如果在群集中手动修改这些资源,则此缓存可能与群集不同步,这可能导致部署作业失败. - -清除缓存: - -1. 导航到您小组的 **Kubernetes**页面,然后选择您的集群. -2. 展开**高级设置**部分. -3. Click **清除集群缓存**. - -## Base domain[](#base-domain "Permalink") - -在 GitLab 11.8 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24580) . - -集群级别的域允许每个[多个 Kubernetes 集群](#multiple-kubernetes-clusters)支持多个域.指定域时,这将在[Auto DevOps](../../../topics/autodevops/index.html)阶段自动设置为环境变量( `KUBE_INGRESS_BASE_DOMAIN` ). - -该域应将通配符 DNS 配置为入口 IP 地址. - -## Environment scopes[](#environment-scopes-premium "Permalink") - -将多个 Kubernetes 集群添加到您的项目时,您需要通过环境范围来区分它们. 环境范围将群集与[环境](../../../ci/environments/index.html)相关联,类似于[特定](../../../ci/variables/README.html#limit-the-environment-scopes-of-environment-variables)于[环境的变量的](../../../ci/variables/README.html#limit-the-environment-scopes-of-environment-variables)工作方式. - -在评估哪个环境与群集的环境范围匹配时, [群集优先级](#cluster-precedence)将生效. 项目级别的集群优先,其次是最接近的祖先组,然后是该组的父级,依此类推. - -例如,如果您的项目具有以下 Kubernetes 集群: - -| Cluster | 环境范围 | Where | -| --- | --- | --- | -| Project | `*` | Project | -| Staging | `staging/*` | Project | -| Production | `production/*` | Project | -| Test | `test` | Group | -| Development | `*` | Group | - -[`.gitlab-ci.yml`](../../../ci/yaml/README.html)中设置了以下环境: - -``` -stages: - - test - - deploy - -test: - stage: test - script: sh test - -deploy to staging: - stage: deploy - script: make deploy - environment: - name: staging/$CI_COMMIT_REF_NAME - url: https://staging.example.com/ - -deploy to production: - stage: deploy - script: make deploy - environment: - name: production/$CI_COMMIT_REF_NAME - url: https://example.com/ -``` - -结果是: - -* 项目集群用于`test`作业. -* 分段群集用于`deploy to staging`作业. -* 生产集群用于`deploy to production`作业. - -## Cluster environments[](#cluster-environments-premium "Permalink") - -有关将哪种 CI [环境](../../../ci/environments/index.html)部署到 Kubernetes 集群的统一视图,请参阅[集群环境](../../clusters/environments.html)文档. - -## Security of Runners[](#security-of-runners "Permalink") - -有关安全配置 GitLab Runners 的重要信息,请参阅项目级集群[的 Runners 安全性](../../project/clusters/add_remove_clusters.html#security-of-gitlab-runners)文档. - -## More information[](#more-information "Permalink") - -For information on integrating GitLab and Kubernetes, see [Kubernetes clusters](../../project/clusters/index.html). \ No newline at end of file diff --git a/docs/021.md b/docs/021.md deleted file mode 100644 index a9f066f1278ddb6dc5e8a5cb06ccf07cf17d1858..0000000000000000000000000000000000000000 --- a/docs/021.md +++ /dev/null @@ -1,34 +0,0 @@ -# Instance-level Kubernetes clusters - -> 原文:[https://docs.gitlab.com/ee/user/instance/clusters/](https://docs.gitlab.com/ee/user/instance/clusters/) - -* [Overview](#overview) -* [Cluster precedence](#cluster-precedence) -* [Cluster environments](#cluster-environments-premium) -* [More information](#more-information) - -# Instance-level Kubernetes clusters[](#instance-level-kubernetes-clusters "Permalink") - -在 GitLab 11.11 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/39840) . - -## Overview[](#overview "Permalink") - -与[项目级](../../project/clusters/index.html)和[组级](../../group/clusters/index.html) Kubernetes 集群类似,实例级 Kubernetes 集群允许您将 Kubernetes 集群连接到 GitLab 实例,这使您可以在多个项目中使用同一集群. - -## Cluster precedence[](#cluster-precedence "Permalink") - -GitLab 将尝试按以下顺序匹配集群: - -* 项目级集群. -* 组级别群集. -* 实例级集群. - -要选择集群,必须启用集群并使其与[环境选择器](../../../ci/environments/index.html#scoping-environments-with-specs)匹配. - -## Cluster environments[](#cluster-environments-premium "Permalink") - -有关将哪种 CI [环境](../../../ci/environments/index.html)部署到 Kubernetes 集群的统一视图,请参阅[集群环境](../../clusters/environments.html)文档. - -## More information[](#more-information "Permalink") - -有关集成 GitLab 和 Kubernetes 的信息,此[Kubernetes 集群](../../project/clusters/index.html) . \ No newline at end of file diff --git a/docs/022.md b/docs/022.md deleted file mode 100644 index 5a0961c34fd6d09c041f896aa2b37619333e2e79..0000000000000000000000000000000000000000 --- a/docs/022.md +++ /dev/null @@ -1,42 +0,0 @@ -# Canary Deployments - -> 原文:[https://docs.gitlab.com/ee/user/project/canary_deployments.html](https://docs.gitlab.com/ee/user/project/canary_deployments.html) - -* [Overview](#overview) -* [Use cases](#use-cases) -* [Enabling Canary Deployments](#enabling-canary-deployments) - -# Canary Deployments[](#canary-deployments-premium "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1659) in [GitLab Premium](https://about.gitlab.com/pricing/) 9.1. - -一种流行的[持续部署](https://en.wikipedia.org/wiki/Continuous_deployment)策略,其中将一小部分机队更新为应用程序的新版本. - -## Overview[](#overview "Permalink") - -在采用[持续交付时](https://about.gitlab.com/blog/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/) ,公司需要决定要使用哪种部署策略. 最受欢迎的策略之一是金丝雀部署,首先将一小部分机队更新为新版本. 金丝雀的这个子集,然后在煤矿中成为众所周知的[金丝雀](https://en.wiktionary.org/wiki/canary_in_a_coal_mine) . - -如果应用程序的新版本存在问题,则仅会影响一小部分用户,并且可以固定更改或快速还原更改. - -利用[Kubernetes 的 Canary 部署](https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments) ,无需离开 GitLab,即可在[Deploy Board](deploy_boards.html)内部可视化您的 Canary 部署. - -## Use cases[](#use-cases "Permalink") - -当您只想向部分 Pod 舰队提供功能并观看其行为时,可以使用 Canary 部署. 如果一切正常,您可以将该功能部署到生产中,因为它不会造成任何问题. - -Canary 部署对于后端重构,性能改进或用户界面不变的其他更改也特别有用,但是您要确保性能保持不变或有所提高. 开发人员在使用面向用户的更改的 Canary 时需要谨慎,因为默认情况下,来自同一用户的请求将随机分布在 Canary 和非 Canary Pod 之间,这可能导致混乱甚至错误. 如果需要,您可能需要考虑[在 Kubernetes 服务定义中将`service.spec.sessionAffinity`设置为`ClientIP`](https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies) ,但这超出了本文档的范围. - -## Enabling Canary Deployments[](#enabling-canary-deployments "Permalink") - -Canary 部署要求您正确配置 Deploy Boards: - -1. 请按照以下步骤[启用 Deploy Boards](deploy_boards.html#enabling-deploy-boards) . -2. 要跟踪 canary 部署,您需要使用`track: canary`标记 Kubernetes 部署和 Pod. 为了快速入门,您可以将[自动部署](../../topics/autodevops/stages.html#auto-deploy)模板用于 GitLab 提供的金丝雀部署. - -根据部署情况,标签应该是`stable`或`canary` . 通常, `stable`且空白或丢失的标签表示同一件事,而`canary`或任何其他轨道表示金丝雀/临时. 这使 GitLab 能够发现部署是稳定的还是金丝雀(临时)的. - -完成以上所有设置并且管道至少运行了一次之后,导航至" **管道">"环境"**下的环境页面. 随着管道的执行,部署委员会将清楚地标记金丝雀荚,从而可以快速,轻松地洞察每种环境和部署的状态. - -Canary deployments are marked with a yellow dot in the Deploy Board so that you can easily notice them. - -[![Canary deployments on Deploy Board](img/9a002df90c6ed1d01c8ae3a9817242df.png)](img/deploy_boards_canary_deployments.png) \ No newline at end of file diff --git a/docs/023.md b/docs/023.md deleted file mode 100644 index 9a11616616052d0777d2aa9e4218d2ab88ef726d..0000000000000000000000000000000000000000 --- a/docs/023.md +++ /dev/null @@ -1,42 +0,0 @@ -# Cluster Environments - -> 原文:[https://docs.gitlab.com/ee/user/clusters/environments.html](https://docs.gitlab.com/ee/user/clusters/environments.html) - -* [Overview](#overview) -* [Usage](#usage) - -# Cluster Environments[](#cluster-environments-premium "Permalink") - -> * 在[GitLab Premium](https://about.gitlab.com/pricing/) 12.3 中针对组级集群[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/13392) . -> * 在[GitLab Premium](https://about.gitlab.com/pricing/) 12.4 中针对实例级集群进行了[介绍](https://gitlab.com/gitlab-org/gitlab/-/issues/14809) . - -群集环境提供了一个统一的视图,用于说明将哪些 CI [环境](../../ci/environments/index.html)部署到 Kubernetes 群集及其: - -* 显示项目和与部署相关的相关环境. -* 显示该环境的窗格的状态. - -## Overview[](#overview "Permalink") - -使用集群环境,您可以深入了解: - -* 哪些项目已部署到集群. -* 每个项目的环境使用了多少个 Pod. -* 用于部署到该环境的 CI 作业. - -[![Cluster environments page](img/662e9b0c090a4f28c82eb779aabdc9c8.png)](img/cluster_environments_table_v12_3.png) - -仅限集群[维护者和所有者](../permissions.html#group-members-permissions)访问集群环境 - -## Usage[](#usage "Permalink") - -为了: - -* 跟踪集群的环境,您必须成功[部署到 Kubernetes 集群](../project/clusters/index.html#deploying-to-a-kubernetes-cluster) . -* 正确显示容器使用情况,必须[启用 Deploy Boards](../project/deploy_boards.html#enabling-deploy-boards) . - -成功部署到组级或实例级集群后: - -1. 导航到您组的**Kubernetes**页面. -2. 单击**环境**选项卡. - -**注意:**此页面仅包含成功部署到群集的信息. 非群集环境将不包括在内. \ No newline at end of file diff --git a/docs/024.md b/docs/024.md deleted file mode 100644 index 0fc69a277907a6d55e4970d65c873902713cfdb5..0000000000000000000000000000000000000000 --- a/docs/024.md +++ /dev/null @@ -1,113 +0,0 @@ -# Deploy Boards - -> 原文:[https://docs.gitlab.com/ee/user/project/deploy_boards.html](https://docs.gitlab.com/ee/user/project/deploy_boards.html) - -* [Overview](#overview) -* [Use cases](#use-cases) -* [Enabling Deploy Boards](#enabling-deploy-boards) - * [Example manifest file](#example-manifest-file) -* [Canary Deployments](#canary-deployments) -* [Further reading](#further-reading) - -# Deploy Boards[](#deploy-boards-premium "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1589) in [GitLab Premium](https://about.gitlab.com/pricing/) 9.0. - -GitLab 的部署板提供了[Kubernetes](https://kubernetes.io)上运行的每个 CI [环境](../../ci/environments/index.html)的当前运行状况和状态的综合视图,显示了部署中 Pod 的状态. 开发人员和其他团队成员可以在已经使用的工作流程中逐个窗格地查看发布的进度和状态,而无需访问 Kubernetes. - -## Overview[](#overview "Permalink") - -使用部署板,您可以通过以下优势对部署进行更多了解: - -* 从头开始进行部署,而不仅仅是完成之后 -* 监视跨多个服务器的构建的推出 -* 更详细的状态详细信息(成功,正在运行,失败,待处理,未知) -* See [Canary Deployments](canary_deployments.html) - -这是生产环境的部署板的示例. - -[![Deploy Boards landing page](img/4ceccc7ae590a56e8b135fa8baaafabe.png)](img/deploy_boards_landing_page.png) - -正方形表示与给定环境关联的 Kubernetes 集群中的 Pod. 将鼠标悬停在每个方块上方,可以看到部署的状态. 百分比是已更新到最新版本的 Pod 的百分比. - -由于部署板与 Kubernetes 紧密结合,因此需要一些知识. 特别是,您应该熟悉: - -* [Kubernetes pods](https://kubernetes.io/docs/concepts/workloads/pods/pod/) -* [Kubernetes labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) -* [Kubernetes namespaces](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/) -* [Kubernetes canary deployments](https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments) - -**注意:**包含多个部署的应用程序在部署板上显示为重复项. 有关详细信息,请关注[此问题](https://gitlab.com/gitlab-org/gitlab/-/issues/8463) . - -## Use cases[](#use-cases "Permalink") - -由于部署板是针对特定环境的 Kubernetes 吊舱的直观表示,因此存在许多用例. 仅举几例: - -* 您想将分阶段运行的产品推广到生产环境. 您转到环境列表,验证阶段运行的是您认为正在运行的,然后单击[手动操作](../../ci/yaml/README.html#whenmanual)以部署到生产环境. -* 您触发了部署,并且有很多容器需要升级,因此您将花费一段时间(您也限制了部署,一次只能删除 X 个容器). 但是您需要告诉某人何时部署,因此您可以转到环境列表,查看生产环境,以了解每个 Pod 滚动时的实时进度. -* 您会得到一份报告,说明生产中有些异常,因此您可以查看生产环境以查看正在运行什么,以及部署是否正在进行,是否停止或失败. -* 您的 MR 看起来不错,但是您希望在登台上运行它,因为登台是在某种程度上更接近生产环境进行设置的. 您转到环境列表,找到您感兴趣的[Review App](../../ci/review_apps/index.html) ,然后单击手动操作将其部署到登台. - -## Enabling Deploy Boards[](#enabling-deploy-boards "Permalink") - -要显示特定[环境](../../ci/environments/index.html)的部署板,您应该: - -1. 用部署阶段[定义了一个环境](../../ci/environments/index.html#defining-environments) . - -2. 使 Kubernetes 集群启动并运行. - - **在 OpenShift 上运行:**如果使用的是 OpenShift,请确保使用的是`Deployment`资源而不是`DeploymentConfiguration` . 否则,部署板将无法正确渲染. 有关更多信息,请阅读[OpenShift docs](https://docs.openshift.com/container-platform/3.7/dev_guide/deployments/kubernetes_deployments.html#kubernetes-deployments-vs-deployment-configurations)和[GitLab 问题#4584](https://gitlab.com/gitlab-org/gitlab/-/issues/4584) . -3. 使用[Docker](https://docs.gitlab.com/runner/executors/docker.html)或[Kubernetes](https://docs.gitlab.com/runner/executors/kubernetes.html)执行器[配置 GitLab Runner](../../ci/runners/README.html) . -4. 在您的项目中为集群配置[Kubernetes 集成](clusters/index.html) . 特别注意 Kubernetes 命名空间,因为部署脚本(由`KUBE_NAMESPACE` env 变量公开)将需要它. -5. 确保将 app.gitlab.com/env:$ `app.gitlab.com/env: $CI_ENVIRONMENT_SLUG`和`app.gitlab.com/app: $CI_PROJECT_PATH_SLUG` CI_PROJECT_PATH_SLUG 的 Kubernetes 注释应用于部署,副本集和 Pod,其中`$CI_ENVIRONMENT_SLUG`和`$CI_PROJECT_PATH_SLUG`是 CI 变量的值. 这样一来,我们便可以在可能有多个的群集/命名空间中查找适当的环境. 这些资源应包含在 Kubernetes 服务设置中定义的名称空间中. 您可以使用[Autodeploy](../../topics/autodevops/stages.html#auto-deploy) `.gitlab-ci.yml`模板,该模板具有要使用的预定义阶段和命令,并自动应用注释. 每个项目还需要在 Kubernetes 中具有唯一的名称空间. 下图演示了如何在 Kubernetes 中显示此内容. - - **注意:**在[GitLab 12.1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/14020)中删除了基于 Kubernetes `app`标签的匹配. 要迁移,请应用所需的注释(请参见上文),然后重新部署您的应用程序. 如果您使用的是 Auto DevOps,这将自动完成,无需采取任何措施. - - [![Deploy Boards Kubernetes Label](img/f5739c1b278ddd91c915c534514b4235.png)](img/deploy_boards_kubernetes_label.png) - -完成以上所有设置并且管道至少运行了一次之后,导航至**Operations> Environments**下的 environment 页面. - -默认情况下,部署板是可见的. 您可以显式单击相应环境名称旁边的三角形以隐藏它们. - -### Example manifest file[](#example-manifest-file "Permalink") - -以下示例是使用两个注释`app.gitlab.com/env`和`app.gitlab.com/app`启用 Kubernetes 清单部署文件的`app.gitlab.com/env` ,以启用**Deploy Boards** : - -``` -apiVersion: apps/v1 -kind: Deployment -metadata: - name: "APPLICATION_NAME" - annotations: - app.gitlab.com/app: ${CI_PROJECT_PATH_SLUG} - app.gitlab.com/env: ${CI_ENVIRONMENT_SLUG} -spec: - replicas: 1 - selector: - matchLabels: - app: "APPLICATION_NAME" - template: - metadata: - labels: - app: "APPLICATION_NAME" - annotations: - app.gitlab.com/app: ${CI_PROJECT_PATH_SLUG} - app.gitlab.com/env: ${CI_ENVIRONMENT_SLUG} -``` - -注释将应用于部署,副本集和 Pod. 通过更改副本数量,例如`kubectl scale --replicas=3 deploy APPLICATION_NAME -n ${KUBE_NAMESPACE}` ,您可以从开发板上跟踪实例的 pod. - -**注意:** YAML 文件是静态的. 如果使用`kubectl apply` ,则必须在`kubectl apply`之前手动提供项目和环境段,或者创建脚本来替换 YAML 中的变量. - -## Canary Deployments[](#canary-deployments "Permalink") - -一种流行的 CI 策略,其中将一小部分车队更新为应用程序的新版本. - -[Read more about Canary Deployments.](canary_deployments.html) - -## Further reading[](#further-reading "Permalink") - -* [GitLab Autodeploy](../../topics/autodevops/stages.html#auto-deploy) -* [GitLab CI/CD environment variables](../../ci/variables/README.html) -* [Environments and deployments](../../ci/environments/index.html) -* [Kubernetes deploy example](https://gitlab.com/gitlab-examples/kubernetes-deploy) \ No newline at end of file diff --git a/docs/025.md b/docs/025.md deleted file mode 100644 index ba3543f75b3deba1b090b905b7b9ef53348754cb..0000000000000000000000000000000000000000 --- a/docs/025.md +++ /dev/null @@ -1,1220 +0,0 @@ -# GitLab Managed Apps - -> 原文:[https://docs.gitlab.com/ee/user/clusters/applications.html](https://docs.gitlab.com/ee/user/clusters/applications.html) - -* [Installing applications](#installing-applications) - * [Helm](#helm) - * [Enable or disable local Tiller](#enable-or-disable-local-tiller-core-only) - * [cert-manager](#cert-manager) - * [GitLab Runner](#gitlab-runner) - * [Ingress](#ingress) - * [Determining the external endpoint automatically](#determining-the-external-endpoint-automatically) - * [Determining the external endpoint manually](#determining-the-external-endpoint-manually) - * [Using a static IP](#using-a-static-ip) - * [Pointing your DNS at the external endpoint](#pointing-your-dns-at-the-external-endpoint) - * [Web Application Firewall (ModSecurity)](#web-application-firewall-modsecurity) - * [Logging and blocking modes](#logging-and-blocking-modes) - * [WAF version updates](#waf-version-updates) - * [Viewing Web Application Firewall traffic](#viewing-web-application-firewall-traffic) - * [JupyterHub](#jupyterhub) - * [Jupyter Git Integration](#jupyter-git-integration) - * [Knative](#knative) - * [Prometheus](#prometheus) - * [Crossplane](#crossplane) - * [Elastic Stack](#elastic-stack) - * [Optional: deploy Kibana to perform advanced queries](#optional-deploy-kibana-to-perform-advanced-queries) - * [Fluentd](#fluentd) - * [Future apps](#future-apps) -* [Install using GitLab CI/CD (alpha)](#install-using-gitlab-cicd-alpha) - * [Usage](#usage) - * [Important notes](#important-notes) - * [Install Ingress using GitLab CI/CD](#install-ingress-using-gitlab-cicd) - * [Install cert-manager using GitLab CI/CD](#install-cert-manager-using-gitlab-cicd) - * [Install Sentry using GitLab CI/CD](#install-sentry-using-gitlab-cicd) - * [Install PostHog using GitLab CI/CD](#install-posthog-using-gitlab-cicd) - * [Install Prometheus using GitLab CI/CD](#install-prometheus-using-gitlab-cicd) - * [Install GitLab Runner using GitLab CI/CD](#install-gitlab-runner-using-gitlab-cicd) - * [Install Cilium using GitLab CI/CD](#install-cilium-using-gitlab-cicd) - * [Install Falco using GitLab CI/CD](#install-falco-using-gitlab-cicd) - * [Install Vault using GitLab CI/CD](#install-vault-using-gitlab-cicd) - * [Install JupyterHub using GitLab CI/CD](#install-jupyterhub-using-gitlab-cicd) - * [Install Elastic Stack using GitLab CI/CD](#install-elastic-stack-using-gitlab-cicd) - * [Install Crossplane using GitLab CI/CD](#install-crossplane-using-gitlab-cicd) - * [Install Fluentd using GitLab CI/CD](#install-fluentd-using-gitlab-cicd) - * [Install Knative using GitLab CI/CD](#install-knative-using-gitlab-cicd) - * [Knative Metrics](#knative-metrics) - * [Uninstall Knative](#uninstall-knative) - * [Install AppArmor using GitLab CI/CD](#install-apparmor-using-gitlab-cicd) - * [Using AppArmor profiles in your deployments](#using-apparmor-profiles-in-your-deployments) -* [Upgrading applications](#upgrading-applications) -* [Uninstalling applications](#uninstalling-applications) -* [Troubleshooting applications](#troubleshooting-applications) - * [Error installing managed apps on EKS cluster](#error-installing-managed-apps-on-eks-cluster) - * [Unable to install Prometheus](#unable-to-install-prometheus) - -# GitLab Managed Apps[](#gitlab-managed-apps "Permalink") - -GitLab 提供**GitLab 托管应用程序** ,一键安装各种应用程序,可以直接将其添加到配置的集群中. - -使用[Auto DevOps](../../topics/autodevops/index.html)时, [Review Apps](../../ci/review_apps/index.html)和[部署](../../ci/environments/index.html)需要这些应用程序. - -您可以在[创建集群](../project/clusters/add_remove_clusters.html)后安装它们. - -## Installing applications[](#installing-applications "Permalink") - -由 GitLab `gitlab-managed-apps`将安装到`gitlab-managed-apps`命名空间中. - -该名称空间: - -* 与用于项目部署的名称空间不同. -* 创建一次. -* 具有不可配置的名称. - -查看可用安装的应用程序列表. 为一个: - -* [项目级集群](../project/clusters/index.html) ,导航到项目的 **运营> Kubernetes** . -* [小组级别的集群](../group/clusters/index.html) ,导航到您小组的 **Kubernetes**页面. - -**注意:**从 GitLab 11.6 开始,Helm 将在安装任何应用程序之前升级到 GitLab 支持的最新版本. - -可以安装以下应用程序: - -* [Helm](#helm) -* [Ingress](#ingress) -* [cert-manager](#cert-manager) -* [Prometheus](#prometheus) -* [GitLab Runner](#gitlab-runner) -* [JupyterHub](#jupyterhub) -* [Knative](#knative) -* [Crossplane](#crossplane) -* [Elastic Stack](#elastic-stack) -* [Fluentd](#fluentd) - -除 Knative 外,这些应用程序将安装在名为`gitlab-managed-apps`的专用命名空间中. - -**注意:**某些应用程序仅可用于项目级集群安装. 计划在将来的发行版中支持在组级群集中安装这些应用程序. 有关更新,请参阅[问题跟踪进度](https://gitlab.com/gitlab-org/gitlab/-/issues/24411) .**注意:**如果您现有的 Kubernetes 集群已安装 Helm,则应谨慎使用,因为 GitLab 无法检测到它. 在这种情况下,通过应用程序安装 Helm 将导致集群对其进行两次配置,这可能导致部署期间的混乱. - -### Helm[](#helm "Permalink") - -版本历史 - -* 在 GitLab 10.2 中针对项目级集群引入. -* 在 GitLab 11.6 中针对组级集群引入. -* 在 GitLab 13.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/209736)了本地 Tiller 选项,该选项在功能标记后(默认情况下启用). -* 在 GitLab.com 上启用了本地 Tiller 的功能标志. - -[Helm](https://helm.sh/docs/)是 Kubernetes 的软件包管理器,用于安装 GitLab 管理的应用程序. GitLab 在集群内`gitlab-managed-apps`命名空间内的 pod 中运行每个`helm`命令. - -从 GitLab 13.2 开始,集成默认使用本地[Tiller](https://v2.helm.sh/docs/glossary/#tiller) . 使用本地 Tiller 时,不需要安装 Helm 应用程序,也不会显示在应用程序列表中. - -**注意:** GitLab 的 Helm 集成不支持在代理后面安装应用程序,但是可以使用一种[解决方法](../../topics/autodevops/index.html#install-applications-behind-a-proxy) . - -### Enable or disable local Tiller[](#enable-or-disable-local-tiller-core-only "Permalink") - -版本历史 - -* 在 GitLab 13.2 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/209736) -* [计划](https://gitlab.com/gitlab-org/gitlab/-/issues/209736)在 GitLab 13.3 中[删除](https://gitlab.com/gitlab-org/gitlab/-/issues/209736)禁用本地 Tiller 的选项 - -本地分 iller 正在开发中,但已准备好用于生产. 它部署在**默认情况下启用**的功能标志的后面. [有权访问 GitLab Rails 控制台的 GitLab 管理员](../../administration/feature_flags.html)可以为您的实例启用它. - -要启用它: - -``` -# Instance-wide -Feature.enable(:managed_apps_local_tiller) -``` - -禁用它: - -``` -# Instance-wide -Feature.disable(:managed_apps_local_tiller) -``` - -### cert-manager[](#cert-manager "Permalink") - -在 GitLab 11.6 中针对项目级和组级集群引入. - -[cert-manager](https://cert-manager.io/docs/)是本地 Kubernetes 证书管理控制器,可帮助颁发证书. 在群集上安装 cert-manager 将通过[Let's Encrypt](https://letsencrypt.org/)颁发证书,并确保证书有效和最新. - -用于安装此应用程序的图表取决于所使用的 GitLab 版本. 在: - -* 在 GitLab 12.3 及更高版本中, [jetstack / cert-manager](https://github.com/jetstack/cert-manager)图表与[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/cert_manager/values.yaml)文件一起使用. -* 在 GitLab 12.2 和更早版本中,使用了[稳定/证书管理器](https://github.com/helm/charts/tree/master/stable/cert-manager)图表. - -如果您在 GitLab 12.3 之前安装了 cert-manager,那么我们加密将[阻止来自较早版本 cert-manager 的请求](https://community.letsencrypt.org/t/blocking-old-cert-manager-versions/98753) . - -要解决此问题: - -1. 卸载 cert-manager(考虑[备份任何其他配置](https://cert-manager.io/docs/tutorials/backup/) ). -2. 再次安装 cert-manager. - -### GitLab Runner[](#gitlab-runner "Permalink") - -版本历史 - -* 在 GitLab 10.6 中针对项目级集群引入. -* 在 GitLab 11.10 中针对组级集群引入. - -[GitLab Runner](https://docs.gitlab.com/runner/)是一个开源项目,用于运行您的作业并将结果发送回 GitLab. 它与[GitLab CI / CD](../../ci/README.html)结合使用, [GitLab CI / CD](../../ci/README.html)是 GitLab 随附的用于协调作业的开源持续集成服务. - -如果该项目在 GitLab.com 上,则可以使用共享的 Runners(前 2000 分钟是免费的,以后您可以[购买更多](../../subscriptions/index.html#purchasing-additional-ci-minutes) ),并且如果它们足以满足您的需求,则不必部署它. 如果需要特定于项目的运行器,或者没有共享的运行器,则部署它很容易. - -请注意,已部署的 Runner 将设置为**privileged** ,这意味着它实际上将具有对基础计算机的 root 访问权限. 这是构建 Docker 映像所必需的,因此它是默认设置. 在部署前,请确保已阅读[安全隐患](../project/clusters/index.html#security-implications) . - -**注意:** [`runner/gitlab-runner`](https://gitlab.com/gitlab-org/charts/gitlab-runner)图表用于使用[预先配置的`values.yaml`](https://gitlab.com/gitlab-org/charts/gitlab-runner/-/blob/master/values.yaml)文件安装此应用程序. 不支持通过修改此文件来自定义安装. - -### Ingress[](#ingress "Permalink") - -版本历史 - -* 在 GitLab 10.2 中针对项目级集群引入. -* 在 GitLab 11.6 中针对组级集群引入. - -[Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/)提供开箱即用的负载平衡,SSL 终止和基于名称的虚拟主机. 它充当应用程序的 Web 代理,如果要使用[Auto DevOps](../../topics/autodevops/index.html)或部署自己的 Web 应用程序,则很有用. - -安装的 Ingress Controller 是[Ingress-NGINX](https://kubernetes.io/docs/concepts/services-networking/ingress/) ,由 Kubernetes 社区支持. - -**注意:**通过以下过程,必须在群集中安装负载均衡器才能获取端点. 如果使用 Knative,则可以使用 Ingress 或 Knative 自己的负载平衡器( [Istio](https://istio.io) ). - -In order to publish your web application, you first need to find the endpoint which will be either an IP address or a hostname associated with your load balancer. - -要安装它,请点击 Ingress 的**安装**按钮. GitLab 将尝试确定外部端点,并且它应在几分钟之内可用. - -#### Determining the external endpoint automatically[](#determining-the-external-endpoint-automatically "Permalink") - -在 GitLab 10.6 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17052) . - -安装 Ingress 之后,外部端点应在几分钟之内可用. - -**提示:**可以使用`KUBE_INGRESS_BASE_DOMAIN`环境变量将此端点用于[Auto DevOps 基础域](../../topics/autodevops/index.html#auto-devops-base-domain) . - -如果没有出现端点,并且您的集群在 Google Kubernetes Engine 上运行: - -1. [在 Google Kubernetes Engine 上](https://console.cloud.google.com/kubernetes)检查您的[Kubernetes 集群,](https://console.cloud.google.com/kubernetes)以确保其节点上没有错误. -2. 确保您在 Google Kubernetes Engine 上有足够的[配额](https://console.cloud.google.com/iam-admin/quotas) . 有关更多信息,请参见[资源配额](https://cloud.google.com/compute/quotas) . -3. 检查[Google Cloud 的状态,](https://status.cloud.google.com/)以确保它们没有任何中断. - -安装后,您可能会看到一个`?` 取决于云提供商的"入口 IP 地址". 特别是对于 EKS,这是因为 ELB 是使用 DNS 名称而不是 IP 地址创建的. 如果 GitLab 仍然无法确定您的 Ingress 或 Knative 应用程序的端点,则可以[手动确定它](#determining-the-external-endpoint-manually) . - -**注意:** [`stable/nginx-ingress`](https://github.com/helm/charts/tree/master/stable/nginx-ingress)图表用于通过[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/ingress/values.yaml)文件安装此应用程序. - -#### Determining the external endpoint manually[](#determining-the-external-endpoint-manually "Permalink") - -如果群集位于 GKE 上,请单击" **高级设置"中**的**Google Kubernetes Engine**链接,或直接转到[Google Kubernetes Engine 仪表板,](https://console.cloud.google.com/kubernetes/)然后选择适当的项目和群集. 然后单击" **连接"** ,然后在本地终端或使用**Cloud Shell**执行`gcloud`命令. - -如果集群不在 GKE 上,请按照 Kubernetes 提供程序的特定说明使用正确的凭据配置`kubectl` . 以下示例的输出将显示集群的外部端点. 然后,可以使用此信息来设置 DNS 条目和转发规则,以允许外部访问已部署的应用程序. - -If you installed Ingress via the **Applications**, run the following command: - -``` -kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}' -``` - -有些 Kubernetes 集群会返回主机名,例如[Amazon EKS](https://aws.amazon.com/eks/) . 对于这些平台,运行: - -``` -kubectl get service --namespace=gitlab-managed-apps ingress-nginx-ingress-controller -o jsonpath='{.status.loadBalancer.ingress[0].hostname}' -``` - -对于 Istio / Knative,命令将有所不同: - -``` -kubectl get svc --namespace=istio-system istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip} ' -``` - -否则,您可以列出所有负载均衡器的 IP 地址: - -``` -kubectl get svc --all-namespaces -o jsonpath='{range.items[?(@.status.loadBalancer.ingress)]}{.status.loadBalancer.ingress[*].ip} ' -``` - -**注意:**如果使用 EKS,还将创建一个[Elastic Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/) ,这将产生额外的 AWS 成本.**注意:**在某些 Kubernetes 版本上,您可能会看到尾随`%` , **但不要包括它** . - -入口现在在此地址可用,并将基于请求中的 DNS 名称将传入请求路由到适当的服务. 为此,应为所需的域名创建通配符 DNS CNAME 记录. 例如, `*.myekscluster.com`将指向之前获得的 Ingress 主机名. - -#### Using a static IP[](#using-a-static-ip "Permalink") - -默认情况下,临时外部 IP 地址与群集的负载平衡器关联. 如果您将临时 IP 与 DNS 关联,并且 IP 更改,则将无法访问您的应用程序,因此您必须再次更改 DNS 记录. 为了避免这种情况,您应该将其更改为静态保留的 IP. - -阅读如何[在 GKE 中提升临时外部 IP 地址](https://cloud.google.com/compute/docs/ip-addresses/reserve-static-external-ip-address#promote_ephemeral_ip) . - -#### Pointing your DNS at the external endpoint[](#pointing-your-dns-at-the-external-endpoint "Permalink") - -设置外部终结点后,应将其与[通配符 DNS 记录(](https://en.wikipedia.org/wiki/Wildcard_DNS_record)例如`*.example.com.`相关联`*.example.com.` 为了能够访问您的应用. 如果您的外部端点是 IP 地址,请使用 A 记录. 如果您的外部端点是主机名,请使用 CNAME 记录. - -#### Web Application Firewall (ModSecurity)[](#web-application-firewall-modsecurity "Permalink") - -在 GitLab 12.7 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21966) . - -Web 应用程序防火墙(WAF)可以检查正在发送或接收的流量,并可以在恶意流量到达您的应用程序之前对其进行阻止. WAF 的好处是: - -* 实时监控您的应用程序 -* 将所有 HTTP 通信记录到应用程序 -* 您的应用程序的访问控制 -* 高度可配置的日志记录和阻止规则 - -开箱即用,GitLab 为您提供了一个称为[`ModSecurity`](https://www.modsecurity.org/)的 WAF. - -ModSecurity 是用于实时 Web 应用程序监视,日志记录和访问控制的工具包. 借助 GitLab 的产品,将自动应用[OWASP 的 Core Rule Set](https://www.modsecurity.org/CRS/Documentation/) (提供通用的攻击检测功能). - -此功能: - -* 除非另有配置,否则以"仅检测模式"运行. -* 通过检查您的 Ingress 控制器的`modsec`日志中是否有违反规则可以查看. 例如: - - ``` - kubectl logs -n gitlab-managed-apps $(kubectl get pod -n gitlab-managed-apps -l app=nginx-ingress,component=controller --no-headers=true -o custom-columns=:metadata.name) modsecurity-log -f - ``` - -要启用 WAF,请在安装或更新[Ingress 应用程序](#ingress)时将其相应的切换开关切换到启用位置. - -如果这是您首次使用 GitLab 的 WAF,我们建议您遵循[快速入门指南](../../topics/web_application_firewall/quick_start_guide.html) . - -通过启用 ModSecurity,性能开销很小. 如果这对于您的应用程序而言很重要,则可以通过以下任何一种方式为已部署的应用程序禁用 ModSecurity 的规则引擎: - -1. Setting [the deployment variable](../../topics/autodevops/index.html) `AUTO_DEVOPS_MODSECURITY_SEC_RULE_ENGINE` to `Off`. This will prevent ModSecurity from processing any requests for the given application or environment. - -2. 将其各自的切换开关切换到禁用位置,然后通过" **保存更改"**按钮应用更改. 这将使用最新更改重新安装 Ingress. - -[![Disabling WAF](img/74f87e79779a102e82a644227e50a2e4.png)](../../topics/web_application_firewall/img/guide_waf_ingress_save_changes_v12_10.png) - -##### Logging and blocking modes[](#logging-and-blocking-modes "Permalink") - -为了帮助您调整 WAF 规则,可以将 WAF 全局设置为" **日志记录"**或" **阻止"**模式: - -* **日志记录模式** -允许符合规则的流量通过并记录事件. -* **阻止模式** -阻止符合规则的流量通过,并记录事件. - -更改 WAF 的模式: - -1. 如果尚未[安装 ModSecurity](../../topics/web_application_firewall/quick_start_guide.html) ,请[安装它](../../topics/web_application_firewall/quick_start_guide.html) . -2. 导航 **运营>州长** . -3. In **Applications**, scroll to **Ingress**. -4. 在" **全局默认值"下** ,选择所需的模式. -5. Click **保存更改**. - -##### WAF version updates[](#waf-version-updates "Permalink") - -由于[Helm 的](https://helm.sh/)限制,在以后的发行版中可能会克服这些问题,因此仅在同一版本的[Ingress 中](#ingress)才允许启用,禁用或更改**ModSecurity**的日志记录模式. - -如果所部署的版本与 GitLab 中可用的版本不同,则将禁用**ModSecurity** UI 控件,而仍可以执行[Ingress](#ingress)级别的操作,例如卸载: - -[![WAF settings disabled](img/27858125d0f3461e373b06413f40e616.png)](../../topics/web_application_firewall/img/guide_waf_ingress_disabled_settings_v12_10.png) - -将[Ingress](#ingress)更新到最新版本使您能够利用错误修复,安全修复和性能改进. 要更新[Ingress 应用程序](#ingress) ,您必须首先将其卸载,然后按照[Install ModSecurity 中的说明](../../topics/web_application_firewall/quick_start_guide.html)进行重新[安装](../../topics/web_application_firewall/quick_start_guide.html) . - -##### Viewing Web Application Firewall traffic[](#viewing-web-application-firewall-traffic "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14707) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.9. - -您可以通过导航到项目的" **安全性和合规性">"威胁监视"**页面来查看 Web 应用程序防火墙的流量. - -从那里,您可以看到随着时间的推移进行跟踪: - -* 您的应用程序的总流量. -* Web 应用程序防火墙的默认[OWASP 规则集](https://www.modsecurity.org/CRS/Documentation/)认为异常的流量比例. - -如果很大一部分流量是异常的,则应[检查](#web-application-firewall-modsecurity)潜在的威胁,这可以通过[检查 Web 应用程序防火墙日志](#web-application-firewall-modsecurity)来完成. - -[![Threat Monitoring](img/a3964b6d91003c90a72b5ca689b9e0c5.png)](img/threat_monitoring_v12_9.png) - -### JupyterHub[](#jupyterhub "Permalink") - -版本历史 - -* 在 GitLab 11.0 中针对项目级集群引入. -* 在 GitLab 12.3 中针对组和实例级集群引入. - -[JupyterHub](https://jupyterhub.readthedocs.io/en/stable/)是用于在团队中管理笔记本的多用户服务. [Jupyter Notebook](https://jupyter-notebook.readthedocs.io/en/latest/)提供了一个基于 Web 的交互式编程环境,用于数据分析,可视化和机器学习. - -Authentication will be enabled only for [project members](../project/members/index.html) for project-level clusters and group members for group-level clusters with [Developer or higher](../permissions.html) access to the associated project or group. - -我们使用一个[自定义的 Jupyter 映像](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) ,该[映像](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile)将在基础 Jupyter 之上安装其他有用的软件包. 您还将看到使用 Nurtch 的[Rubix 库](https://github.com/Nurtch/rubix)构建的即用型 DevOps Runbook. - -有关创建可执行运行本的更多信息,请参见[我们的运行本文档](../project/clusters/runbooks/index.html#configure-an-executable-runbook-with-gitlab) . 请注意,必须先安装 Ingress 并分配 IP 地址,然后才能安装 JupyterHub. - -**注意:** [`jupyter/jupyterhub`](https://jupyterhub.github.io/helm-chart/)图表用于通过[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/jupyter/values.yaml)文件安装此应用程序. - -#### Jupyter Git Integration[](#jupyter-git-integration "Permalink") - -版本历史 - -* 在 GitLab 12.0 中针对项目级集群[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/28783) . -* 在 GitLab 12.3 中针对组和实例级集群[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/32512) . - -将 JupyterHub 安装到 Kubernetes 集群上时,将使用已验证用户的身份自动配置和配置[JupyterLab 的 Git 扩展](https://github.com/jupyterlab/jupyterlab-git) : - -* Name. -* Email. -* 新创建的访问令牌. - -JupyterLab 的 Git 扩展使您能够对笔记本进行完整版本控制,并在 Jupyter 中发布 Git 命令. Git 命令可以通过左侧面板上的**Git**选项卡或 Jupyter 的命令行提示符发出. - -**注意:** JupyterLab 的 Git 扩展将用户令牌以加密格式存储在 JupyterHub DB 中,并以纯文本形式存储在单个用户 Jupyter 实例中. 这是因为[Git 要求将凭据存储为纯文本](https://git-scm.com/docs/git-credential-store) . 潜在地,如果一个邪恶的用户在单用户 Jupyter 实例中找到一种从文件系统读取的方法,则他们可以检索令牌. - -[![Jupyter's Git Extension](img/993315f2d7b2aa15b2f3faa03d14705c.png)](img/jupyter-git-extension.gif) - -您可以从 Jupyter 的"文件"选项卡中克隆存储库: - -[![Jupyter clone repository](img/bed33522d3ca08c8f5c920ba11fa05d4.png)](img/jupyter-gitclone.png) - -### Knative[](#knative "Permalink") - -版本历史 - -* 在 GitLab 11.5 中针对项目级集群引入. -* 在 GitLab 12.3 中针对组和实例级集群引入. - -[Knative](https://cloud.google.com/knative/)提供了一个平台,用于从 Kubernetes 集群创建,部署和管理无服务器工作负载. 它与[Istio](https://istio.io)结合使用并包括在内, [以为 Knative](https://istio.io)托管的所有程序提供外部 IP 地址. - -系统将提示您输入一个通配符域,您的应用程序将在该域中公开. 配置您的 DNS 服务器以使用该域的外部 IP 地址. 对于创建和安装的任何应用程序,可以通过`..` . 这将要求您的 Kubernetes 群集[启用 RBAC](../project/clusters/add_remove_clusters.html#rbac-cluster-resources) . - -**Note:** The [`knative/knative`](https://storage.googleapis.com/triggermesh-charts) chart is used to install this application. - -### Prometheus[](#prometheus "Permalink") - -版本历史 - -* 在 GitLab 10.4 中针对项目级集群引入. -* 在 GitLab 11.11 中针对组级集群引入. - -[Prometheus](https://s0prometheus0io.icopy.site/docs/introduction/overview/)是一个开源监视和警报系统,可用于监督已部署的应用程序. - -GitLab 能够使用[Prometheus 集成](../project/integrations/prometheus.html)自动监视应用程序. Kubernetes 容器的 CPU 和内存指标将自动收集,响应指标也将从 NGINX Ingress 检索. - -要启用监视,只需使用" **安装"**按钮将 Prometheus 安装到群集中. - -**注意:** [`stable/prometheus`](https://github.com/helm/charts/tree/master/stable/prometheus)图表用于通过[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/prometheus/values.yaml)文件安装此应用程序. - -### Crossplane[](#crossplane "Permalink") - -版本历史 - -* 在 GitLab 12.5 中针对项目级集群[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/34702) . - -[Crossplane](https://crossplane.github.io/docs/v0.9/)是一种多云控制平面,可用于跨多个云管理应用程序和基础架构. 它使用以下方法扩展了 Kubernetes API: - -* 自定义资源. -* 监视那些自定义资源的控制器. - -Crossplane 通过抽象特定于云提供商的配置,以统一的方式允许跨云提供商进行基础架构组件的供应和生命周期管理. - -Crossplane GitLab 管理的应用程序: - -* 在连接到项目存储库的 Kubernetes 集群上使用选择的提供程序安装 Crossplane. -* 然后可以用于通过 Auto DevOps 管道来配置基础结构或托管应用程序,例如 PostgreSQL(例如,来自 GCP 的 CloudSQL 或来自 AWS 的 RDS)以及该应用程序所需的其他服务. - -有关配置群集上安装的 Crossplane 的信息,请参阅[Crossplane 配置](crossplane.html) . - -**注意:** [`alpha/crossplane`](https://github.com/crossplane/crossplane/tree/v0.4.1/cluster/charts/crossplane) crossplane 图表 v0.4.1 用于通过[`values.yaml`](https://github.com/crossplane/crossplane/blob/master/cluster/charts/crossplane/values.yaml.tmpl)文件安装 Crossplane. - -### Elastic Stack[](#elastic-stack "Permalink") - -在 GitLab 12.7 中针对项目级和组级集群引入. - -[Elastic Stack](https://www.elastic.co/elastic-stack)是一个完整的端到端日志分析解决方案,可帮助深入搜索,分析和可视化从不同计算机生成的日志. - -GitLab 能够自动从集群中的 Pod 收集日志. Filebeat 将在集群中的每个节点上作为 DaemonSet 运行,并将容器日志发送到 Elasticsearch 进行查询. 然后,GitLab 将连接到 Elasticsearch 以获取日志而不是 Kubernetes API,您将可以使用更高级的查询功能. - -使用[Curator](https://www.elastic.co/guide/en/elasticsearch/client/curator/5.5/about.html)在 30 天后会自动删除日志数据. - -要启用日志传送: - -1. 确保您的集群至少包含 3 个实例类型大于`f1-micro` , `g1-small`或`n1-standard-1`节点. -2. 导航 **运营>州长** . -3. 在**Kubernetes Cluster 中** ,选择一个集群. -4. 在" **应用程序"**部分中,找到" **Elastic Stack"** ,然后单击" **安装"** . - -**注意:** [`gitlab/elastic-stack`](https://gitlab.com/gitlab-org/charts/elastic-stack)图用于通过[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/elastic_stack/values.yaml)文件安装此应用程序.**注意:**该图表部署了 3 个相同的 Elasticsearch Pod,这些 Pod 无法共置,每个 Pod 需要 1 个 CPU 和 2 GB RAM,从而使其与包含少于 3 个节点或由`f1-micro` , `g1-small` , `n1-standard-1`组成的集群不兼容`n1-standard-1`或`*-highcpu-2`实例类型.**注意:** Elastic Stack 群集应用程序旨在用作日志聚合解决方案,并且与我们的[Advanced Global Search](../search/advanced_global_search.html)功能无关,后者使用单独的 Elasticsearch 群集. - -#### Optional: deploy Kibana to perform advanced queries[](#optional-deploy-kibana-to-perform-advanced-queries "Permalink") - -如果您是高级用户,并且可以使用`kubectl`和`helm`直接访问 Kubernetes 集群,则可以手动部署 Kibana. - -下面假设`helm`已经[初始化](https://v2.helm.sh/docs/helm/)与`helm init` . - -将以下内容保存到`kibana.yml` : - -``` -elasticsearch: - enabled: false - -filebeat: - enabled: false - -kibana: - enabled: true - elasticsearchHosts: http://elastic-stack-elasticsearch-master.gitlab-managed-apps.svc.cluster.local:9200 -``` - -然后将其安装在您的集群上: - -``` -helm repo add gitlab https://charts.gitlab.io -helm install --name kibana gitlab/elastic-stack --values kibana.yml -``` - -要访问 Kibana,请将端口转发到本地计算机: - -``` -kubectl port-forward svc/kibana-kibana 5601:5601 -``` - -然后,您可以通过`http://localhost:5601`访问 Kibana. - -### Fluentd[](#fluentd "Permalink") - -在 GitLab 12.10 中针对项目级和组级集群引入. - -[Fluentd](https://www.fluentd.org/)是一个开源数据收集器,它使您能够统一数据收集和使用以更好地使用和理解数据. Fluentd 以 syslog 格式发送日志. - -To enable Fluentd: - -1. 导航 **操作> Kubernetes** ,然后单击**应用程序** . 系统将提示您输入主机,端口和协议,WAF 日志将通过 syslog 发送到该主机,端口和协议. -2. 在**SIEM Hostname 中**提供主机域名或 URL. -3. 在**SIEM Port 中**提供主机端口号. -4. 选择一个**SIEM 协议** . -5. 选择至少一个可用日志(例如 WAF 或 Cilium). -6. Click **保存更改**. - -[![Fluentd input fields](img/f52fe1b4788045a510a1783bfb546b6f.png)](img/fluentd_v13_0.png) - -### Future apps[](#future-apps "Permalink") - -有兴趣贡献一个新的 GitLab 托管应用程序吗? 访问[开发指南页面](../../development/kubernetes.html#gitlab-managed-apps)以开始使用. - -## Install using GitLab CI/CD (alpha)[](#install-using-gitlab-cicd-alpha "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20822) in GitLab 12.6. - -**警告:**这是*Alpha 版*功能,如有更改,恕不另行通知. - -这种替代方法允许用户使用 GitLab CI / CD 安装由 GitLab 管理的应用程序. 它还允许使用 Helm `values.yaml`文件来自定义安装. - -支持的应用程序: - -* [Ingress](#install-ingress-using-gitlab-cicd) -* [cert-manager](#install-cert-manager-using-gitlab-cicd) -* [Sentry](#install-sentry-using-gitlab-cicd) -* [GitLab Runner](#install-gitlab-runner-using-gitlab-cicd) -* [Cilium](#install-cilium-using-gitlab-cicd) -* [Falco](#install-falco-using-gitlab-cicd) -* [Vault](#install-vault-using-gitlab-cicd) -* [JupyterHub](#install-jupyterhub-using-gitlab-cicd) -* [Elastic Stack](#install-elastic-stack-using-gitlab-cicd) -* [Crossplane](#install-crossplane-using-gitlab-cicd) -* [Fluentd](#install-fluentd-using-gitlab-cicd) -* [Knative](#install-knative-using-gitlab-cicd) -* [PostHog](#install-posthog-using-gitlab-cicd) -* [Prometheus](#install-prometheus-using-gitlab-cicd) - -### Usage[](#usage "Permalink") - -您可以在[示例集群应用程序项目中](https://gitlab.com/gitlab-org/cluster-integration/example-cluster-applications/)找到并导入下面引用的所有文件. - -要使用 GitLab CI / CD 安装应用程序: - -1. 将集群连接到[集群管理项目](management_project.html) . -2. 在该项目中,添加具有以下内容的`.gitlab-ci.yml`文件: - - ``` - include: - - template: Managed-Cluster-Applications.gitlab-ci.yml - ``` - - **注意:**此模板提供的作业使用自定义 Docker 映像中提供的工具连接到集群. 它要求您具有在 Docker,Kubernetes 或 Docker Machine 执行器上注册的运行程序. -3. 添加`.gitlab/managed-apps/config.yaml`文件,以定义要安装的应用程序. 将已`installed`密钥定义为`true`以安装应用程序,将`false`为卸载应用程序. 例如,要安装 Ingress: - - ``` - ingress: - installed: true - ``` - -4. (可选)定义`.gitlab/managed-apps//values.yaml`文件,以自定义已安装应用程序的值. - -然后,一个 GitLab CI / CD 管道将在`master`分支上运行,以安装您配置的应用程序. 万一管道发生故障, [Helm Tiller](https://v2.helm.sh/docs/install/#running-tiller-locally)二进制文件的输出将另存为[CI 作业工件](../../ci/pipelines/job_artifacts.html) . - -### Important notes[](#important-notes "Permalink") - -请注意以下几点: - -* 我们建议仅使用集群管理项目来管理集群的部署. 不要将应用程序的源代码添加到此类项目中. -* 当您将`installed`密钥的值`installed`回`false` ,将从群集中取消配置该应用程序. -* 如果使用新值更新`.gitlab/managed-apps//values.yaml` ,则将重新部署该应用程序. - -### Install Ingress using GitLab CI/CD[](#install-ingress-using-gitlab-cicd "Permalink") - -要安装 Ingress,请使用以下命令定义`.gitlab/managed-apps/config.yaml`文件: - -``` -ingress: - installed: true -``` - -然后,Ingress 将安装到集群的`gitlab-managed-apps`命名空间中. - -You can customize the installation of Ingress by defining a `.gitlab/managed-apps/ingress/values.yaml` file in your cluster management project. Refer to the [chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress) for the available configuration options. - -**注意:** GitLab 配置组提供了对安装 Ingress 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从[Configure 组中](https://about.gitlab.com/handbook/product/categories/#configure-group) ping 通至少 2 个人. - -### Install cert-manager using GitLab CI/CD[](#install-cert-manager-using-gitlab-cicd "Permalink") - -通过在`.gitlab/managed-apps/config.yaml`定义配置,使用 GitLab CI / CD 安装了 cert-manager. - -cert-manager: - -* 已安装到集群的`gitlab-managed-apps`命名空间中. -* Can be installed with or without a default [Let’s Encrypt `ClusterIssuer`](https://cert-manager.io/docs/configuration/acme/), which requires an email address to be specified. The email address is used by Let’s Encrypt to contact you about expiring certificates and issues related to your account. - -使用 GitLab CI / CD 安装证书管理器需要以下配置: - -``` -certManager: - installed: true - letsEncryptClusterIssuer: - installed: true - email: "user@example.com" -``` - -以下使用 GitLab CI / CD 安装 cert-manager,而没有默认的`ClusterIssuer` : - -``` -certManager: - installed: true - letsEncryptClusterIssuer: - installed: false -``` - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/cert-manager/values.yaml`文件来自定义 cert-manager 的安装. 请参阅[图表](https://hub.helm.sh/charts/jetstack/cert-manager)以获取可用的配置选项. - -**注意:** GitLab 配置组提供了对安装 Cert Manager 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从[Configure 组中](https://about.gitlab.com/handbook/product/categories/#configure-group) ping 通至少 2 个人. - -### Install Sentry using GitLab CI/CD[](#install-sentry-using-gitlab-cicd "Permalink") - -**注意:** Sentry Helm 图表[建议](https://github.com/helm/charts/blob/f6e5784f265dd459c5a77430185d0302ed372665/stable/sentry/values.yaml#L284-L285)至少 3GB 的可用 RAM 用于数据库迁移. - -To install Sentry, define the `.gitlab/managed-apps/config.yaml` file with: - -``` -sentry: - installed: true -``` - -然后,将 Sentry 安装到集群的`gitlab-managed-apps`命名空间中. - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/sentry/values.yaml`文件来自定义 Sentry 的安装. 请参阅[图表](https://github.com/helm/charts/tree/master/stable/sentry)以获取可用的配置选项. - -我们建议您密切注意以下配置选项: - -* `email` . 需要邀请用户加入您的 Sentry 实例并发送错误电子邮件. -* `user` . 您可以在其中设置默认管理员用户的登录凭据. -* `postgresql` . 有关在将来运行更新时可以使用的 PostgreSQL 密码. - -**注意:**升级时,重要的是提供现有的 PostgreSQL 密码(使用`postgresql.postgresqlPassword`密钥提供),否则您将收到认证错误. 有关更多信息,请参见[PostgreSQL 图表文档](https://github.com/helm/charts/tree/master/stable/postgresql#upgrade) . - -这是 Sentry 的示例配置: - -``` -# Admin user to create -user: - # Indicated to create the admin user or not, - # Default is true as the initial installation. - create: true - email: "" - password: "" - -email: - from_address: "" - host: smtp - port: 25 - use_tls: false - user: "" - password: "" - enable_replies: false - -ingress: - enabled: true - hostname: "" - -# Needs to be here between runs. -# See https://github.com/helm/charts/tree/master/stable/postgresql#upgrade for more info -postgresql: - postgresqlPassword: example-postgresql-password -``` - -**注意:** GitLab Health 组为安装 Sentry 托管应用程序提供支持. 如果您遇到未知问题,请[打开一个新的问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从[健康小组](https://about.gitlab.com/handbook/product/product-categories/#health-group) ping 至少 2 个人. - -### Install PostHog using GitLab CI/CD[](#install-posthog-using-gitlab-cicd "Permalink") - -[PostHog](https://www.posthog.com)是开发人员友好的开源产品分析平台. - -要将 PostHog 安装到群集的`gitlab-managed-apps`命名空间中,请使用以下`.gitlab/managed-apps/config.yaml`定义`.gitlab/managed-apps/config.yaml`文件: - -``` -posthog: - installed: true -``` - -您可以通过在群集管理项目中定义`.gitlab/managed-apps/posthog/values.yaml`来自定义`.gitlab/managed-apps/posthog/values.yaml`的安装. 有关可用的配置选项,请参阅[PostHog 图表的自述文件](https://github.com/PostHog/charts/tree/master/charts/posthog)的" [配置"部分](https://github.com/PostHog/charts/tree/master/charts/posthog) . - -**注意:**您必须在`postgresql.postgresqlPassword`提供 PostgreSQL 密码,否则将收到身份验证错误. 有关更多信息,请参见[PostgreSQL 图表文档](https://github.com/helm/charts/tree/master/stable/postgresql#upgrade) . - -Redis Pod 在升级之间重新启动. 为防止停机,请使用`redis.password`键提供 Redis 密码. 这样可以防止在每次重新启动时生成新密码. - -这是 PostHog 的示例配置: - -``` -ingress: - enabled: true - hostname: "" - -# This will be autogenerated if you skip it. Include if you have 2 or more web replicas -posthogSecret: 'long-secret-key-used-to-sign-cookies' - -# Needs to be here between runs. -# See https://github.com/helm/charts/tree/master/stable/postgresql#upgrade for more info -postgresql: - postgresqlPassword: example-postgresql-password - -# Recommended to set this to a value to redis prevent downtime between upgrades -redis: - password: example-redis-password -``` - -**注意:** PostHog 团队对 PostHog 托管应用程序提供支持. 如果遇到问题,请直接[打开支持凭单](https://github.com/PostHog/posthog/issues/new/choose) . - -### Install Prometheus using GitLab CI/CD[](#install-prometheus-using-gitlab-cicd "Permalink") - -在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25138) . - -[Prometheus](https://s0prometheus0io.icopy.site/docs/introduction/overview/)是用于监视已部署应用程序的开源监视和警报系统. - -要将 Prometheus 安装到群集的`gitlab-managed-apps`命名空间中,请使用以下`.gitlab/managed-apps/config.yaml`定义`.gitlab/managed-apps/config.yaml`文件: - -``` -prometheus: - installed: true -``` - -您可以通过在群集管理项目中定义`.gitlab/managed-apps/prometheus/values.yaml`来定制 Prometheus 的安装. 有关可用的配置选项,请参阅[Prometheus 图的 README](https://github.com/helm/charts/tree/master/stable/prometheus#configuration)的[Configuration(配置)部分](https://github.com/helm/charts/tree/master/stable/prometheus#configuration) . - -**注意:** GitLab APM 组提供了对安装 Prometheus 托管应用程序的支持. 如果遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping [APM 组中的](https://about.gitlab.com/handbook/product/product-categories/#apm-group)至少 2 个人. - -### Install GitLab Runner using GitLab CI/CD[](#install-gitlab-runner-using-gitlab-cicd "Permalink") - -通过在`.gitlab/managed-apps/config.yaml`定义配置,使用 GitLab CI / CD 安装了 GitLab Runner. - -使用 GitLab CI / CD 安装 GitLab Runner 需要以下配置: - -``` -gitlabRunner: - installed: true -``` - -GitLab Runner 已安装到集群的`gitlab-managed-apps`命名空间中. - -为了使 GitLab Runner 运行, **必须**指定以下内容: - -* `gitlabUrl`用于注册 Runner 的 GitLab 服务器完整 URL(例如, `https://example.gitlab.com` `gitlabUrl` ). -* `runnerRegistrationToken`用于将新的`runnerRegistrationToken`添加到 GitLab 的注册令牌. 这必须[从您的 GitLab 实例中检索](../../ci/runners/README.html) . - -这些值可以使用[CI 变量](../../ci/variables/README.html)指定: - -* `GITLAB_RUNNER_GITLAB_URL`将用于`gitlabUrl` . -* `GITLAB_RUNNER_REGISTRATION_TOKEN`将用于`runnerRegistrationToken` - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/gitlab-runner/values.yaml`文件来自定义 GitLab Runner 的安装. 请参阅[图表](https://gitlab.com/gitlab-org/charts/gitlab-runner)以获取可用的配置选项. - -**注意:** GitLab Runner 组提供了对安装 Runner 管理的应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping [Runner 组中的](https://about.gitlab.com/handbook/product/product-categories/#runner-group)至少 2 个人. - -### Install Cilium using GitLab CI/CD[](#install-cilium-using-gitlab-cicd "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/22) in GitLab 12.8. - -[Cilium](https://cilium.io/)是[Kubernetes](https://cilium.io/)的网络插件,可用于实现对[NetworkPolicy](https://kubernetes.io/docs/concepts/services-networking/network-policies/)资源的支持. 有关更多信息,请参阅[网络策略](../../topics/autodevops/stages.html#network-policy) . - -有关概述,请参见[GitLab 12.8](https://www.youtube.com/watch?v=pgUEdhdhoUI)的[容器网络安全演示](https://www.youtube.com/watch?v=pgUEdhdhoUI) . - -在`.gitlab/managed-apps/config.yaml`文件中启用 Cilium 进行安装: - -``` -# possible values are gke, eks or you can leave it blank -clusterType: gke - -cilium: - installed: true -``` - -`clusterType`变量为相应的群集类型启用建议的 Helm 变量. 默认值为空白. 您可以在官方文档中检查每种群集类型的建议变量: - -* [Google GKE](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-gke/#deploy-cilium) -* [AWS EKS](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-eks/#deploy-cilium) - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/cilium/values.yaml`文件来自定义 Cilium 的 Helm 变量. 有关可用的配置选项,请参阅[Cilium 图表](https://github.com/cilium/cilium/tree/master/install/kubernetes/cilium) . - -**注意:**安装和拆卸纤毛的需要**手动** [重新启动](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-gke/#restart-unmanaged-pods)在所有命名空间所有受影响的吊舱,以确保它们[管理](https://docs.cilium.io/en/stable/troubleshooting/#ensure-pod-is-managed-by-cilium)由正确的网络插件.**注意:**主要升级可能需要其他设置步骤,请查阅官方[升级指南](https://docs.cilium.io/en/stable/install/upgrade/)以获取更多信息. - -默认情况下,Cilium 会在策略部署时丢弃所有不允许的数据包. 但是,在[auditmode](https://docs.cilium.io/en/v1.8/gettingstarted/policy-creation/?highlight=policy-audit#enable-policy-audit-mode)中,Cilium 不会丢弃不允许的数据包. 您可以使用`policy-verdict`日志来观察与策略相关的决策. 您可以通过将以下内容添加到`.gitlab/managed-apps/cilium/values.yaml`来启用审核模式: - -``` -config: - policyAuditMode: true - -agent: - monitor: - eventTypes: ["drop", "policy-verdict"] -``` - -用于流量的 Cilium 监视器日志由`cilium-monitor`边车容器注销. 您可以使用以下命令检查这些日志: - -``` -kubectl -n gitlab-managed-apps logs cilium-XXXX cilium-monitor -``` - -您可以在`.gitlab/managed-apps/cilium/values.yaml`禁用监视器日志: - -``` -agent: - monitor: - enabled: false -``` - -默认情况下,启用了[Hubble](https://github.com/cilium/hubble)监视守护程序,并将其设置为收集每个命名空间流指标. 可在" [威胁监控"](../application_security/threat_monitoring/index.html)仪表板上访问此指标. 您可以通过将以下内容添加到`.gitlab/managed-apps/cilium/values.yaml`来禁用 Hubble: - -``` -global: - hubble: - enabled: false -``` - -您还可以通过`.gitlab/managed-apps/cilium/values.yaml`来为哈勃调整 Helm 值: - -``` -global: - hubble: - enabled: true - metrics: - enabled: - - 'flow:sourceContext=namespace;destinationContext=namespace' -``` - -**注意:** GitLab Container Security 组提供了对安装 Cilium 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping 通至少来自[Container Security 组的](https://about.gitlab.com/handbook/product/product-categories/#container-security-group) 2 个人. - -### Install Falco using GitLab CI/CD[](#install-falco-using-gitlab-cicd "Permalink") - -在 GitLab 13.1 中[引入](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/91) . - -GitLab 容器主机安全监视使用[Falco](https://falco.org/)作为运行时安全工具,该工具使用 eBPF 侦听 Linux 内核. Falco 实时解析系统调用并针对可配置的规则引擎声明流. 有关更多信息,请参见[Falco 的文档](https://falco.org/docs/) . - -您可以在`.gitlab/managed-apps/config.yaml`文件中启用 Falco: - -``` -falco: - installed: true -``` - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/falco/values.yaml`文件来自定义 Falco 的 Helm 变量. 有关可用的配置选项,请参考[Falco 图表](https://github.com/falcosecurity/charts/tree/master/falco) . - -**警告:**默认情况下,eBPF 支持已启用,Falco 将使用[eBPF 探针](https://falco.org/docs/event-sources/drivers/#using-the-ebpf-probe)将系统调用传递到用户空间. 如果您的群集不支持此功能,则可以通过将以下内容添加到`.gitlab/managed-apps/falco/values.yaml` ,将其配置为使用 Falco 内核模块: - -``` -ebpf: - enabled: false -``` - -在极少数情况下,无法在群集上自动安装探针并且未预编译内核/探针,您可能需要手动准备带有[driverkit](https://github.com/falcosecurity/driverkit#against-a-kubernetes-cluster)的内核模块或 eBPF 探针,并将其安装在每个群集节点上. - -默认情况下,Falco 部署的规则有限. 要添加更多规则,请将以下内容添加到`.gitlab/managed-apps/falco/values.yaml` (您可以从[Cloud Native Security Hub 中](https://securityhub.dev/)获取示例): - -``` -customRules: - file-integrity.yaml: |- - - rule: Detect New File - desc: detect new file created - condition: > - evt.type = chmod or evt.type = fchmod - output: > - File below a known directory opened for writing (user=%user.name - command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2]) - priority: ERROR - tags: [filesystem] - - rule: Detect New Directory - desc: detect new directory created - condition: > - mkdir - output: > - File below a known directory opened for writing (user=%user.name - command=%proc.cmdline file=%fd.name parent=%proc.pname pcmdline=%proc.pcmdline gparent=%proc.aname[2]) - priority: ERROR - tags: [filesystem] -``` - -默认情况下,Falco 仅将安全事件作为 JSON 对象输出到日志. 要将其设置为输出到[外部 API](https://falco.org/docs/alerts/#https-output-send-alerts-to-an-https-end-point)或[应用程序](https://falco.org/docs/alerts/#program-output) ,请将以下内容添加到`.gitlab/managed-apps/falco/values.yaml` : - -``` -falco: - programOutput: - enabled: true - keepAlive: false - program: mail -s "Falco Notification" someone@example.com - - httpOutput: - enabled: true - url: http://some.url -``` - -您可以使用以下命令检查这些日志: - -``` -kubectl logs -l app=falco -n gitlab-managed-apps -``` - -**注意:** GitLab Container Security 组提供了对安装 Falco 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping 通至少来自[Container Security 组的](https://about.gitlab.com/handbook/product/product-categories/#container-security-group) 2 个人. - -### Install Vault using GitLab CI/CD[](#install-vault-using-gitlab-cicd "Permalink") - -在 GitLab 12.9 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/9982) . - -[Hashicorp Vault](https://www.vaultproject.io/)是一个秘密管理解决方案,可用于安全地管理和存储密码,凭据,证书等. 可以利用 Vault 安装为应用程序,GitLab CI / CD 作业等中使用的凭据提供一个安全的数据存储. 它还可以用作向基础结构中的系统和部署提供 SSL / TLS 证书的方式. 通过将 Vault 作为所有这些凭据的单一来源,可以通过对所有敏感凭据和证书具有单一的访问,控制和可审核性来源,从而提高安全性. - -To install Vault, enable it in the `.gitlab/managed-apps/config.yaml` file: - -``` -vault: - installed: true -``` - -默认情况下,您将获得基本的保险柜设置,没有可扩展的存储后端. 这对于简单的测试和小规模部署就足够了,尽管限制了它可以扩展的规模,并且由于它是单实例部署,因此在升级 Vault 应用程序时会遇到停机时间. - -为了在生产环境中最佳地使用 Vault,理想的是充分了解 Vault 的内部结构以及如何配置它. 这可以通过阅读[Vault 文档](https://www.vaultproject.io/docs/internals)以及 Vault Helm 图表[`values.yaml`文件来完成](https://github.com/hashicorp/vault-helm/blob/v0.3.3/values.yaml) . - -至少您可能会设置: - -* 用于对主密钥进行额外加密的[印章](https://www.vaultproject.io/docs/configuration/seal) . -* 适合于环境和存储安全性要求的[存储后端](https://www.vaultproject.io/docs/configuration/storage) . -* [HA Mode](https://www.vaultproject.io/docs/concepts/ha). -* [The Vault UI](https://www.vaultproject.io/docs/configuration/ui). - -以下是一个示例值文件( `.gitlab/managed-apps/vault/values.yaml` ),该文件使用 Google Cloud Storage 后端,启用 Vault UI 并启用具有 3 个 pod 的 HA,将 Google 密钥管理服务配置为自动`.gitlab/managed-apps/vault/values.yaml`副本. 下面的`storage`和`seal`节是示例,应替换为特定于您的环境的设置. - -``` -# Enable the Vault WebUI -ui: - enabled: true -server: - # Disable the built in data storage volume as it's not safe for Hight Availability mode - dataStorage: - enabled: false - # Enable High Availability Mode - ha: - enabled: true - # Configure Vault to listen on port 8200 for normal traffic and port 8201 for inter-cluster traffic - config: | - listener "tcp" { - tls_disable = 1 - address = "[::]:8200" - cluster_address = "[::]:8201" - } - # Configure Vault to store its data in a GCS Bucket backend - storage "gcs" { - path = "gcs://my-vault-storage/vault-bucket" - ha_enabled = "true" - } - # Configure Vault to automatically unseal storage using a GKMS key - seal "gcpckms" { - project = "vault-helm-dev-246514" - region = "global" - key_ring = "vault-helm-unseal-kr" - crypto_key = "vault-helm-unseal-key" - } -``` - -成功安装保险柜后,您将需要[初始化保险柜](https://learn.hashicorp.com/vault/getting-started/deploy#initializing-the-vault)并获取初始根令牌. 为此,您将需要访问已将 Vault 部署到的 Kubernetes 群集. 要初始化 Vault,请在 Kubernetes 内部运行的一个 Vault 容器中安装一个外壳(通常是通过使用`kubectl`命令行工具来完成). 将外壳放入吊舱后,运行`vault operator init`命令: - -``` -kubectl -n gitlab-managed-apps exec -it vault-0 sh -/ $ vault operator init -``` - -这应该为您提供解封密钥和初始根令牌. 确保记下这些内容并保持安全,因为您将需要它们在保险柜的整个生命周期内将其解封. - -**注意:** GitLab 版本管理组提供了对安装 Vault 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从" [发行管理"组](https://about.gitlab.com/handbook/product/product-categories/#release-management-group) ping 至少 2 个人. - -### Install JupyterHub using GitLab CI/CD[](#install-jupyterhub-using-gitlab-cicd "Permalink") - -在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/40) . - -通过在`.gitlab/managed-apps/config.yaml`定义配置,使用 GitLab CI / CD 安装`.gitlab/managed-apps/config.yaml` ,如下所示: - -``` -jupyterhub: - installed: true - gitlabProjectIdWhitelist: [] - gitlabGroupWhitelist: [] -``` - -在配置中: - -* `gitlabProjectIdWhitelist`将 GitLab 身份验证限制为仅指定项目的成员. -* `gitlabGroupWhitelist`将 GitLab 身份验证限制为仅指定组的成员. -* 为两者指定一个空数组将允许 GitLab 实例上的任何用户登录. - -JupyterHub 已安装到集群的`gitlab-managed-apps`命名空间中. - -为了使 JupyterHub 正常运行,您必须设置一个[OAuth 应用程序](../../integration/oauth_provider.html) . 组: - -* “Redirect URI” to `http:///hub/oauth_callback`. -* `api read_repository write_repository` "范围". - -此外,必须使用[CI 变量](../../ci/variables/README.html)指定以下[变量](../../ci/variables/README.html) : - -| 可变 CI | Description | -| --- | --- | -| `JUPYTERHUB_PROXY_SECRET_TOKEN` | 用于签名来自集线器的通信的安全字符串. 请参阅[`proxy.secretToken`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#proxy-secrettoken) . | -| `JUPYTERHUB_COOKIE_SECRET` | 用于签署安全 cookie 的安全字符串. 参见[`hub.cookieSecret`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#hub-cookiesecret) . | -| `JUPYTERHUB_HOST` | 用于安装的主机名. 例如, `jupyter.gitlab.example.com` . | -| `JUPYTERHUB_GITLAB_HOST` | 用于身份验证的 GitLab 实例的主机名. 例如, `gitlab.example.com` . | -| `JUPYTERHUB_AUTH_CRYPTO_KEY` | 一个 32 字节的加密密钥,用于设置[`auth.state.cryptoKey`](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html#auth-state-cryptokey) . | -| `JUPYTERHUB_AUTH_GITLAB_CLIENT_ID` | OAuth 应用程序的"应用程序 ID". | -| `JUPYTERHUB_AUTH_GITLAB_CLIENT_SECRET` | OAuth 应用程序的"秘密". | - -默认情况下,将使用[默认值文件](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/blob/master/src/default-data/jupyterhub/values.yaml.gotmpl)安装 JupyterHub. 您可以通过在群集管理项目中定义`.gitlab/managed-apps/jupyterhub/values.yaml`文件来自定义`.gitlab/managed-apps/jupyterhub/values.yaml`的安装. - -有关可用的配置选项,请参考[图表参考](https://zero-to-jupyterhub.readthedocs.io/en/stable/reference/reference.html) . - -**注意:** GitLab 配置组提供了对安装 JupyterHub 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从[Configure 组中](https://about.gitlab.com/handbook/product/categories/#configure-group) ping 通至少 2 个人. - -### Install Elastic Stack using GitLab CI/CD[](#install-elastic-stack-using-gitlab-cicd "Permalink") - -在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25138) . - -通过在`.gitlab/managed-apps/config.yaml`定义配置,使用 GitLab CI / CD 安装 Elastic Stack. - -使用 GitLab CI / CD 安装 Elastic Stack 需要以下配置: - -``` -elasticStack: - installed: true -``` - -Elastic Stack 已安装到集群的`gitlab-managed-apps`命名空间中. - -您可以检查默认[`values.yaml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/vendor/elastic_stack/values.yaml)我们此图表设置. - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/elastic-stack/values.yaml`文件来自定义 Elastic Stack 的安装. 请参阅[图表](https://gitlab.com/gitlab-org/charts/elastic-stack)以获取可用的配置选项. - -**注意:**在通过 CI 安装 Elastic Stack 的 alpha 实现中,不支持通过 Elasticsearch 读取环境日志. 如果[通过 UI 安装,](#elastic-stack)则支持此功能.**注意:** GitLab APM 组提供了对安装 Elastic Stack 托管应用程序的支持. 如果遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping [APM 组中的](https://about.gitlab.com/handbook/product/product-categories/#apm-group)至少 2 个人. - -### Install Crossplane using GitLab CI/CD[](#install-crossplane-using-gitlab-cicd "Permalink") - -在 GitLab 12.9 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/35675) . - -通过在`.gitlab/managed-apps/config.yaml`定义配置,使用 GitLab CI / CD 安装 Crossplane. - -使用 GitLab CI / CD 安装 Crossplane 需要以下配置: - -``` -Crossplane: - installed: true -``` - -Crossplane 已安装到集群的`gitlab-managed-apps`命名空间中. - -您可以检查默认[`values.yaml`](https://github.com/crossplane/crossplane/blob/master/cluster/charts/crossplane/values.yaml.tmpl)我们此图表设置. - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/crossplane/values.yaml`文件来自定义 Crossplane 的安装. 请参阅[图表](https://github.com/crossplane/crossplane/tree/master/cluster/charts/crossplane#configuration)以获取可用的配置选项. 请注意,此链接指向当前开发版本的文档,该文档可能与您安装的版本不同. - -**注意:** Crossplane 团队提供对 Crossplane 托管应用程序的支持. 如果遇到问题,请直接[打开支持凭单](https://github.com/crossplane/crossplane/issues/new/choose) . - -### Install Fluentd using GitLab CI/CD[](#install-fluentd-using-gitlab-cicd "Permalink") - -在 GitLab 12.10 中[引入](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/76) . - -要使用 GitLab CI / CD 将`gitlab-managed-apps`安装到群集的`gitlab-managed-apps`命名空间中,请在`.gitlab/managed-apps/config.yaml`定义以下配置: - -``` -Fluentd: - installed: true -``` - -您也可以在[`values.yaml`](https://github.com/helm/charts/blob/master/stable/fluentd/values.yaml)文件中查看为此图表设置的默认值. - -您可以通过在群集管理项目中定义`.gitlab/managed-apps/fluentd/values.yaml`文件来自定义`.gitlab/managed-apps/fluentd/values.yaml`的安装. 有关可用的配置选项,请参阅[Fluentd 当前开发版本](https://github.com/helm/charts/tree/master/stable/fluentd#configuration)的[配置表](https://github.com/helm/charts/tree/master/stable/fluentd#configuration) . - -**注意:**配置图表链接指向当前的开发版本,该版本可能与您安装的版本不同. 为了确保兼容性,请切换到您正在使用的特定分支或标签.**注意:** GitLab Container Security 组提供了对安装 Fluentd 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping 通至少来自[Container Security 组的](https://about.gitlab.com/handbook/product/product-categories/#container-security-group) 2 个人. - -### Install Knative using GitLab CI/CD[](#install-knative-using-gitlab-cicd "Permalink") - -要安装 Knative,请使用以下命令定义`.gitlab/managed-apps/config.yaml`文件: - -``` -knative: - installed: true -``` - -您可以通过在集群管理项目中定义`.gitlab/managed-apps/knative/values.yaml`文件来自定义`.gitlab/managed-apps/knative/values.yaml`的安装. 请参阅[图表](https://gitlab.com/gitlab-org/charts/knative)以获取可用的配置选项. - -这是 Knative 的示例配置: - -``` -domain: 'my.wildcard.A.record.dns' -``` - -如果计划使用 GitLab 无服务器功能,请确保在自定义配置上设置 A 记录通配符域. - -**注意:** GitLab 配置组提供了对安装 Knative 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并从[Configure 组中](https://about.gitlab.com/handbook/product/categories/#configure-group) ping 通至少 2 个人. - -#### Knative Metrics[](#knative-metrics "Permalink") - -GitLab 为您的函数提供了[调用指标](../project/clusters/serverless/index.html#invocation-metrics) . 要收集这些指标,您必须具有: - -1. 在群集上安装了 Knative 和 Prometheus 托管的应用程序. -2. 通过运行以下命令在群集上手动应用自定义指标: - - ``` - kubectl apply -f https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/raw/02c8231e30ef5b6725e6ba368bc63863ceb3c07d/src/default-data/knative/istio-metrics.yaml - ``` - -#### Uninstall Knative[](#uninstall-knative "Permalink") - -要卸载 Knative,必须首先通过运行以下命令手动删除已添加的所有自定义指标: - -``` -kubectl delete -f https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/raw/02c8231e30ef5b6725e6ba368bc63863ceb3c07d/src/default-data/knative/istio-metrics.yaml -``` - -### Install AppArmor using GitLab CI/CD[](#install-apparmor-using-gitlab-cicd "Permalink") - -在 GitLab 13.1 中[引入](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications/-/merge_requests/100) . - -要使用 GitLab CI / CD 将 AppArmor 安装到群集的`gitlab-managed-apps`命名空间中,请在`.gitlab/managed-apps/config.yaml`定义以下配置: - -``` -apparmor: - installed: true -``` - -您可以通过将它们添加到`.gitlab/managed-apps/apparmor/values.yaml`来定义一个或多个 AppArmor 配置文件,如下所示: - -``` -profiles: - profile-one: |- - profile profile-one { - file, - } -``` - -有关此图表的更多信息,请参考[AppArmor](https://gitlab.com/gitlab-org/charts/apparmor)图表. - -#### Using AppArmor profiles in your deployments[](#using-apparmor-profiles-in-your-deployments "Permalink") - -安装 AppAmor 之后,您可以通过添加 Pod 注释来使用配置文件. 如果您使用的是 Auto DevOps,则可以[自定义`auto-deploy-values.yaml`](../../topics/autodevops/customize.html#customize-values-for-helm-chart)来注释您的 Pod. 尽管了解[自定义属性列表](https://gitlab.com/gitlab-org/charts/auto-deploy-app#gitlabs-auto-deploy-helm-chart)会有所帮助,但只需`podAnnotations`如下所示设置`podAnnotations` : - -``` -podAnnotations: - container.apparmor.security.beta.kubernetes.io/auto-deploy-app: localhost/profile-one -``` - -此处唯一要更改的信息是配置文件名称,在本示例中为`profile-one` . 有关如何在 Kubernetes 中集成[AppArmor](https://kubernetes.io/docs/tutorials/clusters/apparmor/#securing-a-pod)的更多信息,请参考[AppArmor 教程](https://kubernetes.io/docs/tutorials/clusters/apparmor/#securing-a-pod) . - -**注意:** GitLab Container Security 组提供了对安装 AppArmor 托管应用程序的支持. 如果您遇到未知问题,请[打开一个新问题,](https://gitlab.com/gitlab-org/gitlab/-/issues/new)并 ping 通至少来自[Container Security 组的](https://about.gitlab.com/handbook/product/product-categories/#container-security-group) 2 个人. - -## Upgrading applications[](#upgrading-applications "Permalink") - -在 GitLab 11.8 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/24789) . - -以下应用程序可以升级. - -| Application | GitLab 版本 | -| --- | --- | -| Runner | 11.8+ | - -升级应用程序: - -1. 为一个: - * [在项目级别的集群中](../project/clusters/index.html) ,导航到项目的**Operations> Kubernetes** . - * [组级别集群](../group/clusters/index.html) ,导航到您组的**Kubernetes**页面. -2. 选择您的集群. -3. 如果有升级,将显示" **升级"**按钮. 单击按钮进行升级. - -**注意:**升级会将值重置为`runner`图表中内置的值, [`values.yaml`](https://gitlab.com/gitlab-org/gitlab/blob/master/vendor/runner/values.yaml)设置的值. - -## Uninstalling applications[](#uninstalling-applications "Permalink") - -在 GitLab 11.11 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/60665) . - -可以卸载以下应用程序. - -| Application | GitLab 版本 | Notes | -| --- | --- | --- | -| cert-manager | 12.2+ | 关联的私钥将被删除,并且无法还原. 部署的应用程序将继续使用 HTTPS,但是不会续订证书. 卸载之前,您可能希望[备份配置](https://cert-manager.io/docs/tutorials/backup/)或[吊销证书](https://letsencrypt.org/docs/revoking/) . | -| 亚搏体育 app Runner | 12.2+ | 任何正在运行的管道将被取消. | -| Helm | 12.2+ | 关联的 Tiller 容器, `gitlab-managed-apps`命名空间及其所有资源将被删除,并且无法还原. | -| Ingress | 12.1+ | 关联的负载均衡器和 IP 将被删除,并且无法还原. 此外,仅当未安装 JupyterHub 时才能将其卸载. | -| JupyterHub | 12.1+ | 所有未提交到 GitLab 的数据将被删除,并且无法还原. | -| Knative | 12.1+ | 关联的 IP 将被删除,无法恢复. | -| Prometheus | 11.11+ | 所有数据将被删除,无法还原. | -| Crossplane | 12.5+ | 所有数据将被删除,无法还原. | -| 弹性堆叠 | 12.7+ | 所有数据将被删除,无法还原. | -| Sentry | 12.6+ | PostgreSQL 永久卷将保留,应手动删除以完全卸载. | - -卸载应用程序: - -1. 为一个: - * [在项目级别的集群中](../project/clusters/index.html) ,导航到项目的**Operations> Kubernetes** . - * [组级别集群](../group/clusters/index.html) ,导航到您组的**Kubernetes**页面. -2. 选择您的集群. -3. 单击该应用程序的" **卸载"**按钮. - -支持逐步卸载所有支持的应用程序. 要了解进度,请参阅[相关的史诗](https://gitlab.com/groups/gitlab-org/-/epics/1201) . - -## Troubleshooting applications[](#troubleshooting-applications "Permalink") - -应用程序可能因以下错误而失败: - -``` -Error: remote error: tls: bad certificate -``` - -为避免安装错误: - -* 在开始安装应用程序之前,请确保您的 GitLab 服务器和 Kubernetes 集群之间的时间已同步. -* 确保证书不同步. 在安装应用程序时,GitLab 需要一个没有先前安装的 Helm 的新集群. - - 您可以通过`kubectl`确认证书匹配: - - ``` - kubectl get configmaps/values-content-configuration-ingress -n gitlab-managed-apps -o \ - "jsonpath={.data['cert\.pem']}" | base64 -d > a.pem - kubectl get secrets/tiller-secret -n gitlab-managed-apps -o "jsonpath={.data['ca\.crt']}" | base64 -d > b.pem - diff a.pem b.pem - ``` - -### Error installing managed apps on EKS cluster[](#error-installing-managed-apps-on-eks-cluster "Permalink") - -如果您在 AWS EKS 上使用托管集群,但无法安装某些托管应用程序,请考虑检查日志. - -您可以通过运行以下命令来检查日志: - -``` -kubectl get pods --all-namespaces -kubectl get services --all-namespaces -``` - -如果遇到`Failed to assign an IP address to container`错误,则可能是由于您在 AWS 配置中指定的实例类型. 节点的数量和大小可能没有足够的 IP 地址来运行或安装这些 Pod. - -作为参考,可以[在 GitHub 上的此 AWS 存储库](https://github.com/aws/amazon-vpc-cni-k8s/blob/master/pkg/awsutils/vpc_ip_resource_limit.go)中找到所有 AWS 实例 IP 限制(搜索`InstanceENIsAvailable` ). - -### Unable to install Prometheus[](#unable-to-install-prometheus "Permalink") - -Prometheus 安装失败,出现以下错误: - -``` -# kubectl -n gitlab-managed-apps logs install-prometheus -... -Error: Could not get apiVersions from Kubernetes: unable to retrieve the complete list of server APIs: admission.certmanager.k8s.io/v1beta1: the server is currently unable to handle the request -``` - -这是在 Helm `2.15`中引入并在`3.0.2`修复的错误. 解决方法是,在安装 Prometheus 之前,需要确保已成功安装[`cert-manager`](#cert-manager) . \ No newline at end of file diff --git a/docs/026.md b/docs/026.md deleted file mode 100644 index 7adc85bef91ade83593af0abc823335be5b3c842..0000000000000000000000000000000000000000 --- a/docs/026.md +++ /dev/null @@ -1,264 +0,0 @@ -# Crossplane configuration - -> 原文:[https://docs.gitlab.com/ee/user/clusters/crossplane.html](https://docs.gitlab.com/ee/user/clusters/crossplane.html) - -* [Configure RBAC permissions](#configure-rbac-permissions) -* [Configure Crossplane with a cloud provider](#configure-crossplane-with-a-cloud-provider) -* [Configure Managed Service Access](#configure-managed-service-access) -* [Setting up Resource classes](#setting-up-resource-classes) -* [Auto DevOps Configuration Options](#auto-devops-configuration-options) -* [Connect to the PostgreSQL instance](#connect-to-the-postgresql-instance) - -# Crossplane configuration[](#crossplane-configuration "Permalink") - -[安装](applications.html#crossplane) Crossplane 后,必须对其进行配置以供使用. 配置 Crossplane 的过程包括: - -1. [Configure RBAC permissions](#configure-rbac-permissions). -2. [Configure Crossplane with a cloud provider](#configure-crossplane-with-a-cloud-provider). -3. [Configure managed service access](#configure-managed-service-access). -4. [Set up Resource classes](#setting-up-resource-classes). -5. Use [Auto DevOps configuration options](#auto-devops-configuration-options). -6. [Connect to the PostgreSQL instance](#connect-to-the-postgresql-instance). - -为了允许 Crossplane 设置诸如 PostgreSQL 之类的云服务,必须使用用户帐户配置云提供商堆栈. 例如: - -* GCP 的服务帐户. -* AWS 的 IAM 用户. - -一些重要的注意事项: - -* 本指南以 GCP 为例,但 AWS 和 Azure 的过程相似. -* Crossplane 要求 Kubernetes 集群是启用了 Alias IP 的 VPC 本机,因此可以在 GCP 网络内路由 Pod 的 IP 地址. - -首先,使用配置声明一些环境变量以供本指南使用: - -``` -export PROJECT_ID=crossplane-playground # the GCP project where all resources reside. -export NETWORK_NAME=default # the GCP network where your GKE is provisioned. -export REGION=us-central1 # the GCP region where the GKE cluster is provisioned. -``` - -## Configure RBAC permissions[](#configure-rbac-permissions "Permalink") - -对于由 GitLab 管理的群集,将自动配置基于角色的访问控制(RBAC). - -对于非 GitLab 管理的群集,请确保提供的令牌的服务帐户可以管理`database.crossplane.io` API 组中的资源: - -1. 将以下 YAML 保存为`crossplane-database-role.yaml` : - - ``` - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole - metadata: - name: crossplane-database-role - labels: - rbac.authorization.k8s.io/aggregate-to-edit: "true" - rules: - - apiGroups: - - database.crossplane.io - resources: - - postgresqlinstances - verbs: - - get - - list - - create - - update - - delete - - patch - - watch - ``` - -2. 将集群角色应用于集群: - - ``` - kubectl apply -f crossplane-database-role.yaml - ``` - -## Configure Crossplane with a cloud provider[](#configure-crossplane-with-a-cloud-provider "Permalink") - -请参阅[配置您的云提供商帐户](https://crossplane.github.io/docs/v0.4/cloud-providers.html)以使用用户帐户配置已安装的云提供商堆栈. - -**注意:必须**将 Secret 和引用该 Secret 的 Provider 资源应用于指南中的`gitlab-managed-apps`命名空间. 请确保在执行该过程时进行更改. - -## Configure Managed Service Access[](#configure-managed-service-access "Permalink") - -接下来,通过以下任一方法配置 PostgreSQL 数据库和 GKE 集群之间的连接: - -* 如下所示使用 Crossplane. -* Directly in the GCP console by [configuring private services access](https://cloud.google.com/vpc/docs/configure-private-services-access). - -1. 运行以下命令,这将创建一个`network.yaml`文件,并配置`GlobalAddress`和连接资源: - - ``` - cat > network.yaml < gcp-postgres-standard.yaml < -Annotations: crossplane.io/propagate-from-name: 108e460e-06c7-11ea-b907-42010a8000bd - crossplane.io/propagate-from-namespace: gitlab-managed-apps - crossplane.io/propagate-from-uid: 10c79605-06c7-11ea-b907-42010a8000bd - -Type: Opaque - -Data -==== -privateIP: 8 bytes -publicIP: 13 bytes -serverCACertificateCert: 1272 bytes -serverCACertificateCertSerialNumber: 1 bytes -serverCACertificateCreateTime: 24 bytes -serverCACertificateExpirationTime: 24 bytes -username: 8 bytes -endpoint: 8 bytes -password: 27 bytes -serverCACertificateCommonName: 98 bytes -serverCACertificateInstance: 41 bytes -serverCACertificateSha1Fingerprint: 40 bytes -``` - -## Connect to the PostgreSQL instance[](#connect-to-the-postgresql-instance "Permalink") - -如果您想连接到 CloudSQL 上新配置的 PostgreSQL 数据库实例,请遵循此[GCP 指南](https://cloud.google.com/sql/docs/postgres/connect-kubernetes-engine) . \ No newline at end of file diff --git a/docs/027.md b/docs/027.md deleted file mode 100644 index 267cdcd9578a0721596624b7b57e6a1cbe5ca77c..0000000000000000000000000000000000000000 --- a/docs/027.md +++ /dev/null @@ -1,103 +0,0 @@ -# Cluster management project (alpha) - -> 原文:[https://docs.gitlab.com/ee/user/clusters/management_project.html](https://docs.gitlab.com/ee/user/clusters/management_project.html) - -* [Permissions](#permissions) -* [Usage](#usage) - * [Selecting a cluster management project](#selecting-a-cluster-management-project) - * [Configuring your pipeline](#configuring-your-pipeline) - * [Setting the environment scope](#setting-the-environment-scope-premium) - -# Cluster management project (alpha)[](#cluster-management-project-alpha "Permalink") - -**警告:**这是*Alpha 版*功能,如有更改,恕不另行通知. - -在 GitLab 12.5 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/32810) - -可以将一个项目指定为集群的管理项目. 管理项目可用于以 Kubernetes [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)权限运行部署作业. - -这对以下情况很有用: - -* 创建管道以将群集范围的应用程序安装到群集中,有关详细信息,请参见[使用 GitLab CI / CD(alpha)](applications.html#install-using-gitlab-cicd-alpha)安装. -* 需要`cluster-admin`权限的所有作业. - -## Permissions[](#permissions "Permalink") - -仅管理项目将获得`cluster-admin`权限. 所有其他项目将继续获得[命名空间范围的`edit`级别特权](../project/clusters/add_remove_clusters.html#rbac-cluster-resources) . - -管理项目仅限于以下内容: - -* 对于项目级集群,管理项目必须与集群项目位于相同的名称空间(或子代)中. -* 对于组级集群,管理项目必须与集群的组位于同一组(或子孙)中. -* 对于实例级群集,没有此类限制. - -## Usage[](#usage "Permalink") - -要将群集管理项目用于群集: - -1. 选择项目. -2. 配置管道. -3. 设置环境范围. - -### Selecting a cluster management project[](#selecting-a-cluster-management-project "Permalink") - -选择要使用的集群管理项目: - -1. 导航到适当的配置页面. 为一个: - * [项目级集群](../project/clusters/index.html) ,导航到项目的**Operations> Kubernetes**页面. - * [组级别集群](../group/clusters/index.html) ,导航到您组的**Kubernetes**页面. - * [实例级集群](../instance/clusters/index.html) ,导航到管理区域的**Kubernetes**页面. -2. 在" **高级设置"**部分中的"使用**集群管理项目"字段**中选择项目. - -[![Selecting a cluster management project under Advanced settings](img/838245c530d1afaf54929d9edd3f6a24.png)](img/advanced-settings-cluster-management-project-v12_5.png) - -### Configuring your pipeline[](#configuring-your-pipeline "Permalink") - -将项目指定为集群的管理项目后,在该项目中编写[`.gitlab-ci.yml`](../../ci/yaml/README.html) . 例如: - -``` -configure cluster: - stage: deploy - script: kubectl get namespaces - environment: - name: production -``` - -### Setting the environment scope[](#setting-the-environment-scope-premium "Permalink") - -将多个群集与同一管理项目关联时,可以使用[环境范围](../project/clusters/index.html#setting-the-environment-scope-premium) . - -每个作用域只能由单个群集用于管理项目. - -例如,假设以下 Kubernetes 集群与管理项目相关联: - -| Cluster | 环境范围 | -| --- | --- | -| Development | `*` | -| Staging | `staging` | -| Production | `production` | - -[`.gitlab-ci.yml`](../../ci/yaml/README.html)设置的以下环境将分别部署到 Development,Staging 和 Production 集群. - -``` -stages: - - deploy - -configure development cluster: - stage: deploy - script: kubectl get namespaces - environment: - name: development - -configure staging cluster: - stage: deploy - script: kubectl get namespaces - environment: - name: staging - -configure production cluster: - stage: deploy - script: kubectl get namespaces - environment: - name: production -``` \ No newline at end of file diff --git a/docs/028.md b/docs/028.md deleted file mode 100644 index 72b89b4e4b654a3acd84f965ee24cc57fbcf96d3..0000000000000000000000000000000000000000 --- a/docs/028.md +++ /dev/null @@ -1,100 +0,0 @@ -# Kubernetes Logs - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/kubernetes_pod_logs.html](https://docs.gitlab.com/ee/user/project/clusters/kubernetes_pod_logs.html) - -* [Overview](#overview) -* [Requirements](#requirements) -* [Usage](#usage) - * [From the project sidebar](#from-the-project-sidebar) - * [From Deploy Boards](#from-deploy-boards) - * [Logs view](#logs-view) - * [Filter by date](#filter-by-date) - * [Full text search](#full-text-search) - -# Kubernetes Logs[](#kubernetes-logs "Permalink") - -版本历史 - -* 在[GitLab Ultimate](https://about.gitlab.com/pricing/) 11.0 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/4752) . -* [移至](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26383) [GitLab Core](https://about.gitlab.com/pricing/) 12.9\. - -使用 GitLab 可以轻松查看[连接的 Kubernetes 集群](index.html)中正在运行的 Pod 的日志. 通过直接在**Log Explorer 的** GitLab 中显示**日志** ,开发人员可以避免管理控制台工具或跳转到其他界面. - -**注意:** [了解有关 Kubernetes + GitLab 的更多信息](https://about.gitlab.com/solutions/kubernetes/) . 大规模构建,测试,部署和运行应用程序所需的一切. - -## Overview[](#overview "Permalink") - -[Kubernetes](https://kubernetes.io)日志可以使用**Log Explorer**在 GitLab 中直接查看. - -[![Pod logs](img/0370f6d6a289b9e8237fcad4c7672e78.png)](img/kubernetes_pod_logs_v12_10.png) - -要了解更多信息,请参阅[APM-Log Explorer](https://www.youtube.com/watch?v=hWclZHA7Dgw) . - -## Requirements[](#requirements "Permalink") - -要使用日志,需要[部署到 Kubernetes 环境](../deploy_boards.html#enabling-deploy-boards) . - -## Usage[](#usage "Permalink") - -要访问日志,您必须具有正确的[权限](../../permissions.html#project-members-permissions) . - -您可以通过两种方式访问​​它们. - -### From the project sidebar[](#from-the-project-sidebar "Permalink") - -在 GitLab 12.5 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22011) . - -去 侧栏菜单上的" **操作">"舱位日志** "以显示" **日志资源管理器"** . - -[![Sidebar menu](img/0050abd936ad2e13e4ad057a58611cc9.png)](img/sidebar_menu_pod_logs_v12_10.png) - -### From Deploy Boards[](#from-deploy-boards "Permalink") - -可以通过单击[Deploy Boards 中](../deploy_boards.html)的特定窗格来显示日志: - -1. 去 **操作>环境,**然后找到包含所需 pod 的环境,例如`production` . -2. 在" **环境"**页面上,您应该通过[Deploy Boards](../deploy_boards.html)看到环境容器的状态. -3. 将鼠标悬停在窗格列表上时,将显示一个工具提示,其中包含确切的窗格名称和状态. [![部署板窗格列表](img/81c888ba61ab652f9505d5b51406ed22.png)](img/pod_logs_deploy_board.png) -4. 单击所需的窗格以显示**Log Explorer** . - -### Logs view[](#logs-view "Permalink") - -**日志浏览**器使您可以通过以下方式过滤日志: - -* Pods. -* [从 GitLab 12.4 开始](https://gitlab.com/gitlab-org/gitlab/-/issues/5769) ,环境. -* [From GitLab 12.7](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21656), [full text search](#full-text-search). -* [从 GitLab 12.8 开始](https://gitlab.com/gitlab-org/gitlab/-/issues/197879) ,日期. - -从[GitLab 12.9](https://gitlab.com/gitlab-org/gitlab/-/issues/198050)起可以加载 500 条以上的日志行. - -[在将来的版本中将](https://gitlab.com/gitlab-org/gitlab/-/issues/13404)支持具有多个容器的 Pod. - -[在将来的版本中将](https://gitlab.com/gitlab-org/gitlab/-/issues/196191)支持历史数据. - -### Filter by date[](#filter-by-date "Permalink") - -在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/197879) . - -在集群上启用[Elastic Stack](../../clusters/applications.html#elastic-stack)时,您可以按日期过滤" **日志浏览**器"中显示的**日志** . - -单击" **日志资源管理器"**中的" **显示最后一个** "以查看可用选项. - -### Full text search[](#full-text-search "Permalink") - -在 GitLab 12.7 中[引入](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21656) . - -在集群上启用[Elastic Stack](../../clusters/applications.html#elastic-stack)时,可以通过搜索栏搜索日志的内容. - -搜索通过使用[simple_query_string](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html) Elasticsearch 函数传递给 Elasticsearch,该函数支持以下运算符: - -| Operator | Description | -| --- | --- | -| `\|` | 或运算. | -| `-` | 取反单个令牌. | -| `+` | AND 运算. | -| `"` | 包装许多标记以表示要搜索的短语. | -| `*` (每学期末) | 前缀查询. | -| `(` and `)` | Precedence. | -| `~N` (一个字之后) | 编辑距离(模糊性). | -| `~N` (在短语之后) | 斜率. | \ No newline at end of file diff --git a/docs/029.md b/docs/029.md deleted file mode 100644 index 695ccf7100dfe06c457b0f23654abdd5166b0968..0000000000000000000000000000000000000000 --- a/docs/029.md +++ /dev/null @@ -1,104 +0,0 @@ -# Runbooks - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/runbooks/](https://docs.gitlab.com/ee/user/project/clusters/runbooks/) - -* [Executable Runbooks](#executable-runbooks) -* [Requirements](#requirements) -* [Nurtch](#nurtch) -* [Configure an executable runbook with GitLab](#configure-an-executable-runbook-with-gitlab) - -# Runbooks[](#runbooks "Permalink") - -Runbooks 是记录在案的过程的集合,这些过程解释了如何执行特定过程,包括启动,停止,调试特定系统或对特定系统进行故障排除. - -使用[Jupyter Notebook](https://jupyter.org/)和[Rubix 库](https://github.com/Nurtch/rubix) ,用户可以开始编写自己的可执行运行手册. - -从历史上看,运行手册根据情况或系统采用决策树或详细的分步指南的形式. - -现代的实现方式引入了"可执行的运行手册"的概念,其中,操作员可以结合定义良好的流程在给定的环境中执行预写的代码块或数据库查询. - -## Executable Runbooks[](#executable-runbooks "Permalink") - -在 GitLab 11.4 中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/45912) . - -通过 GitLab 的 Kubernetes 集成提供的 JupyterHub 应用程序现在随 Nurtch 的 Rubix 库一起提供,提供了一种创建 DevOps Runbook 的简单方法. 提供了一个样本运行手册,其中展示了常见的操作. 虽然 Rubix 使创建常见的 Kubernetes 和 AWS 工作流变得简单,但是您也可以不使用 Rubix 手动创建它们. - -观看此[视频](https://www.youtube.com/watch?v=Q_OqHIIUPjE) ,了解如何在 GitLab 中完成此操作! - -## Requirements[](#requirements "Permalink") - -要创建可执行的运行本,您将需要: - -* **Kubernetes-**需要 Kubernetes 集群才能部署其余应用程序. 最简单的入门方法是使用[GitLab 的集成](../add_remove_clusters.html#create-new-cluster)之一添加集群. -* **入口** -入口可以提供负载平衡,SSL 终止和基于名称的虚拟主机. 它充当您的应用程序的 Web 代理. -* **JupyterHub** - [JupyterHub](https://jupyterhub.readthedocs.io/)是用于在团队中管理笔记本的多用户服务. Jupyter Notebook 提供了一个基于 Web 的交互式编程环境,用于数据分析,可视化和机器学习. - -## Nurtch[](#nurtch "Permalink") - -Nurtch 是[Rubix 库](https://github.com/Nurtch/rubix)背后的公司. Rubix 是一个开源 Python 库,可轻松在 Jupyter Notebooks 中执行常见的 DevOps 任务. 绘制 Cloudwatch 指标和滚动 ECS / Kubernetes 应用之类的任务将简化为几行代码. 有关更多信息,请参见[Nurtch 文档](http://docs.nurtch.com/en/latest/) . - -## Configure an executable runbook with GitLab[](#configure-an-executable-runbook-with-gitlab "Permalink") - -遵循此分步指南,使用上述组件和预加载的演示运行本在 GitLab 中配置可执行运行本. - -1. 遵循[创建新集群中](../add_remove_clusters.html#create-new-cluster)概述的步骤,将 Kubernetes 集群添加到您的项目中. - -2. 单击**Ingress**应用程序旁边的" **安装"**按钮以安装 Ingress. - - [![install ingress](img/5a2430ba8091036f8e9e3308aa845de8.png)](img/ingress-install.png) - -3. 成功安装 Ingress 后,单击**JupyterHub**应用程序旁边的" **安装"**按钮. **下一步,**您将需要此处提供的**Jupyter 主机名** . - - [![install JupyterHub](img/00fd9bca0c7bdc64f74a24b691e0adac.png)](img/jupyterhub-install.png) - -4. 成功安装**JupyterHub 后** ,在浏览器中打开**Jupyter 主机名** . 单击" **使用 GitLab 登录"**按钮登录到 JupyterHub 并启动服务器. 使用 OAuth2 为 GitLab 实例的任何用户启用身份验证. 此按钮将您重定向到 GitLab 上的页面,请求 JupyterHub 授权使用您的 GitLab 帐户. - - [![authorize Jupyter](img/9950340e3b641e3f63d70fb29b2b05bb.png)](img/authorize-jupyter.png) - -5. 单击**Authorize** ,您将被重定向到 JupyterHub 应用程序. -6. 单击" **启动我的服务器"** ,服务器将在几秒钟后启动. -7. 要配置 Runbook 对 GitLab 项目的访问,必须在演示 Runbook 的" **设置"**部分中输入您的[GitLab 访问令牌](../../../profile/personal_access_tokens.html)和项目 ID: - - 1. 双击左侧面板上的**DevOps-Runbook-Demo**文件夹. - - [![demo runbook](img/6809ef73be513357f41ebe6d325265d5.png)](img/demo-runbook.png) - - 2. 双击`Nurtch-DevOps-Demo.ipynb` . - - [![sample runbook](img/ae5a500e2333874603b33328b017eb35.png)](img/sample-runbook.png) - - Jupyter 在屏幕右侧显示 Runbook 的内容. **设置**部分显示您的`PRIVATE_TOKEN`和您的`PROJECT_ID` . 输入这些值,并保持单引号如下: - - ``` - PRIVATE_TOKEN = 'n671WNGecHugsdEDPsyo' - PROJECT_ID = '1234567' - ``` - - 3. Update the `VARIABLE_NAME` on the last line of this section to match the name of the variable you’re using for your access token. In this example, our variable name is `PRIVATE_TOKEN`. - - ``` - VARIABLE_VALUE = project.variables.get('PRIVATE_TOKEN').value - ``` - -8. 要配置运行手册的操作,请创建和配置变量: - - **注意:**对于此示例,我们使用示例**运行簿**中的**笔记本中**的**"运行 SQL 查询"**部分来查询 PostgreSQL 数据库. 以下代码块的前四行定义了此查询运行所需的变量: - - ``` - %env DB_USER={project.variables.get('DB_USER').value} - %env DB_PASSWORD={project.variables.get('DB_PASSWORD').value} - %env DB_ENDPOINT={project.variables.get('DB_ENDPOINT').value} - %env DB_NAME={project.variables.get('DB_NAME').value} - ``` - - 1. 导航 **设置»CI / CD»变量**以在项目中创建变量. - - [![GitLab variables](img/15b455cffa86c3a9234ad8c30082a4df.png)](img/gitlab-variables.png) - - 2. Click **保存变量**. - - 3. 在 Jupyter 中,单击**"笔记本"**标题中的**"运行 SQL 查询"** ,然后单击**"运行"** . 结果以内联方式显示如下: - - [![PostgreSQL query](img/1a1b871d7e874d4f8e2ab4905d000509.png)](img/postgres-query.png) - -您可以尝试其他操作,例如运行 Shell 脚本或与 Kubernetes 集群进行交互. 有关更多信息,请访问[Nurtch 文档](http://docs.nurtch.com/) . \ No newline at end of file diff --git a/docs/030.md b/docs/030.md deleted file mode 100644 index 84e2f128a8540c042191d922cfa21706a323ea2b..0000000000000000000000000000000000000000 --- a/docs/030.md +++ /dev/null @@ -1,734 +0,0 @@ -# Serverless - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/serverless/](https://docs.gitlab.com/ee/user/project/clusters/serverless/) - -* [Overview](#overview) -* [Knative](#knative) -* [Prerequisites](#prerequisites) -* [Installing Knative via GitLab’s Kubernetes integration](#installing-knative-via-gitlabs-kubernetes-integration) -* [Using an existing installation of Knative](#using-an-existing-installation-of-knative) -* [Supported runtimes](#supported-runtimes) - * [GitLab-managed runtimes](#gitlab-managed-runtimes) - * [OpenFaaS runtimes](#openfaas-runtimes) -* [Deploying functions](#deploying-functions) - * [`service`](#service) - * [`provider`](#provider) - * [`functions`](#functions) - * [Deployment](#deployment) - * [Runtime aliases](#runtime-aliases) - * [Secrets](#secrets) - * [CLI example](#cli-example) - * [Part of deployment job](#part-of-deployment-job) - * [Running functions locally](#running-functions-locally) -* [Deploying Serverless applications](#deploying-serverless-applications) - * [Deploy the application with Knative](#deploy-the-application-with-knative) - * [Function details](#function-details) - * [Invocation metrics](#invocation-metrics) -* [Configuring logging](#configuring-logging) - * [Prerequisites](#prerequisites-1) - * [Enable request log template](#enable-request-log-template) - * [Enable request logs](#enable-request-logs) - * [Viewing request logs](#viewing-request-logs) -* [Enabling TLS for Knative services](#enabling-tls-for-knative-services) -* [Using an older version of `gitlabktl`](#using-an-older-version-of-gitlabktl) - -# Serverless[](#serverless "Permalink") - -在 GitLab 11.5 中引入. - -**警告:** Serverless 目前处于[alpha 状态](https://about.gitlab.com/handbook/product/#alpha) . - -## Overview[](#overview "Permalink") - -无服务器架构为运营商和开发人员提供了在不配置单个服务器的情况下编写高度可扩展的应用程序的能力. - -GitLab 支持在 Kubernetes 环境和主要的云 FAAS 环境中部署无服务器应用程序的几种方法. - -目前,我们支持: - -* [Knative](#knative) :在 GKE 和 EKS 上使用 Knative 和`gitlabktl`构建 Knative 应用程序. -* [AWS Lambda](aws.html) :通过无服务器框架和 GitLab CI / CD 创建无服务器应用程序. - -## Knative[](#knative "Permalink") - -使用[Knative](https://cloud.google.com/knative/)在 Kubernetes 上运行无服务器工作负载. - -Knative 扩展了 Kubernetes 以提供一组中间件组件,这些组件对于构建现代的,以源为中心的,基于容器的应用程序很有用. Knative 通过其主要组件带来了一些明显的好处: - -* [服务](https://github.com/knative/serving) :请求驱动的计算,可扩展为零. -* [事件](https://github.com/knative/eventing) : [事件的](https://github.com/knative/eventing)管理和交付. - -有关 Knative 的更多信息,请访问[Knative docs 资源库](https://github.com/knative/docs) . - -借助 GitLab Serverless,您可以部署功能即服务(FaaS)和无服务器应用程序. - -## Prerequisites[](#prerequisites "Permalink") - -要在 GitLab 上运行 Knative,您需要: - -1. **现有的 GitLab 项目:**您将需要一个 GitLab 项目来关联所有资源. 最简单的入门方法: - * 如果您打算[部署功能](#deploying-functions) ,请克隆[功能示例项目](https://gitlab.com/knative-examples/functions)以开始使用. - * 如果您打算[部署无服务器应用程序](#deploying-serverless-applications) ,请克隆示例[Knative Ruby App](https://gitlab.com/knative-examples/knative-ruby-app)以开始使用. -2. **Kubernetes 集群:**部署 Knative 需要启用 RBAC 的 Kubernetes 集群. 最简单的入门方法是使用 GitLab 的[GKE 集成](../add_remove_clusters.html)添加集群. 建议的运行 Knative 的最低建议群集规格为 3 个节点,6 个 vCPU 和 22.50 GB 内存. -3. **GitLab 运行程序:**运行 CI 作业需要运行程序,该作业会将无服务器的应用程序或功能部署到您的集群上. 您可以将 GitLab Runner 安装到现有的 Kubernetes 集群上. 有关更多信息,请参见[安装应用程序](../index.html#installing-applications) . -4. **域名:** Knative 将使用 Istio 提供自己的负载平衡器. 它将为 Knative 服务的所有应用程序提供一个外部 IP 地址或主机名. 系统将提示您输入一个通配符域,将在其中提供您的应用程序. 配置您的 DNS 服务器以使用该域的外部 IP 地址或主机名. -5. **`.gitlab-ci.yml` :** GitLab 使用[Kaniko](https://github.com/GoogleContainerTools/kaniko)来构建应用程序. 我们还使用[GitLab Knative 工具](https://gitlab.com/gitlab-org/gitlabktl) CLI 来简化向 Knative 部署服务和功能. -6. **`serverless.yml`** ( [仅](#deploying-functions)适用于[功能](#deploying-functions) ):使用 lessserver 部署功能时, `serverless.yml`文件将包含存储库中托管的所有功能的信息以及所使用的运行时的引用. -7. **`Dockerfile`** ( [仅](#deploying-serverless-applications)适用于[应用程序](#deploying-serverless-applications) ):Knative 需要`Dockerfile`才能构建您的应用程序. 它应该包含在项目存储库的根目录中,并公开端口`8080` . 如果您打算使用我们的[运行时](https://gitlab.com/gitlab-org/serverless/runtimes)来构建无服务器功能,则不需要`Dockerfile` . -8. **Prometheus** (可选):安装 Prometheus 可使您监视无服务器功能/应用程序的规模和流量. 有关更多信息,请参见[安装应用程序](../index.html#installing-applications) . -9. **日志记录** (可选):配置日志记录可让您查看和搜索无服务器功能/应用程序的请求日志. 有关更多信息,请参见[配置日志记录](#configuring-logging) . - -## Installing Knative via GitLab’s Kubernetes integration[](#installing-knative-via-gitlabs-kubernetes-integration "Permalink") - -**注意:**运行 Knative 的最小建议群集大小是 3 节点,6 vCPU 和 22.50 GB 内存. **必须启用 RBAC.** - -1. [Add a Kubernetes cluster](../add_remove_clusters.html). -2. 选择" **应用程序"**选项卡,然后向下滚动到" Knative 应用程序"部分. 输入要用于您的应用程序/功能的域(例如`example.com` ),然后单击**Install** . - - [![install-knative](img/a93d26d68bbc1f4954a7038e601ba3b6.png)](img/install-knative.png) - -3. Knative 安装完成后,您可以等待 IP 地址或主机名显示在**Knative Endpoint**字段中,或[手动检索 Istio Ingress 端点](../../../clusters/applications.html#determining-the-external-endpoint-manually) . - - **注意:**在集群上运行`kubectl`命令需要首先设置对集群的访问. 对于在 GKE 上创建的集群,请参见[GKE 集群访问](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl) ,对于其他平台,请[安装 kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) . -4. 入口现在在此地址可用,并将基于请求中的 DNS 名称将传入请求路由到适当的服务. 为此,应为所需的域名创建通配符 DNS 记录. 例如,如果您的 Knative 基础域是`knative.info`则需要创建一个 A 记录或 CNAME 记录,其域`*.knative.info`指向 Ingress 的 IP 地址或主机名. - - [![DNS entry](img/e7acd74bc1dc7f0103e1b107aac74f84.png)](img/dns-entry.png) - -**注意:**可以在给定项目上部署[功能](#deploying-functions)或[无服务器应用程序](#deploying-serverless-applications) ,但不能两者都部署. 当前实现利用了的`serverless.yml`文件发信号 FAAS 项目. - -## Using an existing installation of Knative[](#using-an-existing-installation-of-knative "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/58941) in GitLab 12.0. - -**注意:**添加现有的 Knative 安装时,GitLabless server 的"调用"监视功能将不起作用. - -也可以将 GitLab Serverless 与已经安装 Knative 的现有 Kubernetes 集群一起使用. - -您必须执行以下操作: - -1. 按照步骤[添加现有的 Kubernetes 集群](../add_remove_clusters.html#add-existing-cluster) . - -2. 确保 GitLab 可以管理 Knative: - * 对于非 GitLab 托管群集,请确保提供的令牌的服务帐户可以管理`serving.knative.dev` API 组中的资源. - * 对于 GitLab 托管群集,如果您在[GitLab 12.1 或更高版本中](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30235)添加了群集,则 GitLab 将已经具有所需的访问权限,您可以继续进行下一步. - - 否则,您需要手动授权 GitLab 的服务帐户具有管理`serving.knative.dev` API 组中资源的能力. 由于每个 GitLab 服务帐户都具有`edit`集群角色,因此最简单的方法是通过将默认规则添加到默认`edit`集群角色的[聚合 ClusterRole](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles) :首先,将以下 YAML 保存为`knative-serving-only-role.yaml` : - - ``` - apiVersion : rbac.authorization.k8s.io/v1 kind : ClusterRole metadata : name : knative-serving-only-role labels : rbac.authorization.k8s.io/aggregate-to-edit : " true" rules : - apiGroups : - serving.knative.dev resources : - configurations - configurationgenerations - routes - revisions - revisionuids - autoscalers - services verbs : - get - list - create - update - delete - patch - watch - ``` - - 然后运行以下命令: - - ``` - kubectl apply -f knative-serving-only-role.yaml - ``` - - 如果您希望基于每个服务帐户授予权限,则可以使用特定于服务帐户和名称空间的`Role`和`RoleBinding`来执行此操作. - -3. 请按照以下步骤将[功能](#deploying-functions)或[无服务器应用程序](#deploying-serverless-applications)部署到群集上. - -## Supported runtimes[](#supported-runtimes "Permalink") - -GitLab 的无服务器功能可以使用以下命令运行: - -* [GitLab-managed](#gitlab-managed-runtimes) runtimes. -* [OpenFaaS](#openfaas-runtimes) runtimes. - -如果所需的编程语言无法使用运行时,请考虑部署[无服务器应用程序](#deploying-serverless-applications) . - -### GitLab-managed runtimes[](#gitlab-managed-runtimes "Permalink") - -当前,以下 GitLab 管理的[运行时](https://gitlab.com/gitlab-org/serverless/runtimes)可用: - -* `go` (概念证明) -* `nodejs` -* `ruby` - -如果未指定运行时,则必须提供一个`Dockerfile`来运行无服务器功能. - -### OpenFaaS runtimes[](#openfaas-runtimes "Permalink") - -在 GitLab 12.5 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/29253) . - -[OpenFaaS 经典运行时](https://github.com/openfaas/templates#templates-in-store)可与 GitLab 无服务器一起使用. - -OpenFaas 运行时可用于以下语言: - -* C# -* Go -* NodeJS -* PHP -* Python -* Ruby - -使用以下模式指定运行时: `openfaas/classic/` . 下面的示例示出了如何定义一个函数`serverless.yml`使用 OpenFaaS 运行时: - -``` -hello: - source: ./hello - runtime: openfaas/classic/ruby - description: "Ruby function using OpenFaaS classic runtime" -``` - -`handler` is not needed for OpenFaaS functions. The location of the handler is defined by the conventions of the runtime. - -有关使用 OpenFaaS 运行时的函数示例,请参见[`ruby-openfaas-function`](https://gitlab.com/knative-examples/ruby-openfaas-function)项目. - -## Deploying functions[](#deploying-functions "Permalink") - -在 GitLab 11.6 中引入. - -您可以在**[功能示例项目中](https://gitlab.com/knative-examples/functions)**找到并导入此文档中引用的所有文件. - -请按照以下步骤将使用 Node.js 运行时的功能部署到您的 Knative 实例(如果您已克隆示例项目,则可以跳过以下步骤): - -1. 创建一个目录来容纳该函数. 在此示例中,我们将在项目的根目录创建一个名为`echo`的目录. - -2. 创建将包含功能代码的文件. 在此示例中,我们的文件名为`echo.js` ,位于`echo`目录中. 如果您的项目是: - * 公开,继续下一步. - * 私有的,您将需要使用`gitlab-deploy-token`作为名称和`read_registry`范围[创建一个 GitLab 部署令牌](../../deploy_tokens/index.html#creating-a-deploy-token) . -3. `.gitlab-ci.yml` :这定义了用于部署功能的管道. 它必须包含在存储库的根目录中: - - ``` - include: - - template: Serverless.gitlab-ci.yml - - functions:build: - extends: .serverless:build:functions - environment: production - - functions:deploy: - extends: .serverless:deploy:functions - environment: production - ``` - - 这个`.gitlab-ci.yml`创建的作业会调用一些预定义的命令来构建功能并将其部署到集群中. - - `Serverless.gitlab-ci.yml` is a template that allows customization. You can either import it with `include` parameter and use `extends` to customize your jobs, or you can inline the entire template by choosing it from **套用范本** dropdown when editing the `.gitlab-ci.yml` file through the user interface. - -4. `serverless.yml` :此文件包含您的功能的元数据,例如名称,运行时和环境. - - 它必须包含在存储库的根目录中. 下面是一个示例`echo`函数,它显示了文件所需的结构. - - 您可以在[功能示例项目中](https://gitlab.com/knative-examples/functions)找到该项目的相关文件. - - ``` - service: functions - description: "GitLab Serverless functions using Knative" - - provider: - name: triggermesh - envs: - FOO: value - secrets: - - my-secrets - - functions: - echo-js: - handler: echo-js - source: ./echo-js - runtime: gitlab/runtimes/nodejs - description: "node.js runtime function" - envs: - MY_FUNCTION: echo-js - secrets: - - my-secrets - ``` - -上面使用的字段的说明: - -### `service`[](#service "Permalink") - -| Parameter | Description | -| --- | --- | -| `service` | 服务该功能的 Knative 服务的名称. | -| `description` | 在的简短描述`service` . | - -### `provider`[](#provider "Permalink") - -| Parameter | Description | -| --- | --- | -| `name` | 指示使用哪个提供程序来执行`serverless.yml`文件. 在这种情况下,使用 TriggerMesh 中间件. | -| `envs` | 包括要在文件中**所有**函数的函数执行过程中传递的环境变量,其中`FOO`是变量名, `BAR`是变量内容. 您可以将其替换为自己的变量. | -| `secrets` | 包含 Kubernetes 机密的内容作为环境变量,可访问该变量作为文件中**所有**函数的函数执行的一部分进行传递. 机密应采用 INI 格式. | - -### `functions`[](#functions "Permalink") - -在上面的`serverless.yml`示例中,函数名称为`echo` ,随后的行包含函数属性. - -| Parameter | Description | -| --- | --- | -| `handler` | 函数的名称. | -| `source` | 具有功能源的目录. | -| `runtime` (optional) | 用于执行功能的运行时. 这可以是运行时别名(请参阅[运行时别名](#runtime-aliases) ),也可以是自定义运行时存储库的完整 URL. 当未指定运行`Dockerfile` ,我们假定`Dockerfile`存在于`source`指定的函数目录中. | -| `description` | 功能的简短描述. | -| `envs` | 仅为特定功能设置环境变量. | -| `secrets` | 将 Kubernetes 机密的内容作为环境变量包含在内,这些变量只能作为特定函数的函数执行的一部分进行传递. 机密应采用 INI 格式. | - -### Deployment[](#deployment "Permalink") - -#### Runtime aliases[](#runtime-aliases "Permalink") - -可选的`runtime`参数可以引用以下运行时别名之一(另请参阅[受支持的运行时](#supported-runtimes) ): - -| 运行时别名 | 维护者 | -| --- | --- | -| `gitlab/runtimes/go` | GitLab | -| `gitlab/runtimes/nodejs` | GitLab | -| `gitlab/runtimes/ruby` | GitLab | -| `openfaas/classic/csharp` | OpenFaaS | -| `openfaas/classic/go` | OpenFaaS | -| `openfaas/classic/node` | OpenFaaS | -| `openfaas/classic/php7` | OpenFaaS | -| `openfaas/classic/python` | OpenFaaS | -| `openfaas/classic/python3` | OpenFaaS | -| `openfaas/classic/ruby` | OpenFaaS | - -经过`gitlab-ci.yml`模板已添加和`serverless.yml`文件被创建,推动提交到您的项目将导致 CI 管道被执行,而部署的每个功能的 Knative 服务. 部署阶段完成后,该功能的其他详细信息将显示在" **操作">"无服务器"下** . - -[![serverless page](img/e8c78799e0967a32ee1efeaea30f6213.png)](img/serverless-page.png) - -该页面包含可用于项目的所有功能,访问功能的描述以及(如果有)功能的运行时信息. 详细信息来自于项目的每个 Kubernetes 集群中的 Knative 安装. 单击每个功能以获得详细的规模和调用数据. - -可以从集群上的 Knative 直接检索函数详细信息: - -``` -kubectl -n "$KUBE_NAMESPACE" get services.serving.knative.dev -``` - -现在可以使用任何简单的`POST`调用从任何 HTTP 客户端触发示例函数: - -1. 使用 curl(将最后一行的 URL 替换为应用程序的 URL): - - ``` - curl \ - --header "Content-Type: application/json" \ - --request POST \ - --data '{"GitLab":"FaaS"}' \ - http://functions-echo.functions-1.functions.example.com/ - ``` - -2. 使用基于 Web 的工具(例如 Postman 或 Restlet) - - [![function execution](img/676537e7ead1101c5c0668a2adbc08d5.png)](img/function-execution.png) - -### Secrets[](#secrets "Permalink") - -要从函数内部访问 Kubernetes 机密,应在无服务器部署的名称空间下创建该机密,并在上述`serverless.yml`文件中指定这些机密. 您可以通过多种方式创建机密. 以下各节显示了一些示例. - -#### CLI example[](#cli-example "Permalink") - -``` -kubectl create secret generic my-secrets -n "$KUBE_NAMESPACE" --from-literal MY_SECRET=imverysecure -``` - -#### Part of deployment job[](#part-of-deployment-job "Permalink") - -您可以扩展`.gitlab-ci.yml`以在部署期间使用安全存储在 GitLab 项目下的[环境变量](../../../../ci/variables/README.html)来创建秘密. - -``` -deploy:function: - stage: deploy - environment: production - extends: .serverless:deploy:functions - before_script: - - kubectl create secret generic my-secret - --from-literal MY_SECRET="$GITLAB_SECRET_VARIABLE" - --namespace "$KUBE_NAMESPACE" - --dry-run -o yaml | kubectl apply -f - -``` - -### Running functions locally[](#running-functions-locally "Permalink") - -在本地运行功能是在开发过程中快速验证行为的好方法. - -在本地运行功能需要: - -* 转到 1.12 或更高版本. -* Docker Engine 已安装并正在运行. -* 使用 Go 软件包管理器安装的`gitlabktl` : - - ``` - GO111MODULE=on go get gitlab.com/gitlab-org/gitlabktl - ``` - -要在本地运行功能: - -1. 导航到您的 GitLab 无服务器项目的根目录. -2. 将功能构建到 Docker 映像中: - - ``` - gitlabktl serverless build - ``` - -3. 在 Docker 中运行您的函数: - - ``` - docker run -itp 8080:8080 - ``` - -4. 调用您的功能: - - ``` - curl http://localhost:8080 - ``` - -## Deploying Serverless applications[](#deploying-serverless-applications "Permalink") - -在 GitLab 11.5 中引入. - -无服务器应用程序是[无服务器功能](#deploying-functions)的替代[方法](#deploying-functions) . 它们在现有运行时不能满足应用程序需求的情况下很有用,例如以一种没有可用运行时的语言编写的应用程序. 请注意,尽管无服务器应用程序应该是无状态的! - -**注意:**您可以参考并导入示例[Knative Ruby 应用程序](https://gitlab.com/knative-examples/knative-ruby-app)以开始使用. - -将以下`.gitlab-ci.yml`添加到存储库的根目录中(如果您先前已经克隆了上述示例[Knative Ruby App,](https://gitlab.com/knative-examples/knative-ruby-app)则可以跳过此步骤): - -``` -include: - - template: Serverless.gitlab-ci.yml - -build: - extends: .serverless:build:image - -deploy: - extends: .serverless:deploy:image -``` - -`Serverless.gitlab-ci.yml`是允许自定义的模板. 您可以使用`include`参数导入它,并使用`extends`来自定义作业,或者可以通过在通过用户界面编辑`.gitlab-ci.yml`文件时从**Apply a template**下拉列表中选择它来内联整个模板. - -部署无服务器应用程序时,不需要`serverless.yml`文件. - -### Deploy the application with Knative[](#deploy-the-application-with-knative "Permalink") - -一切就绪后,下次运行 CI 管道时,将部署 Knative 应用程序. 导航到**CI / CD>管道** ,然后单击最新的管道. - -### Function details[](#function-details "Permalink") - -转到**操作>无服务器**页面以查看功能的最终 URL. - -[![function_details](img/4e0797b4100df465293bf0c8f24a097b.png)](img/function-list_v12_7.png) - -### Invocation metrics[](#invocation-metrics "Permalink") - -On the same page as above, click on one of the function rows to bring up the function details page. - -[![function_details](img/a0ea9fb503066a9bed377bc4dadb0d59.png)](img/function-details-loaded.png) - -容器数将为您提供在给定集群上运行无服务器功能实例的容器数. - -为了显示 Knative 函数调用, [必须安装 Prometheus](../index.html#installing-applications) . - -一旦安装了 Prometheus,可能会出现一条消息,指示度量标准数据*正在加载或当前不可用.* 它会在首次访问该页面时显示,但应在几秒钟后消失. 如果该消息没有消失,则可能是 GitLab 无法连接到集群上运行的 Prometheus 实例. - -## Configuring logging[](#configuring-logging "Permalink") - -在 GitLab 12.5 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/33330) . - -### Prerequisites[](#prerequisites-1 "Permalink") - -* 由 GitLab 管理的集群. -* `kubectl`已安装并正在运行. - -在集群上运行`kubectl`命令需要首先设置对集群的访问权限. 对于在以下位置创建的集群: - -* GKE,请参阅[GKE 群集访问](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl) -* 其他平台,请参阅[安装和设置 kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) . - -### Enable request log template[](#enable-request-log-template "Permalink") - -运行以下命令以启用请求日志: - -``` -kubectl edit cm -n knative-serving config-observability -``` - -将`logging.request-log-template`从`data._example`字段复制到层次结构中上一层的数据字段. - -### Enable request logs[](#enable-request-logs "Permalink") - -运行以下命令以将 Elasticsearch,Kibana 和 Filebeat 安装到`kube-logging`命名空间中,并配置所有节点以使用 Filebeat 转发日志: - -``` -kubectl apply -f https://gitlab.com/gitlab-org/serverless/configurations/knative/raw/v0.7.0/kube-logging-filebeat.yaml -kubectl label nodes --all beta.kubernetes.io/filebeat-ready="true" -``` - -### Viewing request logs[](#viewing-request-logs "Permalink") - -要查看请求日志: - -1. Run `kubectl proxy`. -2. 导航到[Kibana UI](http://localhost:8001/api/v1/namespaces/kube-logging/services/kibana/proxy/app/kibana) . - -Or: - -1. 打开[Kibana UI](http://localhost:8001/api/v1/namespaces/kube-logging/services/kibana/proxy/app/kibana) . -2. 单击" **发现"** ,然后从左侧的下拉列表中选择`filebeat-*` . -3. 在搜索框中输入`kubernetes.container.name:"queue-proxy" AND message:/httpRequest/` . - -## Enabling TLS for Knative services[](#enabling-tls-for-knative-services "Permalink") - -默认情况下,将通过`http`提供 GitLab 无服务器部署. 为了通过`https`提供服务,您必须手动获取并安装 TLS 证书. - -完成此操作的最简单方法是使用[Certbot 手动获取 Let's Encrypt 证书](https://knative.dev/docs/serving/using-a-tls-cert/#using-certbot-to-manually-obtain-let-s-encrypt-certificates) . Certbot 是一个免费的开源软件工具,可用于在手动管理的网站上自动使用 Let's Encrypt 证书来启用 HTTPS. - -**注意:**以下说明与在安装了 Python 3 且不能在其他操作系统或其他版本的 Python 上运行的 Linux 服务器上安装和运行 Certbot 有关. - -1. 通过运行[`certbot-auto` wrapper 脚本](https://certbot.eff.org/docs/install.html#certbot-auto)安装 Certbot. 在服务器的命令行上,运行以下命令: - - ``` - wget https://dl.eff.org/certbot-auto - sudo mv certbot-auto /usr/local/bin/certbot-auto - sudo chown root /usr/local/bin/certbot-auto - sudo chmod 0755 /usr/local/bin/certbot-auto - /usr/local/bin/certbot-auto --help - ``` - - 要检查`certbot-auto`脚本的完整性,请运行: - - ``` - wget -N https://dl.eff.org/certbot-auto.asc - gpg2 --keyserver ipv4.pool.sks-keyservers.net --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2 - gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc /usr/local/bin/certbot-auto - ``` - - The output of the last command should look something like: - - ``` - gpg: Signature made Mon 10 Jun 2019 06:24:40 PM EDT - gpg: using RSA key A2CFB51FA275A7286234E7B24D17C995CD9775F2 - gpg: key 4D17C995CD9775F2 marked as ultimately trusted - gpg: checking the trustdb - gpg: marginals needed: 3 completes needed: 1 trust model: pgp - gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u - gpg: next trustdb check due at 2027-11-22 - gpg: Good signature from "Let's Encrypt Client Team " [ultimate] - ``` - -2. 运行以下命令以使用 Certbot 在授权过程中使用 DNS 质询来请求证书: - - ``` - /usr/local/bin/certbot-auto certonly --manual --preferred-challenges dns -d '*..example.com' - ``` - - 其中``是 GitLab 为您的无服务器项目创建的名称空间(由`--` ),而`example.com`是用于项目的域. 如果不确定项目的名称空间是什么,请导航至项目的" **操作">"无服务器"**页面,然后检查为功能/应用程序提供的端点. - - [![function_endpoint](img/70c613da170fdfd7665282f16becad56.png)](img/function-endpoint.png) - - 在上图中,项目的名称空间为`node-function-11909507` ,域为`knative.info` ,因此证书申请行如下所示: - - ``` - ./certbot-auto certonly --manual --preferred-challenges dns -d '*.node-function-11909507.knative.info' - ``` - - Certbot 工具将引导您完成通过在这些域中创建 TXT 记录来验证您拥有的每个域的步骤. 此过程完成后,输出应如下所示: - - ``` - IMPORTANT NOTES: - - Congratulations! Your certificate and chain have been saved at: - /etc/letsencrypt/live/namespace.example.com/fullchain.pem - Your key file has been saved at: - /etc/letsencrypt/live/namespace.example/privkey.pem - Your cert will expire on 2019-09-19\. To obtain a new or tweaked - version of this certificate in the future, simply run certbot-auto - again. To non-interactively renew *all* of your certificates, run - "certbot-auto renew" - -----BEGIN PRIVATE KEY----- - - Your account credentials have been saved in your Certbot - configuration directory at /etc/letsencrypt. You should make a - secure backup of this folder now. This configuration directory will - also contain certificates and private keys obtained by Certbot so - making regular backups of this folder is ideal. - ``` - -3. 创建证书和私钥文件. 使用 Certbot 返回的文件的内容,我们将创建两个文件以创建 Kubernetes 机密: - - 运行以下命令以查看`fullchain.pem`的内容: - - ``` - sudo cat /etc/letsencrypt/live/node-function-11909507.knative.info/fullchain.pem - ``` - - 输出应如下所示: - - ``` - -----BEGIN CERTIFICATE----- - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b4ag== - -----END CERTIFICATE----- - -----BEGIN CERTIFICATE----- - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - K2fcb195768c39e9a94cec2c2e30Qg== - -----END CERTIFICATE----- - ``` - - 创建一个名称为`cert.pem`的文件,其中包含整个输出的内容. - - 创建`cert.pem` ,运行以下命令以查看`privkey.pem`的内容: - - ``` - sudo cat /etc/letsencrypt/live/namespace.example/privkey.pem - ``` - - 输出应如下所示: - - ``` - -----BEGIN PRIVATE KEY----- - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df - -----BEGIN CERTIFICATE----- - fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6 - 4f294d1eaca42b8692017b4262== - -----END PRIVATE KEY----- - ``` - - 使用整个输出的内容创建一个名称为`cert.pk`的新文件. - -4. 创建一个 Kubernetes 机密以保存您的 TLS 证书`cert.pem`和私钥`cert.pk` : - - **注意:**在集群上运行`kubectl`命令需要首先设置对集群的访问. 对于在 GKE 上创建的集群,请参阅[GKE 集群访问](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl) . 对于其他平台, [请安装`kubectl`](https://kubernetes.io/docs/tasks/tools/install-kubectl/) . - - ``` - kubectl create --namespace istio-system secret tls istio-ingressgateway-certs \ - --key cert.pk \ - --cert cert.pem - ``` - - 其中`cert.pem`和`cert.pk`是您的证书和私钥文件. 请注意, `istio-ingressgateway-certs`秘密名称是必需的. - -5. 配置 Knative 以使用为 HTTPS 连接创建的新密码. 运行以下命令以编辑方式打开 Knative 共享`gateway` : - - ``` - kubectl edit gateway knative-ingress-gateway --namespace knative-serving - ``` - - 更新网关以包括以下 tls:部分和配置: - - ``` - tls: - mode: SIMPLE - privateKey: /etc/istio/ingressgateway-certs/tls.key - serverCertificate: /etc/istio/ingressgateway-certs/tls.crt - ``` - - Example: - - ``` - apiVersion: networking.istio.io/v1alpha3 - kind: Gateway - metadata: - # ... skipped ... - spec: - selector: - istio: ingressgateway - servers: - - hosts: - - "*" - port: - name: http - number: 80 - protocol: HTTP - - hosts: - - "*" - port: - name: https - number: 443 - protocol: HTTPS - tls: - mode: SIMPLE - privateKey: /etc/istio/ingressgateway-certs/tls.key - serverCertificate: /etc/istio/ingressgateway-certs/tls.crt - ``` - - After your changes are running on your Knative cluster, you can begin using the HTTPS protocol for secure access your deployed Knative services. In the event a mistake is made during this process and you need to update the cert, you will need to edit the gateway `knative-ingress-gateway` to switch back to `PASSTHROUGH` mode. Once corrections are made, edit the file again so the gateway will use the new certificates. - -## Using an older version of `gitlabktl`[](#using-an-older-version-of-gitlabktl "Permalink") - -在某些情况下,您想运行旧版本的`gitlabktl` . 这需要在`.gitlab-ci.yml`文件中设置较旧版本的`gitlabktl`映像. - -要设置较旧的版本,请将`image:`添加到`functions:deploy`块中. 例如: - -``` -functions:deploy: - extends: .serverless:deploy:functions - environment: production - image: registry.gitlab.com/gitlab-org/gitlabktl:0.5.0 -``` - -通过更改注册表 URL 末尾的版本标签(格式为`registry.gitlab.com/gitlab-org/gitlabktl:`可以使用不同的版本. - -有关可用`gitlabktl`版本的完整清单,请参见`gitlabktl`项目的[容器注册表](https://gitlab.com/gitlab-org/gitlabktl/container_registry) . \ No newline at end of file diff --git a/docs/031.md b/docs/031.md deleted file mode 100644 index 79a6a450c6dc9236e4416d505f47aa430d2839ab..0000000000000000000000000000000000000000 --- a/docs/031.md +++ /dev/null @@ -1,488 +0,0 @@ -# Deploying AWS Lambda function using GitLab CI/CD - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/serverless/aws.html](https://docs.gitlab.com/ee/user/project/clusters/serverless/aws.html) - -* [Serverless Framework](#serverless-framework) - * [Example](#example) - * [Steps](#steps) - * [Creating a Lambda handler function](#creating-a-lambda-handler-function) - * [Creating a `serverless.yml` file](#creating-a-serverlessyml-file) - * [Crafting the `.gitlab-ci.yml` file](#crafting-the-gitlab-ciyml-file) - * [Setting up your AWS credentials with your GitLab account](#setting-up-your-aws-credentials-with-your-gitlab-account) - * [Deploying your function](#deploying-your-function) - * [Manually testing your function](#manually-testing-your-function) - * [How To](#how-to) - * [Running function locally](#running-function-locally) - * [Secret variables](#secret-variables) - * [Setting up CORS](#setting-up-cors) - * [Writing automated tests](#writing-automated-tests) - * [Examples and template](#examples-and-template) -* [AWS Serverless Application Model](#aws-serverless-application-model) - * [Deploying AWS Lambda function using AWS SAM and GitLab CI/CD](#deploying-aws-lambda-function-using-aws-sam-and-gitlab-cicd) - * [Example](#example-1) - * [Steps](#steps-1) - * [Installing SAM CLI](#installing-sam-cli) - * [Creating an AWS SAM application using SAM CLI](#creating-an-aws-sam-application-using-sam-cli) - * [Setting up your AWS credentials with your GitLab account](#setting-up-your-aws-credentials-with-your-gitlab-account-1) - * [Crafting the `.gitlab-ci.yml` file](#crafting-the-gitlab-ciyml-file-1) - * [Deploying your application](#deploying-your-application) - * [Testing the deployed application](#testing-the-deployed-application) - * [Testing Locally](#testing-locally) - -# Deploying AWS Lambda function using GitLab CI/CD[](#deploying-aws-lambda-function-using-gitlab-cicd "Permalink") - -GitLab 允许用户轻松部署 AWS Lambda 函数并创建丰富的无服务器应用程序. - -GitLab 支持使用以下无服务器框架通过 GitLab CI / CD 部署 AWS Lambda 功能: - -* [Serverless Framework with AWS](#serverless-framework) -* [AWS’ Serverless Application Model (SAM)](#aws-serverless-application-model) - -## Serverless Framework[](#serverless-framework "Permalink") - -The [Serverless Framework can deploy to AWS](https://www.serverless.com/framework/docs/providers/aws/). - -我们准备了一个包含分步指南的示例,以创建一个简单功能并将其部署在 AWS 上. - -此外,在"操作方法["部分中](#how-to) ,您可以了解不同的用例,例如: - -* 在本地运行功能. -* 处理秘密. -* 设置 CORS. - -或者,您可以[使用 template](../../../../gitlab-basics/create-project.html#project-templates)快速[创建一个新项目](../../../../gitlab-basics/create-project.html#project-templates) . [`Serverless Framework/JS`模板](https://gitlab.com/gitlab-org/project-templates/serverless-framework/)已经包括下面描述的所有部分. - -### Example[](#example "Permalink") - -在以下示例中,您将: - -1. 创建一个基本的 AWS Lambda Node.js 函数. -2. 将该函数链接到 API Gateway `GET`端点. - -#### Steps[](#steps "Permalink") - -该示例包括以下步骤: - -1. 创建 Lambda 处理函数. -2. 创建一个`serverless.yml`文件. -3. 制作`.gitlab-ci.yml`文件. -4. 使用 GitLab 账户设置 AWS 凭证. -5. 部署您的功能. -6. 测试已部署的功能. - -让我们一步一步来. - -#### Creating a Lambda handler function[](#creating-a-lambda-handler-function "Permalink") - -您的 Lambda 函数将是请求的主要处理程序. 在这种情况下,我们将创建一个非常简单的 Node.js `hello`函数: - -``` -'use strict'; - -module.exports.hello = async event => { - return { - statusCode: 200, - body: JSON.stringify( - { - message: 'Your function executed successfully!' - }, - null, - 2 - ), - }; -}; -``` - -将此代码放在文件`src/handler.js` . - -`src`是无服务器功能的标准位置,但是您可以根据需要进行自定义. - -在我们的例子中, `module.exports.hello`定义了`hello` ,这将在以后的引用处理器`serverless.yml` - -您可以在此处了解有关 AWS Lambda Node.js 函数处理程序及其所有各种选项的更多信息: [https](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html) : [//docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html) - -#### Creating a `serverless.yml` file[](#creating-a-serverlessyml-file "Permalink") - -在项目的根目录中,创建一个`serverless.yml`文件,其中将包含 Serverless Framework 的配置详细信息. - -将以下代码放入文件中: - -``` -service: gitlab-example -provider: - name: aws - runtime: nodejs10.x - -functions: - hello: - handler: src/handler.hello - events: - - http: GET hello -``` - -我们的函数包含一个处理程序和一个事件. - -处理程序定义将使用位于`src/handler.hello`的源代码提供 Lambda 函数. - -`events`声明将创建一个 AWS API Gateway `GET`终端节点,以接收外部请求并将其通过服务集成传递给 Lambda 函数. - -您可以阅读有关无服务器框架的[可用属性和其他配置可能性](https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml/)的更多信息. - -#### Crafting the `.gitlab-ci.yml` file[](#crafting-the-gitlab-ciyml-file "Permalink") - -在项目根目录下的`.gitlab-ci.yml`文件中,放置以下代码: - -``` -image: node:latest - -stages: - - deploy - -production: - stage: deploy - before_script: - - npm config set prefix /usr/local - - npm install -g serverless - script: - - serverless deploy --stage production --verbose - environment: production -``` - -此示例代码执行以下操作: - -1. 对所有 GitLab CI / CD 版本使用`node:latest`映像 -2. The `deploy` stage: - * 安装无服务器框架. - * 使用上面定义的 AWS 凭证将无服务器功能部署到您的 AWS 账户. - -#### Setting up your AWS credentials with your GitLab account[](#setting-up-your-aws-credentials-with-your-gitlab-account "Permalink") - -为了与您的 AWS 账户进行交互,GitLab CI / CD 管道要求在您的 GitLab 设置中的**设置> CI / CD>变量**下定义`AWS_ACCESS_KEY_ID`和`AWS_SECRET_ACCESS_KEY` . 有关更多信息,请参见[在 UI 中创建自定义变量](../../../../ci/variables/README.html#create-a-custom-variable-in-the-ui) . - -**注意:**您提供的 AWS 凭证必须包括 IAM 策略,以提供对 AWS Lambda,API 网关,CloudFormation 和 IAM 资源的正确访问控制. - -#### Deploying your function[](#deploying-your-function "Permalink") - -`git push` the changes to your GitLab repository and the GitLab build pipeline will automatically deploy your function. - -在您的 GitLab 部署阶段日志中,将包含您的 AWS Lambda 端点 URL 的输出. 日志行将类似于以下内容: - -``` -endpoints: - GET - https://u768nzby1j.execute-api.us-east-1.amazonaws.com/production/hello -``` - -#### Manually testing your function[](#manually-testing-your-function "Permalink") - -运行以下`curl`命令将触发您的功能. - -**注意:**您的 URL 应该是从 GitLab 部署阶段日志中检索到的 URL. - -``` -curl https://u768nzby1j.execute-api.us-east-1.amazonaws.com/production/hello -``` - -那应该输出: - -``` -{ "message": "Your function executed successfully!" } -``` - -万岁! 现在,您已经通过 GitLab CI / CD 部署了 AWS Lambda 函数. - -干得好! - -### How To[](#how-to "Permalink") - -在本节中,我们向您展示如何在基本示例上构建以下内容: - -* 在本地运行该功能. -* 设置秘密变量. -* 设置 CORS. - -#### Running function locally[](#running-function-locally "Permalink") - -`serverless-offline`插件允许在本地运行代码. 要在本地运行代码: - -1. 将以下内容添加到您的`serverless.yml` : - - ``` - plugins: - - serverless-offline - ``` - -2. 通过运行以下命令来启动服务: - - ``` - serverless offline - ``` - -运行以下`curl`命令将触发您的功能. - -``` -curl http://localhost:3000/hello -``` - -它应该输出: - -``` -{ "message": "Your function executed successfully!" } -``` - -#### Secret variables[](#secret-variables "Permalink") - -Secrets are injected into your functions using environment variables. - -通过在`serverless.yml`的 provider 部分中定义变量,可以将它们添加到已部署函数的环境中: - -``` -provider: - ... - environment: - A_VARIABLE: ${env:A_VARIABLE} -``` - -从那里,您也可以在函数中引用它们. 请记住,在**设置> CI / CD>**变量下,将`A_VARIABLE`添加到您的 GitLab CI / CD 变量中,它将随您的函数一起被拾取和部署. - -**注意:**有权访问 AWS 环境的任何人都可以查看 lambda 定义中保留的那些变量的值. - -#### Setting up CORS[](#setting-up-cors "Permalink") - -如果您想要建立一个调用函数的网页,就像我们在[模板中](https://gitlab.com/gitlab-org/project-templates/serverless-framework/)所做的那样,则需要处理跨域资源共享(CORS). - -快速的方法来做到这一点是添加`cors: true`标志的 HTTP 端点在你`serverless.yml` : - -``` -functions: - hello: - handler: src/handler.hello - events: - - http: # Rewrite this part to enable CORS - path: hello - method: get - cors: true # <-- CORS here -``` - -您还需要在函数响应中返回 CORS 特定的标头: - -``` -'use strict'; - -module.exports.hello = async event => { - return { - statusCode: 200, - headers: { - // Uncomment the line below if you need access to cookies or authentication - // 'Access-Control-Allow-Credentials': true, - 'Access-Control-Allow-Origin': '*' - }, - body: JSON.stringify( - { - message: 'Your function executed successfully!' - }, - null, - 2 - ), - }; -}; -``` - -有关更多信息,请参阅由无服务器框架团队撰写的《 [您的 CORS 和 API 网关生存指南》](https://www.serverless.com/blog/cors-api-gateway-survival-guide/)博客文章. - -#### Writing automated tests[](#writing-automated-tests "Permalink") - -[无服务器框架](https://gitlab.com/gitlab-org/project-templates/serverless-framework/)示例项目展示了如何使用 Jest,Axios 和`serverless-offline`插件对本地和已部署的无服务器功能进行自动化测试. - -### Examples and template[](#examples-and-template "Permalink") - -示例代码可用: - -* 作为[可克隆的存储库](https://gitlab.com/gitlab-org/serverless/examples/serverless-framework-js) . -* 在带有[测试和秘密变量](https://gitlab.com/gitlab-org/project-templates/serverless-framework/)的版本中. - -您还可以在 GitLab UI 中使用[模板](../../../../gitlab-basics/create-project.html#project-templates) (基于带有测试和秘密变量的版本)(请参阅`Serverless Framework/JS`模板). - -## AWS Serverless Application Model[](#aws-serverless-application-model "Permalink") - -AWS 无服务器应用程序模型是用于构建无服务器应用程序的开源框架. 它使构建和部署无服务器应用程序变得更加容易. 有关更多详细信息,请参阅有关[AWS 无服务器应用程序模型的](https://docs.aws.amazon.com/serverless-application-model/) AWS 文档. - -### Deploying AWS Lambda function using AWS SAM and GitLab CI/CD[](#deploying-aws-lambda-function-using-aws-sam-and-gitlab-cicd "Permalink") - -GitLab 允许开发人员使用以下组合来构建和部署无服务器应用程序: - -* [AWS Serverless Application Model (AWS SAM)](https://aws.amazon.com/serverless/sam/). -* 亚搏体育 app CI / CD. - -### Example[](#example-1 "Permalink") - -在以下示例中,您将: - -* 安装 SAM CLI. -* 创建一个示例 SAM 应用程序,其中包括 Lambda 函数和 API 网关. -* 使用 GitLab CI / CD 将应用程序构建并部署到您的 AWS 账户. - -### Steps[](#steps-1 "Permalink") - -该示例包括以下步骤: - -1. 安装 SAM CLI. -2. 使用 SAM CLI 创建 AWS SAM 应用程序. -3. 制作`.gitlab-ci.yml`文件. -4. 使用 GitLab 账户设置 AWS 凭证. -5. 部署您的应用程序. -6. 测试已部署的功能. - -### Installing SAM CLI[](#installing-sam-cli "Permalink") - -AWS SAM 提供了一个称为 AWS SAM CLI 的 CLI,可简化创建和管理应用程序的过程. - -本文档中的某些步骤使用 SAM CLI. 请按照说明[安装 SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)来安装和配置 SAM CLI. - -如果您将[AWS Cloud9](https://aws.amazon.com/cloud9/)用作集成开发环境(IDE),则会为您安装以下软件: - -* [AWS Command Line Interface](https://docs.aws.amazon.com/en_pv/cli/latest/userguide/cli-chap-install.html) -* [SAM CLI](https://docs.aws.amazon.com/en_pv/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) -* [Docker](https://s0docs0docker0com.icopy.site/install/)和必要的 Docker 映像 - -### Creating an AWS SAM application using SAM CLI[](#creating-an-aws-sam-application-using-sam-cli "Permalink") - -要创建新的 AWS SAM 应用程序: - -1. 创建一个新的 GitLab 项目. -2. `git clone`将项目`git clone`到您的本地环境中. -3. 更改为新克隆的项目,并使用以下命令创建新的 SAM 应用程序: - - ``` - sam init -r python3.8 -n gitlabpoc --app-template "hello-world" - ``` - -4. `git push`应用程序`git push`回到 GitLab 项目. - -这将使用默认配置创建一个名为`gitlabpoc`的 SAM 应用程序,该配置是[Amazon API Gateway](https://aws.amazon.com/api-gateway/)端点调用的单个 Python 3.8 函数. 要查看 SAM 支持的其他运行时以及`sam init`选项,请运行: - -``` -sam init -h -``` - -### Setting up your AWS credentials with your GitLab account[](#setting-up-your-aws-credentials-with-your-gitlab-account-1 "Permalink") - -为了与您的 AWS 账户进行交互,GitLab CI / CD 管道要求在项目的 CI / CD 变量中同时设置`AWS_ACCESS_KEY_ID`和`AWS_SECRET_ACCESS_KEY` . - -设置这些: - -1. 导航到项目的 **设置> CI / CD** . -2. 展开**变量**部分,并为`AWS_ACCESS_KEY_ID`和`AWS_SECRET_ACCESS_KEY`创建条目. -3. 屏蔽凭据,以免使用"已**屏蔽"**切换将其显示在日志中. - -**注意:**您提供的 AWS 凭证必须包括 IAM 策略,以提供对 AWS Lambda,API 网关,CloudFormation 和 IAM 资源的正确访问控制. - -### Crafting the `.gitlab-ci.yml` file[](#crafting-the-gitlab-ciyml-file-1 "Permalink") - -在项目根目录中的[`.gitlab-ci.yml`](../../../../ci/yaml/README.html)文件中,添加以下内容,并将``替换为要在其中存储软件包的 S3 存储桶的名称: - -``` -image: python:latest - -stages: - - deploy - -production: - stage: deploy - before_script: - - pip3 install awscli --upgrade - - pip3 install aws-sam-cli --upgrade - script: - - sam build - - sam package --output-template-file packaged.yaml --s3-bucket - - sam deploy --template-file packaged.yaml --stack-name gitlabpoc --s3-bucket --capabilities CAPABILITY_IAM --region us-east-1 - environment: production -``` - -让我们更仔细地检查配置文件: - -* `image`指定用于此构建的 Docker 映像. 由于示例应用程序是用 Python 编写的,因此这是最新的 Python 图像. -* AWS CLI 和 AWS SAM CLI 安装在`before_script`部分中. -* SAM 构建,打包和部署命令用于构建,打包和部署应用程序. - -### Deploying your application[](#deploying-your-application "Permalink") - -Push changes to your GitLab repository and the GitLab build pipeline will automatically deploy your application. If your: - -* 构建和部署成功, [测试已部署的应用程序](#testing-the-deployed-application) . -* 生成失败,请查看生成日志以查看生成失败的原因. 构建可能会失败的一些常见原因是: - - * 不兼容的软件版本. 例如,Python 运行时版本可能与构建计算机上的 Python 不同. 通过安装所需的软件版本来解决此问题. - * 您可能无法从 GitLab 访问您的 AWS 账户. 检查您使用 AWS 凭证设置的环境变量. - * 您可能没有权限部署无服务器应用程序. 确保提供了部署无服务器应用程序所需的所有权限. - -### Testing the deployed application[](#testing-the-deployed-application "Permalink") - -要测试您部署的应用程序,请转到构建日志,然后执行以下步骤: - -1. 点击右上角的"显示完整的原始数据": - - [![sam-complete-raw](img/fd24d5842b589870b2063edaca149511.png)](img/sam-complete-raw.png) - -2. 查找 HelloWorldApi –与以下所示类似的 API 网关端点: - - [![sam-api-endpoint](img/5dd66b504685d06e7b88c8f8a71d39ba.png)](img/sam-api-endpoint.png) - -3. 使用 curl 测试 API. 例如: - - ``` - curl https://py4rg7qtlg.execute-api.us-east-1.amazonaws.com/Prod/hello/ - ``` - -输出应为: - -``` -{"message": "hello world"} -``` - -### Testing Locally[](#testing-locally "Permalink") - -AWS SAM 提供了在本地测试应用程序的功能. 您必须在本地安装 AWS SAM CLI,才能在本地进行测试. - -首先,测试功能. - -SAM 在`events/event.json`中提供一个默认事件,其中包括以下消息主体: - -``` -{\"message\": \"hello world\"} -``` - -如果您将该事件传递给`HelloWorldFunction` ,则它应该以相同的主体响应. - -通过运行以下命令来调用该函数: - -``` -sam local invoke HelloWorldFunction -e events/event.json -``` - -输出应为: - -``` -{"message": "hello world"} -``` - -确认 Lambda 函数按预期工作后,请按照以下步骤测试 API 网关. - -通过运行以下命令在本地启动 API: - -``` -sam local start-api -``` - -SAM 再次启动 Docker 容器,这一次是在`localhost:3000`上侦听的模拟 Amazon API Gateway. - -通过运行以下命令来调用`hello` API: - -``` -curl http://127.0.0.1:3000/hello -``` - -再次输出应为: - -``` -{"message": "hello world"} -``` \ No newline at end of file diff --git a/docs/032.md b/docs/032.md deleted file mode 100644 index 172ec4d47766aaccad586bd350b46920483bb91a..0000000000000000000000000000000000000000 --- a/docs/032.md +++ /dev/null @@ -1,101 +0,0 @@ -# Securing your deployed applications - -> 原文:[https://docs.gitlab.com/ee/user/project/clusters/securing.html](https://docs.gitlab.com/ee/user/project/clusters/securing.html) - -* [Overview](#overview) - * [Requirements](#requirements) - * [Understanding how GitLab Managed Apps are installed](#understanding-how-gitlab-managed-apps-are-installed) -* [Connect the cluster to GitLab](#connect-the-cluster-to-gitlab) -* [Set up a GitLab Runner](#set-up-a-gitlab-runner) -* [Create a Cluster Management Project](#create-a-cluster-management-project) -* [Install GitLab Container Network Policy](#install-gitlab-container-network-policy) -* [Install GitLab Container Host Security](#install-gitlab-container-host-security) - -# Securing your deployed applications[](#securing-your-deployed-applications "Permalink") - -使用 GitLab 可以轻松保护在[连接的 Kubernetes 集群中](index.html)部署的应用程序的安全. 您可以从[Web 应用程序防火墙](../../../topics/web_application_firewall/quick_start_guide.html) , [网络策略](../../../topics/autodevops/stages.html#network-policy)甚至[容器主机安全性](../../clusters/applications.html#install-falco-using-gitlab-cicd)的保护中受益. - -无论您的应用程序是否通过 GitLab CI / CD 进行部署,此页面均包含将群集连接到 GitLab 并安装这些功能的完整的端到端步骤和说明. 如果您使用[Auto DevOps](../../../topics/autodevops/index.html)与 GitLab 一起构建和部署您的应用程序,请参见上面有关[GitLab 托管应用程序](../../clusters/applications.html)的文档. - -## Overview[](#overview "Permalink") - -在较高级别,所需步骤包括以下步骤: - -* 将集群连接到 GitLab. -* 设置一个或多个跑步者. -* 设置集群管理项目. -* 安装 Web 应用程序防火墙,网络策略和/或容器主机安全性. -* 安装 Prometheus,以在[威胁监视](../../application_security/threat_monitoring/)仪表板中获取统计信息和指标. - -### Requirements[](#requirements "Permalink") - -最低要求(取决于您要安装的 GitLab 管理应用程序): - -* 您的群集已连接到 GitLab(ModSecurity,Cilium 和 Falco). -* 至少安装了一个 GitLab Runner(仅限 Cilium 和 Falco). - -### Understanding how GitLab Managed Apps are installed[](#understanding-how-gitlab-managed-apps-are-installed "Permalink") - -**注意:**为简单起见,这些图使用术语*Kubernetes* . 实际上,Sidekiq 连接到在集群中的 Pod 中运行的 Helm Tiller 守护程序. - -您可以通过一键式安装过程从 GitLab Web 界面安装 GitLab 托管应用程序. GitLab 使用 Sidekiq(后台处理服务)来简化此过程. - -sequenceDiagram 自动编号 GitLab->> + Sidekiq:安装 GitLab 托管应用程序 Sidekiq->> + Kubernetes:Helm 安装 Kubernetes->>-Sidekiq:安装完成 Sidekiq->>-GitLab:刷新 UI - -尽管此安装方法比较容易,因为它是用户界面中的"点击"操作,但它不灵活且难以调试. 当出现问题时,您将看不到部署日志. Web 应用程序防火墙功能使用此安装方法. - -但是,下一代的 GitLab 托管应用程序 V2( [基于 CI / CD 的 GitLab 托管应用程序](https://gitlab.com/groups/gitlab-org/-/epics/2103) )不使用 Sidekiq 进行部署. 所有应用程序都使用 GitLab CI / CD 管道以及因此使用的 GitLab Runners 进行部署. - -sequenceDiagram 自动编号 GitLab->> + GitLab:触发管道 GitLab->> + Runner:运行部署作业 Runner->> + Kubernetes:Helm 安装 Kubernetes->>-Runner:安装完成 Runner->>-GitLab:报告工作状态和更新流程 - -调试更容易,因为您可以访问这些作业的原始日志(在失败的情况下,可以将 Helm Tiller 输出作为工件使用),并且灵活性要好得多. 由于这些部署仅在管道正在运行时触发(很可能在集群管理存储库中有新提交时才触发),因此每个操作都具有书面记录,并遵循经典的合并请求工作流程(批准,合并,部署). 网络模型(Cilium)托管的应用程序和容器主机安全性(Falco)都使用此模型进行部署. - -## Connect the cluster to GitLab[](#connect-the-cluster-to-gitlab "Permalink") - -要将 GitLab 托管应用程序部署到群集,必须首先[将群集添加](add_remove_clusters.html)到 GitLab. 然后从项目或组 Kubernetes 页面[安装](../../clusters/applications.html#installing-applications) Web 应用程序防火墙. - -请注意,您的项目不必通过 GitLab 托管或部署. 您可以独立于使用群集的应用程序来管理群集. - -## Set up a GitLab Runner[](#set-up-a-gitlab-runner "Permalink") - -要安装基于 CI / CD 的 GitLab 托管应用程序,必须在 GitLab 中运行使用 GitLab Runner 的管道. 您可以在上一步中添加的 Kubernetes 集群中[安装 GitLab 运行程序](../../clusters/applications.html#gitlab-runner) ,或者如果使用的是 GitLab.com,则可以使用 GitLab 提供的共享运行程序之一. - -将群集连接到 GitLab 并安装好 GitLab Runner 之后,您可以继续执行下一步,并开始安装 Cilium 和 Falco GitLab 托管应用程序以保护托管在此群集上的应用程序. - -## Create a Cluster Management Project[](#create-a-cluster-management-project "Permalink") - -[群集管理项目](../../clusters/management_project.html)是一个 GitLab 项目,其中包含一个`.gitlab-ci.yml`文件,用于将 GitLab 托管应用程序部署到您的群集中. 该项目使用 Kubernetes [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)特权运行所需的图表. - -该项目的创建与其他任何 GitLab 项目一样开始. 使用一个空项目,并在根目录下添加一个`gitlab-ci.yml`文件,其中包含以下模板: - -``` -include: - - template: Managed-Cluster-Applications.gitlab-ci.yml -``` - -要使该项目成为集群管理项目,请遵循以下[说明](../../clusters/management_project.html#selecting-a-cluster-management-project) . 即使您的应用程序未托管在 GitLab 上,也可以这样指定该项目. 在这种情况下,请创建一个新的空项目,您可以在其中选择新创建的集群管理项目. - -## Install GitLab Container Network Policy[](#install-gitlab-container-network-policy "Permalink") - -GitLab 容器网络策略基于[Cilium](https://cilium.io/) . 要安装 Cilium GitLab 托管应用程序,请将`.gitlab/managed-apps/config.yaml`文件添加到群集管理项目中: - -``` -# possible values are gke, eks or you can leave it blank -clusterType: gke - -cilium: - installed: true -``` - -您的应用程序不必由 GitLab 进行管理或部署即可利用此功能. [阅读](../../clusters/applications.html#install-cilium-using-gitlab-cicd)有关配置容器网络策略的[更多](../../clusters/applications.html#install-cilium-using-gitlab-cicd)信息. - -## Install GitLab Container Host Security[](#install-gitlab-container-host-security "Permalink") - -同样,您可以在`.gitlab/managed-apps/config.yaml`基于[Falco](https://falco.org/)安装 Container Host Security: - -``` -falco: - installed: true -``` - -[阅读](../../clusters/applications.html#install-falco-using-gitlab-cicd)有关配置容器主机安全性的[更多](../../clusters/applications.html#install-falco-using-gitlab-cicd)信息. \ No newline at end of file diff --git a/docs/033.md b/docs/033.md index 1d21fad79812ce8e6179ba1acb3cd4a78abd23e3..752aae485be4e9be67afb936c599e6bb22b03236 100644 --- a/docs/033.md +++ b/docs/033.md @@ -1,140 +1,85 @@ -# Groups - -> 原文:[https://docs.gitlab.com/ee/user/group/](https://docs.gitlab.com/ee/user/group/) - -* [Use cases](#use-cases) -* [Namespaces](#namespaces) -* [Issues and merge requests within a group](#issues-and-merge-requests-within-a-group) - * [Bulk editing issues and merge requests](#bulk-editing-issues-and-merge-requests) -* [Create a new group](#create-a-new-group) -* [Add users to a group](#add-users-to-a-group) -* [Request access to a group](#request-access-to-a-group) -* [Changing the owner of a group](#changing-the-owner-of-a-group) -* [Remove a member from the group](#remove-a-member-from-the-group) -* [Changing the default branch protection of a group](#changing-the-default-branch-protection-of-a-group) -* [Add projects to a group](#add-projects-to-a-group) - * [Default project-creation level](#default-project-creation-level) -* [View group details](#view-group-details) - * [Group activity analytics overview](#group-activity-analytics-overview) -* [View group activity](#view-group-activity) -* [Transfer projects into groups](#transfer-projects-into-groups) -* [Sharing a project with a group](#sharing-a-project-with-a-group) -* [Sharing a group with another group](#sharing-a-group-with-another-group) -* [Manage group memberships via LDAP](#manage-group-memberships-via-ldap) - * [Creating group links via CN](#creating-group-links-via-cn-starter-only) - * [Creating group links via filter](#creating-group-links-via-filter-premium-only) - * [Overriding user permissions](#overriding-user-permissions-starter-only) -* [Epics](#epics-ultimate) -* [Group Security Dashboard](#group-security-dashboard-ultimate) -* [Insights](#insights-ultimate) -* [Transferring groups](#transferring-groups) -* [Group settings](#group-settings) - * [General settings](#general-settings) - * [Changing a group’s path](#changing-a-groups-path) - * [Remove a group](#remove-a-group) - * [Restore a group](#restore-a-group-premium) - * [Enforce 2FA to group members](#enforce-2fa-to-group-members) - * [Share with group lock](#share-with-group-lock) - * [Member Lock](#member-lock-starter) - * [IP access restriction](#ip-access-restriction-premium) - * [Allowed domain restriction](#allowed-domain-restriction-premium) - * [Group file templates](#group-file-templates-premium) - * [Group-level project templates](#group-level-project-templates-premium) - * [Disabling email notifications](#disabling-email-notifications) - * [Disabling group mentions](#disabling-group-mentions) - * [Enabling delayed Project removal](#enabling-delayed-project-removal-premium) - * [Advanced settings](#advanced-settings) - * [Storage usage quota](#storage-usage-quota-starter) - * [Group push rules](#group-push-rules-starter) - * [Enabling the feature](#enabling-the-feature) - * [Maximum artifacts size](#maximum-artifacts-size-core-only) -* [User contribution analysis](#user-contribution-analysis-starter) -* [Issues analytics](#issues-analytics-premium) -* [Dependency Proxy](#dependency-proxy-premium) - -# Groups[](#groups "Permalink") - -使用 GitLab 组,您可以: - -* 将相关项目组装在一起. -* 授予成员一次访问多个项目的权限. - -有关 GitLab 组的视频介绍,请参见[GitLab 大学:存储库,项目和组](https://www.youtube.com/watch?v=4TWfh1aKHHw) . - -组也可以嵌套在[子组中](subgroups/index.html) . - -通过单击顶部导航中的**组>您的组**来找到您的组. +# 组织[](#groups "Permalink") -[![GitLab Groups](img/53bcd8c2d2c69aceb7db6677802be6b1.png)](img/groups.png) +通过 CODEChina 的组织,您可以: + +* 将相关项目组装在一起 +* 授予成员一次访问多个项目的权限 + +~~有关 组的视频介绍,请参见[GitLab 大学:存储库,项目和组](https://www.youtube.com/watch?v=4TWfh1aKHHw)~~ + +组也可以嵌套在[子组织中](subgroups/index.html) 。 + +通过单击顶部导航中的**组织>您的组织**来找到您的组织。 -[GitLab 11.1](https://about.gitlab.com/releases/2018/07/22/gitlab-11-1-released/#groups-dropdown-in-navigation)中[引入](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/36234)了顶部导航中的" **组"**下拉列表. +[![GitLab Groups](img/53bcd8c2d2c69aceb7db6677802be6b1.png)](img/groups.png) -" **组"**页面显示: +" **组织"**页面显示: -* 选择**您的组**后, **您将**是**您**所属的所有组. -* 选中" **浏览公共组"**时的公共组列表. +* 选择**您的组织**后, 将会显示**您**所属的全部组织(包括子组织) +* 选中" **浏览组织"**时将显示所有公开的组织列表 -" **组"**页面上的每个组都列出了: +" **组织"**页面上的每个组都列出了: -* 它有多少个子组. -* 它包含多少个项目. -* 该组有多少个成员,不包括从父组继承的成员. -* 小组的知名度. -* 如果您具有足够的权限,则指向组设置的链接. -* 如果您是成员,则退出该组的链接. +* 它有多少个子组 +* 它包含多少个项目 +* 该组织有多少个成员,注意这里面不包括从父组织继承的成员 +* 如果您具有足够的权限,还将显示组织设置的按钮 +* 如果您是成员,也会看到退出该组的按钮 -## Use cases[](#use-cases "Permalink") +## 组织用户示例[](#use-cases "Permalink") -您可以出于多种原因创建组. 列举几个: +您可以出于多种原因创建组织,例如: -* 通过在同一[名称空间](#namespaces)下组织相关项目并将成员添加到顶级组,可以以较少的步骤授予对多个项目和多个团队成员的访问权限. -* 通过创建小组并包括适当的成员,可以轻松地`@mention`所有团队中的问题并合并请求. +* 通过在同一[名称空间](#namespaces)下组织相关项目并将成员添加到顶级组,可以以较少的步骤授予对多个项目和多个团队成员的访问权限。 +* 通过创建小组并包括适当的成员,可以轻松地`@mention`所有团队中的问题并合并请求。 -例如,您可以为公司成员创建一个[组](subgroups/index.html) ,并为每个单独的团队创建一个[子](subgroups/index.html)组. 假设您创建了一个名为`company-team` ,并且在该组中为各个团队`backend-team` , `frontend-team`和`production-team`创建了子组. +例如,您可以为公司成员创建一个[组织](subgroups/index.html) ,并为每个单独的团队创建一个[子组织](subgroups/index.html). 假设您创建了一个名为`company-team` ,并且在该组中为各个团队`backend-team` , `frontend-team`和`production-team`创建了子组。 * 从问题开始新的实现时,请添加评论: *" `@company-team` ,让我们开始吧!* *`@company-team/backend-team`您很高兴!"* * 当您的后端团队需要前端提供帮助时,他们会添加一条评论: *" `@company-team/frontend-team`您能在这里帮助我们吗?"* -* 前端团队完成实施后,他们会评论: *" `@company-team/backend-team` ,它已经完成!* *让我们将其运送到`@company-team/production-team` !* +* 前端团队完成实施后,他们会评论: *" `@company-team/backend-team` ,它已经完成!* *让我们将其推送到`@company-team/production-team` !* -## Namespaces[](#namespaces "Permalink") +## 命名空间[](#namespaces "Permalink") -在 GitLab 中,名称空间是用作用户名,组名或子组名的唯一名称. +在 CODEChina 中,命名空间将会是用户名称、组织名称或子组名的唯一名称。 -* `http://gitlab.example.com/username` -* `http://gitlab.example.com/groupname` -* `http://gitlab.example.com/groupname/subgroup_name` +* `https://codechina.csdn.net/username` +* `https://codechina.csdn.net/groupname` +* `https://codechina.csdn.net/groupname/subgroup_name` -例如,考虑一个名为 Alex 的用户: +例如,假设有一个名为 Miykael 的用户: -1. Alex 在 GitLab.com 上使用用户名`alex`创建了一个帐户; 他们的个人资料将在`https://gitlab.example.com/alex`下访问 -2. Alex 为他们的团队创建了一个小组,小组名称为`alex-team` ; 该小组及其项目将在`https://gitlab.example.com/alex-team`下访问 -3. 亚历克斯(Alex)创建了一个亚历克斯小组( `alex-team`子`alex-team` ,其子小组名称为`marketing` ; 该子小组及其项目将在`https://gitlab.example.com/alex-team/marketing`下访问 +1. Miykael 在 CODEChina 上使用用户名`Miykael`创建了一个帐户; 他们的个人资料将在`https://codechina.csdn.net/miykael`下访问 +2. Miykael 为他们的团队创建了一个组织,名称为`csdn-team` ; 该组织及其项目将在`https://codechina.csdn.net/csdn-team`下访问 +3. CSDN 创建了一个名为`coding`的子组织 ; 该子组织及其项目将在`https://codechina.csdn.net/csdn-team/coding`下访问 通过这样做: -* 任何团队成员都使用`@alex`提及 Alex -* 亚历克斯通过`@alex-team`提及了团队中的每个人 -* 亚历克斯只提及`@alex-team/marketing` +* 任何团队成员都使用`@miykael`提及 Miykael +* CSDN通过`@csdn-team`提及了团队中的每个人 +* CSDN只提及`@csdn-team/coding` + +> 注:出于系统安全以及知识产权、商标保护等因素,我们预留了一部分namespace,如果您的用户名与预留这部分namespace有冲突,系统将会自动对您在CODEChina中的namespace进行调整。 -## Issues and merge requests within a group[](#issues-and-merge-requests-within-a-group "Permalink") +## 组织内的Issue及合并请求[](#issues-and-merge-requests-within-a-group "Permalink") -问题和合并请求是项目的一部分. 对于给定的组,您可以在单个列表视图中查看所有[问题](../project/issues/index.html#issues-list)并将该组中所有项目的[请求合并](../project/merge_requests/reviewing_and_managing_merge_requests.html#view-merge-requests-for-all-projects-in-a-group)在一起. +Issue及合并请求是项目的一部分。对于组织,您可以在单个列表视图中查看所有[Issue](../project/issues/index.html#issues-list),也可以查看组织中所有项目的[请求合并](../project/merge_requests/reviewing_and_managing_merge_requests.html#view-merge-requests-for-all-projects-in-a-group)。 -### Bulk editing issues and merge requests[](#bulk-editing-issues-and-merge-requests "Permalink") +### 批量编辑Issue及合并请求[](#bulk-editing-issues-and-merge-requests "Permalink") -有关详细信息,请参阅[批量编辑问题和合并请求](../group/bulk_editing/index.html) . +有关详细信息,请参考[批量编辑Issue及合并请求](../group/bulk_editing/index.html) 。 -## Create a new group[](#create-a-new-group "Permalink") +## 新建一个组织[](#新建一个组织 "Permalink") > 有关不允许用作组名的单词列表,请参见[保留名称](../reserved_names.html) . -要创建新组,请执行以下任一操作: +通过以下方式,您可以创建一个新的组织: -* 在顶部菜单中,依次单击" **组"**和" **您的组"** ,然后单击绿色按钮" **新建组"** . +* 在顶部菜单中,依次单击" **组织"**和" **您的组织"** ,然后单击绿色按钮" **新建组织"** [![new group from groups page](img/7e5039b0d8fb74c5ea813e354f23493e.png)](img/new_group_from_groups.png) -* 或者,在顶部菜单中,展开`plus`号并选择**新建组** . +* 或者,在顶部菜单中,展开`+`号并选择**新建组织** [![new group from elsewhere](img/ee8ead7652026dd03a75e2551122350f.png)](img/new_group_from_other_pages.png) @@ -142,321 +87,196 @@ [![new group information](img/ad2cdacdd36348cddf7d5c19d8940d5b.png)](img/create_new_group_info.png) -1. **组名将**自动填充 URL. (可选)您可以更改它. 这是在组视图中显示的名称. 该名称只能包含: +1. **组织名称**将自动填充 URL(自动填充不支持中文的组织名称)。(可选)您可以修改它,这是在组视图中显示的名称,该名称只能包含: * 字母数字字符 + * 中文 * 下划线 - * 划线和点 - * 空间 + * 连接符`-`和点 + * 空格 2. **组 URL**是将托管项目的名称空间. 该网址只能包含: * 字母数字字符 * 下划线 - * 破折号和点(不能以破折号开头或以点结尾) -3. (可选)您可以添加简短说明,以告诉其他人该组的内容. -4. (可选)为您的群组选择一个头像. -5. Choose the [visibility level](../../public_access/public_access.html). + * 连接符`-`和点(不能以连接符`-`开头或以点结尾) +3. (可选)可以为新建的组织添加一段简单介绍,以便其他用户了解该组织 +4. (可选)可以为新建的组织上传一个头像 +5. 选择新建的组织 [是否公开可见](../../public_access/public_access.html) -有关创建组的更多详细信息,请观看视频[GitLab 命名空间(用户,组和子组)](https://youtu.be/r0sJgjR2f5A) . -## Add users to a group[](#add-users-to-a-group "Permalink") +## 为组织添加一个用户[](#add-users-to-a-group "Permalink") -将多个项目放在一个组中的好处是,您可以通过一个操作就授予用户访问该组中所有项目的权限. +将多个项目放在一个组织中的好处是,您可以通过一个操作就授予某个用户访问该组织中所有项目的权限。 -通过导航到组的仪表板并单击**Members**将成员添加到组. +在**组织设置-组织成员设置**中将成员添加到组织,可以通过用户名或者注册邮箱来添加组织成员。 [![add members to group](img/ece990045e1a7ae1237b5f2912a2df3e.png)](img/add_new_members.png) -选择[权限级别](../permissions.html#permissions) ,然后添加新成员. 您还可以设置该用户的到期日期. 这是他们将不再有权访问您的网上论坛的日期. +选择[权限级别](../permissions.html#permissions) ,然后添加新成员。您还可以设置该用户的到期日期。 -考虑一个有两个项目的小组: +假设一个有两个项目的组织: -* 现在,在" **组成员"**页面上,可以将新用户添加到组中. -* 现在,由于该用户是该组的**开发人员**成员,因此他们自动获得**开发人员**对该组内**所有项目的**访问权限. +* 在**组织设置-组织成员设置**页面上,可以将新用户添加到组织中; +* 当将新用户设置为组织的**开发人员**成员时,他们将获得**开发人员**对该组内**所有项目的**访问权限。 -要提高特定项目的现有用户的访问级别,请将其作为新成员再次添加到具有所需权限级别的项目中. +如果要提高特定项目的现有用户的访问权限,请将其作为新成员再次添加到特定项目中,并为其添加相应的项目成员角色。 -## Request access to a group[](#request-access-to-a-group "Permalink") +## 申请加入组织[](#request-access-to-a-group "Permalink") -作为论坛所有者,您可以启用或禁用非会员请求访问您论坛的功能. 转到组设置,然后单击**允许用户请求访问权限** . +作为组织所有者,您可以启用或禁用非组织成员请求访问组织的功能。该功能可以通过再**组织设置-常规设置-权限,LFS,2FS**中单击**允许用户请求访问(如果可见性是公开或内部的)**进行开启,该功能默认为启用状态。 -作为用户,如果启用了该设置,则可以请求成为组的成员. 转到您要加入的组,然后单击屏幕右侧的" **请求访问**权"按钮. +如果组织启用了该设置,则非组织成员用户可以请求成为组织的成员。在您要加入的组织页中,单击组织名称后面的**申请权限**按钮即可。 [![Request access button](img/aa2dd1694d7e1573bbd49200ed1ccb04.png)](img/request_access_button.png) -请求访问后: +申请访问权限后: -* 通过电子邮件将多达十个群组所有者的通知通知您. 电子邮件将发送给最近活动的组所有者. -* 任何论坛所有者都可以在会员页面上批准或拒绝您的请求. +* 通过电子邮件将您的申请告知给组织的所有者(电子邮件将发送给最近活跃的组织所有者) +* 任何组织所有者都可以在组组织成员设置页面上批准或拒绝您的申请 [![Manage access requests](img/fd0991d7941fed77c4d82bd219ec713b.png)](img/access_requests_management.png) -如果您在批准请求之前改变主意,只需单击" **撤回访问请求"**按钮. +如果您在申请权限被批准之前改变了主意,只需单击" **撤回访问请求"**按钮即可。 [![Withdraw access request button](img/a6d5e94df0d5d50038a0909603d69933.png)](img/withdraw_access_request_button.png) -## Changing the owner of a group[](#changing-the-owner-of-a-group "Permalink") - -Ownership of a group means at least one of its members has [Owner permission](../permissions.html#group-members-permissions). Groups must have at least one owner. - -可以只更改一个所有者的组所有者. 更改组的唯一所有者: - -* 作为管理员: - 1. 前往小组的 **成员**选项卡. - 2. 赋予其他成员**所有者**权限. - 3. 刷新页面. 现在,您可以从原始所有者中删除**所有者**权限. -* 作为当前组的所有者: - 1. 前往小组的 **成员**选项卡. - 2. 赋予其他成员**所有者**权限. - 3. 让新的所有者登录并从您中删除**所有者**权限. +## 变更组织的所有者[](#changing-the-owner-of-a-group "Permalink") -## Remove a member from the group[](#remove-a-member-from-the-group "Permalink") +组织的所有关系是指至少有一个组织成员拥有组织的 [所有者权限](../permissions.html#group-members-permissions),一个组织至少需要一名所有者。 -只有[拥有所有者](../permissions.html#group-members-permissions)权限的[用户](../permissions.html#group-members-permissions)才能管理组成员. +只有拥有一个所有者的组织可以变更组织的所有者。 可以通过以下方式变更组织唯一所有者: -如果给定成员在该组中具有直接成员资格,则可以从该组中删除该成员. 如果成员资格是从父组继承的,则该成员只能从父组本身中删除. +1. 前往组织的 **组织设置-组织成员设置**选项卡; +2. 赋予其他成员**所有者**权限; +3. 让新的所有者删除您的**所有者**权限。 -删除成员时,您可以决定是从所有问题中取消分配用户,还是合并当前已分配的请求,还是保留分配. +## 移除组织成员[](#remove-a-member-from-the-group "Permalink") -* 当用户离开私人组并且您希望撤消他们对所有问题的访问并分配他们的合并请求时,从所有问题和合并请求中**取消分配已删除的成员**可能会有所帮助. -* **保留问题和合并请求的分配**可能对于接受公共贡献的组很有帮助,在这些组中,用户不必是成员就可以为问题和合并请求做出贡献. +只有[拥有所有者](../permissions.html#group-members-permissions)权限的[用户](../permissions.html#group-members-permissions)才能管理组织成员。 -要从组中删除成员: +如果要移除的成员在该组中具有直接成员资格,则可以从该组织中移除该成员; 如果成员资格是从父组继承的,则该成员只能从父组中进行移除。 -1. 在一个小组中,转到 **成员们** . -2. 点击**删除** 要删除的群组成员旁边的按钮. 出现" **删除成员"**模态. -3. (可选)选中" **也从相关问题中取消分配此用户并合并请求"**复选框. -4. Click **删除会员**. +移除成员时,您可以决定是否取消已经指派给该成员的 Issue 及合并请求。 -## Changing the default branch protection of a group[](#changing-the-default-branch-protection-of-a-group "Permalink") +* **取消分配给已移除的成员的 Issue及合并请求**可以将已经分配给当前要移除用户的 Issue 及合并请求重新进行分配 +* **保留Issue和合并请求的分配**可能对于接受公开贡献的组织很有帮助,用户可以不必是组织成员就可以为 Issue 及合并请求做出贡献 -在 GitLab 12.9 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/7583) . +可以通过以下操作将成员从组织中移除: -默认情况下,每个组都继承全局级别的分支保护集. +1. 在一个组织中,进入 **组织设置-组织成员设置** +2. 找到要移除的成员,并点击**移除**按钮,这时会弹出 **移除成员** 的弹窗 +3. (可选)选中 **取消分配给已移除的成员的 Issue及合并请求** 的复选框 +4. 点击**移除成员**按钮 -要为特定组更改此设置: +## 变更组织的默认保护分支[](#changing-the-default-branch-protection-of-a-group "Permalink") -1. 前往小组的 **设置>常规**页面. -2. 展开" **权限,LFS,2FA"**部分. -3. 在" **默认分支保护"**下拉列表中选择所需的选项. -4. Click **保存更改**. +默认情况下,每个组织都会继承全局级别的分支保护。 -要全局更改此设置,请参阅[默认分支保护](../admin_area/settings/visibility_and_access_controls.html#default-branch-protection) . +您可以通过以下操作为特定组织变更此项设置: -**注意:**在[GitLab Premium 或更高版本中](https://about.gitlab.com/pricing/) ,GitLab 管理员可以选择[禁止组所有者更新默认的分支保护](../admin_area/settings/visibility_and_access_controls.html#disable-group-owners-from-updating-default-branch-protection-premium-only) . +1. 打开组织的 **组织设置-常规设置**页面 +2. 展开 **权限,LFS,2FA**部分 +3. 在**默认分支保护**下拉列表中选择所需的选项 +4. 点击 **保存修改** -## Add projects to a group[](#add-projects-to-a-group "Permalink") +## 在组织中新建项目[](#add-projects-to-a-group "Permalink") -有两种方法可以将新项目添加到组中: +有两种方法可以在组织中新建项目: -* 选择一个组,然后单击" **新建项目"** . 然后,您可以继续[创建您的项目](../../gitlab-basics/create-project.html) . +* 选择一个组,单击**新建项目**按钮 。 然后,您可以继续[创建您的项目](../../basics/create-project.html) . [![New project](img/ef67d77909a856277f9f2821fa0c18ea.png)](img/create_new_project_from_group.png) -* 在创建项目时,请从下拉菜单中选择已经创建的组名称空间. +* 在创建项目时,从下拉菜单中选择已经创建的组名称空间 [![Select group](img/674c1579957cca4a644bc90fb8fbb2f3.png)](img/select_group_dropdown.png) -### Default project-creation level[](#default-project-creation-level "Permalink") +### 项目创建权限[](#default-project-creation-level "Permalink") -版本历史 - -* 在[GitLab Premium](https://about.gitlab.com/pricing/) 10.5 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/2534) . -* 在 10.7 中带到[GitLab Starter](https://about.gitlab.com/pricing/) . -* 在 11.10 中[移至](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/25975) [GitLab Core](https://about.gitlab.com/pricing/) . - -默认情况下, [开发人员和维护人员](../permissions.html#group-members-permissions)可以在一个组下创建项目. - -要为特定组更改此设置: - -1. 转到论坛的**设置>常规**页面. -2. 展开" **权限,LFS,2FA"**部分. -3. 在" **允许创建项目"**下拉列表中选择所需的选项. -4. Click **保存更改**. +默认情况下, [开发人员和维护人员](../permissions.html#group-members-permissions)可以在一个组下创建项目。 -要全局更改此设置,请参阅[默认项目创建保护](../admin_area/settings/visibility_and_access_controls.html#default-project-creation-protection) . +可以通过以下操作为特定组更改此项设置: -## View group details[](#view-group-details "Permalink") +1. 进入组织的**组织设置>常规设置**页面 +2. 展开 **权限,LFS,2FA**部分 +3. 在 **允许创建项目**下拉列表中选择所需的选项 +4. 点击 **保存修改** -组的" **详细信息"**页面包含以下选项卡: - -* 小组和项目. -* 共享的项目. -* 存档的项目. - -### Group activity analytics overview[](#group-activity-analytics-overview "Permalink") - -版本历史 +## 查看组织详情[](#view-group-details "Permalink") -* 在 GitLab [Starter](https://about.gitlab.com/pricing/) 12.10 中作为[测试版功能](https://about.gitlab.com/handbook/product/#beta) [引入](https://gitlab.com/gitlab-org/gitlab/-/issues/207164) +组织的 **详细信息**页面包含以下内容: -组详细信息视图还显示最近 90 天内创建的以下项目数: +* 组织的基本信息和介绍 +* 组织的项目 +* 组织已存档的项目 +* 组织的成员 -* 合并请求. -* Issues. -* Members. -可以使用`group_activity_analytics` [功能标记](../../development/feature_flags/development.html#enabling-a-feature-flag-in-development)启用这些组活动分析. +## 将项目移到组织中[](#transfer-projects-into-groups "Permalink") -[![Recent Group Activity](img/645965e7ebb61697ff42cc06214ca5af.png)](img/group_activity_analytics_v12_10.png) +了解如何[将项目转移到组织中](../project/settings/index.html#transferring-an-existing-project-into-another-namespace) . -有关详细信息,请参阅有关如何[查看组活动的部分](#view-group-activity) . +## 与组织共享一个项目[](#sharing-a-project-with-a-group "Permalink") -## View group activity[](#view-group-activity "Permalink") - -群组的" **活动"**页面显示群组中最近执行的操作,包括: - -* **推送事件** :最近推送到分支. -* **合并事件** :最近合并. -* **发行事件** :已发行或已关闭的发行. -* **史诗般的事件** :史诗集开启或关闭. -* **评论** :评论已打开或关闭. -* **小组** :已加入或离开小组的小组成员. -* **Wiki** :创建,删除或更新的 Wiki. - -单击**RSS**图标,还可以 Atom 格式获得整个活动供稿. - -要查看论坛的" **活动"**页面,请执行以下操作: - -1. 转到论坛的页面. -2. 在左侧导航菜单中,转到" **组概述",**然后选择" **活动"** . - -## Transfer projects into groups[](#transfer-projects-into-groups "Permalink") - -了解如何[将项目转移到小组中](../project/settings/index.html#transferring-an-existing-project-into-another-namespace) . - -## Sharing a project with a group[](#sharing-a-project-with-a-group "Permalink") - -您可以[与一个小组共享您的项目,](../project/members/share_project_with_groups.html)并向所有小组成员立即授予对该项目的访问权限. +您可以[与组织共享您的项目](../project/members/share_project_with_groups.html),并向所有组织成员立即授予对该项目的访问权限。 或者,您可以[锁定共享与组功能](#share-with-group-lock) . -## Sharing a group with another group[](#sharing-a-group-with-another-group "Permalink") +## 与组织共享另一个组织[](#sharing-a-group-with-another-group "Permalink") -在 GitLab 12.7 中[引入](https://gitlab.com/gitlab-org/gitlab/-/issues/18328) . - -与[与组共享项目](#sharing-a-project-with-a-group)类似,您可以与另一个组共享一个组,以使直接的组成员可以访问共享的组. 这对于继承的成员无效. +与[与组织共享项目](#sharing-a-project-with-a-group)类似,您可以与一个组织共享另一个组织,以使组织成员可以直接访问共享的组织(注:这对于继承的成员无效)。 要将给定的组(例如"前端")与另一个组(例如"工程")共享: -1. 导航到"前端"群组页面,然后使用左侧的导航菜单转到群组" **成员"** . -2. Select the **邀请小组** tab. -3. 以您选择的最大访问权限级别添加"工程". -4. Click **Invite**. - -"工程"组的所有成员将被添加到"前端". - -## Manage group memberships via LDAP[](#manage-group-memberships-via-ldap "Permalink") - -组同步允许将 LDAP 组映射到 GitLab 组. 这样可以更好地控制每组用户的管理. 要配置组同步,请编辑`group_base` **DN** ( `'OU=Global Groups,OU=GitLab INT,DC=GitLab,DC=org'` ). 该**OU**包含将与 GitLab 组关联的所有组. - -可以使用 CN 或过滤器创建组链接. 这些组链接在**组设置-> LDAP 同步**页面上创建. 配置链接后,用户可能需要一个多小时才能与 GitLab 组进行同步. - -有关 LDAP 和组同步管理的更多信息,请参阅[LDAP 主文档](../../administration/auth/ldap/index.html#group-sync-starter-only) . - -**注意:**如果在添加 LDAP 同步时 LDAP 用户是组成员,并且它们不属于 LDAP 组,则将从该组中将其删除. - -### Creating group links via CN[](#creating-group-links-via-cn-starter-only "Permalink") - -通过 CN 创建群组链接: +1. 进入到"前端"组织页面,然后进入**组织设置-组织成员设置**页面 +2. 单击 **邀请组织** 按钮 +3. 选择您要共享的组织"工程",并设置访问权限 +4. 点击 **邀请** -1. 选择**LDAP 服务器**作为链接. -2. 选择`LDAP Group cn`作为**同步方法** . -3. 在" **LDAP 组 cn"**文本输入框中,开始输入组的 CN. 在配置的`group_base`中将有一个带有匹配 CN 的下拉菜单. 从此列表中选择您的 CN. -4. 在" **LDAP 访问"**部分中,选择在该组中同步的用户的[权限级别](../permissions.html) . -5. 单击`Add Synchronization`按钮以保存该组链接. +"工程"的所有成员将被添加到"前端"组织中。 -[![Creating group links via CN](img/5d200a6bcc883fcfa57dac51301bc2e3.png)](img/ldap_sync_cn_v13_1.png) -### Creating group links via filter[](#creating-group-links-via-filter-premium-only "Permalink") +## 转移组织[](#transferring-groups "Permalink") -通过过滤器创建组链接: +您可以通过以下方式转移组织: -1. 选择**LDAP 服务器**作为链接. -2. 选择`LDAP user filter`作为**Sync 方法** . -3. 在" **LDAP 用户"过滤器**框中输入过滤**器** . 请遵循[有关用户过滤器](../../administration/auth/ldap/index.html#set-up-ldap-user-filter-core-only)的[文档](../../administration/auth/ldap/index.html#set-up-ldap-user-filter-core-only) . -4. 在" **LDAP 访问"**部分中,选择在该组中同步的用户的[权限级别](../permissions.html) . -5. 单击`Add Synchronization`按钮以保存该组链接. +* 将子组织转移到新的父组织 +* 通过将顶级组织转移到所需的组织,并将其转换为子组织 +* 通过将子组织转移到顶级组织,可以将一个子组织转换为组织 -[![Creating group links via filter](img/5b8558c08a5996468dcd0d1a119ac76b.png)](img/ldap_sync_filter_v13_1.png) +转移组织时,请注意: -### Overriding user permissions[](#overriding-user-permissions-starter-only "Permalink") +* 更改组织的父组织可能会产生一些副作用,具体的请参阅[更改存储库路径时的重定向](../project/index.html#redirects-when-changing-repository-paths) ; +* 您只能将组织/子组织转移到您管理的组织/子组织中; +* 您必须手动更新本地存储库以指向新位置; +* 如果将要转移的父组织的公开可见性设置低于当前父组织,那么待转移组织机器项目的公开可见性将会与即将要转移到的父组织保持一致; +* 转移组织时,只有组织直接成员会被转移,从之前父组织集成的成员不会被转移。如果待转移组织的所有者是继承的身份成员,则该组织转移过去后将不会设有所有者,转移组的用户将会自动成为该组的所有者。 -从 GitLab [v8.15 开始,](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/822) LDAP 用户权限现在可以由管理员用户手动覆盖. 覆盖用户的权限: -1. 转到您小组的" **成员"**页面. -2. 在您要编辑的用户的行中选择铅笔图标. -3. 选择橙色的`Change permissions`按钮. +## 组织设置[](#group-settings "Permalink") -[![Setting manual permissions](img/c6273de0eb8e4c8e7750113a7a66e7d6.png)](img/manual_permissions_v13_1.png) - -现在,您将能够从" **成员"**页面编辑用户的权限. - -## Epics[](#epics-ultimate "Permalink") - -在[GitLab Ultimate](https://about.gitlab.com/pricing/) 10.2 中引入. - -Epics 通过跟踪跨项目和里程碑共享主题的问题组,使您可以更有效,更轻松地管理项目组合. - -[Learn more about Epics.](epics/index.html) - -## Group Security Dashboard[](#group-security-dashboard-ultimate "Permalink") - -概述组及其子组中所有项目的漏洞. - -[Learn more about the Group Security Dashboard.](security_dashboard/index.html) - -## Insights[](#insights-ultimate "Permalink") - -[Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0. - -配置对您的组或项目重要的见解,使用户可以浏览以下数据: - -* 分诊卫生 -* 在给定期间内创建/关闭的问题 -* 合并请求的平均合并时间 -* 多得多 - -[Learn more about Insights](insights/index.html). - -## Transferring groups[](#transferring-groups "Permalink") - -在 GitLab 10.5 中,您可以通过以下方式转移组: - -* 将子组转移到新的父组. -* 通过将顶级组转移到所需的组,将其转换为子组. -* Convert a subgroup into a top-level group by transferring it out of its current group. - -转移群组时,请注意: - -* 更改组的父母可能会产生意想不到的副作用. 请参阅[更改存储库路径时的重定向](../project/index.html#redirects-when-changing-repository-paths) . -* 您只能将群组转移到您管理的群组中. -* 您必须更新本地存储库以指向新位置. -* If the immediate parent group’s visibility is lower than the group’s current visibility, visibility levels for subgroups and projects will change to match the new parent group’s visibility. -* 仅传输显式组成员身份,不继承继承成员身份. 如果组的所有者仅继承了成员身份,则该组将没有所有者. 在这种情况下,转移组的用户将成为该组的所有者. - -## Group settings[](#group-settings "Permalink") - -创建群组后,您可以导航至该群组的信息中心,然后点击**设置**来管理其设置. +创建组织后,在组织详情页您可以进入**组织设置**来对组织进行设置及管理: [![group settings](img/b98f1bb6205ce5c692946b81e8c78003.png)](img/group_settings.png) -### General settings[](#general-settings "Permalink") +### 常规设置[](#general-settings "Permalink") -除了编辑您在[创建组](#create-a-new-group)时先前设置的任何设置之外,您还可以访问[该组的](#create-a-new-group)其他配置. +除了编辑您在[创建组织](#新建一个组织)时预先设置的内容外,您还可以对该组织的其他内容进行设置。 -#### Changing a group’s path[](#changing-a-groups-path "Permalink") +#### 变更组织的路径[](#changing-a-groups-path "Permalink") -更改组的路径可能会有意想不到的副作用. 在继续之前,请阅读[重定向的行为](../project/index.html#redirects-when-changing-repository-paths) . +变更组织的路径也可能会产生一些副作用,具体的请参考[重定向的行为](../project/index.html#redirects-when-changing-repository-paths) 。 -如果您要腾出路径,以便其他组或用户可以声明该路径,则由于名称和路径都必须是唯一的,因此您可能也需要重命名该组. +如果您要腾出路径,以便其他组织或用户可以使用该路径,由于名称和路径都必须是唯一的,因此您在变更路径的同时也可能需要重命名该组织。 -更改组路径: +您可以通过以下操作更改组织的路径: -1. 导航到论坛的**"设置">"常规"**页面. -2. 展开**路径,传输,删除**部分. -3. 在" **更改组路径"**下输入新名称. -4. Click **变更群组路径**. +1. 进入到组织的**组织设置>常规设置**页面 +2. 展开**高级**部分 +3. 在 **更改组织路径**下输入新的路径 +4. 点击 **变更组织路径** -**注意:**如果命名空间包含带有[Container Registry](../packages/container_registry/index.html)标记的项目,则当前无法重命名该命名空间,因为该项目无法移动.**提示:**如果要保留对原始名称空间的所有权并保护 URL 重定向,则可以更改一个组并向其传输项目,而无需更改组的路径或重命名用户名. +> **注意:**如果命名空间包含带有[Container Registry](../packages/container_registry/index.html)标记的项目,则无法重命名该空间,因为该项目无法移动。 +> +> **提示:**如果要保留对原始名称空间的所有权并保护 URL 重定向,我们建议您新建一个群组并向其转移项目,而无需更改组织的路径或重命名用户名。 ### Remove a group[](#remove-a-group "Permalink") @@ -637,17 +457,6 @@ Epics 通过跟踪跨项目和里程碑共享主题的问题组,使您可以 * **审核事件** :查看该组的[审核事件](../../administration/audit_events.html) . * **管道配额** :跟踪组的[管道配额](../admin_area/settings/continuous_integration.html) . -#### Storage usage quota[](#storage-usage-quota-starter "Permalink") - -[Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/13294) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.0. - -组所有者可以在组页面设置列表可用的" **使用配额"**页面的" **存储"**选项卡中,查看一个组(包括子组)中所有项目的聚合存储使用情况. - -[![Group storage usage quota](img/7042e9f430cefb3a9c62194cec839692.png)](img/group_storage_usage_quota.png) - -如果触发了任何会影响其值的相关事件(例如,提交推送),则将更新存储的总使用量. 出于性能原因,我们可能会将更新延迟最多 1 小时 30 分钟. - -如果您的名称空间显示`N/A`作为总存储使用量,则可以通过将提交推送到该名称空间中的任何项目来触发重新计算. #### Group push rules[](#group-push-rules-starter "Permalink") @@ -660,28 +469,4 @@ Epics 通过跟踪跨项目和里程碑共享主题的问题组,使您可以 设置后,新的子组将根据以下任一条件为其设置推送规则: * 定义了推送规则的最接近的父组. -* 如果没有父组定义推送规则,则在实例级别设置推送规则. - -##### Enabling the feature[](#enabling-the-feature "Permalink") - -默认情况下,此功能带有`:group_push_rules`功能标记. 可以使用功能标记[API 端点](../../api/features.html#set-or-create-a-feature)或通过具有 Rails 控制台访问权限的 GitLab 管理员为特定组启用它,方法是运行: - -``` -Feature.enable(:group_push_rules) -``` - -### Maximum artifacts size[](#maximum-artifacts-size-core-only "Permalink") - -有关为组设置最大工件大小的信息,请参见[最大工件大小](../admin_area/settings/continuous_integration.html#maximum-artifacts-size-core-only) . - -## User contribution analysis[](#user-contribution-analysis-starter "Permalink") - -使用[GitLab Contribution Analytics](contribution_analytics/index.html) ,您可以概述组成员执行的贡献(推送,合并请求和问题). - -## Issues analytics[](#issues-analytics-premium "Permalink") - -使用[GitLab Issues Analytics](issues_analytics/index.html) ,您可以查看组中每个月创建的问题数量的条形图. - -## Dependency Proxy[](#dependency-proxy-premium "Permalink") - -使用 GitLab 作为上游 Docker 映像的[依赖项代理](../packages/dependency_proxy/index.html) . \ No newline at end of file +* 如果没有父组定义推送规则,则在实例级别设置推送规则. \ No newline at end of file diff --git a/node_modules/.bin/cake b/node_modules/.bin/cake deleted file mode 120000 index d95f32af48adc98f911bba3e83f3724566fd35c9..0000000000000000000000000000000000000000 --- a/node_modules/.bin/cake +++ /dev/null @@ -1 +0,0 @@ -../coffee-script/bin/cake \ No newline at end of file diff --git a/node_modules/.bin/coffee b/node_modules/.bin/coffee deleted file mode 120000 index b57f275d7de58767bfe8245846ac09dbc80a9173..0000000000000000000000000000000000000000 --- a/node_modules/.bin/coffee +++ /dev/null @@ -1 +0,0 @@ -../coffee-script/bin/coffee \ No newline at end of file diff --git a/node_modules/.bin/esparse b/node_modules/.bin/esparse deleted file mode 120000 index 7423b18b24efb09ee2916ad6db079b83ef0eb132..0000000000000000000000000000000000000000 --- a/node_modules/.bin/esparse +++ /dev/null @@ -1 +0,0 @@ -../esprima/bin/esparse.js \ No newline at end of file diff --git a/node_modules/.bin/esvalidate b/node_modules/.bin/esvalidate deleted file mode 120000 index 16069effbc99a3dfc83b6a7b8f04a2c18fb9861f..0000000000000000000000000000000000000000 --- a/node_modules/.bin/esvalidate +++ /dev/null @@ -1 +0,0 @@ -../esprima/bin/esvalidate.js \ No newline at end of file diff --git a/node_modules/.bin/js-yaml b/node_modules/.bin/js-yaml deleted file mode 120000 index 9dbd010d470368b942148cb9ec3acf02d7aac993..0000000000000000000000000000000000000000 --- a/node_modules/.bin/js-yaml +++ /dev/null @@ -1 +0,0 @@ -../js-yaml/bin/js-yaml.js \ No newline at end of file diff --git a/node_modules/.bin/markdown-toc b/node_modules/.bin/markdown-toc deleted file mode 120000 index d18b9c774e36bf8b1f17b7784d06d018f930ee53..0000000000000000000000000000000000000000 --- a/node_modules/.bin/markdown-toc +++ /dev/null @@ -1 +0,0 @@ -../markdown-toc/cli.js \ No newline at end of file diff --git a/node_modules/.bin/remarkable b/node_modules/.bin/remarkable deleted file mode 120000 index 29c2d736a85a68acd911b4c564ccf7f35f6b3365..0000000000000000000000000000000000000000 --- a/node_modules/.bin/remarkable +++ /dev/null @@ -1 +0,0 @@ -../remarkable/bin/remarkable.js \ No newline at end of file diff --git a/node_modules/ansi-red/LICENSE b/node_modules/ansi-red/LICENSE deleted file mode 100644 index 41283c9f71f85ee1686a2721160fde87677044f5..0000000000000000000000000000000000000000 --- a/node_modules/ansi-red/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) <%= year() %>, Jon Schlinkert. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/node_modules/ansi-red/index.js b/node_modules/ansi-red/index.js deleted file mode 100644 index 00ea30283a8d04d3f3d0f51e031add4e975ea58b..0000000000000000000000000000000000000000 --- a/node_modules/ansi-red/index.js +++ /dev/null @@ -1,14 +0,0 @@ -/*! - * ansi-red - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ - -'use strict'; - -var wrap = require('ansi-wrap'); - -module.exports = function red(message) { - return wrap(31, 39, message); -}; diff --git a/node_modules/ansi-red/package.json b/node_modules/ansi-red/package.json deleted file mode 100644 index 11d085a4be2ad4b59d9f0c66c871645ba59e936e..0000000000000000000000000000000000000000 --- a/node_modules/ansi-red/package.json +++ /dev/null @@ -1,115 +0,0 @@ -{ - "_args": [ - [ - { - "name": "ansi-red", - "raw": "ansi-red@^0.1.1", - "rawSpec": "^0.1.1", - "scope": null, - "spec": ">=0.1.1 <0.2.0", - "type": "range" - }, - "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/gray-matter" - ] - ], - "_from": "ansi-red@>=0.1.1 <0.2.0", - "_id": "ansi-red@0.1.1", - "_inCache": true, - "_installable": true, - "_location": "/ansi-red", - "_nodeVersion": "0.12.0", - "_npmUser": { - "email": "github@sellside.com", - "name": "jonschlinkert" - }, - "_npmVersion": "2.10.0", - "_phantomChildren": {}, - "_requested": { - "name": "ansi-red", - "raw": "ansi-red@^0.1.1", - "rawSpec": "^0.1.1", - "scope": null, - "spec": ">=0.1.1 <0.2.0", - "type": "range" - }, - "_requiredBy": [ - "/gray-matter" - ], - "_resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", - "_shasum": "8c638f9d1080800a353c9c28c8a81ca4705d946c", - "_shrinkwrap": null, - "_spec": "ansi-red@^0.1.1", - "_where": "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/gray-matter", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/ansi-red/issues" - }, - "dependencies": { - "ansi-wrap": "0.1.0" - }, - "description": "The color red, in ansi.", - "devDependencies": { - "mocha": "*" - }, - "directories": {}, - "dist": { - "shasum": "8c638f9d1080800a353c9c28c8a81ca4705d946c", - "tarball": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz" - }, - "engines": { - "node": ">=0.10.0" - }, - "files": [ - "index.js" - ], - "homepage": "https://github.com/jonschlinkert/ansi-red", - "keywords": [ - "red", - "256", - "ansi", - "cli", - "color", - "colors", - "colour", - "command", - "command-line", - "console", - "format", - "formatting", - "iterm", - "log", - "logging", - "rgb", - "shell", - "string", - "style", - "styles", - "styling", - "terminal", - "text", - "tty", - "xterm" - ], - "license": "MIT", - "main": "index.js", - "maintainers": [ - { - "email": "github@sellside.com", - "name": "jonschlinkert" - } - ], - "name": "ansi-red", - "optionalDependencies": {}, - "readme": "ERROR: No README data found!", - "repository": { - "type": "git", - "url": "git+https://github.com/jonschlinkert/ansi-red.git" - }, - "scripts": { - "test": "mocha" - }, - "version": "0.1.1" -} diff --git a/node_modules/ansi-red/readme.md b/node_modules/ansi-red/readme.md deleted file mode 100644 index e09e77b3ec2fb5cd3deeb4590e788ad28639e236..0000000000000000000000000000000000000000 --- a/node_modules/ansi-red/readme.md +++ /dev/null @@ -1,74 +0,0 @@ -# ansi-red [![NPM version](https://badge.fury.io/js/ansi-red.svg)](http://badge.fury.io/js/ansi-red) - -> The color red, in ansi. - -## Install - -Install with [npm](https://www.npmjs.com/) - -```sh -$ npm i ansi-red --save -``` - -## Usage - -```js -var red = require('ansi-red'); -``` - -## Related projects - -* [ansi-reset](https://github.com/jonschlinkert/ansi-reset) -* [ansi-bold](https://github.com/jonschlinkert/ansi-bold) -* [ansi-dim](https://github.com/jonschlinkert/ansi-dim) -* [ansi-italic](https://github.com/jonschlinkert/ansi-italic) -* [ansi-underline](https://github.com/jonschlinkert/ansi-underline) -* [ansi-inverse](https://github.com/jonschlinkert/ansi-inverse) -* [ansi-hidden](https://github.com/jonschlinkert/ansi-hidden) -* [ansi-strikethrough](https://github.com/jonschlinkert/ansi-strikethrough) -* [ansi-black](https://github.com/jonschlinkert/ansi-black) -* [ansi-red](https://github.com/jonschlinkert/ansi-red) -* [ansi-green](https://github.com/jonschlinkert/ansi-green) -* [ansi-yellow](https://github.com/jonschlinkert/ansi-yellow) -* [ansi-blue](https://github.com/jonschlinkert/ansi-blue) -* [ansi-magenta](https://github.com/jonschlinkert/ansi-magenta) -* [ansi-cyan](https://github.com/jonschlinkert/ansi-cyan) -* [ansi-white](https://github.com/jonschlinkert/ansi-white) -* [ansi-gray](https://github.com/jonschlinkert/ansi-gray) -* [ansi-grey](https://github.com/jonschlinkert/ansi-grey) -* [ansi-bgblack](https://github.com/jonschlinkert/ansi-bgblack) -* [ansi-bgred](https://github.com/jonschlinkert/ansi-bgred) -* [ansi-bggreen](https://github.com/jonschlinkert/ansi-bggreen) -* [ansi-bgyellow](https://github.com/jonschlinkert/ansi-bgyellow) -* [ansi-bgblue](https://github.com/jonschlinkert/ansi-bgblue) -* [ansi-bgmagenta](https://github.com/jonschlinkert/ansi-bgmagenta) -* [ansi-bgcyan](https://github.com/jonschlinkert/ansi-bgcyan) -* [ansi-bgwhite](https://github.com/jonschlinkert/ansi-bgwhite) - -## Running tests - -Install dev dependencies: - -```sh -$ npm i -d && npm test -``` - -## Contributing - -Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/jonschlinkert/ansi-red/issues/new) - -## Author - -**Jon Schlinkert** - -+ [github/jonschlinkert](https://github.com/jonschlinkert) -+ [twitter/jonschlinkert](http://twitter.com/jonschlinkert) - -## License - -Copyright © 2015 Jon Schlinkert -Released under the MIT license. - -*** - -_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on May 21, 2015._ \ No newline at end of file diff --git a/node_modules/ansi-wrap/LICENSE b/node_modules/ansi-wrap/LICENSE deleted file mode 100644 index 65f90aca8c2fff1b890f31f571aa41ddfc8d9a10..0000000000000000000000000000000000000000 --- a/node_modules/ansi-wrap/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015, Jon Schlinkert. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/node_modules/ansi-wrap/README.md b/node_modules/ansi-wrap/README.md deleted file mode 100644 index 032c1e6b2e3dc9cd69564ac09daccf0970b929da..0000000000000000000000000000000000000000 --- a/node_modules/ansi-wrap/README.md +++ /dev/null @@ -1,89 +0,0 @@ -# ansi-wrap [![NPM version](https://badge.fury.io/js/ansi-wrap.svg)](http://badge.fury.io/js/ansi-wrap) - -> Create ansi colors by passing the open and close codes. - -## Install - -Install with [npm](https://www.npmjs.com/) - -```sh -$ npm i ansi-wrap --save -``` - -## Usage - -```js -var wrap = require('ansi-wrap'); -``` - -**Example** - -Pass codes for [ansi magenta background](https://github.com/jonschlinkert/ansi-bgmagenta): - -```js -console.log(wrap(45, 49, 'This is a message...')); -//=> '\u001b[45mfoo\u001b[49m' -``` - -Which prints out... - -[![screen shot 2015-05-21 at 8 28 32 pm](https://cloud.githubusercontent.com/assets/383994/7761769/12488afa-fff8-11e4-9cc1-71a8a6ec14a4.png)](https://www.npmjs.com/) - -## Related projects - -This is used in these projects: - -* [ansi-reset](https://github.com/jonschlinkert/ansi-reset) -* [ansi-bold](https://github.com/jonschlinkert/ansi-bold) -* [ansi-dim](https://github.com/jonschlinkert/ansi-dim) -* [ansi-italic](https://github.com/jonschlinkert/ansi-italic) -* [ansi-underline](https://github.com/jonschlinkert/ansi-underline) -* [ansi-inverse](https://github.com/jonschlinkert/ansi-inverse) -* [ansi-hidden](https://github.com/jonschlinkert/ansi-hidden) -* [ansi-strikethrough](https://github.com/jonschlinkert/ansi-strikethrough) -* [ansi-black](https://github.com/jonschlinkert/ansi-black) -* [ansi-red](https://github.com/jonschlinkert/ansi-red) -* [ansi-green](https://github.com/jonschlinkert/ansi-green) -* [ansi-yellow](https://github.com/jonschlinkert/ansi-yellow) -* [ansi-blue](https://github.com/jonschlinkert/ansi-blue) -* [ansi-magenta](https://github.com/jonschlinkert/ansi-magenta) -* [ansi-cyan](https://github.com/jonschlinkert/ansi-cyan) -* [ansi-white](https://github.com/jonschlinkert/ansi-white) -* [ansi-gray](https://github.com/jonschlinkert/ansi-gray) -* [ansi-grey](https://github.com/jonschlinkert/ansi-grey) -* [ansi-bgblack](https://github.com/jonschlinkert/ansi-bgblack) -* [ansi-bgred](https://github.com/jonschlinkert/ansi-bgred) -* [ansi-bggreen](https://github.com/jonschlinkert/ansi-bggreen) -* [ansi-bgyellow](https://github.com/jonschlinkert/ansi-bgyellow) -* [ansi-bgblue](https://github.com/jonschlinkert/ansi-bgblue) -* [ansi-bgmagenta](https://github.com/jonschlinkert/ansi-bgmagenta) -* [ansi-bgcyan](https://github.com/jonschlinkert/ansi-bgcyan) -* [ansi-bgwhite](https://github.com/jonschlinkert/ansi-bgwhite) - -## Running tests - -Install dev dependencies: - -```sh -$ npm i -d && npm test -``` - -## Contributing - -Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](https://github.com/jonschlinkert/ansi-wrap/issues/new) - -## Author - -**Jon Schlinkert** - -+ [github/jonschlinkert](https://github.com/jonschlinkert) -+ [twitter/jonschlinkert](http://twitter.com/jonschlinkert) - -## License - -Copyright © 2015 Jon Schlinkert -Released under the MIT license. - -*** - -_This file was generated by [verb-cli](https://github.com/assemble/verb-cli) on May 21, 2015._ \ No newline at end of file diff --git a/node_modules/ansi-wrap/index.js b/node_modules/ansi-wrap/index.js deleted file mode 100644 index ffc52d75cc2d41695520f51ce6c99b6906f1da67..0000000000000000000000000000000000000000 --- a/node_modules/ansi-wrap/index.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -module.exports = function(a, b, msg) { - return '\u001b['+ a + 'm' + msg + '\u001b[' + b + 'm'; -}; diff --git a/node_modules/ansi-wrap/package.json b/node_modules/ansi-wrap/package.json deleted file mode 100644 index 31adc316cc77b21f834efa59c4e06349b4b6d0cd..0000000000000000000000000000000000000000 --- a/node_modules/ansi-wrap/package.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "_args": [ - [ - { - "name": "ansi-wrap", - "raw": "ansi-wrap@0.1.0", - "rawSpec": "0.1.0", - "scope": null, - "spec": "0.1.0", - "type": "version" - }, - "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/ansi-red" - ] - ], - "_from": "ansi-wrap@0.1.0", - "_id": "ansi-wrap@0.1.0", - "_inCache": true, - "_installable": true, - "_location": "/ansi-wrap", - "_nodeVersion": "0.12.0", - "_npmUser": { - "email": "github@sellside.com", - "name": "jonschlinkert" - }, - "_npmVersion": "2.5.1", - "_phantomChildren": {}, - "_requested": { - "name": "ansi-wrap", - "raw": "ansi-wrap@0.1.0", - "rawSpec": "0.1.0", - "scope": null, - "spec": "0.1.0", - "type": "version" - }, - "_requiredBy": [ - "/ansi-red" - ], - "_resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "_shasum": "a82250ddb0015e9a27ca82e82ea603bbfa45efaf", - "_shrinkwrap": null, - "_spec": "ansi-wrap@0.1.0", - "_where": "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/ansi-red", - "author": { - "name": "Jon Schlinkert", - "url": "https://github.com/jonschlinkert" - }, - "bugs": { - "url": "https://github.com/jonschlinkert/ansi-wrap/issues" - }, - "dependencies": {}, - "description": "Create ansi colors by passing the open and close codes.", - "devDependencies": {}, - "directories": {}, - "dist": { - "shasum": "a82250ddb0015e9a27ca82e82ea603bbfa45efaf", - "tarball": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz" - }, - "engines": { - "node": ">=0.10.0" - }, - "files": [ - "index.js" - ], - "homepage": "https://github.com/jonschlinkert/ansi-wrap", - "keywords": [], - "license": { - "type": "MIT", - "url": "https://github.com/jonschlinkert/ansi-wrap/blob/master/LICENSE" - }, - "main": "index.js", - "maintainers": [ - { - "email": "github@sellside.com", - "name": "jonschlinkert" - } - ], - "name": "ansi-wrap", - "optionalDependencies": {}, - "readme": "ERROR: No README data found!", - "repository": { - "type": "git", - "url": "git+https://github.com/jonschlinkert/ansi-wrap.git" - }, - "scripts": { - "test": "mocha" - }, - "version": "0.1.0" -} diff --git a/node_modules/argparse/CHANGELOG.md b/node_modules/argparse/CHANGELOG.md deleted file mode 100644 index a43c628ccc2ecf2d41b29b14704f2caff4b7f91d..0000000000000000000000000000000000000000 --- a/node_modules/argparse/CHANGELOG.md +++ /dev/null @@ -1,185 +0,0 @@ -1.0.10 / 2018-02-15 ------------------- - -- Use .concat instead of + for arrays, #122. - - -1.0.9 / 2016-09-29 ------------------- - -- Rerelease after 1.0.8 - deps cleanup. - - -1.0.8 / 2016-09-29 ------------------- - -- Maintenance (deps bump, fix node 6.5+ tests, coverage report). - - -1.0.7 / 2016-03-17 ------------------- - -- Teach `addArgument` to accept string arg names. #97, @tomxtobin. - - -1.0.6 / 2016-02-06 ------------------- - -- Maintenance: moved to eslint & updated CS. - - -1.0.5 / 2016-02-05 ------------------- - -- Removed lodash dependency to significantly reduce install size. - Thanks to @mourner. - - -1.0.4 / 2016-01-17 ------------------- - -- Maintenance: lodash update to 4.0.0. - - -1.0.3 / 2015-10-27 ------------------- - -- Fix parse `=` in args: `--examplepath="C:\myfolder\env=x64"`. #84, @CatWithApple. - - -1.0.2 / 2015-03-22 ------------------- - -- Relaxed lodash version dependency. - - -1.0.1 / 2015-02-20 ------------------- - -- Changed dependencies to be compatible with ancient nodejs. - - -1.0.0 / 2015-02-19 ------------------- - -- Maintenance release. -- Replaced `underscore` with `lodash`. -- Bumped version to 1.0.0 to better reflect semver meaning. -- HISTORY.md -> CHANGELOG.md - - -0.1.16 / 2013-12-01 -------------------- - -- Maintenance release. Updated dependencies and docs. - - -0.1.15 / 2013-05-13 -------------------- - -- Fixed #55, @trebor89 - - -0.1.14 / 2013-05-12 -------------------- - -- Fixed #62, @maxtaco - - -0.1.13 / 2013-04-08 -------------------- - -- Added `.npmignore` to reduce package size - - -0.1.12 / 2013-02-10 -------------------- - -- Fixed conflictHandler (#46), @hpaulj - - -0.1.11 / 2013-02-07 -------------------- - -- Multiple bugfixes, @hpaulj -- Added 70+ tests (ported from python), @hpaulj -- Added conflictHandler, @applepicke -- Added fromfilePrefixChar, @hpaulj - - -0.1.10 / 2012-12-30 -------------------- - -- Added [mutual exclusion](http://docs.python.org/dev/library/argparse.html#mutual-exclusion) - support, thanks to @hpaulj -- Fixed options check for `storeConst` & `appendConst` actions, thanks to @hpaulj - - -0.1.9 / 2012-12-27 ------------------- - -- Fixed option dest interferens with other options (issue #23), thanks to @hpaulj -- Fixed default value behavior with `*` positionals, thanks to @hpaulj -- Improve `getDefault()` behavior, thanks to @hpaulj -- Imrove negative argument parsing, thanks to @hpaulj - - -0.1.8 / 2012-12-01 ------------------- - -- Fixed parser parents (issue #19), thanks to @hpaulj -- Fixed negative argument parse (issue #20), thanks to @hpaulj - - -0.1.7 / 2012-10-14 ------------------- - -- Fixed 'choices' argument parse (issue #16) -- Fixed stderr output (issue #15) - - -0.1.6 / 2012-09-09 ------------------- - -- Fixed check for conflict of options (thanks to @tomxtobin) - - -0.1.5 / 2012-09-03 ------------------- - -- Fix parser #setDefaults method (thanks to @tomxtobin) - - -0.1.4 / 2012-07-30 ------------------- - -- Fixed pseudo-argument support (thanks to @CGamesPlay) -- Fixed addHelp default (should be true), if not set (thanks to @benblank) - - -0.1.3 / 2012-06-27 ------------------- - -- Fixed formatter api name: Formatter -> HelpFormatter - - -0.1.2 / 2012-05-29 ------------------- - -- Added basic tests -- Removed excess whitespace in help -- Fixed error reporting, when parcer with subcommands - called with empty arguments - - -0.1.1 / 2012-05-23 ------------------- - -- Fixed line wrapping in help formatter -- Added better error reporting on invalid arguments - - -0.1.0 / 2012-05-16 ------------------- - -- First release. diff --git a/node_modules/argparse/LICENSE b/node_modules/argparse/LICENSE deleted file mode 100644 index 1afdae5584056a7a33e9ebf747979baf6cac762a..0000000000000000000000000000000000000000 --- a/node_modules/argparse/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -(The MIT License) - -Copyright (C) 2012 by Vitaly Puzrin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/node_modules/argparse/README.md b/node_modules/argparse/README.md deleted file mode 100644 index 7fa6c40503e56ad3afed1a26c2e8ee0b74f0eeef..0000000000000000000000000000000000000000 --- a/node_modules/argparse/README.md +++ /dev/null @@ -1,257 +0,0 @@ -argparse -======== - -[![Build Status](https://secure.travis-ci.org/nodeca/argparse.svg?branch=master)](http://travis-ci.org/nodeca/argparse) -[![NPM version](https://img.shields.io/npm/v/argparse.svg)](https://www.npmjs.org/package/argparse) - -CLI arguments parser for node.js. Javascript port of python's -[argparse](http://docs.python.org/dev/library/argparse.html) module -(original version 3.2). That's a full port, except some very rare options, -recorded in issue tracker. - -**NB. Difference with original.** - -- Method names changed to camelCase. See [generated docs](http://nodeca.github.com/argparse/). -- Use `defaultValue` instead of `default`. -- Use `argparse.Const.REMAINDER` instead of `argparse.REMAINDER`, and - similarly for constant values `OPTIONAL`, `ZERO_OR_MORE`, and `ONE_OR_MORE` - (aliases for `nargs` values `'?'`, `'*'`, `'+'`, respectively), and - `SUPPRESS`. - - -Example -======= - -test.js file: - -```javascript -#!/usr/bin/env node -'use strict'; - -var ArgumentParser = require('../lib/argparse').ArgumentParser; -var parser = new ArgumentParser({ - version: '0.0.1', - addHelp:true, - description: 'Argparse example' -}); -parser.addArgument( - [ '-f', '--foo' ], - { - help: 'foo bar' - } -); -parser.addArgument( - [ '-b', '--bar' ], - { - help: 'bar foo' - } -); -parser.addArgument( - '--baz', - { - help: 'baz bar' - } -); -var args = parser.parseArgs(); -console.dir(args); -``` - -Display help: - -``` -$ ./test.js -h -usage: example.js [-h] [-v] [-f FOO] [-b BAR] [--baz BAZ] - -Argparse example - -Optional arguments: - -h, --help Show this help message and exit. - -v, --version Show program's version number and exit. - -f FOO, --foo FOO foo bar - -b BAR, --bar BAR bar foo - --baz BAZ baz bar -``` - -Parse arguments: - -``` -$ ./test.js -f=3 --bar=4 --baz 5 -{ foo: '3', bar: '4', baz: '5' } -``` - -More [examples](https://github.com/nodeca/argparse/tree/master/examples). - - -ArgumentParser objects -====================== - -``` -new ArgumentParser({parameters hash}); -``` - -Creates a new ArgumentParser object. - -**Supported params:** - -- ```description``` - Text to display before the argument help. -- ```epilog``` - Text to display after the argument help. -- ```addHelp``` - Add a -h/–help option to the parser. (default: true) -- ```argumentDefault``` - Set the global default value for arguments. (default: null) -- ```parents``` - A list of ArgumentParser objects whose arguments should also be included. -- ```prefixChars``` - The set of characters that prefix optional arguments. (default: ‘-‘) -- ```formatterClass``` - A class for customizing the help output. -- ```prog``` - The name of the program (default: `path.basename(process.argv[1])`) -- ```usage``` - The string describing the program usage (default: generated) -- ```conflictHandler``` - Usually unnecessary, defines strategy for resolving conflicting optionals. - -**Not supported yet** - -- ```fromfilePrefixChars``` - The set of characters that prefix files from which additional arguments should be read. - - -Details in [original ArgumentParser guide](http://docs.python.org/dev/library/argparse.html#argumentparser-objects) - - -addArgument() method -==================== - -``` -ArgumentParser.addArgument(name or flag or [name] or [flags...], {options}) -``` - -Defines how a single command-line argument should be parsed. - -- ```name or flag or [name] or [flags...]``` - Either a positional name - (e.g., `'foo'`), a single option (e.g., `'-f'` or `'--foo'`), an array - of a single positional name (e.g., `['foo']`), or an array of options - (e.g., `['-f', '--foo']`). - -Options: - -- ```action``` - The basic type of action to be taken when this argument is encountered at the command line. -- ```nargs```- The number of command-line arguments that should be consumed. -- ```constant``` - A constant value required by some action and nargs selections. -- ```defaultValue``` - The value produced if the argument is absent from the command line. -- ```type``` - The type to which the command-line argument should be converted. -- ```choices``` - A container of the allowable values for the argument. -- ```required``` - Whether or not the command-line option may be omitted (optionals only). -- ```help``` - A brief description of what the argument does. -- ```metavar``` - A name for the argument in usage messages. -- ```dest``` - The name of the attribute to be added to the object returned by parseArgs(). - -Details in [original add_argument guide](http://docs.python.org/dev/library/argparse.html#the-add-argument-method) - - -Action (some details) -================ - -ArgumentParser objects associate command-line arguments with actions. -These actions can do just about anything with the command-line arguments associated -with them, though most actions simply add an attribute to the object returned by -parseArgs(). The action keyword argument specifies how the command-line arguments -should be handled. The supported actions are: - -- ```store``` - Just stores the argument’s value. This is the default action. -- ```storeConst``` - Stores value, specified by the const keyword argument. - (Note that the const keyword argument defaults to the rather unhelpful None.) - The 'storeConst' action is most commonly used with optional arguments, that - specify some sort of flag. -- ```storeTrue``` and ```storeFalse``` - Stores values True and False - respectively. These are special cases of 'storeConst'. -- ```append``` - Stores a list, and appends each argument value to the list. - This is useful to allow an option to be specified multiple times. -- ```appendConst``` - Stores a list, and appends value, specified by the - const keyword argument to the list. (Note, that the const keyword argument defaults - is None.) The 'appendConst' action is typically used when multiple arguments need - to store constants to the same list. -- ```count``` - Counts the number of times a keyword argument occurs. For example, - used for increasing verbosity levels. -- ```help``` - Prints a complete help message for all the options in the current - parser and then exits. By default a help action is automatically added to the parser. - See ArgumentParser for details of how the output is created. -- ```version``` - Prints version information and exit. Expects a `version=` - keyword argument in the addArgument() call. - -Details in [original action guide](http://docs.python.org/dev/library/argparse.html#action) - - -Sub-commands -============ - -ArgumentParser.addSubparsers() - -Many programs split their functionality into a number of sub-commands, for -example, the svn program can invoke sub-commands like `svn checkout`, `svn update`, -and `svn commit`. Splitting up functionality this way can be a particularly good -idea when a program performs several different functions which require different -kinds of command-line arguments. `ArgumentParser` supports creation of such -sub-commands with `addSubparsers()` method. The `addSubparsers()` method is -normally called with no arguments and returns an special action object. -This object has a single method `addParser()`, which takes a command name and -any `ArgumentParser` constructor arguments, and returns an `ArgumentParser` object -that can be modified as usual. - -Example: - -sub_commands.js -```javascript -#!/usr/bin/env node -'use strict'; - -var ArgumentParser = require('../lib/argparse').ArgumentParser; -var parser = new ArgumentParser({ - version: '0.0.1', - addHelp:true, - description: 'Argparse examples: sub-commands', -}); - -var subparsers = parser.addSubparsers({ - title:'subcommands', - dest:"subcommand_name" -}); - -var bar = subparsers.addParser('c1', {addHelp:true}); -bar.addArgument( - [ '-f', '--foo' ], - { - action: 'store', - help: 'foo3 bar3' - } -); -var bar = subparsers.addParser( - 'c2', - {aliases:['co'], addHelp:true} -); -bar.addArgument( - [ '-b', '--bar' ], - { - action: 'store', - type: 'int', - help: 'foo3 bar3' - } -); - -var args = parser.parseArgs(); -console.dir(args); - -``` - -Details in [original sub-commands guide](http://docs.python.org/dev/library/argparse.html#sub-commands) - - -Contributors -============ - -- [Eugene Shkuropat](https://github.com/shkuropat) -- [Paul Jacobson](https://github.com/hpaulj) - -[others](https://github.com/nodeca/argparse/graphs/contributors) - -License -======= - -Copyright (c) 2012 [Vitaly Puzrin](https://github.com/puzrin). -Released under the MIT license. See -[LICENSE](https://github.com/nodeca/argparse/blob/master/LICENSE) for details. - - diff --git a/node_modules/argparse/index.js b/node_modules/argparse/index.js deleted file mode 100644 index 3bbc143200483c06ce8cdc5b8fef406bdabf2268..0000000000000000000000000000000000000000 --- a/node_modules/argparse/index.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict'; - -module.exports = require('./lib/argparse'); diff --git a/node_modules/argparse/lib/action.js b/node_modules/argparse/lib/action.js deleted file mode 100644 index 1483c79ffa53d6537fbae068987e39a50e2cfa08..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action.js +++ /dev/null @@ -1,146 +0,0 @@ -/** - * class Action - * - * Base class for all actions - * Do not call in your code, use this class only for inherits your own action - * - * Information about how to convert command line strings to Javascript objects. - * Action objects are used by an ArgumentParser to represent the information - * needed to parse a single argument from one or more strings from the command - * line. The keyword arguments to the Action constructor are also all attributes - * of Action instances. - * - * ##### Allowed keywords: - * - * - `store` - * - `storeConstant` - * - `storeTrue` - * - `storeFalse` - * - `append` - * - `appendConstant` - * - `count` - * - `help` - * - `version` - * - * Information about action options see [[Action.new]] - * - * See also [original guide](http://docs.python.org/dev/library/argparse.html#action) - * - **/ - -'use strict'; - - -// Constants -var c = require('./const'); - - -/** - * new Action(options) - * - * Base class for all actions. Used only for inherits - * - * - * ##### Options: - * - * - `optionStrings` A list of command-line option strings for the action. - * - `dest` Attribute to hold the created object(s) - * - `nargs` The number of command-line arguments that should be consumed. - * By default, one argument will be consumed and a single value will be - * produced. - * - `constant` Default value for an action with no value. - * - `defaultValue` The value to be produced if the option is not specified. - * - `type` Cast to 'string'|'int'|'float'|'complex'|function (string). If - * None, 'string'. - * - `choices` The choices available. - * - `required` True if the action must always be specified at the command - * line. - * - `help` The help describing the argument. - * - `metavar` The name to be used for the option's argument with the help - * string. If None, the 'dest' value will be used as the name. - * - * ##### nargs supported values: - * - * - `N` (an integer) consumes N arguments (and produces a list) - * - `?` consumes zero or one arguments - * - `*` consumes zero or more arguments (and produces a list) - * - `+` consumes one or more arguments (and produces a list) - * - * Note: that the difference between the default and nargs=1 is that with the - * default, a single value will be produced, while with nargs=1, a list - * containing a single value will be produced. - **/ -var Action = module.exports = function Action(options) { - options = options || {}; - this.optionStrings = options.optionStrings || []; - this.dest = options.dest; - this.nargs = typeof options.nargs !== 'undefined' ? options.nargs : null; - this.constant = typeof options.constant !== 'undefined' ? options.constant : null; - this.defaultValue = options.defaultValue; - this.type = typeof options.type !== 'undefined' ? options.type : null; - this.choices = typeof options.choices !== 'undefined' ? options.choices : null; - this.required = typeof options.required !== 'undefined' ? options.required : false; - this.help = typeof options.help !== 'undefined' ? options.help : null; - this.metavar = typeof options.metavar !== 'undefined' ? options.metavar : null; - - if (!(this.optionStrings instanceof Array)) { - throw new Error('optionStrings should be an array'); - } - if (typeof this.required !== 'undefined' && typeof this.required !== 'boolean') { - throw new Error('required should be a boolean'); - } -}; - -/** - * Action#getName -> String - * - * Tells action name - **/ -Action.prototype.getName = function () { - if (this.optionStrings.length > 0) { - return this.optionStrings.join('/'); - } else if (this.metavar !== null && this.metavar !== c.SUPPRESS) { - return this.metavar; - } else if (typeof this.dest !== 'undefined' && this.dest !== c.SUPPRESS) { - return this.dest; - } - return null; -}; - -/** - * Action#isOptional -> Boolean - * - * Return true if optional - **/ -Action.prototype.isOptional = function () { - return !this.isPositional(); -}; - -/** - * Action#isPositional -> Boolean - * - * Return true if positional - **/ -Action.prototype.isPositional = function () { - return (this.optionStrings.length === 0); -}; - -/** - * Action#call(parser, namespace, values, optionString) -> Void - * - parser (ArgumentParser): current parser - * - namespace (Namespace): namespace for output data - * - values (Array): parsed values - * - optionString (Array): input option string(not parsed) - * - * Call the action. Should be implemented in inherited classes - * - * ##### Example - * - * ActionCount.prototype.call = function (parser, namespace, values, optionString) { - * namespace.set(this.dest, (namespace[this.dest] || 0) + 1); - * }; - * - **/ -Action.prototype.call = function () { - throw new Error('.call() not defined');// Not Implemented error -}; diff --git a/node_modules/argparse/lib/action/append.js b/node_modules/argparse/lib/action/append.js deleted file mode 100644 index b5da0de2327504e69266b713f07fd4cc3c83ecaa..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action/append.js +++ /dev/null @@ -1,53 +0,0 @@ -/*:nodoc:* - * class ActionAppend - * - * This action stores a list, and appends each argument value to the list. - * This is useful to allow an option to be specified multiple times. - * This class inherided from [[Action]] - * - **/ - -'use strict'; - -var util = require('util'); - -var Action = require('../action'); - -// Constants -var c = require('../const'); - -/*:nodoc:* - * new ActionAppend(options) - * - options (object): options hash see [[Action.new]] - * - * Note: options.nargs should be optional for constants - * and more then zero for other - **/ -var ActionAppend = module.exports = function ActionAppend(options) { - options = options || {}; - if (this.nargs <= 0) { - throw new Error('nargs for append actions must be > 0; if arg ' + - 'strings are not supplying the value to append, ' + - 'the append const action may be more appropriate'); - } - if (!!this.constant && this.nargs !== c.OPTIONAL) { - throw new Error('nargs must be OPTIONAL to supply const'); - } - Action.call(this, options); -}; -util.inherits(ActionAppend, Action); - -/*:nodoc:* - * ActionAppend#call(parser, namespace, values, optionString) -> Void - * - parser (ArgumentParser): current parser - * - namespace (Namespace): namespace for output data - * - values (Array): parsed values - * - optionString (Array): input option string(not parsed) - * - * Call the action. Save result in namespace object - **/ -ActionAppend.prototype.call = function (parser, namespace, values) { - var items = (namespace[this.dest] || []).slice(); - items.push(values); - namespace.set(this.dest, items); -}; diff --git a/node_modules/argparse/lib/action/append/constant.js b/node_modules/argparse/lib/action/append/constant.js deleted file mode 100644 index 313f5d2efcb03fa8d62b5f9d79d0577bed0b6ea4..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action/append/constant.js +++ /dev/null @@ -1,47 +0,0 @@ -/*:nodoc:* - * class ActionAppendConstant - * - * This stores a list, and appends the value specified by - * the const keyword argument to the list. - * (Note that the const keyword argument defaults to null.) - * The 'appendConst' action is typically useful when multiple - * arguments need to store constants to the same list. - * - * This class inherited from [[Action]] - **/ - -'use strict'; - -var util = require('util'); - -var Action = require('../../action'); - -/*:nodoc:* - * new ActionAppendConstant(options) - * - options (object): options hash see [[Action.new]] - * - **/ -var ActionAppendConstant = module.exports = function ActionAppendConstant(options) { - options = options || {}; - options.nargs = 0; - if (typeof options.constant === 'undefined') { - throw new Error('constant option is required for appendAction'); - } - Action.call(this, options); -}; -util.inherits(ActionAppendConstant, Action); - -/*:nodoc:* - * ActionAppendConstant#call(parser, namespace, values, optionString) -> Void - * - parser (ArgumentParser): current parser - * - namespace (Namespace): namespace for output data - * - values (Array): parsed values - * - optionString (Array): input option string(not parsed) - * - * Call the action. Save result in namespace object - **/ -ActionAppendConstant.prototype.call = function (parser, namespace) { - var items = [].concat(namespace[this.dest] || []); - items.push(this.constant); - namespace.set(this.dest, items); -}; diff --git a/node_modules/argparse/lib/action/count.js b/node_modules/argparse/lib/action/count.js deleted file mode 100644 index d6a5899d07ef2405d31777a2616bed14a0485d74..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action/count.js +++ /dev/null @@ -1,40 +0,0 @@ -/*:nodoc:* - * class ActionCount - * - * This counts the number of times a keyword argument occurs. - * For example, this is useful for increasing verbosity levels - * - * This class inherided from [[Action]] - * - **/ -'use strict'; - -var util = require('util'); - -var Action = require('../action'); - -/*:nodoc:* - * new ActionCount(options) - * - options (object): options hash see [[Action.new]] - * - **/ -var ActionCount = module.exports = function ActionCount(options) { - options = options || {}; - options.nargs = 0; - - Action.call(this, options); -}; -util.inherits(ActionCount, Action); - -/*:nodoc:* - * ActionCount#call(parser, namespace, values, optionString) -> Void - * - parser (ArgumentParser): current parser - * - namespace (Namespace): namespace for output data - * - values (Array): parsed values - * - optionString (Array): input option string(not parsed) - * - * Call the action. Save result in namespace object - **/ -ActionCount.prototype.call = function (parser, namespace) { - namespace.set(this.dest, (namespace[this.dest] || 0) + 1); -}; diff --git a/node_modules/argparse/lib/action/help.js b/node_modules/argparse/lib/action/help.js deleted file mode 100644 index b40e05a6f0b3eb2382b7d7c78b67653a5be18ce5..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action/help.js +++ /dev/null @@ -1,47 +0,0 @@ -/*:nodoc:* - * class ActionHelp - * - * Support action for printing help - * This class inherided from [[Action]] - **/ -'use strict'; - -var util = require('util'); - -var Action = require('../action'); - -// Constants -var c = require('../const'); - -/*:nodoc:* - * new ActionHelp(options) - * - options (object): options hash see [[Action.new]] - * - **/ -var ActionHelp = module.exports = function ActionHelp(options) { - options = options || {}; - if (options.defaultValue !== null) { - options.defaultValue = options.defaultValue; - } else { - options.defaultValue = c.SUPPRESS; - } - options.dest = (options.dest !== null ? options.dest : c.SUPPRESS); - options.nargs = 0; - Action.call(this, options); - -}; -util.inherits(ActionHelp, Action); - -/*:nodoc:* - * ActionHelp#call(parser, namespace, values, optionString) - * - parser (ArgumentParser): current parser - * - namespace (Namespace): namespace for output data - * - values (Array): parsed values - * - optionString (Array): input option string(not parsed) - * - * Print help and exit - **/ -ActionHelp.prototype.call = function (parser) { - parser.printHelp(); - parser.exit(); -}; diff --git a/node_modules/argparse/lib/action/store.js b/node_modules/argparse/lib/action/store.js deleted file mode 100644 index 283b8609217561910aca7d0eb725a37b4966d314..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action/store.js +++ /dev/null @@ -1,50 +0,0 @@ -/*:nodoc:* - * class ActionStore - * - * This action just stores the argument’s value. This is the default action. - * - * This class inherited from [[Action]] - * - **/ -'use strict'; - -var util = require('util'); - -var Action = require('../action'); - -// Constants -var c = require('../const'); - - -/*:nodoc:* - * new ActionStore(options) - * - options (object): options hash see [[Action.new]] - * - **/ -var ActionStore = module.exports = function ActionStore(options) { - options = options || {}; - if (this.nargs <= 0) { - throw new Error('nargs for store actions must be > 0; if you ' + - 'have nothing to store, actions such as store ' + - 'true or store const may be more appropriate'); - - } - if (typeof this.constant !== 'undefined' && this.nargs !== c.OPTIONAL) { - throw new Error('nargs must be OPTIONAL to supply const'); - } - Action.call(this, options); -}; -util.inherits(ActionStore, Action); - -/*:nodoc:* - * ActionStore#call(parser, namespace, values, optionString) -> Void - * - parser (ArgumentParser): current parser - * - namespace (Namespace): namespace for output data - * - values (Array): parsed values - * - optionString (Array): input option string(not parsed) - * - * Call the action. Save result in namespace object - **/ -ActionStore.prototype.call = function (parser, namespace, values) { - namespace.set(this.dest, values); -}; diff --git a/node_modules/argparse/lib/action/store/constant.js b/node_modules/argparse/lib/action/store/constant.js deleted file mode 100644 index 23caa897b375d47cf8e07a6b2e80b92f867fc1c7..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action/store/constant.js +++ /dev/null @@ -1,43 +0,0 @@ -/*:nodoc:* - * class ActionStoreConstant - * - * This action stores the value specified by the const keyword argument. - * (Note that the const keyword argument defaults to the rather unhelpful null.) - * The 'store_const' action is most commonly used with optional - * arguments that specify some sort of flag. - * - * This class inherited from [[Action]] - **/ -'use strict'; - -var util = require('util'); - -var Action = require('../../action'); - -/*:nodoc:* - * new ActionStoreConstant(options) - * - options (object): options hash see [[Action.new]] - * - **/ -var ActionStoreConstant = module.exports = function ActionStoreConstant(options) { - options = options || {}; - options.nargs = 0; - if (typeof options.constant === 'undefined') { - throw new Error('constant option is required for storeAction'); - } - Action.call(this, options); -}; -util.inherits(ActionStoreConstant, Action); - -/*:nodoc:* - * ActionStoreConstant#call(parser, namespace, values, optionString) -> Void - * - parser (ArgumentParser): current parser - * - namespace (Namespace): namespace for output data - * - values (Array): parsed values - * - optionString (Array): input option string(not parsed) - * - * Call the action. Save result in namespace object - **/ -ActionStoreConstant.prototype.call = function (parser, namespace) { - namespace.set(this.dest, this.constant); -}; diff --git a/node_modules/argparse/lib/action/store/false.js b/node_modules/argparse/lib/action/store/false.js deleted file mode 100644 index 9924f461dadfe687903a93825a59f819b01eb989..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action/store/false.js +++ /dev/null @@ -1,27 +0,0 @@ -/*:nodoc:* - * class ActionStoreFalse - * - * This action store the values False respectively. - * This is special cases of 'storeConst' - * - * This class inherited from [[Action]] - **/ - -'use strict'; - -var util = require('util'); - -var ActionStoreConstant = require('./constant'); - -/*:nodoc:* - * new ActionStoreFalse(options) - * - options (object): hash of options see [[Action.new]] - * - **/ -var ActionStoreFalse = module.exports = function ActionStoreFalse(options) { - options = options || {}; - options.constant = false; - options.defaultValue = options.defaultValue !== null ? options.defaultValue : true; - ActionStoreConstant.call(this, options); -}; -util.inherits(ActionStoreFalse, ActionStoreConstant); diff --git a/node_modules/argparse/lib/action/store/true.js b/node_modules/argparse/lib/action/store/true.js deleted file mode 100644 index 9e22f7d4419eeafd4c4ce2136aa492d781de2818..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action/store/true.js +++ /dev/null @@ -1,26 +0,0 @@ -/*:nodoc:* - * class ActionStoreTrue - * - * This action store the values True respectively. - * This isspecial cases of 'storeConst' - * - * This class inherited from [[Action]] - **/ -'use strict'; - -var util = require('util'); - -var ActionStoreConstant = require('./constant'); - -/*:nodoc:* - * new ActionStoreTrue(options) - * - options (object): options hash see [[Action.new]] - * - **/ -var ActionStoreTrue = module.exports = function ActionStoreTrue(options) { - options = options || {}; - options.constant = true; - options.defaultValue = options.defaultValue !== null ? options.defaultValue : false; - ActionStoreConstant.call(this, options); -}; -util.inherits(ActionStoreTrue, ActionStoreConstant); diff --git a/node_modules/argparse/lib/action/subparsers.js b/node_modules/argparse/lib/action/subparsers.js deleted file mode 100644 index 99dfedd0f1aa02e7a55cc9b75512e31f40f382d4..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action/subparsers.js +++ /dev/null @@ -1,149 +0,0 @@ -/** internal - * class ActionSubparsers - * - * Support the creation of such sub-commands with the addSubparsers() - * - * This class inherited from [[Action]] - **/ -'use strict'; - -var util = require('util'); -var format = require('util').format; - - -var Action = require('../action'); - -// Constants -var c = require('../const'); - -// Errors -var argumentErrorHelper = require('../argument/error'); - - -/*:nodoc:* - * new ChoicesPseudoAction(name, help) - * - * Create pseudo action for correct help text - * - **/ -function ChoicesPseudoAction(name, help) { - var options = { - optionStrings: [], - dest: name, - help: help - }; - - Action.call(this, options); -} - -util.inherits(ChoicesPseudoAction, Action); - -/** - * new ActionSubparsers(options) - * - options (object): options hash see [[Action.new]] - * - **/ -function ActionSubparsers(options) { - options = options || {}; - options.dest = options.dest || c.SUPPRESS; - options.nargs = c.PARSER; - - this.debug = (options.debug === true); - - this._progPrefix = options.prog; - this._parserClass = options.parserClass; - this._nameParserMap = {}; - this._choicesActions = []; - - options.choices = this._nameParserMap; - Action.call(this, options); -} - -util.inherits(ActionSubparsers, Action); - -/*:nodoc:* - * ActionSubparsers#addParser(name, options) -> ArgumentParser - * - name (string): sub-command name - * - options (object): see [[ArgumentParser.new]] - * - * Note: - * addParser supports an additional aliases option, - * which allows multiple strings to refer to the same subparser. - * This example, like svn, aliases co as a shorthand for checkout - * - **/ -ActionSubparsers.prototype.addParser = function (name, options) { - var parser; - - var self = this; - - options = options || {}; - - options.debug = (this.debug === true); - - // set program from the existing prefix - if (!options.prog) { - options.prog = this._progPrefix + ' ' + name; - } - - var aliases = options.aliases || []; - - // create a pseudo-action to hold the choice help - if (!!options.help || typeof options.help === 'string') { - var help = options.help; - delete options.help; - - var choiceAction = new ChoicesPseudoAction(name, help); - this._choicesActions.push(choiceAction); - } - - // create the parser and add it to the map - parser = new this._parserClass(options); - this._nameParserMap[name] = parser; - - // make parser available under aliases also - aliases.forEach(function (alias) { - self._nameParserMap[alias] = parser; - }); - - return parser; -}; - -ActionSubparsers.prototype._getSubactions = function () { - return this._choicesActions; -}; - -/*:nodoc:* - * ActionSubparsers#call(parser, namespace, values, optionString) -> Void - * - parser (ArgumentParser): current parser - * - namespace (Namespace): namespace for output data - * - values (Array): parsed values - * - optionString (Array): input option string(not parsed) - * - * Call the action. Parse input aguments - **/ -ActionSubparsers.prototype.call = function (parser, namespace, values) { - var parserName = values[0]; - var argStrings = values.slice(1); - - // set the parser name if requested - if (this.dest !== c.SUPPRESS) { - namespace[this.dest] = parserName; - } - - // select the parser - if (this._nameParserMap[parserName]) { - parser = this._nameParserMap[parserName]; - } else { - throw argumentErrorHelper(format( - 'Unknown parser "%s" (choices: [%s]).', - parserName, - Object.keys(this._nameParserMap).join(', ') - )); - } - - // parse all the remaining options into the namespace - parser.parseArgs(argStrings, namespace); -}; - -module.exports = ActionSubparsers; diff --git a/node_modules/argparse/lib/action/version.js b/node_modules/argparse/lib/action/version.js deleted file mode 100644 index 8053328cdef44694a00f2cc31d72818d967ce4dc..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action/version.js +++ /dev/null @@ -1,47 +0,0 @@ -/*:nodoc:* - * class ActionVersion - * - * Support action for printing program version - * This class inherited from [[Action]] - **/ -'use strict'; - -var util = require('util'); - -var Action = require('../action'); - -// -// Constants -// -var c = require('../const'); - -/*:nodoc:* - * new ActionVersion(options) - * - options (object): options hash see [[Action.new]] - * - **/ -var ActionVersion = module.exports = function ActionVersion(options) { - options = options || {}; - options.defaultValue = (options.defaultValue ? options.defaultValue : c.SUPPRESS); - options.dest = (options.dest || c.SUPPRESS); - options.nargs = 0; - this.version = options.version; - Action.call(this, options); -}; -util.inherits(ActionVersion, Action); - -/*:nodoc:* - * ActionVersion#call(parser, namespace, values, optionString) -> Void - * - parser (ArgumentParser): current parser - * - namespace (Namespace): namespace for output data - * - values (Array): parsed values - * - optionString (Array): input option string(not parsed) - * - * Print version and exit - **/ -ActionVersion.prototype.call = function (parser) { - var version = this.version || parser.version; - var formatter = parser._getFormatter(); - formatter.addText(version); - parser.exit(0, formatter.formatHelp()); -}; diff --git a/node_modules/argparse/lib/action_container.js b/node_modules/argparse/lib/action_container.js deleted file mode 100644 index 6f1237bea23d59b8cb1bb0d8778bcd1e0c1a2c39..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/action_container.js +++ /dev/null @@ -1,482 +0,0 @@ -/** internal - * class ActionContainer - * - * Action container. Parent for [[ArgumentParser]] and [[ArgumentGroup]] - **/ - -'use strict'; - -var format = require('util').format; - -// Constants -var c = require('./const'); - -var $$ = require('./utils'); - -//Actions -var ActionHelp = require('./action/help'); -var ActionAppend = require('./action/append'); -var ActionAppendConstant = require('./action/append/constant'); -var ActionCount = require('./action/count'); -var ActionStore = require('./action/store'); -var ActionStoreConstant = require('./action/store/constant'); -var ActionStoreTrue = require('./action/store/true'); -var ActionStoreFalse = require('./action/store/false'); -var ActionVersion = require('./action/version'); -var ActionSubparsers = require('./action/subparsers'); - -// Errors -var argumentErrorHelper = require('./argument/error'); - -/** - * new ActionContainer(options) - * - * Action container. Parent for [[ArgumentParser]] and [[ArgumentGroup]] - * - * ##### Options: - * - * - `description` -- A description of what the program does - * - `prefixChars` -- Characters that prefix optional arguments - * - `argumentDefault` -- The default value for all arguments - * - `conflictHandler` -- The conflict handler to use for duplicate arguments - **/ -var ActionContainer = module.exports = function ActionContainer(options) { - options = options || {}; - - this.description = options.description; - this.argumentDefault = options.argumentDefault; - this.prefixChars = options.prefixChars || ''; - this.conflictHandler = options.conflictHandler; - - // set up registries - this._registries = {}; - - // register actions - this.register('action', null, ActionStore); - this.register('action', 'store', ActionStore); - this.register('action', 'storeConst', ActionStoreConstant); - this.register('action', 'storeTrue', ActionStoreTrue); - this.register('action', 'storeFalse', ActionStoreFalse); - this.register('action', 'append', ActionAppend); - this.register('action', 'appendConst', ActionAppendConstant); - this.register('action', 'count', ActionCount); - this.register('action', 'help', ActionHelp); - this.register('action', 'version', ActionVersion); - this.register('action', 'parsers', ActionSubparsers); - - // raise an exception if the conflict handler is invalid - this._getHandler(); - - // action storage - this._actions = []; - this._optionStringActions = {}; - - // groups - this._actionGroups = []; - this._mutuallyExclusiveGroups = []; - - // defaults storage - this._defaults = {}; - - // determines whether an "option" looks like a negative number - // -1, -1.5 -5e+4 - this._regexpNegativeNumber = new RegExp('^[-]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$'); - - // whether or not there are any optionals that look like negative - // numbers -- uses a list so it can be shared and edited - this._hasNegativeNumberOptionals = []; -}; - -// Groups must be required, then ActionContainer already defined -var ArgumentGroup = require('./argument/group'); -var MutuallyExclusiveGroup = require('./argument/exclusive'); - -// -// Registration methods -// - -/** - * ActionContainer#register(registryName, value, object) -> Void - * - registryName (String) : object type action|type - * - value (string) : keyword - * - object (Object|Function) : handler - * - * Register handlers - **/ -ActionContainer.prototype.register = function (registryName, value, object) { - this._registries[registryName] = this._registries[registryName] || {}; - this._registries[registryName][value] = object; -}; - -ActionContainer.prototype._registryGet = function (registryName, value, defaultValue) { - if (arguments.length < 3) { - defaultValue = null; - } - return this._registries[registryName][value] || defaultValue; -}; - -// -// Namespace default accessor methods -// - -/** - * ActionContainer#setDefaults(options) -> Void - * - options (object):hash of options see [[Action.new]] - * - * Set defaults - **/ -ActionContainer.prototype.setDefaults = function (options) { - options = options || {}; - for (var property in options) { - if ($$.has(options, property)) { - this._defaults[property] = options[property]; - } - } - - // if these defaults match any existing arguments, replace the previous - // default on the object with the new one - this._actions.forEach(function (action) { - if ($$.has(options, action.dest)) { - action.defaultValue = options[action.dest]; - } - }); -}; - -/** - * ActionContainer#getDefault(dest) -> Mixed - * - dest (string): action destination - * - * Return action default value - **/ -ActionContainer.prototype.getDefault = function (dest) { - var result = $$.has(this._defaults, dest) ? this._defaults[dest] : null; - - this._actions.forEach(function (action) { - if (action.dest === dest && $$.has(action, 'defaultValue')) { - result = action.defaultValue; - } - }); - - return result; -}; -// -// Adding argument actions -// - -/** - * ActionContainer#addArgument(args, options) -> Object - * - args (String|Array): argument key, or array of argument keys - * - options (Object): action objects see [[Action.new]] - * - * #### Examples - * - addArgument([ '-f', '--foo' ], { action: 'store', defaultValue: 1, ... }) - * - addArgument([ 'bar' ], { action: 'store', nargs: 1, ... }) - * - addArgument('--baz', { action: 'store', nargs: 1, ... }) - **/ -ActionContainer.prototype.addArgument = function (args, options) { - args = args; - options = options || {}; - - if (typeof args === 'string') { - args = [ args ]; - } - if (!Array.isArray(args)) { - throw new TypeError('addArgument first argument should be a string or an array'); - } - if (typeof options !== 'object' || Array.isArray(options)) { - throw new TypeError('addArgument second argument should be a hash'); - } - - // if no positional args are supplied or only one is supplied and - // it doesn't look like an option string, parse a positional argument - if (!args || args.length === 1 && this.prefixChars.indexOf(args[0][0]) < 0) { - if (args && !!options.dest) { - throw new Error('dest supplied twice for positional argument'); - } - options = this._getPositional(args, options); - - // otherwise, we're adding an optional argument - } else { - options = this._getOptional(args, options); - } - - // if no default was supplied, use the parser-level default - if (typeof options.defaultValue === 'undefined') { - var dest = options.dest; - if ($$.has(this._defaults, dest)) { - options.defaultValue = this._defaults[dest]; - } else if (typeof this.argumentDefault !== 'undefined') { - options.defaultValue = this.argumentDefault; - } - } - - // create the action object, and add it to the parser - var ActionClass = this._popActionClass(options); - if (typeof ActionClass !== 'function') { - throw new Error(format('Unknown action "%s".', ActionClass)); - } - var action = new ActionClass(options); - - // throw an error if the action type is not callable - var typeFunction = this._registryGet('type', action.type, action.type); - if (typeof typeFunction !== 'function') { - throw new Error(format('"%s" is not callable', typeFunction)); - } - - return this._addAction(action); -}; - -/** - * ActionContainer#addArgumentGroup(options) -> ArgumentGroup - * - options (Object): hash of options see [[ArgumentGroup.new]] - * - * Create new arguments groups - **/ -ActionContainer.prototype.addArgumentGroup = function (options) { - var group = new ArgumentGroup(this, options); - this._actionGroups.push(group); - return group; -}; - -/** - * ActionContainer#addMutuallyExclusiveGroup(options) -> ArgumentGroup - * - options (Object): {required: false} - * - * Create new mutual exclusive groups - **/ -ActionContainer.prototype.addMutuallyExclusiveGroup = function (options) { - var group = new MutuallyExclusiveGroup(this, options); - this._mutuallyExclusiveGroups.push(group); - return group; -}; - -ActionContainer.prototype._addAction = function (action) { - var self = this; - - // resolve any conflicts - this._checkConflict(action); - - // add to actions list - this._actions.push(action); - action.container = this; - - // index the action by any option strings it has - action.optionStrings.forEach(function (optionString) { - self._optionStringActions[optionString] = action; - }); - - // set the flag if any option strings look like negative numbers - action.optionStrings.forEach(function (optionString) { - if (optionString.match(self._regexpNegativeNumber)) { - if (!self._hasNegativeNumberOptionals.some(Boolean)) { - self._hasNegativeNumberOptionals.push(true); - } - } - }); - - // return the created action - return action; -}; - -ActionContainer.prototype._removeAction = function (action) { - var actionIndex = this._actions.indexOf(action); - if (actionIndex >= 0) { - this._actions.splice(actionIndex, 1); - } -}; - -ActionContainer.prototype._addContainerActions = function (container) { - // collect groups by titles - var titleGroupMap = {}; - this._actionGroups.forEach(function (group) { - if (titleGroupMap[group.title]) { - throw new Error(format('Cannot merge actions - two groups are named "%s".', group.title)); - } - titleGroupMap[group.title] = group; - }); - - // map each action to its group - var groupMap = {}; - function actionHash(action) { - // unique (hopefully?) string suitable as dictionary key - return action.getName(); - } - container._actionGroups.forEach(function (group) { - // if a group with the title exists, use that, otherwise - // create a new group matching the container's group - if (!titleGroupMap[group.title]) { - titleGroupMap[group.title] = this.addArgumentGroup({ - title: group.title, - description: group.description - }); - } - - // map the actions to their new group - group._groupActions.forEach(function (action) { - groupMap[actionHash(action)] = titleGroupMap[group.title]; - }); - }, this); - - // add container's mutually exclusive groups - // NOTE: if add_mutually_exclusive_group ever gains title= and - // description= then this code will need to be expanded as above - var mutexGroup; - container._mutuallyExclusiveGroups.forEach(function (group) { - mutexGroup = this.addMutuallyExclusiveGroup({ - required: group.required - }); - // map the actions to their new mutex group - group._groupActions.forEach(function (action) { - groupMap[actionHash(action)] = mutexGroup; - }); - }, this); // forEach takes a 'this' argument - - // add all actions to this container or their group - container._actions.forEach(function (action) { - var key = actionHash(action); - if (groupMap[key]) { - groupMap[key]._addAction(action); - } else { - this._addAction(action); - } - }); -}; - -ActionContainer.prototype._getPositional = function (dest, options) { - if (Array.isArray(dest)) { - dest = dest[0]; - } - // make sure required is not specified - if (options.required) { - throw new Error('"required" is an invalid argument for positionals.'); - } - - // mark positional arguments as required if at least one is - // always required - if (options.nargs !== c.OPTIONAL && options.nargs !== c.ZERO_OR_MORE) { - options.required = true; - } - if (options.nargs === c.ZERO_OR_MORE && typeof options.defaultValue === 'undefined') { - options.required = true; - } - - // return the keyword arguments with no option strings - options.dest = dest; - options.optionStrings = []; - return options; -}; - -ActionContainer.prototype._getOptional = function (args, options) { - var prefixChars = this.prefixChars; - var optionStrings = []; - var optionStringsLong = []; - - // determine short and long option strings - args.forEach(function (optionString) { - // error on strings that don't start with an appropriate prefix - if (prefixChars.indexOf(optionString[0]) < 0) { - throw new Error(format('Invalid option string "%s": must start with a "%s".', - optionString, - prefixChars - )); - } - - // strings starting with two prefix characters are long options - optionStrings.push(optionString); - if (optionString.length > 1 && prefixChars.indexOf(optionString[1]) >= 0) { - optionStringsLong.push(optionString); - } - }); - - // infer dest, '--foo-bar' -> 'foo_bar' and '-x' -> 'x' - var dest = options.dest || null; - delete options.dest; - - if (!dest) { - var optionStringDest = optionStringsLong.length ? optionStringsLong[0] : optionStrings[0]; - dest = $$.trimChars(optionStringDest, this.prefixChars); - - if (dest.length === 0) { - throw new Error( - format('dest= is required for options like "%s"', optionStrings.join(', ')) - ); - } - dest = dest.replace(/-/g, '_'); - } - - // return the updated keyword arguments - options.dest = dest; - options.optionStrings = optionStrings; - - return options; -}; - -ActionContainer.prototype._popActionClass = function (options, defaultValue) { - defaultValue = defaultValue || null; - - var action = (options.action || defaultValue); - delete options.action; - - var actionClass = this._registryGet('action', action, action); - return actionClass; -}; - -ActionContainer.prototype._getHandler = function () { - var handlerString = this.conflictHandler; - var handlerFuncName = '_handleConflict' + $$.capitalize(handlerString); - var func = this[handlerFuncName]; - if (typeof func === 'undefined') { - var msg = 'invalid conflict resolution value: ' + handlerString; - throw new Error(msg); - } else { - return func; - } -}; - -ActionContainer.prototype._checkConflict = function (action) { - var optionStringActions = this._optionStringActions; - var conflictOptionals = []; - - // find all options that conflict with this option - // collect pairs, the string, and an existing action that it conflicts with - action.optionStrings.forEach(function (optionString) { - var conflOptional = optionStringActions[optionString]; - if (typeof conflOptional !== 'undefined') { - conflictOptionals.push([ optionString, conflOptional ]); - } - }); - - if (conflictOptionals.length > 0) { - var conflictHandler = this._getHandler(); - conflictHandler.call(this, action, conflictOptionals); - } -}; - -ActionContainer.prototype._handleConflictError = function (action, conflOptionals) { - var conflicts = conflOptionals.map(function (pair) { return pair[0]; }); - conflicts = conflicts.join(', '); - throw argumentErrorHelper( - action, - format('Conflicting option string(s): %s', conflicts) - ); -}; - -ActionContainer.prototype._handleConflictResolve = function (action, conflOptionals) { - // remove all conflicting options - var self = this; - conflOptionals.forEach(function (pair) { - var optionString = pair[0]; - var conflictingAction = pair[1]; - // remove the conflicting option string - var i = conflictingAction.optionStrings.indexOf(optionString); - if (i >= 0) { - conflictingAction.optionStrings.splice(i, 1); - } - delete self._optionStringActions[optionString]; - // if the option now has no option string, remove it from the - // container holding it - if (conflictingAction.optionStrings.length === 0) { - conflictingAction.container._removeAction(conflictingAction); - } - }); -}; diff --git a/node_modules/argparse/lib/argparse.js b/node_modules/argparse/lib/argparse.js deleted file mode 100644 index f2a2c51d9a8917bc2089cf662b84a1032ecd6ddd..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/argparse.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -module.exports.ArgumentParser = require('./argument_parser.js'); -module.exports.Namespace = require('./namespace'); -module.exports.Action = require('./action'); -module.exports.HelpFormatter = require('./help/formatter.js'); -module.exports.Const = require('./const.js'); - -module.exports.ArgumentDefaultsHelpFormatter = - require('./help/added_formatters.js').ArgumentDefaultsHelpFormatter; -module.exports.RawDescriptionHelpFormatter = - require('./help/added_formatters.js').RawDescriptionHelpFormatter; -module.exports.RawTextHelpFormatter = - require('./help/added_formatters.js').RawTextHelpFormatter; diff --git a/node_modules/argparse/lib/argument/error.js b/node_modules/argparse/lib/argument/error.js deleted file mode 100644 index c8a02a08b8fbafb1c4f609f1f7195a84042e619a..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/argument/error.js +++ /dev/null @@ -1,50 +0,0 @@ -'use strict'; - - -var format = require('util').format; - - -var ERR_CODE = 'ARGError'; - -/*:nodoc:* - * argumentError(argument, message) -> TypeError - * - argument (Object): action with broken argument - * - message (String): error message - * - * Error format helper. An error from creating or using an argument - * (optional or positional). The string value of this exception - * is the message, augmented with information - * about the argument that caused it. - * - * #####Example - * - * var argumentErrorHelper = require('./argument/error'); - * if (conflictOptionals.length > 0) { - * throw argumentErrorHelper( - * action, - * format('Conflicting option string(s): %s', conflictOptionals.join(', ')) - * ); - * } - * - **/ -module.exports = function (argument, message) { - var argumentName = null; - var errMessage; - var err; - - if (argument.getName) { - argumentName = argument.getName(); - } else { - argumentName = '' + argument; - } - - if (!argumentName) { - errMessage = message; - } else { - errMessage = format('argument "%s": %s', argumentName, message); - } - - err = new TypeError(errMessage); - err.code = ERR_CODE; - return err; -}; diff --git a/node_modules/argparse/lib/argument/exclusive.js b/node_modules/argparse/lib/argument/exclusive.js deleted file mode 100644 index 8287e00d0464f37c2f5ab02e3750d56c3dc56ff3..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/argument/exclusive.js +++ /dev/null @@ -1,54 +0,0 @@ -/** internal - * class MutuallyExclusiveGroup - * - * Group arguments. - * By default, ArgumentParser groups command-line arguments - * into “positional arguments” and “optional arguments” - * when displaying help messages. When there is a better - * conceptual grouping of arguments than this default one, - * appropriate groups can be created using the addArgumentGroup() method - * - * This class inherited from [[ArgumentContainer]] - **/ -'use strict'; - -var util = require('util'); - -var ArgumentGroup = require('./group'); - -/** - * new MutuallyExclusiveGroup(container, options) - * - container (object): main container - * - options (object): options.required -> true/false - * - * `required` could be an argument itself, but making it a property of - * the options argument is more consistent with the JS adaptation of the Python) - **/ -var MutuallyExclusiveGroup = module.exports = function MutuallyExclusiveGroup(container, options) { - var required; - options = options || {}; - required = options.required || false; - ArgumentGroup.call(this, container); - this.required = required; - -}; -util.inherits(MutuallyExclusiveGroup, ArgumentGroup); - - -MutuallyExclusiveGroup.prototype._addAction = function (action) { - var msg; - if (action.required) { - msg = 'mutually exclusive arguments must be optional'; - throw new Error(msg); - } - action = this._container._addAction(action); - this._groupActions.push(action); - return action; -}; - - -MutuallyExclusiveGroup.prototype._removeAction = function (action) { - this._container._removeAction(action); - this._groupActions.remove(action); -}; - diff --git a/node_modules/argparse/lib/argument/group.js b/node_modules/argparse/lib/argument/group.js deleted file mode 100644 index 58b271f2fec8d005065c9001c2fb65b960185fd0..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/argument/group.js +++ /dev/null @@ -1,75 +0,0 @@ -/** internal - * class ArgumentGroup - * - * Group arguments. - * By default, ArgumentParser groups command-line arguments - * into “positional arguments” and “optional arguments” - * when displaying help messages. When there is a better - * conceptual grouping of arguments than this default one, - * appropriate groups can be created using the addArgumentGroup() method - * - * This class inherited from [[ArgumentContainer]] - **/ -'use strict'; - -var util = require('util'); - -var ActionContainer = require('../action_container'); - - -/** - * new ArgumentGroup(container, options) - * - container (object): main container - * - options (object): hash of group options - * - * #### options - * - **prefixChars** group name prefix - * - **argumentDefault** default argument value - * - **title** group title - * - **description** group description - * - **/ -var ArgumentGroup = module.exports = function ArgumentGroup(container, options) { - - options = options || {}; - - // add any missing keyword arguments by checking the container - options.conflictHandler = (options.conflictHandler || container.conflictHandler); - options.prefixChars = (options.prefixChars || container.prefixChars); - options.argumentDefault = (options.argumentDefault || container.argumentDefault); - - ActionContainer.call(this, options); - - // group attributes - this.title = options.title; - this._groupActions = []; - - // share most attributes with the container - this._container = container; - this._registries = container._registries; - this._actions = container._actions; - this._optionStringActions = container._optionStringActions; - this._defaults = container._defaults; - this._hasNegativeNumberOptionals = container._hasNegativeNumberOptionals; - this._mutuallyExclusiveGroups = container._mutuallyExclusiveGroups; -}; -util.inherits(ArgumentGroup, ActionContainer); - - -ArgumentGroup.prototype._addAction = function (action) { - // Parent add action - action = ActionContainer.prototype._addAction.call(this, action); - this._groupActions.push(action); - return action; -}; - - -ArgumentGroup.prototype._removeAction = function (action) { - // Parent remove action - ActionContainer.prototype._removeAction.call(this, action); - var actionIndex = this._groupActions.indexOf(action); - if (actionIndex >= 0) { - this._groupActions.splice(actionIndex, 1); - } -}; - diff --git a/node_modules/argparse/lib/argument_parser.js b/node_modules/argparse/lib/argument_parser.js deleted file mode 100644 index bd9a59a453c946f47032be60f4b26ca0430fbe0f..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/argument_parser.js +++ /dev/null @@ -1,1161 +0,0 @@ -/** - * class ArgumentParser - * - * Object for parsing command line strings into js objects. - * - * Inherited from [[ActionContainer]] - **/ -'use strict'; - -var util = require('util'); -var format = require('util').format; -var Path = require('path'); -var sprintf = require('sprintf-js').sprintf; - -// Constants -var c = require('./const'); - -var $$ = require('./utils'); - -var ActionContainer = require('./action_container'); - -// Errors -var argumentErrorHelper = require('./argument/error'); - -var HelpFormatter = require('./help/formatter'); - -var Namespace = require('./namespace'); - - -/** - * new ArgumentParser(options) - * - * Create a new ArgumentParser object. - * - * ##### Options: - * - `prog` The name of the program (default: Path.basename(process.argv[1])) - * - `usage` A usage message (default: auto-generated from arguments) - * - `description` A description of what the program does - * - `epilog` Text following the argument descriptions - * - `parents` Parsers whose arguments should be copied into this one - * - `formatterClass` HelpFormatter class for printing help messages - * - `prefixChars` Characters that prefix optional arguments - * - `fromfilePrefixChars` Characters that prefix files containing additional arguments - * - `argumentDefault` The default value for all arguments - * - `addHelp` Add a -h/-help option - * - `conflictHandler` Specifies how to handle conflicting argument names - * - `debug` Enable debug mode. Argument errors throw exception in - * debug mode and process.exit in normal. Used for development and - * testing (default: false) - * - * See also [original guide][1] - * - * [1]:http://docs.python.org/dev/library/argparse.html#argumentparser-objects - **/ -function ArgumentParser(options) { - if (!(this instanceof ArgumentParser)) { - return new ArgumentParser(options); - } - var self = this; - options = options || {}; - - options.description = (options.description || null); - options.argumentDefault = (options.argumentDefault || null); - options.prefixChars = (options.prefixChars || '-'); - options.conflictHandler = (options.conflictHandler || 'error'); - ActionContainer.call(this, options); - - options.addHelp = typeof options.addHelp === 'undefined' || !!options.addHelp; - options.parents = options.parents || []; - // default program name - options.prog = (options.prog || Path.basename(process.argv[1])); - this.prog = options.prog; - this.usage = options.usage; - this.epilog = options.epilog; - this.version = options.version; - - this.debug = (options.debug === true); - - this.formatterClass = (options.formatterClass || HelpFormatter); - this.fromfilePrefixChars = options.fromfilePrefixChars || null; - this._positionals = this.addArgumentGroup({ title: 'Positional arguments' }); - this._optionals = this.addArgumentGroup({ title: 'Optional arguments' }); - this._subparsers = null; - - // register types - function FUNCTION_IDENTITY(o) { - return o; - } - this.register('type', 'auto', FUNCTION_IDENTITY); - this.register('type', null, FUNCTION_IDENTITY); - this.register('type', 'int', function (x) { - var result = parseInt(x, 10); - if (isNaN(result)) { - throw new Error(x + ' is not a valid integer.'); - } - return result; - }); - this.register('type', 'float', function (x) { - var result = parseFloat(x); - if (isNaN(result)) { - throw new Error(x + ' is not a valid float.'); - } - return result; - }); - this.register('type', 'string', function (x) { - return '' + x; - }); - - // add help and version arguments if necessary - var defaultPrefix = (this.prefixChars.indexOf('-') > -1) ? '-' : this.prefixChars[0]; - if (options.addHelp) { - this.addArgument( - [ defaultPrefix + 'h', defaultPrefix + defaultPrefix + 'help' ], - { - action: 'help', - defaultValue: c.SUPPRESS, - help: 'Show this help message and exit.' - } - ); - } - if (typeof this.version !== 'undefined') { - this.addArgument( - [ defaultPrefix + 'v', defaultPrefix + defaultPrefix + 'version' ], - { - action: 'version', - version: this.version, - defaultValue: c.SUPPRESS, - help: "Show program's version number and exit." - } - ); - } - - // add parent arguments and defaults - options.parents.forEach(function (parent) { - self._addContainerActions(parent); - if (typeof parent._defaults !== 'undefined') { - for (var defaultKey in parent._defaults) { - if (parent._defaults.hasOwnProperty(defaultKey)) { - self._defaults[defaultKey] = parent._defaults[defaultKey]; - } - } - } - }); -} - -util.inherits(ArgumentParser, ActionContainer); - -/** - * ArgumentParser#addSubparsers(options) -> [[ActionSubparsers]] - * - options (object): hash of options see [[ActionSubparsers.new]] - * - * See also [subcommands][1] - * - * [1]:http://docs.python.org/dev/library/argparse.html#sub-commands - **/ -ArgumentParser.prototype.addSubparsers = function (options) { - if (this._subparsers) { - this.error('Cannot have multiple subparser arguments.'); - } - - options = options || {}; - options.debug = (this.debug === true); - options.optionStrings = []; - options.parserClass = (options.parserClass || ArgumentParser); - - - if (!!options.title || !!options.description) { - - this._subparsers = this.addArgumentGroup({ - title: (options.title || 'subcommands'), - description: options.description - }); - delete options.title; - delete options.description; - - } else { - this._subparsers = this._positionals; - } - - // prog defaults to the usage message of this parser, skipping - // optional arguments and with no "usage:" prefix - if (!options.prog) { - var formatter = this._getFormatter(); - var positionals = this._getPositionalActions(); - var groups = this._mutuallyExclusiveGroups; - formatter.addUsage(this.usage, positionals, groups, ''); - options.prog = formatter.formatHelp().trim(); - } - - // create the parsers action and add it to the positionals list - var ParsersClass = this._popActionClass(options, 'parsers'); - var action = new ParsersClass(options); - this._subparsers._addAction(action); - - // return the created parsers action - return action; -}; - -ArgumentParser.prototype._addAction = function (action) { - if (action.isOptional()) { - this._optionals._addAction(action); - } else { - this._positionals._addAction(action); - } - return action; -}; - -ArgumentParser.prototype._getOptionalActions = function () { - return this._actions.filter(function (action) { - return action.isOptional(); - }); -}; - -ArgumentParser.prototype._getPositionalActions = function () { - return this._actions.filter(function (action) { - return action.isPositional(); - }); -}; - - -/** - * ArgumentParser#parseArgs(args, namespace) -> Namespace|Object - * - args (array): input elements - * - namespace (Namespace|Object): result object - * - * Parsed args and throws error if some arguments are not recognized - * - * See also [original guide][1] - * - * [1]:http://docs.python.org/dev/library/argparse.html#the-parse-args-method - **/ -ArgumentParser.prototype.parseArgs = function (args, namespace) { - var argv; - var result = this.parseKnownArgs(args, namespace); - - args = result[0]; - argv = result[1]; - if (argv && argv.length > 0) { - this.error( - format('Unrecognized arguments: %s.', argv.join(' ')) - ); - } - return args; -}; - -/** - * ArgumentParser#parseKnownArgs(args, namespace) -> array - * - args (array): input options - * - namespace (Namespace|Object): result object - * - * Parse known arguments and return tuple of result object - * and unknown args - * - * See also [original guide][1] - * - * [1]:http://docs.python.org/dev/library/argparse.html#partial-parsing - **/ -ArgumentParser.prototype.parseKnownArgs = function (args, namespace) { - var self = this; - - // args default to the system args - args = args || process.argv.slice(2); - - // default Namespace built from parser defaults - namespace = namespace || new Namespace(); - - self._actions.forEach(function (action) { - if (action.dest !== c.SUPPRESS) { - if (!$$.has(namespace, action.dest)) { - if (action.defaultValue !== c.SUPPRESS) { - var defaultValue = action.defaultValue; - if (typeof action.defaultValue === 'string') { - defaultValue = self._getValue(action, defaultValue); - } - namespace[action.dest] = defaultValue; - } - } - } - }); - - Object.keys(self._defaults).forEach(function (dest) { - namespace[dest] = self._defaults[dest]; - }); - - // parse the arguments and exit if there are any errors - try { - var res = this._parseKnownArgs(args, namespace); - - namespace = res[0]; - args = res[1]; - if ($$.has(namespace, c._UNRECOGNIZED_ARGS_ATTR)) { - args = $$.arrayUnion(args, namespace[c._UNRECOGNIZED_ARGS_ATTR]); - delete namespace[c._UNRECOGNIZED_ARGS_ATTR]; - } - return [ namespace, args ]; - } catch (e) { - this.error(e); - } -}; - -ArgumentParser.prototype._parseKnownArgs = function (argStrings, namespace) { - var self = this; - - var extras = []; - - // replace arg strings that are file references - if (this.fromfilePrefixChars !== null) { - argStrings = this._readArgsFromFiles(argStrings); - } - // map all mutually exclusive arguments to the other arguments - // they can't occur with - // Python has 'conflicts = action_conflicts.setdefault(mutex_action, [])' - // though I can't conceive of a way in which an action could be a member - // of two different mutually exclusive groups. - - function actionHash(action) { - // some sort of hashable key for this action - // action itself cannot be a key in actionConflicts - // I think getName() (join of optionStrings) is unique enough - return action.getName(); - } - - var conflicts, key; - var actionConflicts = {}; - - this._mutuallyExclusiveGroups.forEach(function (mutexGroup) { - mutexGroup._groupActions.forEach(function (mutexAction, i, groupActions) { - key = actionHash(mutexAction); - if (!$$.has(actionConflicts, key)) { - actionConflicts[key] = []; - } - conflicts = actionConflicts[key]; - conflicts.push.apply(conflicts, groupActions.slice(0, i)); - conflicts.push.apply(conflicts, groupActions.slice(i + 1)); - }); - }); - - // find all option indices, and determine the arg_string_pattern - // which has an 'O' if there is an option at an index, - // an 'A' if there is an argument, or a '-' if there is a '--' - var optionStringIndices = {}; - - var argStringPatternParts = []; - - argStrings.forEach(function (argString, argStringIndex) { - if (argString === '--') { - argStringPatternParts.push('-'); - while (argStringIndex < argStrings.length) { - argStringPatternParts.push('A'); - argStringIndex++; - } - } else { - // otherwise, add the arg to the arg strings - // and note the index if it was an option - var pattern; - var optionTuple = self._parseOptional(argString); - if (!optionTuple) { - pattern = 'A'; - } else { - optionStringIndices[argStringIndex] = optionTuple; - pattern = 'O'; - } - argStringPatternParts.push(pattern); - } - }); - var argStringsPattern = argStringPatternParts.join(''); - - var seenActions = []; - var seenNonDefaultActions = []; - - - function takeAction(action, argumentStrings, optionString) { - seenActions.push(action); - var argumentValues = self._getValues(action, argumentStrings); - - // error if this argument is not allowed with other previously - // seen arguments, assuming that actions that use the default - // value don't really count as "present" - if (argumentValues !== action.defaultValue) { - seenNonDefaultActions.push(action); - if (actionConflicts[actionHash(action)]) { - actionConflicts[actionHash(action)].forEach(function (actionConflict) { - if (seenNonDefaultActions.indexOf(actionConflict) >= 0) { - throw argumentErrorHelper( - action, - format('Not allowed with argument "%s".', actionConflict.getName()) - ); - } - }); - } - } - - if (argumentValues !== c.SUPPRESS) { - action.call(self, namespace, argumentValues, optionString); - } - } - - function consumeOptional(startIndex) { - // get the optional identified at this index - var optionTuple = optionStringIndices[startIndex]; - var action = optionTuple[0]; - var optionString = optionTuple[1]; - var explicitArg = optionTuple[2]; - - // identify additional optionals in the same arg string - // (e.g. -xyz is the same as -x -y -z if no args are required) - var actionTuples = []; - - var args, argCount, start, stop; - - for (;;) { - if (!action) { - extras.push(argStrings[startIndex]); - return startIndex + 1; - } - if (explicitArg) { - argCount = self._matchArgument(action, 'A'); - - // if the action is a single-dash option and takes no - // arguments, try to parse more single-dash options out - // of the tail of the option string - var chars = self.prefixChars; - if (argCount === 0 && chars.indexOf(optionString[1]) < 0) { - actionTuples.push([ action, [], optionString ]); - optionString = optionString[0] + explicitArg[0]; - var newExplicitArg = explicitArg.slice(1) || null; - var optionalsMap = self._optionStringActions; - - if (Object.keys(optionalsMap).indexOf(optionString) >= 0) { - action = optionalsMap[optionString]; - explicitArg = newExplicitArg; - } else { - throw argumentErrorHelper(action, sprintf('ignored explicit argument %r', explicitArg)); - } - } else if (argCount === 1) { - // if the action expect exactly one argument, we've - // successfully matched the option; exit the loop - stop = startIndex + 1; - args = [ explicitArg ]; - actionTuples.push([ action, args, optionString ]); - break; - } else { - // error if a double-dash option did not use the - // explicit argument - throw argumentErrorHelper(action, sprintf('ignored explicit argument %r', explicitArg)); - } - } else { - // if there is no explicit argument, try to match the - // optional's string arguments with the following strings - // if successful, exit the loop - - start = startIndex + 1; - var selectedPatterns = argStringsPattern.substr(start); - - argCount = self._matchArgument(action, selectedPatterns); - stop = start + argCount; - - - args = argStrings.slice(start, stop); - - actionTuples.push([ action, args, optionString ]); - break; - } - - } - - // add the Optional to the list and return the index at which - // the Optional's string args stopped - if (actionTuples.length < 1) { - throw new Error('length should be > 0'); - } - for (var i = 0; i < actionTuples.length; i++) { - takeAction.apply(self, actionTuples[i]); - } - return stop; - } - - // the list of Positionals left to be parsed; this is modified - // by consume_positionals() - var positionals = self._getPositionalActions(); - - function consumePositionals(startIndex) { - // match as many Positionals as possible - var selectedPattern = argStringsPattern.substr(startIndex); - var argCounts = self._matchArgumentsPartial(positionals, selectedPattern); - - // slice off the appropriate arg strings for each Positional - // and add the Positional and its args to the list - for (var i = 0; i < positionals.length; i++) { - var action = positionals[i]; - var argCount = argCounts[i]; - if (typeof argCount === 'undefined') { - continue; - } - var args = argStrings.slice(startIndex, startIndex + argCount); - - startIndex += argCount; - takeAction(action, args); - } - - // slice off the Positionals that we just parsed and return the - // index at which the Positionals' string args stopped - positionals = positionals.slice(argCounts.length); - return startIndex; - } - - // consume Positionals and Optionals alternately, until we have - // passed the last option string - var startIndex = 0; - var position; - - var maxOptionStringIndex = -1; - - Object.keys(optionStringIndices).forEach(function (position) { - maxOptionStringIndex = Math.max(maxOptionStringIndex, parseInt(position, 10)); - }); - - var positionalsEndIndex, nextOptionStringIndex; - - while (startIndex <= maxOptionStringIndex) { - // consume any Positionals preceding the next option - nextOptionStringIndex = null; - for (position in optionStringIndices) { - if (!optionStringIndices.hasOwnProperty(position)) { continue; } - - position = parseInt(position, 10); - if (position >= startIndex) { - if (nextOptionStringIndex !== null) { - nextOptionStringIndex = Math.min(nextOptionStringIndex, position); - } else { - nextOptionStringIndex = position; - } - } - } - - if (startIndex !== nextOptionStringIndex) { - positionalsEndIndex = consumePositionals(startIndex); - // only try to parse the next optional if we didn't consume - // the option string during the positionals parsing - if (positionalsEndIndex > startIndex) { - startIndex = positionalsEndIndex; - continue; - } else { - startIndex = positionalsEndIndex; - } - } - - // if we consumed all the positionals we could and we're not - // at the index of an option string, there were extra arguments - if (!optionStringIndices[startIndex]) { - var strings = argStrings.slice(startIndex, nextOptionStringIndex); - extras = extras.concat(strings); - startIndex = nextOptionStringIndex; - } - // consume the next optional and any arguments for it - startIndex = consumeOptional(startIndex); - } - - // consume any positionals following the last Optional - var stopIndex = consumePositionals(startIndex); - - // if we didn't consume all the argument strings, there were extras - extras = extras.concat(argStrings.slice(stopIndex)); - - // if we didn't use all the Positional objects, there were too few - // arg strings supplied. - if (positionals.length > 0) { - self.error('too few arguments'); - } - - // make sure all required actions were present - self._actions.forEach(function (action) { - if (action.required) { - if (seenActions.indexOf(action) < 0) { - self.error(format('Argument "%s" is required', action.getName())); - } - } - }); - - // make sure all required groups have one option present - var actionUsed = false; - self._mutuallyExclusiveGroups.forEach(function (group) { - if (group.required) { - actionUsed = group._groupActions.some(function (action) { - return seenNonDefaultActions.indexOf(action) !== -1; - }); - - // if no actions were used, report the error - if (!actionUsed) { - var names = []; - group._groupActions.forEach(function (action) { - if (action.help !== c.SUPPRESS) { - names.push(action.getName()); - } - }); - names = names.join(' '); - var msg = 'one of the arguments ' + names + ' is required'; - self.error(msg); - } - } - }); - - // return the updated namespace and the extra arguments - return [ namespace, extras ]; -}; - -ArgumentParser.prototype._readArgsFromFiles = function (argStrings) { - // expand arguments referencing files - var self = this; - var fs = require('fs'); - var newArgStrings = []; - argStrings.forEach(function (argString) { - if (self.fromfilePrefixChars.indexOf(argString[0]) < 0) { - // for regular arguments, just add them back into the list - newArgStrings.push(argString); - } else { - // replace arguments referencing files with the file content - try { - var argstrs = []; - var filename = argString.slice(1); - var content = fs.readFileSync(filename, 'utf8'); - content = content.trim().split('\n'); - content.forEach(function (argLine) { - self.convertArgLineToArgs(argLine).forEach(function (arg) { - argstrs.push(arg); - }); - argstrs = self._readArgsFromFiles(argstrs); - }); - newArgStrings.push.apply(newArgStrings, argstrs); - } catch (error) { - return self.error(error.message); - } - } - }); - return newArgStrings; -}; - -ArgumentParser.prototype.convertArgLineToArgs = function (argLine) { - return [ argLine ]; -}; - -ArgumentParser.prototype._matchArgument = function (action, regexpArgStrings) { - - // match the pattern for this action to the arg strings - var regexpNargs = new RegExp('^' + this._getNargsPattern(action)); - var matches = regexpArgStrings.match(regexpNargs); - var message; - - // throw an exception if we weren't able to find a match - if (!matches) { - switch (action.nargs) { - /*eslint-disable no-undefined*/ - case undefined: - case null: - message = 'Expected one argument.'; - break; - case c.OPTIONAL: - message = 'Expected at most one argument.'; - break; - case c.ONE_OR_MORE: - message = 'Expected at least one argument.'; - break; - default: - message = 'Expected %s argument(s)'; - } - - throw argumentErrorHelper( - action, - format(message, action.nargs) - ); - } - // return the number of arguments matched - return matches[1].length; -}; - -ArgumentParser.prototype._matchArgumentsPartial = function (actions, regexpArgStrings) { - // progressively shorten the actions list by slicing off the - // final actions until we find a match - var self = this; - var result = []; - var actionSlice, pattern, matches; - var i, j; - - function getLength(string) { - return string.length; - } - - for (i = actions.length; i > 0; i--) { - pattern = ''; - actionSlice = actions.slice(0, i); - for (j = 0; j < actionSlice.length; j++) { - pattern += self._getNargsPattern(actionSlice[j]); - } - - pattern = new RegExp('^' + pattern); - matches = regexpArgStrings.match(pattern); - - if (matches && matches.length > 0) { - // need only groups - matches = matches.splice(1); - result = result.concat(matches.map(getLength)); - break; - } - } - - // return the list of arg string counts - return result; -}; - -ArgumentParser.prototype._parseOptional = function (argString) { - var action, optionString, argExplicit, optionTuples; - - // if it's an empty string, it was meant to be a positional - if (!argString) { - return null; - } - - // if it doesn't start with a prefix, it was meant to be positional - if (this.prefixChars.indexOf(argString[0]) < 0) { - return null; - } - - // if the option string is present in the parser, return the action - if (this._optionStringActions[argString]) { - return [ this._optionStringActions[argString], argString, null ]; - } - - // if it's just a single character, it was meant to be positional - if (argString.length === 1) { - return null; - } - - // if the option string before the "=" is present, return the action - if (argString.indexOf('=') >= 0) { - optionString = argString.split('=', 1)[0]; - argExplicit = argString.slice(optionString.length + 1); - - if (this._optionStringActions[optionString]) { - action = this._optionStringActions[optionString]; - return [ action, optionString, argExplicit ]; - } - } - - // search through all possible prefixes of the option string - // and all actions in the parser for possible interpretations - optionTuples = this._getOptionTuples(argString); - - // if multiple actions match, the option string was ambiguous - if (optionTuples.length > 1) { - var optionStrings = optionTuples.map(function (optionTuple) { - return optionTuple[1]; - }); - this.error(format( - 'Ambiguous option: "%s" could match %s.', - argString, optionStrings.join(', ') - )); - // if exactly one action matched, this segmentation is good, - // so return the parsed action - } else if (optionTuples.length === 1) { - return optionTuples[0]; - } - - // if it was not found as an option, but it looks like a negative - // number, it was meant to be positional - // unless there are negative-number-like options - if (argString.match(this._regexpNegativeNumber)) { - if (!this._hasNegativeNumberOptionals.some(Boolean)) { - return null; - } - } - // if it contains a space, it was meant to be a positional - if (argString.search(' ') >= 0) { - return null; - } - - // it was meant to be an optional but there is no such option - // in this parser (though it might be a valid option in a subparser) - return [ null, argString, null ]; -}; - -ArgumentParser.prototype._getOptionTuples = function (optionString) { - var result = []; - var chars = this.prefixChars; - var optionPrefix; - var argExplicit; - var action; - var actionOptionString; - - // option strings starting with two prefix characters are only split at - // the '=' - if (chars.indexOf(optionString[0]) >= 0 && chars.indexOf(optionString[1]) >= 0) { - if (optionString.indexOf('=') >= 0) { - var optionStringSplit = optionString.split('=', 1); - - optionPrefix = optionStringSplit[0]; - argExplicit = optionStringSplit[1]; - } else { - optionPrefix = optionString; - argExplicit = null; - } - - for (actionOptionString in this._optionStringActions) { - if (actionOptionString.substr(0, optionPrefix.length) === optionPrefix) { - action = this._optionStringActions[actionOptionString]; - result.push([ action, actionOptionString, argExplicit ]); - } - } - - // single character options can be concatenated with their arguments - // but multiple character options always have to have their argument - // separate - } else if (chars.indexOf(optionString[0]) >= 0 && chars.indexOf(optionString[1]) < 0) { - optionPrefix = optionString; - argExplicit = null; - var optionPrefixShort = optionString.substr(0, 2); - var argExplicitShort = optionString.substr(2); - - for (actionOptionString in this._optionStringActions) { - if (!$$.has(this._optionStringActions, actionOptionString)) continue; - - action = this._optionStringActions[actionOptionString]; - if (actionOptionString === optionPrefixShort) { - result.push([ action, actionOptionString, argExplicitShort ]); - } else if (actionOptionString.substr(0, optionPrefix.length) === optionPrefix) { - result.push([ action, actionOptionString, argExplicit ]); - } - } - - // shouldn't ever get here - } else { - throw new Error(format('Unexpected option string: %s.', optionString)); - } - // return the collected option tuples - return result; -}; - -ArgumentParser.prototype._getNargsPattern = function (action) { - // in all examples below, we have to allow for '--' args - // which are represented as '-' in the pattern - var regexpNargs; - - switch (action.nargs) { - // the default (null) is assumed to be a single argument - case undefined: - case null: - regexpNargs = '(-*A-*)'; - break; - // allow zero or more arguments - case c.OPTIONAL: - regexpNargs = '(-*A?-*)'; - break; - // allow zero or more arguments - case c.ZERO_OR_MORE: - regexpNargs = '(-*[A-]*)'; - break; - // allow one or more arguments - case c.ONE_OR_MORE: - regexpNargs = '(-*A[A-]*)'; - break; - // allow any number of options or arguments - case c.REMAINDER: - regexpNargs = '([-AO]*)'; - break; - // allow one argument followed by any number of options or arguments - case c.PARSER: - regexpNargs = '(-*A[-AO]*)'; - break; - // all others should be integers - default: - regexpNargs = '(-*' + $$.repeat('-*A', action.nargs) + '-*)'; - } - - // if this is an optional action, -- is not allowed - if (action.isOptional()) { - regexpNargs = regexpNargs.replace(/-\*/g, ''); - regexpNargs = regexpNargs.replace(/-/g, ''); - } - - // return the pattern - return regexpNargs; -}; - -// -// Value conversion methods -// - -ArgumentParser.prototype._getValues = function (action, argStrings) { - var self = this; - - // for everything but PARSER args, strip out '--' - if (action.nargs !== c.PARSER && action.nargs !== c.REMAINDER) { - argStrings = argStrings.filter(function (arrayElement) { - return arrayElement !== '--'; - }); - } - - var value, argString; - - // optional argument produces a default when not present - if (argStrings.length === 0 && action.nargs === c.OPTIONAL) { - - value = (action.isOptional()) ? action.constant : action.defaultValue; - - if (typeof (value) === 'string') { - value = this._getValue(action, value); - this._checkValue(action, value); - } - - // when nargs='*' on a positional, if there were no command-line - // args, use the default if it is anything other than None - } else if (argStrings.length === 0 && action.nargs === c.ZERO_OR_MORE && - action.optionStrings.length === 0) { - - value = (action.defaultValue || argStrings); - this._checkValue(action, value); - - // single argument or optional argument produces a single value - } else if (argStrings.length === 1 && - (!action.nargs || action.nargs === c.OPTIONAL)) { - - argString = argStrings[0]; - value = this._getValue(action, argString); - this._checkValue(action, value); - - // REMAINDER arguments convert all values, checking none - } else if (action.nargs === c.REMAINDER) { - value = argStrings.map(function (v) { - return self._getValue(action, v); - }); - - // PARSER arguments convert all values, but check only the first - } else if (action.nargs === c.PARSER) { - value = argStrings.map(function (v) { - return self._getValue(action, v); - }); - this._checkValue(action, value[0]); - - // all other types of nargs produce a list - } else { - value = argStrings.map(function (v) { - return self._getValue(action, v); - }); - value.forEach(function (v) { - self._checkValue(action, v); - }); - } - - // return the converted value - return value; -}; - -ArgumentParser.prototype._getValue = function (action, argString) { - var result; - - var typeFunction = this._registryGet('type', action.type, action.type); - if (typeof typeFunction !== 'function') { - var message = format('%s is not callable', typeFunction); - throw argumentErrorHelper(action, message); - } - - // convert the value to the appropriate type - try { - result = typeFunction(argString); - - // ArgumentTypeErrors indicate errors - // If action.type is not a registered string, it is a function - // Try to deduce its name for inclusion in the error message - // Failing that, include the error message it raised. - } catch (e) { - var name = null; - if (typeof action.type === 'string') { - name = action.type; - } else { - name = action.type.name || action.type.displayName || ''; - } - var msg = format('Invalid %s value: %s', name, argString); - if (name === '') { msg += '\n' + e.message; } - throw argumentErrorHelper(action, msg); - } - // return the converted value - return result; -}; - -ArgumentParser.prototype._checkValue = function (action, value) { - // converted value must be one of the choices (if specified) - var choices = action.choices; - if (choices) { - // choise for argument can by array or string - if ((typeof choices === 'string' || Array.isArray(choices)) && - choices.indexOf(value) !== -1) { - return; - } - // choise for subparsers can by only hash - if (typeof choices === 'object' && !Array.isArray(choices) && choices[value]) { - return; - } - - if (typeof choices === 'string') { - choices = choices.split('').join(', '); - } else if (Array.isArray(choices)) { - choices = choices.join(', '); - } else { - choices = Object.keys(choices).join(', '); - } - var message = format('Invalid choice: %s (choose from [%s])', value, choices); - throw argumentErrorHelper(action, message); - } -}; - -// -// Help formatting methods -// - -/** - * ArgumentParser#formatUsage -> string - * - * Return usage string - * - * See also [original guide][1] - * - * [1]:http://docs.python.org/dev/library/argparse.html#printing-help - **/ -ArgumentParser.prototype.formatUsage = function () { - var formatter = this._getFormatter(); - formatter.addUsage(this.usage, this._actions, this._mutuallyExclusiveGroups); - return formatter.formatHelp(); -}; - -/** - * ArgumentParser#formatHelp -> string - * - * Return help - * - * See also [original guide][1] - * - * [1]:http://docs.python.org/dev/library/argparse.html#printing-help - **/ -ArgumentParser.prototype.formatHelp = function () { - var formatter = this._getFormatter(); - - // usage - formatter.addUsage(this.usage, this._actions, this._mutuallyExclusiveGroups); - - // description - formatter.addText(this.description); - - // positionals, optionals and user-defined groups - this._actionGroups.forEach(function (actionGroup) { - formatter.startSection(actionGroup.title); - formatter.addText(actionGroup.description); - formatter.addArguments(actionGroup._groupActions); - formatter.endSection(); - }); - - // epilog - formatter.addText(this.epilog); - - // determine help from format above - return formatter.formatHelp(); -}; - -ArgumentParser.prototype._getFormatter = function () { - var FormatterClass = this.formatterClass; - var formatter = new FormatterClass({ prog: this.prog }); - return formatter; -}; - -// -// Print functions -// - -/** - * ArgumentParser#printUsage() -> Void - * - * Print usage - * - * See also [original guide][1] - * - * [1]:http://docs.python.org/dev/library/argparse.html#printing-help - **/ -ArgumentParser.prototype.printUsage = function () { - this._printMessage(this.formatUsage()); -}; - -/** - * ArgumentParser#printHelp() -> Void - * - * Print help - * - * See also [original guide][1] - * - * [1]:http://docs.python.org/dev/library/argparse.html#printing-help - **/ -ArgumentParser.prototype.printHelp = function () { - this._printMessage(this.formatHelp()); -}; - -ArgumentParser.prototype._printMessage = function (message, stream) { - if (!stream) { - stream = process.stdout; - } - if (message) { - stream.write('' + message); - } -}; - -// -// Exit functions -// - -/** - * ArgumentParser#exit(status=0, message) -> Void - * - status (int): exit status - * - message (string): message - * - * Print message in stderr/stdout and exit program - **/ -ArgumentParser.prototype.exit = function (status, message) { - if (message) { - if (status === 0) { - this._printMessage(message); - } else { - this._printMessage(message, process.stderr); - } - } - - process.exit(status); -}; - -/** - * ArgumentParser#error(message) -> Void - * - err (Error|string): message - * - * Error method Prints a usage message incorporating the message to stderr and - * exits. If you override this in a subclass, - * it should not return -- it should - * either exit or throw an exception. - * - **/ -ArgumentParser.prototype.error = function (err) { - var message; - if (err instanceof Error) { - if (this.debug === true) { - throw err; - } - message = err.message; - } else { - message = err; - } - var msg = format('%s: error: %s', this.prog, message) + c.EOL; - - if (this.debug === true) { - throw new Error(msg); - } - - this.printUsage(process.stderr); - - return this.exit(2, msg); -}; - -module.exports = ArgumentParser; diff --git a/node_modules/argparse/lib/const.js b/node_modules/argparse/lib/const.js deleted file mode 100644 index b1fd4ced4e888b0aa67dd7cde76c6f41f582c3d6..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/const.js +++ /dev/null @@ -1,21 +0,0 @@ -// -// Constants -// - -'use strict'; - -module.exports.EOL = '\n'; - -module.exports.SUPPRESS = '==SUPPRESS=='; - -module.exports.OPTIONAL = '?'; - -module.exports.ZERO_OR_MORE = '*'; - -module.exports.ONE_OR_MORE = '+'; - -module.exports.PARSER = 'A...'; - -module.exports.REMAINDER = '...'; - -module.exports._UNRECOGNIZED_ARGS_ATTR = '_unrecognized_args'; diff --git a/node_modules/argparse/lib/help/added_formatters.js b/node_modules/argparse/lib/help/added_formatters.js deleted file mode 100644 index f8e42998e9bf5871f3c0e42ce8a00ae048178c90..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/help/added_formatters.js +++ /dev/null @@ -1,87 +0,0 @@ -'use strict'; - -var util = require('util'); - -// Constants -var c = require('../const'); - -var $$ = require('../utils'); -var HelpFormatter = require('./formatter.js'); - -/** - * new RawDescriptionHelpFormatter(options) - * new ArgumentParser({formatterClass: argparse.RawDescriptionHelpFormatter, ...}) - * - * Help message formatter which adds default values to argument help. - * - * Only the name of this class is considered a public API. All the methods - * provided by the class are considered an implementation detail. - **/ - -function ArgumentDefaultsHelpFormatter(options) { - HelpFormatter.call(this, options); -} - -util.inherits(ArgumentDefaultsHelpFormatter, HelpFormatter); - -ArgumentDefaultsHelpFormatter.prototype._getHelpString = function (action) { - var help = action.help; - if (action.help.indexOf('%(defaultValue)s') === -1) { - if (action.defaultValue !== c.SUPPRESS) { - var defaulting_nargs = [ c.OPTIONAL, c.ZERO_OR_MORE ]; - if (action.isOptional() || (defaulting_nargs.indexOf(action.nargs) >= 0)) { - help += ' (default: %(defaultValue)s)'; - } - } - } - return help; -}; - -module.exports.ArgumentDefaultsHelpFormatter = ArgumentDefaultsHelpFormatter; - -/** - * new RawDescriptionHelpFormatter(options) - * new ArgumentParser({formatterClass: argparse.RawDescriptionHelpFormatter, ...}) - * - * Help message formatter which retains any formatting in descriptions. - * - * Only the name of this class is considered a public API. All the methods - * provided by the class are considered an implementation detail. - **/ - -function RawDescriptionHelpFormatter(options) { - HelpFormatter.call(this, options); -} - -util.inherits(RawDescriptionHelpFormatter, HelpFormatter); - -RawDescriptionHelpFormatter.prototype._fillText = function (text, width, indent) { - var lines = text.split('\n'); - lines = lines.map(function (line) { - return $$.trimEnd(indent + line); - }); - return lines.join('\n'); -}; -module.exports.RawDescriptionHelpFormatter = RawDescriptionHelpFormatter; - -/** - * new RawTextHelpFormatter(options) - * new ArgumentParser({formatterClass: argparse.RawTextHelpFormatter, ...}) - * - * Help message formatter which retains formatting of all help text. - * - * Only the name of this class is considered a public API. All the methods - * provided by the class are considered an implementation detail. - **/ - -function RawTextHelpFormatter(options) { - RawDescriptionHelpFormatter.call(this, options); -} - -util.inherits(RawTextHelpFormatter, RawDescriptionHelpFormatter); - -RawTextHelpFormatter.prototype._splitLines = function (text) { - return text.split('\n'); -}; - -module.exports.RawTextHelpFormatter = RawTextHelpFormatter; diff --git a/node_modules/argparse/lib/help/formatter.js b/node_modules/argparse/lib/help/formatter.js deleted file mode 100644 index 29036c14b2e156e4287e8136a545ec0be17fc5b4..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/help/formatter.js +++ /dev/null @@ -1,795 +0,0 @@ -/** - * class HelpFormatter - * - * Formatter for generating usage messages and argument help strings. Only the - * name of this class is considered a public API. All the methods provided by - * the class are considered an implementation detail. - * - * Do not call in your code, use this class only for inherits your own forvatter - * - * ToDo add [additonal formatters][1] - * - * [1]:http://docs.python.org/dev/library/argparse.html#formatter-class - **/ -'use strict'; - -var sprintf = require('sprintf-js').sprintf; - -// Constants -var c = require('../const'); - -var $$ = require('../utils'); - - -/*:nodoc:* internal - * new Support(parent, heding) - * - parent (object): parent section - * - heading (string): header string - * - **/ -function Section(parent, heading) { - this._parent = parent; - this._heading = heading; - this._items = []; -} - -/*:nodoc:* internal - * Section#addItem(callback) -> Void - * - callback (array): tuple with function and args - * - * Add function for single element - **/ -Section.prototype.addItem = function (callback) { - this._items.push(callback); -}; - -/*:nodoc:* internal - * Section#formatHelp(formatter) -> string - * - formatter (HelpFormatter): current formatter - * - * Form help section string - * - **/ -Section.prototype.formatHelp = function (formatter) { - var itemHelp, heading; - - // format the indented section - if (this._parent) { - formatter._indent(); - } - - itemHelp = this._items.map(function (item) { - var obj, func, args; - - obj = formatter; - func = item[0]; - args = item[1]; - return func.apply(obj, args); - }); - itemHelp = formatter._joinParts(itemHelp); - - if (this._parent) { - formatter._dedent(); - } - - // return nothing if the section was empty - if (!itemHelp) { - return ''; - } - - // add the heading if the section was non-empty - heading = ''; - if (this._heading && this._heading !== c.SUPPRESS) { - var currentIndent = formatter.currentIndent; - heading = $$.repeat(' ', currentIndent) + this._heading + ':' + c.EOL; - } - - // join the section-initialize newline, the heading and the help - return formatter._joinParts([ c.EOL, heading, itemHelp, c.EOL ]); -}; - -/** - * new HelpFormatter(options) - * - * #### Options: - * - `prog`: program name - * - `indentIncriment`: indent step, default value 2 - * - `maxHelpPosition`: max help position, default value = 24 - * - `width`: line width - * - **/ -var HelpFormatter = module.exports = function HelpFormatter(options) { - options = options || {}; - - this._prog = options.prog; - - this._maxHelpPosition = options.maxHelpPosition || 24; - this._width = (options.width || ((process.env.COLUMNS || 80) - 2)); - - this._currentIndent = 0; - this._indentIncriment = options.indentIncriment || 2; - this._level = 0; - this._actionMaxLength = 0; - - this._rootSection = new Section(null); - this._currentSection = this._rootSection; - - this._whitespaceMatcher = new RegExp('\\s+', 'g'); - this._longBreakMatcher = new RegExp(c.EOL + c.EOL + c.EOL + '+', 'g'); -}; - -HelpFormatter.prototype._indent = function () { - this._currentIndent += this._indentIncriment; - this._level += 1; -}; - -HelpFormatter.prototype._dedent = function () { - this._currentIndent -= this._indentIncriment; - this._level -= 1; - if (this._currentIndent < 0) { - throw new Error('Indent decreased below 0.'); - } -}; - -HelpFormatter.prototype._addItem = function (func, args) { - this._currentSection.addItem([ func, args ]); -}; - -// -// Message building methods -// - -/** - * HelpFormatter#startSection(heading) -> Void - * - heading (string): header string - * - * Start new help section - * - * See alse [code example][1] - * - * ##### Example - * - * formatter.startSection(actionGroup.title); - * formatter.addText(actionGroup.description); - * formatter.addArguments(actionGroup._groupActions); - * formatter.endSection(); - * - **/ -HelpFormatter.prototype.startSection = function (heading) { - this._indent(); - var section = new Section(this._currentSection, heading); - var func = section.formatHelp.bind(section); - this._addItem(func, [ this ]); - this._currentSection = section; -}; - -/** - * HelpFormatter#endSection -> Void - * - * End help section - * - * ##### Example - * - * formatter.startSection(actionGroup.title); - * formatter.addText(actionGroup.description); - * formatter.addArguments(actionGroup._groupActions); - * formatter.endSection(); - **/ -HelpFormatter.prototype.endSection = function () { - this._currentSection = this._currentSection._parent; - this._dedent(); -}; - -/** - * HelpFormatter#addText(text) -> Void - * - text (string): plain text - * - * Add plain text into current section - * - * ##### Example - * - * formatter.startSection(actionGroup.title); - * formatter.addText(actionGroup.description); - * formatter.addArguments(actionGroup._groupActions); - * formatter.endSection(); - * - **/ -HelpFormatter.prototype.addText = function (text) { - if (text && text !== c.SUPPRESS) { - this._addItem(this._formatText, [ text ]); - } -}; - -/** - * HelpFormatter#addUsage(usage, actions, groups, prefix) -> Void - * - usage (string): usage text - * - actions (array): actions list - * - groups (array): groups list - * - prefix (string): usage prefix - * - * Add usage data into current section - * - * ##### Example - * - * formatter.addUsage(this.usage, this._actions, []); - * return formatter.formatHelp(); - * - **/ -HelpFormatter.prototype.addUsage = function (usage, actions, groups, prefix) { - if (usage !== c.SUPPRESS) { - this._addItem(this._formatUsage, [ usage, actions, groups, prefix ]); - } -}; - -/** - * HelpFormatter#addArgument(action) -> Void - * - action (object): action - * - * Add argument into current section - * - * Single variant of [[HelpFormatter#addArguments]] - **/ -HelpFormatter.prototype.addArgument = function (action) { - if (action.help !== c.SUPPRESS) { - var self = this; - - // find all invocations - var invocations = [ this._formatActionInvocation(action) ]; - var invocationLength = invocations[0].length; - - var actionLength; - - if (action._getSubactions) { - this._indent(); - action._getSubactions().forEach(function (subaction) { - - var invocationNew = self._formatActionInvocation(subaction); - invocations.push(invocationNew); - invocationLength = Math.max(invocationLength, invocationNew.length); - - }); - this._dedent(); - } - - // update the maximum item length - actionLength = invocationLength + this._currentIndent; - this._actionMaxLength = Math.max(this._actionMaxLength, actionLength); - - // add the item to the list - this._addItem(this._formatAction, [ action ]); - } -}; - -/** - * HelpFormatter#addArguments(actions) -> Void - * - actions (array): actions list - * - * Mass add arguments into current section - * - * ##### Example - * - * formatter.startSection(actionGroup.title); - * formatter.addText(actionGroup.description); - * formatter.addArguments(actionGroup._groupActions); - * formatter.endSection(); - * - **/ -HelpFormatter.prototype.addArguments = function (actions) { - var self = this; - actions.forEach(function (action) { - self.addArgument(action); - }); -}; - -// -// Help-formatting methods -// - -/** - * HelpFormatter#formatHelp -> string - * - * Format help - * - * ##### Example - * - * formatter.addText(this.epilog); - * return formatter.formatHelp(); - * - **/ -HelpFormatter.prototype.formatHelp = function () { - var help = this._rootSection.formatHelp(this); - if (help) { - help = help.replace(this._longBreakMatcher, c.EOL + c.EOL); - help = $$.trimChars(help, c.EOL) + c.EOL; - } - return help; -}; - -HelpFormatter.prototype._joinParts = function (partStrings) { - return partStrings.filter(function (part) { - return (part && part !== c.SUPPRESS); - }).join(''); -}; - -HelpFormatter.prototype._formatUsage = function (usage, actions, groups, prefix) { - if (!prefix && typeof prefix !== 'string') { - prefix = 'usage: '; - } - - actions = actions || []; - groups = groups || []; - - - // if usage is specified, use that - if (usage) { - usage = sprintf(usage, { prog: this._prog }); - - // if no optionals or positionals are available, usage is just prog - } else if (!usage && actions.length === 0) { - usage = this._prog; - - // if optionals and positionals are available, calculate usage - } else if (!usage) { - var prog = this._prog; - var optionals = []; - var positionals = []; - var actionUsage; - var textWidth; - - // split optionals from positionals - actions.forEach(function (action) { - if (action.isOptional()) { - optionals.push(action); - } else { - positionals.push(action); - } - }); - - // build full usage string - actionUsage = this._formatActionsUsage([].concat(optionals, positionals), groups); - usage = [ prog, actionUsage ].join(' '); - - // wrap the usage parts if it's too long - textWidth = this._width - this._currentIndent; - if ((prefix.length + usage.length) > textWidth) { - - // break usage into wrappable parts - var regexpPart = new RegExp('\\(.*?\\)+|\\[.*?\\]+|\\S+', 'g'); - var optionalUsage = this._formatActionsUsage(optionals, groups); - var positionalUsage = this._formatActionsUsage(positionals, groups); - - - var optionalParts = optionalUsage.match(regexpPart); - var positionalParts = positionalUsage.match(regexpPart) || []; - - if (optionalParts.join(' ') !== optionalUsage) { - throw new Error('assert "optionalParts.join(\' \') === optionalUsage"'); - } - if (positionalParts.join(' ') !== positionalUsage) { - throw new Error('assert "positionalParts.join(\' \') === positionalUsage"'); - } - - // helper for wrapping lines - /*eslint-disable func-style*/ // node 0.10 compat - var _getLines = function (parts, indent, prefix) { - var lines = []; - var line = []; - - var lineLength = prefix ? prefix.length - 1 : indent.length - 1; - - parts.forEach(function (part) { - if (lineLength + 1 + part.length > textWidth) { - lines.push(indent + line.join(' ')); - line = []; - lineLength = indent.length - 1; - } - line.push(part); - lineLength += part.length + 1; - }); - - if (line) { - lines.push(indent + line.join(' ')); - } - if (prefix) { - lines[0] = lines[0].substr(indent.length); - } - return lines; - }; - - var lines, indent, parts; - // if prog is short, follow it with optionals or positionals - if (prefix.length + prog.length <= 0.75 * textWidth) { - indent = $$.repeat(' ', (prefix.length + prog.length + 1)); - if (optionalParts) { - lines = [].concat( - _getLines([ prog ].concat(optionalParts), indent, prefix), - _getLines(positionalParts, indent) - ); - } else if (positionalParts) { - lines = _getLines([ prog ].concat(positionalParts), indent, prefix); - } else { - lines = [ prog ]; - } - - // if prog is long, put it on its own line - } else { - indent = $$.repeat(' ', prefix.length); - parts = optionalParts.concat(positionalParts); - lines = _getLines(parts, indent); - if (lines.length > 1) { - lines = [].concat( - _getLines(optionalParts, indent), - _getLines(positionalParts, indent) - ); - } - lines = [ prog ].concat(lines); - } - // join lines into usage - usage = lines.join(c.EOL); - } - } - - // prefix with 'usage:' - return prefix + usage + c.EOL + c.EOL; -}; - -HelpFormatter.prototype._formatActionsUsage = function (actions, groups) { - // find group indices and identify actions in groups - var groupActions = []; - var inserts = []; - var self = this; - - groups.forEach(function (group) { - var end; - var i; - - var start = actions.indexOf(group._groupActions[0]); - if (start >= 0) { - end = start + group._groupActions.length; - - //if (actions.slice(start, end) === group._groupActions) { - if ($$.arrayEqual(actions.slice(start, end), group._groupActions)) { - group._groupActions.forEach(function (action) { - groupActions.push(action); - }); - - if (!group.required) { - if (inserts[start]) { - inserts[start] += ' ['; - } else { - inserts[start] = '['; - } - inserts[end] = ']'; - } else { - if (inserts[start]) { - inserts[start] += ' ('; - } else { - inserts[start] = '('; - } - inserts[end] = ')'; - } - for (i = start + 1; i < end; i += 1) { - inserts[i] = '|'; - } - } - } - }); - - // collect all actions format strings - var parts = []; - - actions.forEach(function (action, actionIndex) { - var part; - var optionString; - var argsDefault; - var argsString; - - // suppressed arguments are marked with None - // remove | separators for suppressed arguments - if (action.help === c.SUPPRESS) { - parts.push(null); - if (inserts[actionIndex] === '|') { - inserts.splice(actionIndex, actionIndex); - } else if (inserts[actionIndex + 1] === '|') { - inserts.splice(actionIndex + 1, actionIndex + 1); - } - - // produce all arg strings - } else if (!action.isOptional()) { - part = self._formatArgs(action, action.dest); - - // if it's in a group, strip the outer [] - if (groupActions.indexOf(action) >= 0) { - if (part[0] === '[' && part[part.length - 1] === ']') { - part = part.slice(1, -1); - } - } - // add the action string to the list - parts.push(part); - - // produce the first way to invoke the option in brackets - } else { - optionString = action.optionStrings[0]; - - // if the Optional doesn't take a value, format is: -s or --long - if (action.nargs === 0) { - part = '' + optionString; - - // if the Optional takes a value, format is: -s ARGS or --long ARGS - } else { - argsDefault = action.dest.toUpperCase(); - argsString = self._formatArgs(action, argsDefault); - part = optionString + ' ' + argsString; - } - // make it look optional if it's not required or in a group - if (!action.required && groupActions.indexOf(action) < 0) { - part = '[' + part + ']'; - } - // add the action string to the list - parts.push(part); - } - }); - - // insert things at the necessary indices - for (var i = inserts.length - 1; i >= 0; --i) { - if (inserts[i] !== null) { - parts.splice(i, 0, inserts[i]); - } - } - - // join all the action items with spaces - var text = parts.filter(function (part) { - return !!part; - }).join(' '); - - // clean up separators for mutually exclusive groups - text = text.replace(/([\[(]) /g, '$1'); // remove spaces - text = text.replace(/ ([\])])/g, '$1'); - text = text.replace(/\[ *\]/g, ''); // remove empty groups - text = text.replace(/\( *\)/g, ''); - text = text.replace(/\(([^|]*)\)/g, '$1'); // remove () from single action groups - - text = text.trim(); - - // return the text - return text; -}; - -HelpFormatter.prototype._formatText = function (text) { - text = sprintf(text, { prog: this._prog }); - var textWidth = this._width - this._currentIndent; - var indentIncriment = $$.repeat(' ', this._currentIndent); - return this._fillText(text, textWidth, indentIncriment) + c.EOL + c.EOL; -}; - -HelpFormatter.prototype._formatAction = function (action) { - var self = this; - - var helpText; - var helpLines; - var parts; - var indentFirst; - - // determine the required width and the entry label - var helpPosition = Math.min(this._actionMaxLength + 2, this._maxHelpPosition); - var helpWidth = this._width - helpPosition; - var actionWidth = helpPosition - this._currentIndent - 2; - var actionHeader = this._formatActionInvocation(action); - - // no help; start on same line and add a final newline - if (!action.help) { - actionHeader = $$.repeat(' ', this._currentIndent) + actionHeader + c.EOL; - - // short action name; start on the same line and pad two spaces - } else if (actionHeader.length <= actionWidth) { - actionHeader = $$.repeat(' ', this._currentIndent) + - actionHeader + - ' ' + - $$.repeat(' ', actionWidth - actionHeader.length); - indentFirst = 0; - - // long action name; start on the next line - } else { - actionHeader = $$.repeat(' ', this._currentIndent) + actionHeader + c.EOL; - indentFirst = helpPosition; - } - - // collect the pieces of the action help - parts = [ actionHeader ]; - - // if there was help for the action, add lines of help text - if (action.help) { - helpText = this._expandHelp(action); - helpLines = this._splitLines(helpText, helpWidth); - parts.push($$.repeat(' ', indentFirst) + helpLines[0] + c.EOL); - helpLines.slice(1).forEach(function (line) { - parts.push($$.repeat(' ', helpPosition) + line + c.EOL); - }); - - // or add a newline if the description doesn't end with one - } else if (actionHeader.charAt(actionHeader.length - 1) !== c.EOL) { - parts.push(c.EOL); - } - // if there are any sub-actions, add their help as well - if (action._getSubactions) { - this._indent(); - action._getSubactions().forEach(function (subaction) { - parts.push(self._formatAction(subaction)); - }); - this._dedent(); - } - // return a single string - return this._joinParts(parts); -}; - -HelpFormatter.prototype._formatActionInvocation = function (action) { - if (!action.isOptional()) { - var format_func = this._metavarFormatter(action, action.dest); - var metavars = format_func(1); - return metavars[0]; - } - - var parts = []; - var argsDefault; - var argsString; - - // if the Optional doesn't take a value, format is: -s, --long - if (action.nargs === 0) { - parts = parts.concat(action.optionStrings); - - // if the Optional takes a value, format is: -s ARGS, --long ARGS - } else { - argsDefault = action.dest.toUpperCase(); - argsString = this._formatArgs(action, argsDefault); - action.optionStrings.forEach(function (optionString) { - parts.push(optionString + ' ' + argsString); - }); - } - return parts.join(', '); -}; - -HelpFormatter.prototype._metavarFormatter = function (action, metavarDefault) { - var result; - - if (action.metavar || action.metavar === '') { - result = action.metavar; - } else if (action.choices) { - var choices = action.choices; - - if (typeof choices === 'string') { - choices = choices.split('').join(', '); - } else if (Array.isArray(choices)) { - choices = choices.join(','); - } else { - choices = Object.keys(choices).join(','); - } - result = '{' + choices + '}'; - } else { - result = metavarDefault; - } - - return function (size) { - if (Array.isArray(result)) { - return result; - } - - var metavars = []; - for (var i = 0; i < size; i += 1) { - metavars.push(result); - } - return metavars; - }; -}; - -HelpFormatter.prototype._formatArgs = function (action, metavarDefault) { - var result; - var metavars; - - var buildMetavar = this._metavarFormatter(action, metavarDefault); - - switch (action.nargs) { - /*eslint-disable no-undefined*/ - case undefined: - case null: - metavars = buildMetavar(1); - result = '' + metavars[0]; - break; - case c.OPTIONAL: - metavars = buildMetavar(1); - result = '[' + metavars[0] + ']'; - break; - case c.ZERO_OR_MORE: - metavars = buildMetavar(2); - result = '[' + metavars[0] + ' [' + metavars[1] + ' ...]]'; - break; - case c.ONE_OR_MORE: - metavars = buildMetavar(2); - result = '' + metavars[0] + ' [' + metavars[1] + ' ...]'; - break; - case c.REMAINDER: - result = '...'; - break; - case c.PARSER: - metavars = buildMetavar(1); - result = metavars[0] + ' ...'; - break; - default: - metavars = buildMetavar(action.nargs); - result = metavars.join(' '); - } - return result; -}; - -HelpFormatter.prototype._expandHelp = function (action) { - var params = { prog: this._prog }; - - Object.keys(action).forEach(function (actionProperty) { - var actionValue = action[actionProperty]; - - if (actionValue !== c.SUPPRESS) { - params[actionProperty] = actionValue; - } - }); - - if (params.choices) { - if (typeof params.choices === 'string') { - params.choices = params.choices.split('').join(', '); - } else if (Array.isArray(params.choices)) { - params.choices = params.choices.join(', '); - } else { - params.choices = Object.keys(params.choices).join(', '); - } - } - - return sprintf(this._getHelpString(action), params); -}; - -HelpFormatter.prototype._splitLines = function (text, width) { - var lines = []; - var delimiters = [ ' ', '.', ',', '!', '?' ]; - var re = new RegExp('[' + delimiters.join('') + '][^' + delimiters.join('') + ']*$'); - - text = text.replace(/[\n\|\t]/g, ' '); - - text = text.trim(); - text = text.replace(this._whitespaceMatcher, ' '); - - // Wraps the single paragraph in text (a string) so every line - // is at most width characters long. - text.split(c.EOL).forEach(function (line) { - if (width >= line.length) { - lines.push(line); - return; - } - - var wrapStart = 0; - var wrapEnd = width; - var delimiterIndex = 0; - while (wrapEnd <= line.length) { - if (wrapEnd !== line.length && delimiters.indexOf(line[wrapEnd] < -1)) { - delimiterIndex = (re.exec(line.substring(wrapStart, wrapEnd)) || {}).index; - wrapEnd = wrapStart + delimiterIndex + 1; - } - lines.push(line.substring(wrapStart, wrapEnd)); - wrapStart = wrapEnd; - wrapEnd += width; - } - if (wrapStart < line.length) { - lines.push(line.substring(wrapStart, wrapEnd)); - } - }); - - return lines; -}; - -HelpFormatter.prototype._fillText = function (text, width, indent) { - var lines = this._splitLines(text, width); - lines = lines.map(function (line) { - return indent + line; - }); - return lines.join(c.EOL); -}; - -HelpFormatter.prototype._getHelpString = function (action) { - return action.help; -}; diff --git a/node_modules/argparse/lib/namespace.js b/node_modules/argparse/lib/namespace.js deleted file mode 100644 index a860de9ecc48ddc61ef65fab4794406005f67a48..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/namespace.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * class Namespace - * - * Simple object for storing attributes. Implements equality by attribute names - * and values, and provides a simple string representation. - * - * See also [original guide][1] - * - * [1]:http://docs.python.org/dev/library/argparse.html#the-namespace-object - **/ -'use strict'; - -var $$ = require('./utils'); - -/** - * new Namespace(options) - * - options(object): predefined propertis for result object - * - **/ -var Namespace = module.exports = function Namespace(options) { - $$.extend(this, options); -}; - -/** - * Namespace#isset(key) -> Boolean - * - key (string|number): property name - * - * Tells whenever `namespace` contains given `key` or not. - **/ -Namespace.prototype.isset = function (key) { - return $$.has(this, key); -}; - -/** - * Namespace#set(key, value) -> self - * -key (string|number|object): propery name - * -value (mixed): new property value - * - * Set the property named key with value. - * If key object then set all key properties to namespace object - **/ -Namespace.prototype.set = function (key, value) { - if (typeof (key) === 'object') { - $$.extend(this, key); - } else { - this[key] = value; - } - return this; -}; - -/** - * Namespace#get(key, defaultValue) -> mixed - * - key (string|number): property name - * - defaultValue (mixed): default value - * - * Return the property key or defaulValue if not set - **/ -Namespace.prototype.get = function (key, defaultValue) { - return !this[key] ? defaultValue : this[key]; -}; - -/** - * Namespace#unset(key, defaultValue) -> mixed - * - key (string|number): property name - * - defaultValue (mixed): default value - * - * Return data[key](and delete it) or defaultValue - **/ -Namespace.prototype.unset = function (key, defaultValue) { - var value = this[key]; - if (value !== null) { - delete this[key]; - return value; - } - return defaultValue; -}; diff --git a/node_modules/argparse/lib/utils.js b/node_modules/argparse/lib/utils.js deleted file mode 100644 index 4a9cf3edb615ce9a5f572836c66711e0814cec9c..0000000000000000000000000000000000000000 --- a/node_modules/argparse/lib/utils.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict'; - -exports.repeat = function (str, num) { - var result = ''; - for (var i = 0; i < num; i++) { result += str; } - return result; -}; - -exports.arrayEqual = function (a, b) { - if (a.length !== b.length) { return false; } - for (var i = 0; i < a.length; i++) { - if (a[i] !== b[i]) { return false; } - } - return true; -}; - -exports.trimChars = function (str, chars) { - var start = 0; - var end = str.length - 1; - while (chars.indexOf(str.charAt(start)) >= 0) { start++; } - while (chars.indexOf(str.charAt(end)) >= 0) { end--; } - return str.slice(start, end + 1); -}; - -exports.capitalize = function (str) { - return str.charAt(0).toUpperCase() + str.slice(1); -}; - -exports.arrayUnion = function () { - var result = []; - for (var i = 0, values = {}; i < arguments.length; i++) { - var arr = arguments[i]; - for (var j = 0; j < arr.length; j++) { - if (!values[arr[j]]) { - values[arr[j]] = true; - result.push(arr[j]); - } - } - } - return result; -}; - -function has(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - -exports.has = has; - -exports.extend = function (dest, src) { - for (var i in src) { - if (has(src, i)) { dest[i] = src[i]; } - } -}; - -exports.trimEnd = function (str) { - return str.replace(/\s+$/g, ''); -}; diff --git a/node_modules/argparse/package.json b/node_modules/argparse/package.json deleted file mode 100644 index 3080ced3e533c46bf3bda85738437270fe8cd7d0..0000000000000000000000000000000000000000 --- a/node_modules/argparse/package.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "_args": [ - [ - { - "name": "argparse", - "raw": "argparse@^1.0.7", - "rawSpec": "^1.0.7", - "scope": null, - "spec": ">=1.0.7 <2.0.0", - "type": "range" - }, - "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/js-yaml" - ] - ], - "_from": "argparse@>=1.0.7 <2.0.0", - "_hasShrinkwrap": false, - "_id": "argparse@1.0.10", - "_inCache": true, - "_installable": true, - "_location": "/argparse", - "_nodeVersion": "8.9.1", - "_npmOperationalInternal": { - "host": "s3://npm-registry-packages", - "tmp": "tmp/argparse_1.0.10_1518704641025_0.2567322588736727" - }, - "_npmUser": { - "email": "vitaly@rcdesign.ru", - "name": "vitaly" - }, - "_npmVersion": "5.5.1", - "_phantomChildren": {}, - "_requested": { - "name": "argparse", - "raw": "argparse@^1.0.7", - "rawSpec": "^1.0.7", - "scope": null, - "spec": ">=1.0.7 <2.0.0", - "type": "range" - }, - "_requiredBy": [ - "/js-yaml", - "/remarkable" - ], - "_resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "_shasum": "bcd6791ea5ae09725e17e5ad988134cd40b3d911", - "_shrinkwrap": null, - "_spec": "argparse@^1.0.7", - "_where": "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/js-yaml", - "bugs": { - "url": "https://github.com/nodeca/argparse/issues" - }, - "contributors": [ - { - "name": "Eugene Shkuropat" - }, - { - "name": "Paul Jacobson" - } - ], - "dependencies": { - "sprintf-js": "~1.0.2" - }, - "description": "Very powerful CLI arguments parser. Native port of argparse - python's options parsing library", - "devDependencies": { - "eslint": "^2.13.1", - "istanbul": "^0.4.5", - "mocha": "^3.1.0", - "ndoc": "^5.0.1" - }, - "directories": {}, - "dist": { - "fileCount": 27, - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "shasum": "bcd6791ea5ae09725e17e5ad988134cd40b3d911", - "tarball": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "unpackedSize": 116446 - }, - "files": [ - "index.js", - "lib/" - ], - "gitHead": "ea45e14bad13b9e4a10af28f11fb7e731079ab72", - "homepage": "https://github.com/nodeca/argparse#readme", - "keywords": [ - "cli", - "parser", - "argparse", - "option", - "args" - ], - "license": "MIT", - "maintainers": [ - { - "email": "vitaly@rcdesign.ru", - "name": "vitaly" - } - ], - "name": "argparse", - "optionalDependencies": {}, - "readme": "ERROR: No README data found!", - "repository": { - "type": "git", - "url": "git+https://github.com/nodeca/argparse.git" - }, - "scripts": { - "test": "make test" - }, - "version": "1.0.10" -} diff --git a/node_modules/autolinker/LICENSE b/node_modules/autolinker/LICENSE deleted file mode 100644 index 3ff145b9fa33846bf8ff36b6c6eca9c6705591a3..0000000000000000000000000000000000000000 --- a/node_modules/autolinker/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Gregory Jacobs (http://greg-jacobs.com) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/autolinker/README.md b/node_modules/autolinker/README.md deleted file mode 100644 index 78cc38973072192d1e1598d70e849c8c335cb6e1..0000000000000000000000000000000000000000 --- a/node_modules/autolinker/README.md +++ /dev/null @@ -1,340 +0,0 @@ -# Autolinker.js - -Because I had so much trouble finding a good auto-linking implementation out in -the wild, I decided to roll my own. It seemed that everything I found out there -was either an implementation that didn't cover every case, or was just limited -in one way or another. - -So, this utility attempts to handle everything. It: - -- Autolinks URLs, whether or not they start with the protocol (i.e. 'http://'). - In other words, it will automatically link the text "google.com", as well as - "http://google.com". -- Will properly handle URLs with special characters -- Will properly handle URLs with query parameters or a named anchor (i.e. hash) -- Will autolink email addresses. -- Will autolink phone numbers. -- Will autolink Twitter handles. -- Will autolink hashtags. -- Will properly handle HTML input. The utility will not change the `href` - attribute inside anchor (<a>) tags (or any other tag/attribute for that - matter), and will not accidentally wrap the inner text of an anchor tag with a - new one (which would cause doubly-nested anchor tags). - -Hope that this utility helps you as well! - -Full API Docs: [http://gregjacobs.github.io/Autolinker.js/docs/](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker)
-Live Example: [http://gregjacobs.github.io/Autolinker.js/examples/live-example/](http://gregjacobs.github.io/Autolinker.js/examples/live-example/) - - -## Installation - -#### Download - -Simply clone or download the zip of the project, and link to either -`dist/Autolinker.js` or `dist/Autolinker.min.js` with a script tag: - -```html - -``` - -#### Using with the [Bower](http://bower.io) package manager: - -Command line: - -```shell -bower install Autolinker.js --save -``` - -#### Using with [Node.js](http://nodejs.org) via [npm](https://www.npmjs.org/): - -Command Line: - -```shell -npm install autolinker --save -``` - -JavaScript: - -```javascript -var Autolinker = require( 'autolinker' ); -// note: npm wants an all-lowercase package name, but the utility is a class and -// should be aliased with a capital letter -``` - - -## Usage - -Using the static [link()](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-static-method-link) -method: - -```javascript -var linkedText = Autolinker.link( textToAutolink[, options] ); -``` - -Using as a class: - -```javascript -var autolinker = new Autolinker( [ options ] ); - -var linkedText = autolinker.link( textToAutoLink ); -``` - -Note: if using the same options to autolink multiple pieces of html/text, it is -slightly more efficient to create a single Autolinker instance, and run the -[link()](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-method-link) -method repeatedly (i.e. use the "class" form above). - - -#### Example: - -```javascript -var linkedText = Autolinker.link( "Check out google.com", { className: "myLink" } ); -// Produces: "Check out google.com" -``` - -## Options - -These are the options which may be specified for linking. These are specified by -providing an Object as the second parameter to [Autolinker.link()](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-static-method-link). These include: - -- [newWindow](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-newWindow) : Boolean
- `true` to have the links should open in a new window when clicked, `false` - otherwise. Defaults to `true`.

-- [stripPrefix](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-stripPrefix) : Boolean
- `true` to have the 'http://' or 'https://' and/or the 'www.' stripped from the - beginning of links, `false` otherwise. Defaults to `true`.

-- [truncate](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-truncate) : Number/Object
- A number for how many characters long URLs/emails/Twitter handles/Twitter - hashtags should be truncated to inside the text of a link. If the match is - over the number of characters, it will be truncated to this length by - replacing the end of the string with a two period ellipsis ('..').

- - Example: a url like 'http://www.yahoo.com/some/long/path/to/a/file' truncated - to 25 characters may look like this: 'yahoo.com/some/long/pat..'

- - In the object form, both `length` and `location` may be specified to perform - truncation. Available options for `location` are: 'end' (default), 'middle', - or 'smart'. Example usage: - - ```javascript - truncate: { length: 32, location: 'middle' } - ``` - - The 'smart' truncation option is for URLs where the algorithm attempts to - strip out unnecessary parts of the URL (such as the 'www.', then URL scheme, - hash, etc.) before trying to find a good point to insert the ellipsis if it is - still too long. For details, see source code of: - [TruncateSmart](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker.truncate.TruncateSmart) -- [className](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-className) : String
- A CSS class name to add to the generated anchor tags. This class will be added - to all links, as well as this class plus "url"/"email"/"phone"/"twitter"/"hashtag" - suffixes for styling url/email/phone/twitter/hashtag links differently. - - For example, if this config is provided as "myLink", then: - - 1) URL links will have the CSS classes: "myLink myLink-url"
- 2) Email links will have the CSS classes: "myLink myLink-email"
- 3) Phone links will have the CSS classes: "myLink myLink-phone"
- 4) Twitter links will have the CSS classes: "myLink myLink-twitter"
- 5) Hashtag links will have the CSS classes: "myLink myLink-hashtag"
- -- [urls](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-urls) : Boolean/Object
- `true` to have URLs auto-linked, `false` to skip auto-linking of URLs. - Defaults to `true`.
- - This option also accepts an Object form with 3 properties, to allow for more - customization of what exactly gets linked. All default to `true`: - - - schemeMatches (Boolean): `true` to match URLs found prefixed with a scheme, - i.e. `http://google.com`, or `other+scheme://google.com`, `false` to - prevent these types of matches. - - wwwMatches (Boolean): `true` to match urls found prefixed with `'www.'`, - i.e. `www.google.com`. `false` to prevent these types of matches. Note - that if the URL had a prefixed scheme, and `schemeMatches` is true, it - will still be linked. - - tldMatches: `true` to match URLs with known top level domains (.com, .net, - etc.) that are not prefixed with a scheme or `'www.'`. Ex: `google.com`, - `asdf.org/?page=1`, etc. `false` to prevent these types of matches. -
- - Example usage: `urls: { schemeMatches: true, wwwMatches: true, tldMatches: false }` - -- [email](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-email) : Boolean
- `true` to have email addresses auto-linked, `false` to skip auto-linking of - email addresses. Defaults to `true`.

-- [phone](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-phone) : Boolean
- `true` to have phone numbers auto-linked, `false` to skip auto-linking of - phone numbers. Defaults to `true`.

-- [twitter](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-twitter) : Boolean
- `true` to have Twitter handles auto-linked, `false` to skip auto-linking of - Twitter handles. Defaults to `true`.

-- [hashtag](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-hashtag) : Boolean/String
- A string for the service name to have hashtags auto-linked to. Supported - values at this time are 'twitter', 'facebook' and 'instagram'. Pass `false` to skip - auto-linking of hashtags. Defaults to `false`.

-- [replaceFn](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-replaceFn) : Function
- A function to use to programmatically make replacements of matches in the - input string, one at a time. See the section - Custom Replacement Function for - more details. - - -For example, if you wanted to disable links from opening in [new windows](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-newWindow), you could do: - -```javascript -var linkedText = Autolinker.link( "Check out google.com", { newWindow: false } ); -// Produces: "Check out google.com" -``` - -And if you wanted to truncate the length of URLs (while also not opening in a new window), you could do: - -```javascript -var linkedText = Autolinker.link( "http://www.yahoo.com/some/long/path/to/a/file", { truncate: 25, newWindow: false } ); -// Produces: "yahoo.com/some/long/pat.." -``` - -## More Examples -One could update an entire DOM element that has unlinked text to auto-link them -as such: - -```javascript -var myTextEl = document.getElementById( 'text' ); -myTextEl.innerHTML = Autolinker.link( myTextEl.innerHTML ); -``` - -Using the same pre-configured [Autolinker](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker) -instance in multiple locations of a codebase (usually by dependency injection): - -```javascript -var autolinker = new Autolinker( { newWindow: false, truncate: 25 } ); - -//... - -autolinker.link( "Check out http://www.yahoo.com/some/long/path/to/a/file" ); -// Produces: "Check out yahoo.com/some/long/pat.." - -//... - -autolinker.link( "Go to www.google.com" ); -// Produces: "Go to google.com" - -``` - - -## Custom Replacement Function - -A custom replacement function ([replaceFn](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker-cfg-replaceFn)) -may be provided to replace url/email/phone/Twitter handle/hashtag matches on an -individual basis, based on the return from this function. - -#### Full example, for purposes of documenting the API: - -```javascript -var input = "..."; // string with URLs, Email Addresses, Twitter Handles, and Hashtags - -var linkedText = Autolinker.link( input, { - replaceFn : function( autolinker, match ) { - console.log( "href = ", match.getAnchorHref() ); - console.log( "text = ", match.getAnchorText() ); - - switch( match.getType() ) { - case 'url' : - console.log( "url: ", match.getUrl() ); - - return true; // let Autolinker perform its normal anchor tag replacement - - case 'email' : - var email = match.getEmail(); - console.log( "email: ", email ); - - if( email === "my@own.address" ) { - return false; // don't auto-link this particular email address; leave as-is - } else { - return; // no return value will have Autolinker perform its normal anchor tag replacement (same as returning `true`) - } - - case 'phone' : - console.log( "Phone Number: ", match.getNumber() ); - - return '' + match.getNumber() + ''; - - case 'twitter' : - console.log( "Twitter Handle: ", match.getTwitterHandle() ); - - return '' + match.getTwitterHandle() + ''; - - case 'hashtag' : - console.log( "Hashtag: ", match.getHashtag() ); - - return '' + match.getHashtag() + ''; - } - } -} ); -``` - -#### Modifying the default generated anchor tag - -```javascript -var input = "..."; // string with URLs, Email Addresses, Twitter Handles, and Hashtags - -var linkedText = Autolinker.link( input, { - replaceFn : function( autolinker, match ) { - console.log( "href = ", match.getAnchorHref() ); - console.log( "text = ", match.getAnchorText() ); - - var tag = match.buildTag(); // returns an `Autolinker.HtmlTag` instance for an tag - tag.setAttr( 'rel', 'nofollow' ); // adds a 'rel' attribute - tag.addClass( 'external-link' ); // adds a CSS class - tag.setInnerHtml( 'Click here!' ); // sets the inner html for the anchor tag - - return tag; - } -} ); -``` - - -The `replaceFn` is provided two arguments: - -1. The [Autolinker](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker) instance that is performing replacements. -2. An [Autolinker.match.Match](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker.match.Match) - object which details the match that is to be replaced. - - -A replacement of the match is made based on the return value of the function. -The following return values may be provided: - -1. No return value (`undefined`), or `true` (Boolean): Delegate back to - Autolinker to replace the match as it normally would. -2. `false` (Boolean): Do not replace the current match at all - leave as-is. -3. Any String: If a string is returned from the function, the string will be used - directly as the replacement HTML for the match. -4. An [Autolinker.HtmlTag](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker.HtmlTag) - instance, which can be used to build/modify an HTML tag before writing out its - HTML text. - - -## Full API Docs - -The full API docs for Autolinker may be referenced at: -[http://gregjacobs.github.io/Autolinker.js/docs/](http://gregjacobs.github.io/Autolinker.js/docs/#!/api/Autolinker) - -## Live Example - -[http://gregjacobs.github.io/Autolinker.js/examples/live-example/](http://gregjacobs.github.io/Autolinker.js/examples/live-example/) - - - -## Contributing - -Pull requests definitely welcome. - -- Make sure to add tests to cover your new functionality/bugfix. -- Run the `gulp` command to build/test (or alternatively, open the `tests/index.html` file to run the tests). -- When committing, please omit checking in the files in the `dist/` folder after building/testing. These are only committed to the repository for users downloading Autolinker via Bower. I will build these files and assign them a version number when merging your PR. -- Please use tabs for indents! Tabs are better for everybody (individuals can set their editors to different tab sizes based on their visual preferences). - - -## Changelog - -See [Releases](https://github.com/gregjacobs/Autolinker.js/releases) diff --git a/node_modules/autolinker/dist/Autolinker.js b/node_modules/autolinker/dist/Autolinker.js deleted file mode 100644 index 36b655315ea0747597753dacf6cf4bbd049f76ae..0000000000000000000000000000000000000000 --- a/node_modules/autolinker/dist/Autolinker.js +++ /dev/null @@ -1,3770 +0,0 @@ -/*! - * Autolinker.js - * 0.28.1 - * - * Copyright(c) 2016 Gregory Jacobs - * MIT License - * - * https://github.com/gregjacobs/Autolinker.js - */ -;(function(root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.Autolinker = factory(); - } -}(this, function() { -/** - * @class Autolinker - * @extends Object - * - * Utility class used to process a given string of text, and wrap the matches in - * the appropriate anchor (<a>) tags to turn them into links. - * - * Any of the configuration options may be provided in an Object (map) provided - * to the Autolinker constructor, which will configure how the {@link #link link()} - * method will process the links. - * - * For example: - * - * var autolinker = new Autolinker( { - * newWindow : false, - * truncate : 30 - * } ); - * - * var html = autolinker.link( "Joe went to www.yahoo.com" ); - * // produces: 'Joe went to yahoo.com' - * - * - * The {@link #static-link static link()} method may also be used to inline - * options into a single call, which may be more convenient for one-off uses. - * For example: - * - * var html = Autolinker.link( "Joe went to www.yahoo.com", { - * newWindow : false, - * truncate : 30 - * } ); - * // produces: 'Joe went to yahoo.com' - * - * - * ## Custom Replacements of Links - * - * If the configuration options do not provide enough flexibility, a {@link #replaceFn} - * may be provided to fully customize the output of Autolinker. This function is - * called once for each URL/Email/Phone#/Twitter Handle/Hashtag match that is - * encountered. - * - * For example: - * - * var input = "..."; // string with URLs, Email Addresses, Phone #s, Twitter Handles, and Hashtags - * - * var linkedText = Autolinker.link( input, { - * replaceFn : function( autolinker, match ) { - * console.log( "href = ", match.getAnchorHref() ); - * console.log( "text = ", match.getAnchorText() ); - * - * switch( match.getType() ) { - * case 'url' : - * console.log( "url: ", match.getUrl() ); - * - * if( match.getUrl().indexOf( 'mysite.com' ) === -1 ) { - * var tag = autolinker.getTagBuilder().build( match ); // returns an `Autolinker.HtmlTag` instance, which provides mutator methods for easy changes - * tag.setAttr( 'rel', 'nofollow' ); - * tag.addClass( 'external-link' ); - * - * return tag; - * - * } else { - * return true; // let Autolinker perform its normal anchor tag replacement - * } - * - * case 'email' : - * var email = match.getEmail(); - * console.log( "email: ", email ); - * - * if( email === "my@own.address" ) { - * return false; // don't auto-link this particular email address; leave as-is - * } else { - * return; // no return value will have Autolinker perform its normal anchor tag replacement (same as returning `true`) - * } - * - * case 'phone' : - * var phoneNumber = match.getPhoneNumber(); - * console.log( phoneNumber ); - * - * return '' + phoneNumber + ''; - * - * case 'twitter' : - * var twitterHandle = match.getTwitterHandle(); - * console.log( twitterHandle ); - * - * return '' + twitterHandle + ''; - * - * case 'hashtag' : - * var hashtag = match.getHashtag(); - * console.log( hashtag ); - * - * return '' + hashtag + ''; - * } - * } - * } ); - * - * - * The function may return the following values: - * - * - `true` (Boolean): Allow Autolinker to replace the match as it normally - * would. - * - `false` (Boolean): Do not replace the current match at all - leave as-is. - * - Any String: If a string is returned from the function, the string will be - * used directly as the replacement HTML for the match. - * - An {@link Autolinker.HtmlTag} instance, which can be used to build/modify - * an HTML tag before writing out its HTML text. - * - * @constructor - * @param {Object} [cfg] The configuration options for the Autolinker instance, - * specified in an Object (map). - */ -var Autolinker = function( cfg ) { - cfg = cfg || {}; - - this.version = Autolinker.version; - - this.urls = this.normalizeUrlsCfg( cfg.urls ); - this.email = typeof cfg.email === 'boolean' ? cfg.email : true; - this.twitter = typeof cfg.twitter === 'boolean' ? cfg.twitter : true; - this.phone = typeof cfg.phone === 'boolean' ? cfg.phone : true; - this.hashtag = cfg.hashtag || false; - this.newWindow = typeof cfg.newWindow === 'boolean' ? cfg.newWindow : true; - this.stripPrefix = typeof cfg.stripPrefix === 'boolean' ? cfg.stripPrefix : true; - - // Validate the value of the `hashtag` cfg. - var hashtag = this.hashtag; - if( hashtag !== false && hashtag !== 'twitter' && hashtag !== 'facebook' && hashtag !== 'instagram' ) { - throw new Error( "invalid `hashtag` cfg - see docs" ); - } - - this.truncate = this.normalizeTruncateCfg( cfg.truncate ); - this.className = cfg.className || ''; - this.replaceFn = cfg.replaceFn || null; - - this.htmlParser = null; - this.matchers = null; - this.tagBuilder = null; -}; - - - -/** - * Automatically links URLs, Email addresses, Phone Numbers, Twitter handles, - * and Hashtags found in the given chunk of HTML. Does not link URLs found - * within HTML tags. - * - * For instance, if given the text: `You should go to http://www.yahoo.com`, - * then the result will be `You should go to <a href="http://www.yahoo.com">http://www.yahoo.com</a>` - * - * Example: - * - * var linkedText = Autolinker.link( "Go to google.com", { newWindow: false } ); - * // Produces: "Go to google.com" - * - * @static - * @param {String} textOrHtml The HTML or text to find matches within (depending - * on if the {@link #urls}, {@link #email}, {@link #phone}, {@link #twitter}, - * and {@link #hashtag} options are enabled). - * @param {Object} [options] Any of the configuration options for the Autolinker - * class, specified in an Object (map). See the class description for an - * example call. - * @return {String} The HTML text, with matches automatically linked. - */ -Autolinker.link = function( textOrHtml, options ) { - var autolinker = new Autolinker( options ); - return autolinker.link( textOrHtml ); -}; - - -/** - * @static - * @property {String} version (readonly) - * - * The Autolinker version number in the form major.minor.patch - * - * Ex: 0.25.1 - */ -Autolinker.version = '0.28.1'; - - -Autolinker.prototype = { - constructor : Autolinker, // fix constructor property - - /** - * @cfg {Boolean/Object} [urls=true] - * - * `true` if URLs should be automatically linked, `false` if they should not - * be. - * - * This option also accepts an Object form with 3 properties, to allow for - * more customization of what exactly gets linked. All default to `true`: - * - * @param {Boolean} schemeMatches `true` to match URLs found prefixed with a - * scheme, i.e. `http://google.com`, or `other+scheme://google.com`, - * `false` to prevent these types of matches. - * @param {Boolean} wwwMatches `true` to match urls found prefixed with - * `'www.'`, i.e. `www.google.com`. `false` to prevent these types of - * matches. Note that if the URL had a prefixed scheme, and - * `schemeMatches` is true, it will still be linked. - * @param {Boolean} tldMatches `true` to match URLs with known top level - * domains (.com, .net, etc.) that are not prefixed with a scheme or - * `'www.'`. This option attempts to match anything that looks like a URL - * in the given text. Ex: `google.com`, `asdf.org/?page=1`, etc. `false` - * to prevent these types of matches. - */ - - /** - * @cfg {Boolean} [email=true] - * - * `true` if email addresses should be automatically linked, `false` if they - * should not be. - */ - - /** - * @cfg {Boolean} [twitter=true] - * - * `true` if Twitter handles ("@example") should be automatically linked, - * `false` if they should not be. - */ - - /** - * @cfg {Boolean} [phone=true] - * - * `true` if Phone numbers ("(555)555-5555") should be automatically linked, - * `false` if they should not be. - */ - - /** - * @cfg {Boolean/String} [hashtag=false] - * - * A string for the service name to have hashtags (ex: "#myHashtag") - * auto-linked to. The currently-supported values are: - * - * - 'twitter' - * - 'facebook' - * - 'instagram' - * - * Pass `false` to skip auto-linking of hashtags. - */ - - /** - * @cfg {Boolean} [newWindow=true] - * - * `true` if the links should open in a new window, `false` otherwise. - */ - - /** - * @cfg {Boolean} [stripPrefix=true] - * - * `true` if 'http://' or 'https://' and/or the 'www.' should be stripped - * from the beginning of URL links' text, `false` otherwise. - */ - - /** - * @cfg {Number/Object} [truncate=0] - * - * ## Number Form - * - * A number for how many characters matched text should be truncated to - * inside the text of a link. If the matched text is over this number of - * characters, it will be truncated to this length by adding a two period - * ellipsis ('..') to the end of the string. - * - * For example: A url like 'http://www.yahoo.com/some/long/path/to/a/file' - * truncated to 25 characters might look something like this: - * 'yahoo.com/some/long/pat..' - * - * Example Usage: - * - * truncate: 25 - * - * - * Defaults to `0` for "no truncation." - * - * - * ## Object Form - * - * An Object may also be provided with two properties: `length` (Number) and - * `location` (String). `location` may be one of the following: 'end' - * (default), 'middle', or 'smart'. - * - * Example Usage: - * - * truncate: { length: 25, location: 'middle' } - * - * @cfg {Number} [truncate.length=0] How many characters to allow before - * truncation will occur. Defaults to `0` for "no truncation." - * @cfg {"end"/"middle"/"smart"} [truncate.location="end"] - * - * - 'end' (default): will truncate up to the number of characters, and then - * add an ellipsis at the end. Ex: 'yahoo.com/some/long/pat..' - * - 'middle': will truncate and add the ellipsis in the middle. Ex: - * 'yahoo.com/s..th/to/a/file' - * - 'smart': for URLs where the algorithm attempts to strip out unnecessary - * parts first (such as the 'www.', then URL scheme, hash, etc.), - * attempting to make the URL human-readable before looking for a good - * point to insert the ellipsis if it is still too long. Ex: - * 'yahoo.com/some..to/a/file'. For more details, see - * {@link Autolinker.truncate.TruncateSmart}. - */ - - /** - * @cfg {String} className - * - * A CSS class name to add to the generated links. This class will be added - * to all links, as well as this class plus match suffixes for styling - * url/email/phone/twitter/hashtag links differently. - * - * For example, if this config is provided as "myLink", then: - * - * - URL links will have the CSS classes: "myLink myLink-url" - * - Email links will have the CSS classes: "myLink myLink-email", and - * - Twitter links will have the CSS classes: "myLink myLink-twitter" - * - Phone links will have the CSS classes: "myLink myLink-phone" - * - Hashtag links will have the CSS classes: "myLink myLink-hashtag" - */ - - /** - * @cfg {Function} replaceFn - * - * A function to individually process each match found in the input string. - * - * See the class's description for usage. - * - * This function is called with the following parameters: - * - * @cfg {Autolinker} replaceFn.autolinker The Autolinker instance, which may - * be used to retrieve child objects from (such as the instance's - * {@link #getTagBuilder tag builder}). - * @cfg {Autolinker.match.Match} replaceFn.match The Match instance which - * can be used to retrieve information about the match that the `replaceFn` - * is currently processing. See {@link Autolinker.match.Match} subclasses - * for details. - */ - - - /** - * @property {String} version (readonly) - * - * The Autolinker version number in the form major.minor.patch - * - * Ex: 0.25.1 - */ - - /** - * @private - * @property {Autolinker.htmlParser.HtmlParser} htmlParser - * - * The HtmlParser instance used to skip over HTML tags, while finding text - * nodes to process. This is lazily instantiated in the {@link #getHtmlParser} - * method. - */ - - /** - * @private - * @property {Autolinker.matcher.Matcher[]} matchers - * - * The {@link Autolinker.matcher.Matcher} instances for this Autolinker - * instance. - * - * This is lazily created in {@link #getMatchers}. - */ - - /** - * @private - * @property {Autolinker.AnchorTagBuilder} tagBuilder - * - * The AnchorTagBuilder instance used to build match replacement anchor tags. - * Note: this is lazily instantiated in the {@link #getTagBuilder} method. - */ - - - /** - * Normalizes the {@link #urls} config into an Object with 3 properties: - * `schemeMatches`, `wwwMatches`, and `tldMatches`, all Booleans. - * - * See {@link #urls} config for details. - * - * @private - * @param {Boolean/Object} urls - * @return {Object} - */ - normalizeUrlsCfg : function( urls ) { - if( urls == null ) urls = true; // default to `true` - - if( typeof urls === 'boolean' ) { - return { schemeMatches: urls, wwwMatches: urls, tldMatches: urls }; - - } else { // object form - return { - schemeMatches : typeof urls.schemeMatches === 'boolean' ? urls.schemeMatches : true, - wwwMatches : typeof urls.wwwMatches === 'boolean' ? urls.wwwMatches : true, - tldMatches : typeof urls.tldMatches === 'boolean' ? urls.tldMatches : true - }; - } - }, - - - /** - * Normalizes the {@link #truncate} config into an Object with 2 properties: - * `length` (Number), and `location` (String). - * - * See {@link #truncate} config for details. - * - * @private - * @param {Number/Object} truncate - * @return {Object} - */ - normalizeTruncateCfg : function( truncate ) { - if( typeof truncate === 'number' ) { - return { length: truncate, location: 'end' }; - - } else { // object, or undefined/null - return Autolinker.Util.defaults( truncate || {}, { - length : Number.POSITIVE_INFINITY, - location : 'end' - } ); - } - }, - - - /** - * Parses the input `textOrHtml` looking for URLs, email addresses, phone - * numbers, username handles, and hashtags (depending on the configuration - * of the Autolinker instance), and returns an array of {@link Autolinker.match.Match} - * objects describing those matches. - * - * This method is used by the {@link #link} method, but can also be used to - * simply do parsing of the input in order to discover what kinds of links - * there are and how many. - * - * @param {String} textOrHtml The HTML or text to find matches within - * (depending on if the {@link #urls}, {@link #email}, {@link #phone}, - * {@link #twitter}, and {@link #hashtag} options are enabled). - * @return {Autolinker.match.Match[]} The array of Matches found in the - * given input `textOrHtml`. - */ - parse : function( textOrHtml ) { - var htmlParser = this.getHtmlParser(), - htmlNodes = htmlParser.parse( textOrHtml ), - anchorTagStackCount = 0, // used to only process text around anchor tags, and any inner text/html they may have; - matches = []; - - // Find all matches within the `textOrHtml` (but not matches that are - // already nested within tags) - for( var i = 0, len = htmlNodes.length; i < len; i++ ) { - var node = htmlNodes[ i ], - nodeType = node.getType(); - - if( nodeType === 'element' && node.getTagName() === 'a' ) { // Process HTML anchor element nodes in the input `textOrHtml` to find out when we're within an tag - if( !node.isClosing() ) { // it's the start tag - anchorTagStackCount++; - } else { // it's the end tag - anchorTagStackCount = Math.max( anchorTagStackCount - 1, 0 ); // attempt to handle extraneous tags by making sure the stack count never goes below 0 - } - - } else if( nodeType === 'text' && anchorTagStackCount === 0 ) { // Process text nodes that are not within an tag - var textNodeMatches = this.parseText( node.getText(), node.getOffset() ); - - matches.push.apply( matches, textNodeMatches ); - } - } - - - // After we have found all matches, remove subsequent matches that - // overlap with a previous match. This can happen for instance with URLs, - // where the url 'google.com/#link' would match '#link' as a hashtag. - matches = this.compactMatches( matches ); - - // And finally, remove matches for match types that have been turned - // off. We needed to have all match types turned on initially so that - // things like hashtags could be filtered out if they were really just - // part of a URL match (for instance, as a named anchor). - matches = this.removeUnwantedMatches( matches ); - - return matches; - }, - - - /** - * After we have found all matches, we need to remove subsequent matches - * that overlap with a previous match. This can happen for instance with - * URLs, where the url 'google.com/#link' would match '#link' as a hashtag. - * - * @private - * @param {Autolinker.match.Match[]} matches - * @return {Autolinker.match.Match[]} - */ - compactMatches : function( matches ) { - // First, the matches need to be sorted in order of offset - matches.sort( function( a, b ) { return a.getOffset() - b.getOffset(); } ); - - for( var i = 0; i < matches.length - 1; i++ ) { - var match = matches[ i ], - endIdx = match.getOffset() + match.getMatchedText().length; - - // Remove subsequent matches that overlap with the current match - while( i + 1 < matches.length && matches[ i + 1 ].getOffset() <= endIdx ) { - matches.splice( i + 1, 1 ); - } - } - - return matches; - }, - - - /** - * Removes matches for matchers that were turned off in the options. For - * example, if {@link #hashtag hashtags} were not to be matched, we'll - * remove them from the `matches` array here. - * - * @private - * @param {Autolinker.match.Match[]} matches The array of matches to remove - * the unwanted matches from. Note: this array is mutated for the - * removals. - * @return {Autolinker.match.Match[]} The mutated input `matches` array. - */ - removeUnwantedMatches : function( matches ) { - var remove = Autolinker.Util.remove; - - if( !this.hashtag ) remove( matches, function( match ) { return match.getType() === 'hashtag'; } ); - if( !this.email ) remove( matches, function( match ) { return match.getType() === 'email'; } ); - if( !this.phone ) remove( matches, function( match ) { return match.getType() === 'phone'; } ); - if( !this.twitter ) remove( matches, function( match ) { return match.getType() === 'twitter'; } ); - if( !this.urls.schemeMatches ) { - remove( matches, function( m ) { return m.getType() === 'url' && m.getUrlMatchType() === 'scheme'; } ); - } - if( !this.urls.wwwMatches ) { - remove( matches, function( m ) { return m.getType() === 'url' && m.getUrlMatchType() === 'www'; } ); - } - if( !this.urls.tldMatches ) { - remove( matches, function( m ) { return m.getType() === 'url' && m.getUrlMatchType() === 'tld'; } ); - } - - return matches; - }, - - - /** - * Parses the input `text` looking for URLs, email addresses, phone - * numbers, username handles, and hashtags (depending on the configuration - * of the Autolinker instance), and returns an array of {@link Autolinker.match.Match} - * objects describing those matches. - * - * This method processes a **non-HTML string**, and is used to parse and - * match within the text nodes of an HTML string. This method is used - * internally by {@link #parse}. - * - * @private - * @param {String} text The text to find matches within (depending on if the - * {@link #urls}, {@link #email}, {@link #phone}, {@link #twitter}, and - * {@link #hashtag} options are enabled). This must be a non-HTML string. - * @param {Number} [offset=0] The offset of the text node within the - * original string. This is used when parsing with the {@link #parse} - * method to generate correct offsets within the {@link Autolinker.match.Match} - * instances, but may be omitted if calling this method publicly. - * @return {Autolinker.match.Match[]} The array of Matches found in the - * given input `text`. - */ - parseText : function( text, offset ) { - offset = offset || 0; - var matchers = this.getMatchers(), - matches = []; - - for( var i = 0, numMatchers = matchers.length; i < numMatchers; i++ ) { - var textMatches = matchers[ i ].parseMatches( text ); - - // Correct the offset of each of the matches. They are originally - // the offset of the match within the provided text node, but we - // need to correct them to be relative to the original HTML input - // string (i.e. the one provided to #parse). - for( var j = 0, numTextMatches = textMatches.length; j < numTextMatches; j++ ) { - textMatches[ j ].setOffset( offset + textMatches[ j ].getOffset() ); - } - - matches.push.apply( matches, textMatches ); - } - return matches; - }, - - - /** - * Automatically links URLs, Email addresses, Phone numbers, Twitter - * handles, and Hashtags found in the given chunk of HTML. Does not link - * URLs found within HTML tags. - * - * For instance, if given the text: `You should go to http://www.yahoo.com`, - * then the result will be `You should go to - * <a href="http://www.yahoo.com">http://www.yahoo.com</a>` - * - * This method finds the text around any HTML elements in the input - * `textOrHtml`, which will be the text that is processed. Any original HTML - * elements will be left as-is, as well as the text that is already wrapped - * in anchor (<a>) tags. - * - * @param {String} textOrHtml The HTML or text to autolink matches within - * (depending on if the {@link #urls}, {@link #email}, {@link #phone}, - * {@link #twitter}, and {@link #hashtag} options are enabled). - * @return {String} The HTML, with matches automatically linked. - */ - link : function( textOrHtml ) { - if( !textOrHtml ) { return ""; } // handle `null` and `undefined` - - var matches = this.parse( textOrHtml ), - newHtml = [], - lastIndex = 0; - - for( var i = 0, len = matches.length; i < len; i++ ) { - var match = matches[ i ]; - - newHtml.push( textOrHtml.substring( lastIndex, match.getOffset() ) ); - newHtml.push( this.createMatchReturnVal( match ) ); - - lastIndex = match.getOffset() + match.getMatchedText().length; - } - newHtml.push( textOrHtml.substring( lastIndex ) ); // handle the text after the last match - - return newHtml.join( '' ); - }, - - - /** - * Creates the return string value for a given match in the input string. - * - * This method handles the {@link #replaceFn}, if one was provided. - * - * @private - * @param {Autolinker.match.Match} match The Match object that represents - * the match. - * @return {String} The string that the `match` should be replaced with. - * This is usually the anchor tag string, but may be the `matchStr` itself - * if the match is not to be replaced. - */ - createMatchReturnVal : function( match ) { - // Handle a custom `replaceFn` being provided - var replaceFnResult; - if( this.replaceFn ) { - replaceFnResult = this.replaceFn.call( this, this, match ); // Autolinker instance is the context, and the first arg - } - - if( typeof replaceFnResult === 'string' ) { - return replaceFnResult; // `replaceFn` returned a string, use that - - } else if( replaceFnResult === false ) { - return match.getMatchedText(); // no replacement for the match - - } else if( replaceFnResult instanceof Autolinker.HtmlTag ) { - return replaceFnResult.toAnchorString(); - - } else { // replaceFnResult === true, or no/unknown return value from function - // Perform Autolinker's default anchor tag generation - var anchorTag = match.buildTag(); // returns an Autolinker.HtmlTag instance - - return anchorTag.toAnchorString(); - } - }, - - - /** - * Lazily instantiates and returns the {@link #htmlParser} instance for this - * Autolinker instance. - * - * @protected - * @return {Autolinker.htmlParser.HtmlParser} - */ - getHtmlParser : function() { - var htmlParser = this.htmlParser; - - if( !htmlParser ) { - htmlParser = this.htmlParser = new Autolinker.htmlParser.HtmlParser(); - } - - return htmlParser; - }, - - - /** - * Lazily instantiates and returns the {@link Autolinker.matcher.Matcher} - * instances for this Autolinker instance. - * - * @protected - * @return {Autolinker.matcher.Matcher[]} - */ - getMatchers : function() { - if( !this.matchers ) { - var matchersNs = Autolinker.matcher, - tagBuilder = this.getTagBuilder(); - - var matchers = [ - new matchersNs.Hashtag( { tagBuilder: tagBuilder, serviceName: this.hashtag } ), - new matchersNs.Email( { tagBuilder: tagBuilder } ), - new matchersNs.Phone( { tagBuilder: tagBuilder } ), - new matchersNs.Twitter( { tagBuilder: tagBuilder } ), - new matchersNs.Url( { tagBuilder: tagBuilder, stripPrefix: this.stripPrefix } ) - ]; - - return ( this.matchers = matchers ); - - } else { - return this.matchers; - } - }, - - - /** - * Returns the {@link #tagBuilder} instance for this Autolinker instance, lazily instantiating it - * if it does not yet exist. - * - * This method may be used in a {@link #replaceFn} to generate the {@link Autolinker.HtmlTag HtmlTag} instance that - * Autolinker would normally generate, and then allow for modifications before returning it. For example: - * - * var html = Autolinker.link( "Test google.com", { - * replaceFn : function( autolinker, match ) { - * var tag = autolinker.getTagBuilder().build( match ); // returns an {@link Autolinker.HtmlTag} instance - * tag.setAttr( 'rel', 'nofollow' ); - * - * return tag; - * } - * } ); - * - * // generated html: - * // Test google.com - * - * @return {Autolinker.AnchorTagBuilder} - */ - getTagBuilder : function() { - var tagBuilder = this.tagBuilder; - - if( !tagBuilder ) { - tagBuilder = this.tagBuilder = new Autolinker.AnchorTagBuilder( { - newWindow : this.newWindow, - truncate : this.truncate, - className : this.className - } ); - } - - return tagBuilder; - } - -}; - - -// Autolinker Namespaces - -Autolinker.match = {}; -Autolinker.matcher = {}; -Autolinker.htmlParser = {}; -Autolinker.truncate = {}; - -/*global Autolinker */ -/*jshint eqnull:true, boss:true */ -/** - * @class Autolinker.Util - * @singleton - * - * A few utility methods for Autolinker. - */ -Autolinker.Util = { - - /** - * @property {Function} abstractMethod - * - * A function object which represents an abstract method. - */ - abstractMethod : function() { throw "abstract"; }, - - - /** - * @private - * @property {RegExp} trimRegex - * - * The regular expression used to trim the leading and trailing whitespace - * from a string. - */ - trimRegex : /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - - /** - * Assigns (shallow copies) the properties of `src` onto `dest`. - * - * @param {Object} dest The destination object. - * @param {Object} src The source object. - * @return {Object} The destination object (`dest`) - */ - assign : function( dest, src ) { - for( var prop in src ) { - if( src.hasOwnProperty( prop ) ) { - dest[ prop ] = src[ prop ]; - } - } - - return dest; - }, - - - /** - * Assigns (shallow copies) the properties of `src` onto `dest`, if the - * corresponding property on `dest` === `undefined`. - * - * @param {Object} dest The destination object. - * @param {Object} src The source object. - * @return {Object} The destination object (`dest`) - */ - defaults : function( dest, src ) { - for( var prop in src ) { - if( src.hasOwnProperty( prop ) && dest[ prop ] === undefined ) { - dest[ prop ] = src[ prop ]; - } - } - - return dest; - }, - - - /** - * Extends `superclass` to create a new subclass, adding the `protoProps` to the new subclass's prototype. - * - * @param {Function} superclass The constructor function for the superclass. - * @param {Object} protoProps The methods/properties to add to the subclass's prototype. This may contain the - * special property `constructor`, which will be used as the new subclass's constructor function. - * @return {Function} The new subclass function. - */ - extend : function( superclass, protoProps ) { - var superclassProto = superclass.prototype; - - var F = function() {}; - F.prototype = superclassProto; - - var subclass; - if( protoProps.hasOwnProperty( 'constructor' ) ) { - subclass = protoProps.constructor; - } else { - subclass = function() { superclassProto.constructor.apply( this, arguments ); }; - } - - var subclassProto = subclass.prototype = new F(); // set up prototype chain - subclassProto.constructor = subclass; // fix constructor property - subclassProto.superclass = superclassProto; - - delete protoProps.constructor; // don't re-assign constructor property to the prototype, since a new function may have been created (`subclass`), which is now already there - Autolinker.Util.assign( subclassProto, protoProps ); - - return subclass; - }, - - - /** - * Truncates the `str` at `len - ellipsisChars.length`, and adds the `ellipsisChars` to the - * end of the string (by default, two periods: '..'). If the `str` length does not exceed - * `len`, the string will be returned unchanged. - * - * @param {String} str The string to truncate and add an ellipsis to. - * @param {Number} truncateLen The length to truncate the string at. - * @param {String} [ellipsisChars=..] The ellipsis character(s) to add to the end of `str` - * when truncated. Defaults to '..' - */ - ellipsis : function( str, truncateLen, ellipsisChars ) { - if( str.length > truncateLen ) { - ellipsisChars = ( ellipsisChars == null ) ? '..' : ellipsisChars; - str = str.substring( 0, truncateLen - ellipsisChars.length ) + ellipsisChars; - } - return str; - }, - - - /** - * Supports `Array.prototype.indexOf()` functionality for old IE (IE8 and below). - * - * @param {Array} arr The array to find an element of. - * @param {*} element The element to find in the array, and return the index of. - * @return {Number} The index of the `element`, or -1 if it was not found. - */ - indexOf : function( arr, element ) { - if( Array.prototype.indexOf ) { - return arr.indexOf( element ); - - } else { - for( var i = 0, len = arr.length; i < len; i++ ) { - if( arr[ i ] === element ) return i; - } - return -1; - } - }, - - - /** - * Removes array elements based on a filtering function. Mutates the input - * array. - * - * Using this instead of the ES5 Array.prototype.filter() function, to allow - * Autolinker compatibility with IE8, and also to prevent creating many new - * arrays in memory for filtering. - * - * @param {Array} arr The array to remove elements from. This array is - * mutated. - * @param {Function} fn A function which should return `true` to - * remove an element. - * @return {Array} The mutated input `arr`. - */ - remove : function( arr, fn ) { - for( var i = arr.length - 1; i >= 0; i-- ) { - if( fn( arr[ i ] ) === true ) { - arr.splice( i, 1 ); - } - } - }, - - - /** - * Performs the functionality of what modern browsers do when `String.prototype.split()` is called - * with a regular expression that contains capturing parenthesis. - * - * For example: - * - * // Modern browsers: - * "a,b,c".split( /(,)/ ); // --> [ 'a', ',', 'b', ',', 'c' ] - * - * // Old IE (including IE8): - * "a,b,c".split( /(,)/ ); // --> [ 'a', 'b', 'c' ] - * - * This method emulates the functionality of modern browsers for the old IE case. - * - * @param {String} str The string to split. - * @param {RegExp} splitRegex The regular expression to split the input `str` on. The splitting - * character(s) will be spliced into the array, as in the "modern browsers" example in the - * description of this method. - * Note #1: the supplied regular expression **must** have the 'g' flag specified. - * Note #2: for simplicity's sake, the regular expression does not need - * to contain capturing parenthesis - it will be assumed that any match has them. - * @return {String[]} The split array of strings, with the splitting character(s) included. - */ - splitAndCapture : function( str, splitRegex ) { - if( !splitRegex.global ) throw new Error( "`splitRegex` must have the 'g' flag set" ); - - var result = [], - lastIdx = 0, - match; - - while( match = splitRegex.exec( str ) ) { - result.push( str.substring( lastIdx, match.index ) ); - result.push( match[ 0 ] ); // push the splitting char(s) - - lastIdx = match.index + match[ 0 ].length; - } - result.push( str.substring( lastIdx ) ); - - return result; - }, - - - /** - * Trims the leading and trailing whitespace from a string. - * - * @param {String} str The string to trim. - * @return {String} - */ - trim : function( str ) { - return str.replace( this.trimRegex, '' ); - } - -}; -/*global Autolinker */ -/*jshint boss:true */ -/** - * @class Autolinker.HtmlTag - * @extends Object - * - * Represents an HTML tag, which can be used to easily build/modify HTML tags programmatically. - * - * Autolinker uses this abstraction to create HTML tags, and then write them out as strings. You may also use - * this class in your code, especially within a {@link Autolinker#replaceFn replaceFn}. - * - * ## Examples - * - * Example instantiation: - * - * var tag = new Autolinker.HtmlTag( { - * tagName : 'a', - * attrs : { 'href': 'http://google.com', 'class': 'external-link' }, - * innerHtml : 'Google' - * } ); - * - * tag.toAnchorString(); // Google - * - * // Individual accessor methods - * tag.getTagName(); // 'a' - * tag.getAttr( 'href' ); // 'http://google.com' - * tag.hasClass( 'external-link' ); // true - * - * - * Using mutator methods (which may be used in combination with instantiation config properties): - * - * var tag = new Autolinker.HtmlTag(); - * tag.setTagName( 'a' ); - * tag.setAttr( 'href', 'http://google.com' ); - * tag.addClass( 'external-link' ); - * tag.setInnerHtml( 'Google' ); - * - * tag.getTagName(); // 'a' - * tag.getAttr( 'href' ); // 'http://google.com' - * tag.hasClass( 'external-link' ); // true - * - * tag.toAnchorString(); // Google - * - * - * ## Example use within a {@link Autolinker#replaceFn replaceFn} - * - * var html = Autolinker.link( "Test google.com", { - * replaceFn : function( autolinker, match ) { - * var tag = match.buildTag(); // returns an {@link Autolinker.HtmlTag} instance, configured with the Match's href and anchor text - * tag.setAttr( 'rel', 'nofollow' ); - * - * return tag; - * } - * } ); - * - * // generated html: - * // Test google.com - * - * - * ## Example use with a new tag for the replacement - * - * var html = Autolinker.link( "Test google.com", { - * replaceFn : function( autolinker, match ) { - * var tag = new Autolinker.HtmlTag( { - * tagName : 'button', - * attrs : { 'title': 'Load URL: ' + match.getAnchorHref() }, - * innerHtml : 'Load URL: ' + match.getAnchorText() - * } ); - * - * return tag; - * } - * } ); - * - * // generated html: - * // Test - */ -Autolinker.HtmlTag = Autolinker.Util.extend( Object, { - - /** - * @cfg {String} tagName - * - * The tag name. Ex: 'a', 'button', etc. - * - * Not required at instantiation time, but should be set using {@link #setTagName} before {@link #toAnchorString} - * is executed. - */ - - /** - * @cfg {Object.} attrs - * - * An key/value Object (map) of attributes to create the tag with. The keys are the attribute names, and the - * values are the attribute values. - */ - - /** - * @cfg {String} innerHtml - * - * The inner HTML for the tag. - * - * Note the camel case name on `innerHtml`. Acronyms are camelCased in this utility (such as not to run into the acronym - * naming inconsistency that the DOM developers created with `XMLHttpRequest`). You may alternatively use {@link #innerHTML} - * if you prefer, but this one is recommended. - */ - - /** - * @cfg {String} innerHTML - * - * Alias of {@link #innerHtml}, accepted for consistency with the browser DOM api, but prefer the camelCased version - * for acronym names. - */ - - - /** - * @protected - * @property {RegExp} whitespaceRegex - * - * Regular expression used to match whitespace in a string of CSS classes. - */ - whitespaceRegex : /\s+/, - - - /** - * @constructor - * @param {Object} [cfg] The configuration properties for this class, in an Object (map) - */ - constructor : function( cfg ) { - Autolinker.Util.assign( this, cfg ); - - this.innerHtml = this.innerHtml || this.innerHTML; // accept either the camelCased form or the fully capitalized acronym - }, - - - /** - * Sets the tag name that will be used to generate the tag with. - * - * @param {String} tagName - * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. - */ - setTagName : function( tagName ) { - this.tagName = tagName; - return this; - }, - - - /** - * Retrieves the tag name. - * - * @return {String} - */ - getTagName : function() { - return this.tagName || ""; - }, - - - /** - * Sets an attribute on the HtmlTag. - * - * @param {String} attrName The attribute name to set. - * @param {String} attrValue The attribute value to set. - * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. - */ - setAttr : function( attrName, attrValue ) { - var tagAttrs = this.getAttrs(); - tagAttrs[ attrName ] = attrValue; - - return this; - }, - - - /** - * Retrieves an attribute from the HtmlTag. If the attribute does not exist, returns `undefined`. - * - * @param {String} attrName The attribute name to retrieve. - * @return {String} The attribute's value, or `undefined` if it does not exist on the HtmlTag. - */ - getAttr : function( attrName ) { - return this.getAttrs()[ attrName ]; - }, - - - /** - * Sets one or more attributes on the HtmlTag. - * - * @param {Object.} attrs A key/value Object (map) of the attributes to set. - * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. - */ - setAttrs : function( attrs ) { - var tagAttrs = this.getAttrs(); - Autolinker.Util.assign( tagAttrs, attrs ); - - return this; - }, - - - /** - * Retrieves the attributes Object (map) for the HtmlTag. - * - * @return {Object.} A key/value object of the attributes for the HtmlTag. - */ - getAttrs : function() { - return this.attrs || ( this.attrs = {} ); - }, - - - /** - * Sets the provided `cssClass`, overwriting any current CSS classes on the HtmlTag. - * - * @param {String} cssClass One or more space-separated CSS classes to set (overwrite). - * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. - */ - setClass : function( cssClass ) { - return this.setAttr( 'class', cssClass ); - }, - - - /** - * Convenience method to add one or more CSS classes to the HtmlTag. Will not add duplicate CSS classes. - * - * @param {String} cssClass One or more space-separated CSS classes to add. - * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. - */ - addClass : function( cssClass ) { - var classAttr = this.getClass(), - whitespaceRegex = this.whitespaceRegex, - indexOf = Autolinker.Util.indexOf, // to support IE8 and below - classes = ( !classAttr ) ? [] : classAttr.split( whitespaceRegex ), - newClasses = cssClass.split( whitespaceRegex ), - newClass; - - while( newClass = newClasses.shift() ) { - if( indexOf( classes, newClass ) === -1 ) { - classes.push( newClass ); - } - } - - this.getAttrs()[ 'class' ] = classes.join( " " ); - return this; - }, - - - /** - * Convenience method to remove one or more CSS classes from the HtmlTag. - * - * @param {String} cssClass One or more space-separated CSS classes to remove. - * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. - */ - removeClass : function( cssClass ) { - var classAttr = this.getClass(), - whitespaceRegex = this.whitespaceRegex, - indexOf = Autolinker.Util.indexOf, // to support IE8 and below - classes = ( !classAttr ) ? [] : classAttr.split( whitespaceRegex ), - removeClasses = cssClass.split( whitespaceRegex ), - removeClass; - - while( classes.length && ( removeClass = removeClasses.shift() ) ) { - var idx = indexOf( classes, removeClass ); - if( idx !== -1 ) { - classes.splice( idx, 1 ); - } - } - - this.getAttrs()[ 'class' ] = classes.join( " " ); - return this; - }, - - - /** - * Convenience method to retrieve the CSS class(es) for the HtmlTag, which will each be separated by spaces when - * there are multiple. - * - * @return {String} - */ - getClass : function() { - return this.getAttrs()[ 'class' ] || ""; - }, - - - /** - * Convenience method to check if the tag has a CSS class or not. - * - * @param {String} cssClass The CSS class to check for. - * @return {Boolean} `true` if the HtmlTag has the CSS class, `false` otherwise. - */ - hasClass : function( cssClass ) { - return ( ' ' + this.getClass() + ' ' ).indexOf( ' ' + cssClass + ' ' ) !== -1; - }, - - - /** - * Sets the inner HTML for the tag. - * - * @param {String} html The inner HTML to set. - * @return {Autolinker.HtmlTag} This HtmlTag instance, so that method calls may be chained. - */ - setInnerHtml : function( html ) { - this.innerHtml = html; - - return this; - }, - - - /** - * Retrieves the inner HTML for the tag. - * - * @return {String} - */ - getInnerHtml : function() { - return this.innerHtml || ""; - }, - - - /** - * Override of superclass method used to generate the HTML string for the tag. - * - * @return {String} - */ - toAnchorString : function() { - var tagName = this.getTagName(), - attrsStr = this.buildAttrsStr(); - - attrsStr = ( attrsStr ) ? ' ' + attrsStr : ''; // prepend a space if there are actually attributes - - return [ '<', tagName, attrsStr, '>', this.getInnerHtml(), '' ].join( "" ); - }, - - - /** - * Support method for {@link #toAnchorString}, returns the string space-separated key="value" pairs, used to populate - * the stringified HtmlTag. - * - * @protected - * @return {String} Example return: `attr1="value1" attr2="value2"` - */ - buildAttrsStr : function() { - if( !this.attrs ) return ""; // no `attrs` Object (map) has been set, return empty string - - var attrs = this.getAttrs(), - attrsArr = []; - - for( var prop in attrs ) { - if( attrs.hasOwnProperty( prop ) ) { - attrsArr.push( prop + '="' + attrs[ prop ] + '"' ); - } - } - return attrsArr.join( " " ); - } - -} ); - -/*global Autolinker */ -/** - * @class Autolinker.RegexLib - * @singleton - * - * Builds and stores a library of the common regular expressions used by the - * Autolinker utility. - * - * Other regular expressions may exist ad-hoc, but these are generally the - * regular expressions that are shared between source files. - */ -Autolinker.RegexLib = (function() { - - /** - * The string form of a regular expression that would match all of the - * alphabetic ("letter") chars in the unicode character set when placed in a - * RegExp character class (`[]`). This includes all international alphabetic - * characters. - * - * These would be the characters matched by unicode regex engines `\p{L}` - * escape ("all letters"). - * - * Taken from the XRegExp library: http://xregexp.com/ - * Specifically: http://xregexp.com/v/3.0.0/unicode-categories.js - * - * @private - * @type {String} - */ - var alphaCharsStr = 'A-Za-z\\xAA\\xB5\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC'; - - /** - * The string form of a regular expression that would match all of the - * decimal number chars in the unicode character set when placed in a RegExp - * character class (`[]`). - * - * These would be the characters matched by unicode regex engines `\p{Nd}` - * escape ("all decimal numbers") - * - * Taken from the XRegExp library: http://xregexp.com/ - * Specifically: http://xregexp.com/v/3.0.0/unicode-categories.js - * - * @private - * @type {String} - */ - var decimalNumbersStr = '0-9\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE6-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29\u1040-\u1049\u1090-\u1099\u17E0-\u17E9\u1810-\u1819\u1946-\u194F\u19D0-\u19D9\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\uA620-\uA629\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19'; - - - // See documentation below - var alphaNumericCharsStr = alphaCharsStr + decimalNumbersStr; - - - // See documentation below - var domainNameRegex = new RegExp( '[' + alphaNumericCharsStr + '.\\-]*[' + alphaNumericCharsStr + '\\-]' ); - - - // See documentation below - var tldRegex = /(?:travelersinsurance|sandvikcoromant|kerryproperties|cancerresearch|weatherchannel|kerrylogistics|spreadbetting|international|wolterskluwer|lifeinsurance|construction|pamperedchef|scholarships|versicherung|bridgestone|creditunion|kerryhotels|investments|productions|blackfriday|enterprises|lamborghini|photography|motorcycles|williamhill|playstation|contractors|barclaycard|accountants|redumbrella|engineering|management|telefonica|protection|consulting|tatamotors|creditcard|vlaanderen|schaeffler|associates|properties|foundation|republican|bnpparibas|boehringer|eurovision|extraspace|industries|immobilien|university|technology|volkswagen|healthcare|restaurant|cuisinella|vistaprint|apartments|accountant|travelers|homedepot|institute|vacations|furniture|fresenius|insurance|christmas|bloomberg|solutions|barcelona|firestone|financial|kuokgroup|fairwinds|community|passagens|goldpoint|equipment|lifestyle|yodobashi|aquarelle|marketing|analytics|education|amsterdam|statefarm|melbourne|allfinanz|directory|microsoft|stockholm|montblanc|accenture|lancaster|landrover|everbank|istanbul|graphics|grainger|ipiranga|softbank|attorney|pharmacy|saarland|catering|airforce|yokohama|mortgage|frontier|mutuelle|stcgroup|memorial|pictures|football|symantec|cipriani|ventures|telecity|cityeats|verisign|flsmidth|boutique|cleaning|firmdale|clinique|clothing|redstone|infiniti|deloitte|feedback|services|broadway|plumbing|commbank|training|barclays|exchange|computer|brussels|software|delivery|barefoot|builders|business|bargains|engineer|holdings|download|security|helsinki|lighting|movistar|discount|hdfcbank|supplies|marriott|property|diamonds|capetown|partners|democrat|jpmorgan|bradesco|budapest|rexroth|zuerich|shriram|academy|science|support|youtube|singles|surgery|alibaba|statoil|dentist|schwarz|android|cruises|cricket|digital|markets|starhub|systems|courses|coupons|netbank|country|domains|corsica|network|neustar|realtor|lincoln|limited|schmidt|yamaxun|cooking|contact|auction|spiegel|liaison|leclerc|latrobe|lasalle|abogado|compare|lanxess|exposed|express|company|cologne|college|avianca|lacaixa|fashion|recipes|ferrero|komatsu|storage|wanggou|clubmed|sandvik|fishing|fitness|bauhaus|kitchen|flights|florist|flowers|watches|weather|temasek|samsung|bentley|forsale|channel|theater|frogans|theatre|okinawa|website|tickets|jewelry|gallery|tiffany|iselect|shiksha|brother|organic|wedding|genting|toshiba|origins|philips|hyundai|hotmail|hoteles|hosting|rentals|windows|cartier|bugatti|holiday|careers|whoswho|hitachi|panerai|caravan|reviews|guitars|capital|trading|hamburg|hangout|finance|stream|family|abbott|health|review|travel|report|hermes|hiphop|gratis|career|toyota|hockey|dating|repair|google|social|soccer|reisen|global|otsuka|giving|unicom|casino|photos|center|broker|rocher|orange|bostik|garden|insure|ryukyu|bharti|safety|physio|sakura|oracle|online|jaguar|gallup|piaget|tienda|futbol|pictet|joburg|webcam|berlin|office|juegos|kaufen|chanel|chrome|xihuan|church|tennis|circle|kinder|flickr|bayern|claims|clinic|viajes|nowruz|xperia|norton|yachts|studio|coffee|camera|sanofi|nissan|author|expert|events|comsec|lawyer|tattoo|viking|estate|villas|condos|realty|yandex|energy|emerck|virgin|vision|durban|living|school|coupon|london|taobao|natura|taipei|nagoya|luxury|walter|aramco|sydney|madrid|credit|maison|makeup|schule|market|anquan|direct|design|swatch|suzuki|alsace|vuelos|dental|alipay|voyage|shouji|voting|airtel|mutual|degree|supply|agency|museum|mobily|dealer|monash|select|mormon|active|moscow|racing|datsun|quebec|nissay|rodeo|email|gifts|works|photo|chloe|edeka|cheap|earth|vista|tushu|koeln|glass|shoes|globo|tunes|gmail|nokia|space|kyoto|black|ricoh|seven|lamer|sener|epson|cisco|praxi|trust|citic|crown|shell|lease|green|legal|lexus|ninja|tatar|gripe|nikon|group|video|wales|autos|gucci|party|nexus|guide|linde|adult|parts|amica|lixil|boats|azure|loans|locus|cymru|lotte|lotto|stada|click|poker|quest|dabur|lupin|nadex|paris|faith|dance|canon|place|gives|trade|skype|rocks|mango|cloud|boots|smile|final|swiss|homes|honda|media|horse|cards|deals|watch|bosch|house|pizza|miami|osaka|tours|total|xerox|coach|sucks|style|delta|toray|iinet|tools|money|codes|beats|tokyo|salon|archi|movie|baidu|study|actor|yahoo|store|apple|world|forex|today|bible|tmall|tirol|irish|tires|forum|reise|vegas|vodka|sharp|omega|weber|jetzt|audio|promo|build|bingo|chase|gallo|drive|dubai|rehab|press|solar|sale|beer|bbva|bank|band|auto|sapo|sarl|saxo|audi|asia|arte|arpa|army|yoga|ally|zara|scor|scot|sexy|seat|zero|seek|aero|adac|zone|aarp|maif|meet|meme|menu|surf|mini|mobi|mtpc|porn|desi|star|ltda|name|talk|navy|love|loan|live|link|news|limo|like|spot|life|nico|lidl|lgbt|land|taxi|team|tech|kred|kpmg|sony|song|kiwi|kddi|jprs|jobs|sohu|java|itau|tips|info|immo|icbc|hsbc|town|host|page|toys|here|help|pars|haus|guru|guge|tube|goog|golf|gold|sncf|gmbh|gift|ggee|gent|gbiz|game|vana|pics|fund|ford|ping|pink|fish|film|fast|farm|play|fans|fail|plus|skin|pohl|fage|moda|post|erni|dvag|prod|doha|prof|docs|viva|diet|luxe|site|dell|sina|dclk|show|qpon|date|vote|cyou|voto|read|coop|cool|wang|club|city|chat|cern|cash|reit|rent|casa|cars|care|camp|rest|call|cafe|weir|wien|rich|wiki|buzz|wine|book|bond|room|work|rsvp|shia|ruhr|blue|bing|shaw|bike|safe|xbox|best|pwc|mtn|lds|aig|boo|fyi|nra|nrw|ntt|car|gal|obi|zip|aeg|vin|how|one|ong|onl|dad|ooo|bet|esq|org|htc|bar|uol|ibm|ovh|gdn|ice|icu|uno|gea|ifm|bot|top|wtf|lol|day|pet|eus|wtc|ubs|tvs|aco|ing|ltd|ink|tab|abb|afl|cat|int|pid|pin|bid|cba|gle|com|cbn|ads|man|wed|ceb|gmo|sky|ist|gmx|tui|mba|fan|ski|iwc|app|pro|med|ceo|jcb|jcp|goo|dev|men|aaa|meo|pub|jlc|bom|jll|gop|jmp|mil|got|gov|win|jot|mma|joy|trv|red|cfa|cfd|bio|moe|moi|mom|ren|biz|aws|xin|bbc|dnp|buy|kfh|mov|thd|xyz|fit|kia|rio|rip|kim|dog|vet|nyc|bcg|mtr|bcn|bms|bmw|run|bzh|rwe|tel|stc|axa|kpn|fly|krd|cab|bnl|foo|crs|eat|tci|sap|srl|nec|sas|net|cal|sbs|sfr|sca|scb|csc|edu|new|xxx|hiv|fox|wme|ngo|nhk|vip|sex|frl|lat|yun|law|you|tax|soy|sew|om|ac|hu|se|sc|sg|sh|sb|sa|rw|ru|rs|ro|re|qa|py|si|pw|pt|ps|sj|sk|pr|pn|pm|pl|sl|sm|pk|sn|ph|so|pg|pf|pe|pa|zw|nz|nu|nr|np|no|nl|ni|ng|nf|sr|ne|st|nc|na|mz|my|mx|mw|mv|mu|mt|ms|mr|mq|mp|mo|su|mn|mm|ml|mk|mh|mg|me|sv|md|mc|sx|sy|ma|ly|lv|sz|lu|lt|ls|lr|lk|li|lc|lb|la|tc|kz|td|ky|kw|kr|kp|kn|km|ki|kh|tf|tg|th|kg|ke|jp|jo|jm|je|it|is|ir|tj|tk|tl|tm|iq|tn|to|io|in|im|il|ie|ad|sd|ht|hr|hn|hm|tr|hk|gy|gw|gu|gt|gs|gr|gq|tt|gp|gn|gm|gl|tv|gi|tw|tz|ua|gh|ug|uk|gg|gf|ge|gd|us|uy|uz|va|gb|ga|vc|ve|fr|fo|fm|fk|fj|vg|vi|fi|eu|et|es|er|eg|ee|ec|dz|do|dm|dk|vn|dj|de|cz|cy|cx|cw|vu|cv|cu|cr|co|cn|cm|cl|ck|ci|ch|cg|cf|cd|cc|ca|wf|bz|by|bw|bv|bt|bs|br|bo|bn|bm|bj|bi|ws|bh|bg|bf|be|bd|bb|ba|az|ax|aw|au|at|as|ye|ar|aq|ao|am|al|yt|ai|za|ag|af|ae|zm|id)\b/; - - - return { - - /** - * The string form of a regular expression that would match all of the - * letters and decimal number chars in the unicode character set when placed - * in a RegExp character class (`[]`). - * - * These would be the characters matched by unicode regex engines `[\p{L}\p{Nd}]` - * escape ("all letters and decimal numbers") - * - * @property {String} alphaNumericCharsStr - */ - alphaNumericCharsStr : alphaNumericCharsStr, - - /** - * A regular expression to match domain names of a URL or email address. - * Ex: 'google', 'yahoo', 'some-other-company', etc. - * - * @property {RegExp} domainNameRegex - */ - domainNameRegex : domainNameRegex, - - /** - * A regular expression to match top level domains (TLDs) for a URL or - * email address. Ex: 'com', 'org', 'net', etc. - * - * @property {RegExp} tldRegex - */ - tldRegex : tldRegex - - }; - - -}() ); -/*global Autolinker */ -/*jshint sub:true */ -/** - * @protected - * @class Autolinker.AnchorTagBuilder - * @extends Object - * - * Builds anchor (<a>) tags for the Autolinker utility when a match is - * found. - * - * Normally this class is instantiated, configured, and used internally by an - * {@link Autolinker} instance, but may actually be retrieved in a {@link Autolinker#replaceFn replaceFn} - * to create {@link Autolinker.HtmlTag HtmlTag} instances which may be modified - * before returning from the {@link Autolinker#replaceFn replaceFn}. For - * example: - * - * var html = Autolinker.link( "Test google.com", { - * replaceFn : function( autolinker, match ) { - * var tag = autolinker.getTagBuilder().build( match ); // returns an {@link Autolinker.HtmlTag} instance - * tag.setAttr( 'rel', 'nofollow' ); - * - * return tag; - * } - * } ); - * - * // generated html: - * // Test google.com - */ -Autolinker.AnchorTagBuilder = Autolinker.Util.extend( Object, { - - /** - * @cfg {Boolean} newWindow - * @inheritdoc Autolinker#newWindow - */ - - /** - * @cfg {Object} truncate - * @inheritdoc Autolinker#truncate - */ - - /** - * @cfg {String} className - * @inheritdoc Autolinker#className - */ - - - /** - * @constructor - * @param {Object} [cfg] The configuration options for the AnchorTagBuilder instance, specified in an Object (map). - */ - constructor : function( cfg ) { - Autolinker.Util.assign( this, cfg ); - }, - - - /** - * Generates the actual anchor (<a>) tag to use in place of the - * matched text, via its `match` object. - * - * @param {Autolinker.match.Match} match The Match instance to generate an - * anchor tag from. - * @return {Autolinker.HtmlTag} The HtmlTag instance for the anchor tag. - */ - build : function( match ) { - return new Autolinker.HtmlTag( { - tagName : 'a', - attrs : this.createAttrs( match.getType(), match.getAnchorHref() ), - innerHtml : this.processAnchorText( match.getAnchorText() ) - } ); - }, - - - /** - * Creates the Object (map) of the HTML attributes for the anchor (<a>) - * tag being generated. - * - * @protected - * @param {"url"/"email"/"phone"/"twitter"/"hashtag"} matchType The type of - * match that an anchor tag is being generated for. - * @param {String} anchorHref The href for the anchor tag. - * @return {Object} A key/value Object (map) of the anchor tag's attributes. - */ - createAttrs : function( matchType, anchorHref ) { - var attrs = { - 'href' : anchorHref // we'll always have the `href` attribute - }; - - var cssClass = this.createCssClass( matchType ); - if( cssClass ) { - attrs[ 'class' ] = cssClass; - } - if( this.newWindow ) { - attrs[ 'target' ] = "_blank"; - attrs[ 'rel' ] = "noopener noreferrer"; - } - - return attrs; - }, - - - /** - * Creates the CSS class that will be used for a given anchor tag, based on - * the `matchType` and the {@link #className} config. - * - * @private - * @param {"url"/"email"/"phone"/"twitter"/"hashtag"} matchType The type of - * match that an anchor tag is being generated for. - * @return {String} The CSS class string for the link. Example return: - * "myLink myLink-url". If no {@link #className} was configured, returns - * an empty string. - */ - createCssClass : function( matchType ) { - var className = this.className; - - if( !className ) - return ""; - else - return className + " " + className + "-" + matchType; // ex: "myLink myLink-url", "myLink myLink-email", "myLink myLink-phone", "myLink myLink-twitter", or "myLink myLink-hashtag" - }, - - - /** - * Processes the `anchorText` by truncating the text according to the - * {@link #truncate} config. - * - * @private - * @param {String} anchorText The anchor tag's text (i.e. what will be - * displayed). - * @return {String} The processed `anchorText`. - */ - processAnchorText : function( anchorText ) { - anchorText = this.doTruncate( anchorText ); - - return anchorText; - }, - - - /** - * Performs the truncation of the `anchorText` based on the {@link #truncate} - * option. If the `anchorText` is longer than the length specified by the - * {@link #truncate} option, the truncation is performed based on the - * `location` property. See {@link #truncate} for details. - * - * @private - * @param {String} anchorText The anchor tag's text (i.e. what will be - * displayed). - * @return {String} The truncated anchor text. - */ - doTruncate : function( anchorText ) { - var truncate = this.truncate; - if( !truncate || !truncate.length ) return anchorText; - - var truncateLength = truncate.length, - truncateLocation = truncate.location; - - if( truncateLocation === 'smart' ) { - return Autolinker.truncate.TruncateSmart( anchorText, truncateLength, '..' ); - - } else if( truncateLocation === 'middle' ) { - return Autolinker.truncate.TruncateMiddle( anchorText, truncateLength, '..' ); - - } else { - return Autolinker.truncate.TruncateEnd( anchorText, truncateLength, '..' ); - } - } - -} ); - -/*global Autolinker */ -/** - * @class Autolinker.htmlParser.HtmlParser - * @extends Object - * - * An HTML parser implementation which simply walks an HTML string and returns an array of - * {@link Autolinker.htmlParser.HtmlNode HtmlNodes} that represent the basic HTML structure of the input string. - * - * Autolinker uses this to only link URLs/emails/Twitter handles within text nodes, effectively ignoring / "walking - * around" HTML tags. - */ -Autolinker.htmlParser.HtmlParser = Autolinker.Util.extend( Object, { - - /** - * @private - * @property {RegExp} htmlRegex - * - * The regular expression used to pull out HTML tags from a string. Handles namespaced HTML tags and - * attribute names, as specified by http://www.w3.org/TR/html-markup/syntax.html. - * - * Capturing groups: - * - * 1. The "!DOCTYPE" tag name, if a tag is a <!DOCTYPE> tag. - * 2. If it is an end tag, this group will have the '/'. - * 3. If it is a comment tag, this group will hold the comment text (i.e. - * the text inside the `<!--` and `-->`. - * 4. The tag name for all tags (other than the <!DOCTYPE> tag) - */ - htmlRegex : (function() { - var commentTagRegex = /!--([\s\S]+?)--/, - tagNameRegex = /[0-9a-zA-Z][0-9a-zA-Z:]*/, - attrNameRegex = /[^\s"'>\/=\x00-\x1F\x7F]+/, // the unicode range accounts for excluding control chars, and the delete char - attrValueRegex = /(?:"[^"]*?"|'[^']*?'|[^'"=<>`\s]+)/, // double quoted, single quoted, or unquoted attribute values - nameEqualsValueRegex = attrNameRegex.source + '(?:\\s*=\\s*' + attrValueRegex.source + ')?'; // optional '=[value]' - - return new RegExp( [ - // for tag. Ex: ) - '(?:', - '<(!DOCTYPE)', // *** Capturing Group 1 - If it's a doctype tag - - // Zero or more attributes following the tag name - '(?:', - '\\s+', // one or more whitespace chars before an attribute - - // Either: - // A. attr="value", or - // B. "value" alone (To cover example doctype tag: ) - '(?:', nameEqualsValueRegex, '|', attrValueRegex.source + ')', - ')*', - '>', - ')', - - '|', - - // All other HTML tags (i.e. tags that are not ) - '(?:', - '<(/)?', // Beginning of a tag or comment. Either '<' for a start tag, or '' - - ')', - ')', - '>', - ')' - ].join( "" ), 'gi' ); - } )(), - - /** - * @private - * @property {RegExp} htmlCharacterEntitiesRegex - * - * The regular expression that matches common HTML character entities. - * - * Ignoring & as it could be part of a query string -- handling it separately. - */ - htmlCharacterEntitiesRegex: /( | |<|<|>|>|"|"|')/gi, - - - /** - * Parses an HTML string and returns a simple array of {@link Autolinker.htmlParser.HtmlNode HtmlNodes} - * to represent the HTML structure of the input string. - * - * @param {String} html The HTML to parse. - * @return {Autolinker.htmlParser.HtmlNode[]} - */ - parse : function( html ) { - var htmlRegex = this.htmlRegex, - currentResult, - lastIndex = 0, - textAndEntityNodes, - nodes = []; // will be the result of the method - - while( ( currentResult = htmlRegex.exec( html ) ) !== null ) { - var tagText = currentResult[ 0 ], - commentText = currentResult[ 3 ], // if we've matched a comment - tagName = currentResult[ 1 ] || currentResult[ 4 ], // The tag (ex: "!DOCTYPE"), or another tag (ex: "a" or "img") - isClosingTag = !!currentResult[ 2 ], - offset = currentResult.index, - inBetweenTagsText = html.substring( lastIndex, offset ); - - // Push TextNodes and EntityNodes for any text found between tags - if( inBetweenTagsText ) { - textAndEntityNodes = this.parseTextAndEntityNodes( lastIndex, inBetweenTagsText ); - nodes.push.apply( nodes, textAndEntityNodes ); - } - - // Push the CommentNode or ElementNode - if( commentText ) { - nodes.push( this.createCommentNode( offset, tagText, commentText ) ); - } else { - nodes.push( this.createElementNode( offset, tagText, tagName, isClosingTag ) ); - } - - lastIndex = offset + tagText.length; - } - - // Process any remaining text after the last HTML element. Will process all of the text if there were no HTML elements. - if( lastIndex < html.length ) { - var text = html.substring( lastIndex ); - - // Push TextNodes and EntityNodes for any text found between tags - if( text ) { - textAndEntityNodes = this.parseTextAndEntityNodes( lastIndex, text ); - nodes.push.apply( nodes, textAndEntityNodes ); - } - } - - return nodes; - }, - - - /** - * Parses text and HTML entity nodes from a given string. The input string - * should not have any HTML tags (elements) within it. - * - * @private - * @param {Number} offset The offset of the text node match within the - * original HTML string. - * @param {String} text The string of text to parse. This is from an HTML - * text node. - * @return {Autolinker.htmlParser.HtmlNode[]} An array of HtmlNodes to - * represent the {@link Autolinker.htmlParser.TextNode TextNodes} and - * {@link Autolinker.htmlParser.EntityNode EntityNodes} found. - */ - parseTextAndEntityNodes : function( offset, text ) { - var nodes = [], - textAndEntityTokens = Autolinker.Util.splitAndCapture( text, this.htmlCharacterEntitiesRegex ); // split at HTML entities, but include the HTML entities in the results array - - // Every even numbered token is a TextNode, and every odd numbered token is an EntityNode - // For example: an input `text` of "Test "this" today" would turn into the - // `textAndEntityTokens`: [ 'Test ', '"', 'this', '"', ' today' ] - for( var i = 0, len = textAndEntityTokens.length; i < len; i += 2 ) { - var textToken = textAndEntityTokens[ i ], - entityToken = textAndEntityTokens[ i + 1 ]; - - if( textToken ) { - nodes.push( this.createTextNode( offset, textToken ) ); - offset += textToken.length; - } - if( entityToken ) { - nodes.push( this.createEntityNode( offset, entityToken ) ); - offset += entityToken.length; - } - } - return nodes; - }, - - - /** - * Factory method to create an {@link Autolinker.htmlParser.CommentNode CommentNode}. - * - * @private - * @param {Number} offset The offset of the match within the original HTML - * string. - * @param {String} tagText The full text of the tag (comment) that was - * matched, including its <!-- and -->. - * @param {String} commentText The full text of the comment that was matched. - */ - createCommentNode : function( offset, tagText, commentText ) { - return new Autolinker.htmlParser.CommentNode( { - offset : offset, - text : tagText, - comment: Autolinker.Util.trim( commentText ) - } ); - }, - - - /** - * Factory method to create an {@link Autolinker.htmlParser.ElementNode ElementNode}. - * - * @private - * @param {Number} offset The offset of the match within the original HTML - * string. - * @param {String} tagText The full text of the tag (element) that was - * matched, including its attributes. - * @param {String} tagName The name of the tag. Ex: An <img> tag would - * be passed to this method as "img". - * @param {Boolean} isClosingTag `true` if it's a closing tag, false - * otherwise. - * @return {Autolinker.htmlParser.ElementNode} - */ - createElementNode : function( offset, tagText, tagName, isClosingTag ) { - return new Autolinker.htmlParser.ElementNode( { - offset : offset, - text : tagText, - tagName : tagName.toLowerCase(), - closing : isClosingTag - } ); - }, - - - /** - * Factory method to create a {@link Autolinker.htmlParser.EntityNode EntityNode}. - * - * @private - * @param {Number} offset The offset of the match within the original HTML - * string. - * @param {String} text The text that was matched for the HTML entity (such - * as '&nbsp;'). - * @return {Autolinker.htmlParser.EntityNode} - */ - createEntityNode : function( offset, text ) { - return new Autolinker.htmlParser.EntityNode( { offset: offset, text: text } ); - }, - - - /** - * Factory method to create a {@link Autolinker.htmlParser.TextNode TextNode}. - * - * @private - * @param {Number} offset The offset of the match within the original HTML - * string. - * @param {String} text The text that was matched. - * @return {Autolinker.htmlParser.TextNode} - */ - createTextNode : function( offset, text ) { - return new Autolinker.htmlParser.TextNode( { offset: offset, text: text } ); - } - -} ); -/*global Autolinker */ -/** - * @abstract - * @class Autolinker.htmlParser.HtmlNode - * - * Represents an HTML node found in an input string. An HTML node is one of the - * following: - * - * 1. An {@link Autolinker.htmlParser.ElementNode ElementNode}, which represents - * HTML tags. - * 2. A {@link Autolinker.htmlParser.CommentNode CommentNode}, which represents - * HTML comments. - * 3. A {@link Autolinker.htmlParser.TextNode TextNode}, which represents text - * outside or within HTML tags. - * 4. A {@link Autolinker.htmlParser.EntityNode EntityNode}, which represents - * one of the known HTML entities that Autolinker looks for. This includes - * common ones such as &quot; and &nbsp; - */ -Autolinker.htmlParser.HtmlNode = Autolinker.Util.extend( Object, { - - /** - * @cfg {Number} offset (required) - * - * The offset of the HTML node in the original text that was parsed. - */ - offset : undefined, - - /** - * @cfg {String} text (required) - * - * The text that was matched for the HtmlNode. - * - * - In the case of an {@link Autolinker.htmlParser.ElementNode ElementNode}, - * this will be the tag's text. - * - In the case of an {@link Autolinker.htmlParser.CommentNode CommentNode}, - * this will be the comment's text. - * - In the case of a {@link Autolinker.htmlParser.TextNode TextNode}, this - * will be the text itself. - * - In the case of a {@link Autolinker.htmlParser.EntityNode EntityNode}, - * this will be the text of the HTML entity. - */ - text : undefined, - - - /** - * @constructor - * @param {Object} cfg The configuration properties for the Match instance, - * specified in an Object (map). - */ - constructor : function( cfg ) { - Autolinker.Util.assign( this, cfg ); - - if( this.offset == null ) throw new Error( '`offset` cfg required' ); - if( this.text == null ) throw new Error( '`text` cfg required' ); - }, - - - /** - * Returns a string name for the type of node that this class represents. - * - * @abstract - * @return {String} - */ - getType : Autolinker.Util.abstractMethod, - - - /** - * Retrieves the {@link #offset} of the HtmlNode. This is the offset of the - * HTML node in the original string that was parsed. - * - * @return {Number} - */ - getOffset : function() { - return this.offset; - }, - - - /** - * Retrieves the {@link #text} for the HtmlNode. - * - * @return {String} - */ - getText : function() { - return this.text; - } - -} ); -/*global Autolinker */ -/** - * @class Autolinker.htmlParser.CommentNode - * @extends Autolinker.htmlParser.HtmlNode - * - * Represents an HTML comment node that has been parsed by the - * {@link Autolinker.htmlParser.HtmlParser}. - * - * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more - * details. - */ -Autolinker.htmlParser.CommentNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, { - - /** - * @cfg {String} comment (required) - * - * The text inside the comment tag. This text is stripped of any leading or - * trailing whitespace. - */ - comment : '', - - - /** - * Returns a string name for the type of node that this class represents. - * - * @return {String} - */ - getType : function() { - return 'comment'; - }, - - - /** - * Returns the comment inside the comment tag. - * - * @return {String} - */ - getComment : function() { - return this.comment; - } - -} ); -/*global Autolinker */ -/** - * @class Autolinker.htmlParser.ElementNode - * @extends Autolinker.htmlParser.HtmlNode - * - * Represents an HTML element node that has been parsed by the {@link Autolinker.htmlParser.HtmlParser}. - * - * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more - * details. - */ -Autolinker.htmlParser.ElementNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, { - - /** - * @cfg {String} tagName (required) - * - * The name of the tag that was matched. - */ - tagName : '', - - /** - * @cfg {Boolean} closing (required) - * - * `true` if the element (tag) is a closing tag, `false` if its an opening - * tag. - */ - closing : false, - - - /** - * Returns a string name for the type of node that this class represents. - * - * @return {String} - */ - getType : function() { - return 'element'; - }, - - - /** - * Returns the HTML element's (tag's) name. Ex: for an <img> tag, - * returns "img". - * - * @return {String} - */ - getTagName : function() { - return this.tagName; - }, - - - /** - * Determines if the HTML element (tag) is a closing tag. Ex: <div> - * returns `false`, while </div> returns `true`. - * - * @return {Boolean} - */ - isClosing : function() { - return this.closing; - } - -} ); -/*global Autolinker */ -/** - * @class Autolinker.htmlParser.EntityNode - * @extends Autolinker.htmlParser.HtmlNode - * - * Represents a known HTML entity node that has been parsed by the {@link Autolinker.htmlParser.HtmlParser}. - * Ex: '&nbsp;', or '&#160;' (which will be retrievable from the {@link #getText} - * method. - * - * Note that this class will only be returned from the HtmlParser for the set of - * checked HTML entity nodes defined by the {@link Autolinker.htmlParser.HtmlParser#htmlCharacterEntitiesRegex}. - * - * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more - * details. - */ -Autolinker.htmlParser.EntityNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, { - - /** - * Returns a string name for the type of node that this class represents. - * - * @return {String} - */ - getType : function() { - return 'entity'; - } - -} ); -/*global Autolinker */ -/** - * @class Autolinker.htmlParser.TextNode - * @extends Autolinker.htmlParser.HtmlNode - * - * Represents a text node that has been parsed by the {@link Autolinker.htmlParser.HtmlParser}. - * - * See this class's superclass ({@link Autolinker.htmlParser.HtmlNode}) for more - * details. - */ -Autolinker.htmlParser.TextNode = Autolinker.Util.extend( Autolinker.htmlParser.HtmlNode, { - - /** - * Returns a string name for the type of node that this class represents. - * - * @return {String} - */ - getType : function() { - return 'text'; - } - -} ); -/*global Autolinker */ -/** - * @abstract - * @class Autolinker.match.Match - * - * Represents a match found in an input string which should be Autolinked. A Match object is what is provided in a - * {@link Autolinker#replaceFn replaceFn}, and may be used to query for details about the match. - * - * For example: - * - * var input = "..."; // string with URLs, Email Addresses, and Twitter Handles - * - * var linkedText = Autolinker.link( input, { - * replaceFn : function( autolinker, match ) { - * console.log( "href = ", match.getAnchorHref() ); - * console.log( "text = ", match.getAnchorText() ); - * - * switch( match.getType() ) { - * case 'url' : - * console.log( "url: ", match.getUrl() ); - * - * case 'email' : - * console.log( "email: ", match.getEmail() ); - * - * case 'twitter' : - * console.log( "twitter: ", match.getTwitterHandle() ); - * } - * } - * } ); - * - * See the {@link Autolinker} class for more details on using the {@link Autolinker#replaceFn replaceFn}. - */ -Autolinker.match.Match = Autolinker.Util.extend( Object, { - - /** - * @cfg {Autolinker.AnchorTagBuilder} tagBuilder (required) - * - * Reference to the AnchorTagBuilder instance to use to generate an anchor - * tag for the Match. - */ - - /** - * @cfg {String} matchedText (required) - * - * The original text that was matched by the {@link Autolinker.matcher.Matcher}. - */ - - /** - * @cfg {Number} offset (required) - * - * The offset of where the match was made in the input string. - */ - - - /** - * @constructor - * @param {Object} cfg The configuration properties for the Match - * instance, specified in an Object (map). - */ - constructor : function( cfg ) { - if( cfg.tagBuilder == null ) throw new Error( '`tagBuilder` cfg required' ); - if( cfg.matchedText == null ) throw new Error( '`matchedText` cfg required' ); - if( cfg.offset == null ) throw new Error( '`offset` cfg required' ); - - this.tagBuilder = cfg.tagBuilder; - this.matchedText = cfg.matchedText; - this.offset = cfg.offset; - }, - - - /** - * Returns a string name for the type of match that this class represents. - * - * @abstract - * @return {String} - */ - getType : Autolinker.Util.abstractMethod, - - - /** - * Returns the original text that was matched. - * - * @return {String} - */ - getMatchedText : function() { - return this.matchedText; - }, - - - /** - * Sets the {@link #offset} of where the match was made in the input string. - * - * A {@link Autolinker.matcher.Matcher} will be fed only HTML text nodes, - * and will therefore set an original offset that is relative to the HTML - * text node itself. However, we want this offset to be relative to the full - * HTML input string, and thus if using {@link Autolinker#parse} (rather - * than calling a {@link Autolinker.matcher.Matcher} directly), then this - * offset is corrected after the Matcher itself has done its job. - * - * @param {Number} offset - */ - setOffset : function( offset ) { - this.offset = offset; - }, - - - /** - * Returns the offset of where the match was made in the input string. This - * is the 0-based index of the match. - * - * @return {Number} - */ - getOffset : function() { - return this.offset; - }, - - - /** - * Returns the anchor href that should be generated for the match. - * - * @abstract - * @return {String} - */ - getAnchorHref : Autolinker.Util.abstractMethod, - - - /** - * Returns the anchor text that should be generated for the match. - * - * @abstract - * @return {String} - */ - getAnchorText : Autolinker.Util.abstractMethod, - - - /** - * Builds and returns an {@link Autolinker.HtmlTag} instance based on the - * Match. - * - * This can be used to easily generate anchor tags from matches, and either - * return their HTML string, or modify them before doing so. - * - * Example Usage: - * - * var tag = match.buildTag(); - * tag.addClass( 'cordova-link' ); - * tag.setAttr( 'target', '_system' ); - * - * tag.toAnchorString(); // Google - */ - buildTag : function() { - return this.tagBuilder.build( this ); - } - -} ); -/*global Autolinker */ -/** - * @class Autolinker.match.Email - * @extends Autolinker.match.Match - * - * Represents a Email match found in an input string which should be Autolinked. - * - * See this class's superclass ({@link Autolinker.match.Match}) for more details. - */ -Autolinker.match.Email = Autolinker.Util.extend( Autolinker.match.Match, { - - /** - * @cfg {String} email (required) - * - * The email address that was matched. - */ - - - /** - * @constructor - * @param {Object} cfg The configuration properties for the Match - * instance, specified in an Object (map). - */ - constructor : function( cfg ) { - Autolinker.match.Match.prototype.constructor.call( this, cfg ); - - if( !cfg.email ) throw new Error( '`email` cfg required' ); - - this.email = cfg.email; - }, - - - /** - * Returns a string name for the type of match that this class represents. - * - * @return {String} - */ - getType : function() { - return 'email'; - }, - - - /** - * Returns the email address that was matched. - * - * @return {String} - */ - getEmail : function() { - return this.email; - }, - - - /** - * Returns the anchor href that should be generated for the match. - * - * @return {String} - */ - getAnchorHref : function() { - return 'mailto:' + this.email; - }, - - - /** - * Returns the anchor text that should be generated for the match. - * - * @return {String} - */ - getAnchorText : function() { - return this.email; - } - -} ); -/*global Autolinker */ -/** - * @class Autolinker.match.Hashtag - * @extends Autolinker.match.Match - * - * Represents a Hashtag match found in an input string which should be - * Autolinked. - * - * See this class's superclass ({@link Autolinker.match.Match}) for more - * details. - */ -Autolinker.match.Hashtag = Autolinker.Util.extend( Autolinker.match.Match, { - - /** - * @cfg {String} serviceName - * - * The service to point hashtag matches to. See {@link Autolinker#hashtag} - * for available values. - */ - - /** - * @cfg {String} hashtag (required) - * - * The Hashtag that was matched, without the '#'. - */ - - - /** - * @constructor - * @param {Object} cfg The configuration properties for the Match - * instance, specified in an Object (map). - */ - constructor : function( cfg ) { - Autolinker.match.Match.prototype.constructor.call( this, cfg ); - - // TODO: if( !serviceName ) throw new Error( '`serviceName` cfg required' ); - if( !cfg.hashtag ) throw new Error( '`hashtag` cfg required' ); - - this.serviceName = cfg.serviceName; - this.hashtag = cfg.hashtag; - }, - - - /** - * Returns the type of match that this class represents. - * - * @return {String} - */ - getType : function() { - return 'hashtag'; - }, - - - /** - * Returns the configured {@link #serviceName} to point the Hashtag to. - * Ex: 'facebook', 'twitter'. - * - * @return {String} - */ - getServiceName : function() { - return this.serviceName; - }, - - - /** - * Returns the matched hashtag, without the '#' character. - * - * @return {String} - */ - getHashtag : function() { - return this.hashtag; - }, - - - /** - * Returns the anchor href that should be generated for the match. - * - * @return {String} - */ - getAnchorHref : function() { - var serviceName = this.serviceName, - hashtag = this.hashtag; - - switch( serviceName ) { - case 'twitter' : - return 'https://twitter.com/hashtag/' + hashtag; - case 'facebook' : - return 'https://www.facebook.com/hashtag/' + hashtag; - case 'instagram' : - return 'https://instagram.com/explore/tags/' + hashtag; - - default : // Shouldn't happen because Autolinker's constructor should block any invalid values, but just in case. - throw new Error( 'Unknown service name to point hashtag to: ', serviceName ); - } - }, - - - /** - * Returns the anchor text that should be generated for the match. - * - * @return {String} - */ - getAnchorText : function() { - return '#' + this.hashtag; - } - -} ); - -/*global Autolinker */ -/** - * @class Autolinker.match.Phone - * @extends Autolinker.match.Match - * - * Represents a Phone number match found in an input string which should be - * Autolinked. - * - * See this class's superclass ({@link Autolinker.match.Match}) for more - * details. - */ -Autolinker.match.Phone = Autolinker.Util.extend( Autolinker.match.Match, { - - /** - * @protected - * @property {String} number (required) - * - * The phone number that was matched, without any delimiter characters. - * - * Note: This is a string to allow for prefixed 0's. - */ - - /** - * @protected - * @property {Boolean} plusSign (required) - * - * `true` if the matched phone number started with a '+' sign. We'll include - * it in the `tel:` URL if so, as this is needed for international numbers. - * - * Ex: '+1 (123) 456 7879' - */ - - - /** - * @constructor - * @param {Object} cfg The configuration properties for the Match - * instance, specified in an Object (map). - */ - constructor : function( cfg ) { - Autolinker.match.Match.prototype.constructor.call( this, cfg ); - - if( !cfg.number ) throw new Error( '`number` cfg required' ); - if( cfg.plusSign == null ) throw new Error( '`plusSign` cfg required' ); - - this.number = cfg.number; - this.plusSign = cfg.plusSign; - }, - - - /** - * Returns a string name for the type of match that this class represents. - * - * @return {String} - */ - getType : function() { - return 'phone'; - }, - - - /** - * Returns the phone number that was matched as a string, without any - * delimiter characters. - * - * Note: This is a string to allow for prefixed 0's. - * - * @return {String} - */ - getNumber: function() { - return this.number; - }, - - - /** - * Returns the anchor href that should be generated for the match. - * - * @return {String} - */ - getAnchorHref : function() { - return 'tel:' + ( this.plusSign ? '+' : '' ) + this.number; - }, - - - /** - * Returns the anchor text that should be generated for the match. - * - * @return {String} - */ - getAnchorText : function() { - return this.matchedText; - } - -} ); - -/*global Autolinker */ -/** - * @class Autolinker.match.Twitter - * @extends Autolinker.match.Match - * - * Represents a Twitter match found in an input string which should be Autolinked. - * - * See this class's superclass ({@link Autolinker.match.Match}) for more details. - */ -Autolinker.match.Twitter = Autolinker.Util.extend( Autolinker.match.Match, { - - /** - * @cfg {String} twitterHandle (required) - * - * The Twitter handle that was matched, without the '@' character. - */ - - - /** - * @constructor - * @param {Object} cfg The configuration properties for the Match - * instance, specified in an Object (map). - */ - constructor : function( cfg) { - Autolinker.match.Match.prototype.constructor.call( this, cfg ); - - if( !cfg.twitterHandle ) throw new Error( '`twitterHandle` cfg required' ); - - this.twitterHandle = cfg.twitterHandle; - }, - - - /** - * Returns the type of match that this class represents. - * - * @return {String} - */ - getType : function() { - return 'twitter'; - }, - - - /** - * Returns the twitter handle, without the '@' character. - * - * @return {String} - */ - getTwitterHandle : function() { - return this.twitterHandle; - }, - - - /** - * Returns the anchor href that should be generated for the match. - * - * @return {String} - */ - getAnchorHref : function() { - return 'https://twitter.com/' + this.twitterHandle; - }, - - - /** - * Returns the anchor text that should be generated for the match. - * - * @return {String} - */ - getAnchorText : function() { - return '@' + this.twitterHandle; - } - -} ); -/*global Autolinker */ -/** - * @class Autolinker.match.Url - * @extends Autolinker.match.Match - * - * Represents a Url match found in an input string which should be Autolinked. - * - * See this class's superclass ({@link Autolinker.match.Match}) for more details. - */ -Autolinker.match.Url = Autolinker.Util.extend( Autolinker.match.Match, { - - /** - * @cfg {String} url (required) - * - * The url that was matched. - */ - - /** - * @cfg {"scheme"/"www"/"tld"} urlMatchType (required) - * - * The type of URL match that this class represents. This helps to determine - * if the match was made in the original text with a prefixed scheme (ex: - * 'http://www.google.com'), a prefixed 'www' (ex: 'www.google.com'), or - * was matched by a known top-level domain (ex: 'google.com'). - */ - - /** - * @cfg {Boolean} protocolUrlMatch (required) - * - * `true` if the URL is a match which already has a protocol (i.e. - * 'http://'), `false` if the match was from a 'www' or known TLD match. - */ - - /** - * @cfg {Boolean} protocolRelativeMatch (required) - * - * `true` if the URL is a protocol-relative match. A protocol-relative match - * is a URL that starts with '//', and will be either http:// or https:// - * based on the protocol that the site is loaded under. - */ - - /** - * @cfg {Boolean} stripPrefix (required) - * @inheritdoc Autolinker#cfg-stripPrefix - */ - - - /** - * @constructor - * @param {Object} cfg The configuration properties for the Match - * instance, specified in an Object (map). - */ - constructor : function( cfg ) { - Autolinker.match.Match.prototype.constructor.call( this, cfg ); - - if( cfg.urlMatchType !== 'scheme' && cfg.urlMatchType !== 'www' && cfg.urlMatchType !== 'tld' ) throw new Error( '`urlMatchType` cfg must be one of: "scheme", "www", or "tld"' ); - if( !cfg.url ) throw new Error( '`url` cfg required' ); - if( cfg.protocolUrlMatch == null ) throw new Error( '`protocolUrlMatch` cfg required' ); - if( cfg.protocolRelativeMatch == null ) throw new Error( '`protocolRelativeMatch` cfg required' ); - if( cfg.stripPrefix == null ) throw new Error( '`stripPrefix` cfg required' ); - - this.urlMatchType = cfg.urlMatchType; - this.url = cfg.url; - this.protocolUrlMatch = cfg.protocolUrlMatch; - this.protocolRelativeMatch = cfg.protocolRelativeMatch; - this.stripPrefix = cfg.stripPrefix; - }, - - - /** - * @private - * @property {RegExp} urlPrefixRegex - * - * A regular expression used to remove the 'http://' or 'https://' and/or the 'www.' from URLs. - */ - urlPrefixRegex: /^(https?:\/\/)?(www\.)?/i, - - /** - * @private - * @property {RegExp} protocolRelativeRegex - * - * The regular expression used to remove the protocol-relative '//' from the {@link #url} string, for purposes - * of {@link #getAnchorText}. A protocol-relative URL is, for example, "//yahoo.com" - */ - protocolRelativeRegex : /^\/\//, - - /** - * @private - * @property {Boolean} protocolPrepended - * - * Will be set to `true` if the 'http://' protocol has been prepended to the {@link #url} (because the - * {@link #url} did not have a protocol) - */ - protocolPrepended : false, - - - /** - * Returns a string name for the type of match that this class represents. - * - * @return {String} - */ - getType : function() { - return 'url'; - }, - - - /** - * Returns a string name for the type of URL match that this class - * represents. - * - * This helps to determine if the match was made in the original text with a - * prefixed scheme (ex: 'http://www.google.com'), a prefixed 'www' (ex: - * 'www.google.com'), or was matched by a known top-level domain (ex: - * 'google.com'). - * - * @return {"scheme"/"www"/"tld"} - */ - getUrlMatchType : function() { - return this.urlMatchType; - }, - - - /** - * Returns the url that was matched, assuming the protocol to be 'http://' if the original - * match was missing a protocol. - * - * @return {String} - */ - getUrl : function() { - var url = this.url; - - // if the url string doesn't begin with a protocol, assume 'http://' - if( !this.protocolRelativeMatch && !this.protocolUrlMatch && !this.protocolPrepended ) { - url = this.url = 'http://' + url; - - this.protocolPrepended = true; - } - - return url; - }, - - - /** - * Returns the anchor href that should be generated for the match. - * - * @return {String} - */ - getAnchorHref : function() { - var url = this.getUrl(); - - return url.replace( /&/g, '&' ); // any &'s in the URL should be converted back to '&' if they were displayed as & in the source html - }, - - - /** - * Returns the anchor text that should be generated for the match. - * - * @return {String} - */ - getAnchorText : function() { - var anchorText = this.getMatchedText(); - - if( this.protocolRelativeMatch ) { - // Strip off any protocol-relative '//' from the anchor text - anchorText = this.stripProtocolRelativePrefix( anchorText ); - } - if( this.stripPrefix ) { - anchorText = this.stripUrlPrefix( anchorText ); - } - anchorText = this.removeTrailingSlash( anchorText ); // remove trailing slash, if there is one - - return anchorText; - }, - - - // --------------------------------------- - - // Utility Functionality - - /** - * Strips the URL prefix (such as "http://" or "https://") from the given text. - * - * @private - * @param {String} text The text of the anchor that is being generated, for which to strip off the - * url prefix (such as stripping off "http://") - * @return {String} The `anchorText`, with the prefix stripped. - */ - stripUrlPrefix : function( text ) { - return text.replace( this.urlPrefixRegex, '' ); - }, - - - /** - * Strips any protocol-relative '//' from the anchor text. - * - * @private - * @param {String} text The text of the anchor that is being generated, for which to strip off the - * protocol-relative prefix (such as stripping off "//") - * @return {String} The `anchorText`, with the protocol-relative prefix stripped. - */ - stripProtocolRelativePrefix : function( text ) { - return text.replace( this.protocolRelativeRegex, '' ); - }, - - - /** - * Removes any trailing slash from the given `anchorText`, in preparation for the text to be displayed. - * - * @private - * @param {String} anchorText The text of the anchor that is being generated, for which to remove any trailing - * slash ('/') that may exist. - * @return {String} The `anchorText`, with the trailing slash removed. - */ - removeTrailingSlash : function( anchorText ) { - if( anchorText.charAt( anchorText.length - 1 ) === '/' ) { - anchorText = anchorText.slice( 0, -1 ); - } - return anchorText; - } - -} ); -/*global Autolinker */ -/** - * @abstract - * @class Autolinker.matcher.Matcher - * - * An abstract class and interface for individual matchers to find matches in - * an input string with linkified versions of them. - * - * Note that Matchers do not take HTML into account - they must be fed the text - * nodes of any HTML string, which is handled by {@link Autolinker#parse}. - */ -Autolinker.matcher.Matcher = Autolinker.Util.extend( Object, { - - /** - * @cfg {Autolinker.AnchorTagBuilder} tagBuilder (required) - * - * Reference to the AnchorTagBuilder instance to use to generate HTML tags - * for {@link Autolinker.match.Match Matches}. - */ - - - /** - * @constructor - * @param {Object} cfg The configuration properties for the Matcher - * instance, specified in an Object (map). - */ - constructor : function( cfg ) { - if( !cfg.tagBuilder ) throw new Error( '`tagBuilder` cfg required' ); - - this.tagBuilder = cfg.tagBuilder; - }, - - - /** - * Parses the input `text` and returns the array of {@link Autolinker.match.Match Matches} - * for the matcher. - * - * @abstract - * @param {String} text The text to scan and replace matches in. - * @return {Autolinker.match.Match[]} - */ - parseMatches : Autolinker.Util.abstractMethod - -} ); -/*global Autolinker */ -/** - * @class Autolinker.matcher.Email - * @extends Autolinker.matcher.Matcher - * - * Matcher to find email matches in an input string. - * - * See this class's superclass ({@link Autolinker.matcher.Matcher}) for more details. - */ -Autolinker.matcher.Email = Autolinker.Util.extend( Autolinker.matcher.Matcher, { - - /** - * The regular expression to match email addresses. Example match: - * - * person@place.com - * - * @private - * @property {RegExp} matcherRegex - */ - matcherRegex : (function() { - var alphaNumericChars = Autolinker.RegexLib.alphaNumericCharsStr, - emailRegex = new RegExp( '[' + alphaNumericChars + '\\-_\';:&=+$.,]+@' ), // something@ for email addresses (a.k.a. local-part) - domainNameRegex = Autolinker.RegexLib.domainNameRegex, - tldRegex = Autolinker.RegexLib.tldRegex; // match our known top level domains (TLDs) - - return new RegExp( [ - emailRegex.source, - domainNameRegex.source, - '\\.', tldRegex.source // '.com', '.net', etc - ].join( "" ), 'gi' ); - } )(), - - - /** - * @inheritdoc - */ - parseMatches : function( text ) { - var matcherRegex = this.matcherRegex, - tagBuilder = this.tagBuilder, - matches = [], - match; - - while( ( match = matcherRegex.exec( text ) ) !== null ) { - var matchedText = match[ 0 ]; - - matches.push( new Autolinker.match.Email( { - tagBuilder : tagBuilder, - matchedText : matchedText, - offset : match.index, - email : matchedText - } ) ); - } - - return matches; - } - -} ); -/*global Autolinker */ -/** - * @class Autolinker.matcher.Hashtag - * @extends Autolinker.matcher.Matcher - * - * Matcher to find Hashtag matches in an input string. - */ -Autolinker.matcher.Hashtag = Autolinker.Util.extend( Autolinker.matcher.Matcher, { - - /** - * @cfg {String} serviceName - * - * The service to point hashtag matches to. See {@link Autolinker#hashtag} - * for available values. - */ - - - /** - * The regular expression to match Hashtags. Example match: - * - * #asdf - * - * @private - * @property {RegExp} matcherRegex - */ - matcherRegex : new RegExp( '#[_' + Autolinker.RegexLib.alphaNumericCharsStr + ']{1,139}', 'g' ), - - /** - * The regular expression to use to check the character before a username match to - * make sure we didn't accidentally match an email address. - * - * For example, the string "asdf@asdf.com" should not match "@asdf" as a username. - * - * @private - * @property {RegExp} nonWordCharRegex - */ - nonWordCharRegex : new RegExp( '[^' + Autolinker.RegexLib.alphaNumericCharsStr + ']' ), - - - /** - * @constructor - * @param {Object} cfg The configuration properties for the Match instance, - * specified in an Object (map). - */ - constructor : function( cfg ) { - Autolinker.matcher.Matcher.prototype.constructor.call( this, cfg ); - - this.serviceName = cfg.serviceName; - }, - - - /** - * @inheritdoc - */ - parseMatches : function( text ) { - var matcherRegex = this.matcherRegex, - nonWordCharRegex = this.nonWordCharRegex, - serviceName = this.serviceName, - tagBuilder = this.tagBuilder, - matches = [], - match; - - while( ( match = matcherRegex.exec( text ) ) !== null ) { - var offset = match.index, - prevChar = text.charAt( offset - 1 ); - - // If we found the match at the beginning of the string, or we found the match - // and there is a whitespace char in front of it (meaning it is not a '#' char - // in the middle of a word), then it is a hashtag match. - if( offset === 0 || nonWordCharRegex.test( prevChar ) ) { - var matchedText = match[ 0 ], - hashtag = match[ 0 ].slice( 1 ); // strip off the '#' character at the beginning - - matches.push( new Autolinker.match.Hashtag( { - tagBuilder : tagBuilder, - matchedText : matchedText, - offset : offset, - serviceName : serviceName, - hashtag : hashtag - } ) ); - } - } - - return matches; - } - -} ); -/*global Autolinker */ -/** - * @class Autolinker.matcher.Phone - * @extends Autolinker.matcher.Matcher - * - * Matcher to find Phone number matches in an input string. - * - * See this class's superclass ({@link Autolinker.matcher.Matcher}) for more - * details. - */ -Autolinker.matcher.Phone = Autolinker.Util.extend( Autolinker.matcher.Matcher, { - - /** - * The regular expression to match Phone numbers. Example match: - * - * (123) 456-7890 - * - * This regular expression has the following capturing groups: - * - * 1. The prefixed '+' sign, if there is one. - * - * @private - * @property {RegExp} matcherRegex - */ - matcherRegex : /(?:(\+)?\d{1,3}[-\040.])?\(?\d{3}\)?[-\040.]?\d{3}[-\040.]\d{4}/g, // ex: (123) 456-7890, 123 456 7890, 123-456-7890, etc. - - /** - * @inheritdoc - */ - parseMatches : function( text ) { - var matcherRegex = this.matcherRegex, - tagBuilder = this.tagBuilder, - matches = [], - match; - - while( ( match = matcherRegex.exec( text ) ) !== null ) { - // Remove non-numeric values from phone number string - var matchedText = match[ 0 ], - cleanNumber = matchedText.replace( /\D/g, '' ), // strip out non-digit characters - plusSign = !!match[ 1 ]; // match[ 1 ] is the prefixed plus sign, if there is one - - matches.push( new Autolinker.match.Phone( { - tagBuilder : tagBuilder, - matchedText : matchedText, - offset : match.index, - number : cleanNumber, - plusSign : plusSign - } ) ); - } - - return matches; - } - -} ); -/*global Autolinker */ -/** - * @class Autolinker.matcher.Twitter - * @extends Autolinker.matcher.Matcher - * - * Matcher to find/replace username matches in an input string. - */ -Autolinker.matcher.Twitter = Autolinker.Util.extend( Autolinker.matcher.Matcher, { - - /** - * The regular expression to match username handles. Example match: - * - * @asdf - * - * @private - * @property {RegExp} matcherRegex - */ - matcherRegex : new RegExp( '@[_' + Autolinker.RegexLib.alphaNumericCharsStr + ']{1,20}', 'g' ), - - /** - * The regular expression to use to check the character before a username match to - * make sure we didn't accidentally match an email address. - * - * For example, the string "asdf@asdf.com" should not match "@asdf" as a username. - * - * @private - * @property {RegExp} nonWordCharRegex - */ - nonWordCharRegex : new RegExp( '[^' + Autolinker.RegexLib.alphaNumericCharsStr + ']' ), - - - /** - * @inheritdoc - */ - parseMatches : function( text ) { - var matcherRegex = this.matcherRegex, - nonWordCharRegex = this.nonWordCharRegex, - tagBuilder = this.tagBuilder, - matches = [], - match; - - while( ( match = matcherRegex.exec( text ) ) !== null ) { - var offset = match.index, - prevChar = text.charAt( offset - 1 ); - - // If we found the match at the beginning of the string, or we found the match - // and there is a whitespace char in front of it (meaning it is not an email - // address), then it is a username match. - if( offset === 0 || nonWordCharRegex.test( prevChar ) ) { - var matchedText = match[ 0 ], - twitterHandle = match[ 0 ].slice( 1 ); // strip off the '@' character at the beginning - - matches.push( new Autolinker.match.Twitter( { - tagBuilder : tagBuilder, - matchedText : matchedText, - offset : offset, - twitterHandle : twitterHandle - } ) ); - } - } - - return matches; - } - -} ); -/*global Autolinker */ -/** - * @class Autolinker.matcher.Url - * @extends Autolinker.matcher.Matcher - * - * Matcher to find URL matches in an input string. - * - * See this class's superclass ({@link Autolinker.matcher.Matcher}) for more details. - */ -Autolinker.matcher.Url = Autolinker.Util.extend( Autolinker.matcher.Matcher, { - - /** - * @cfg {Boolean} stripPrefix (required) - * @inheritdoc Autolinker#stripPrefix - */ - - - /** - * @private - * @property {RegExp} matcherRegex - * - * The regular expression to match URLs with an optional scheme, port - * number, path, query string, and hash anchor. - * - * Example matches: - * - * http://google.com - * www.google.com - * google.com/path/to/file?q1=1&q2=2#myAnchor - * - * - * This regular expression will have the following capturing groups: - * - * 1. Group that matches a scheme-prefixed URL (i.e. 'http://google.com'). - * This is used to match scheme URLs with just a single word, such as - * 'http://localhost', where we won't double check that the domain name - * has at least one dot ('.') in it. - * 2. Group that matches a 'www.' prefixed URL. This is only matched if the - * 'www.' text was not prefixed by a scheme (i.e.: not prefixed by - * 'http://', 'ftp:', etc.) - * 3. A protocol-relative ('//') match for the case of a 'www.' prefixed - * URL. Will be an empty string if it is not a protocol-relative match. - * We need to know the character before the '//' in order to determine - * if it is a valid match or the // was in a string we don't want to - * auto-link. - * 4. Group that matches a known TLD (top level domain), when a scheme - * or 'www.'-prefixed domain is not matched. - * 5. A protocol-relative ('//') match for the case of a known TLD prefixed - * URL. Will be an empty string if it is not a protocol-relative match. - * See #3 for more info. - */ - matcherRegex : (function() { - var schemeRegex = /(?:[A-Za-z][-.+A-Za-z0-9]*:(?![A-Za-z][-.+A-Za-z0-9]*:\/\/)(?!\d+\/?)(?:\/\/)?)/, // match protocol, allow in format "http://" or "mailto:". However, do not match the first part of something like 'link:http://www.google.com' (i.e. don't match "link:"). Also, make sure we don't interpret 'google.com:8000' as if 'google.com' was a protocol here (i.e. ignore a trailing port number in this regex) - wwwRegex = /(?:www\.)/, // starting with 'www.' - domainNameRegex = Autolinker.RegexLib.domainNameRegex, - tldRegex = Autolinker.RegexLib.tldRegex, // match our known top level domains (TLDs) - alphaNumericCharsStr = Autolinker.RegexLib.alphaNumericCharsStr, - - // Allow optional path, query string, and hash anchor, not ending in the following characters: "?!:,.;" - // http://blog.codinghorror.com/the-problem-with-urls/ - urlSuffixRegex = new RegExp( '[' + alphaNumericCharsStr + '\\-+&@#/%=~_()|\'$*\\[\\]?!:,.;]*[' + alphaNumericCharsStr + '\\-+&@#/%=~_()|\'$*\\[\\]]' ); - - return new RegExp( [ - '(?:', // parens to cover match for scheme (optional), and domain - '(', // *** Capturing group $1, for a scheme-prefixed url (ex: http://google.com) - schemeRegex.source, - domainNameRegex.source, - ')', - - '|', - - '(', // *** Capturing group $2, for a 'www.' prefixed url (ex: www.google.com) - '(//)?', // *** Capturing group $3 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character (handled later) - wwwRegex.source, - domainNameRegex.source, - ')', - - '|', - - '(', // *** Capturing group $4, for known a TLD url (ex: google.com) - '(//)?', // *** Capturing group $5 for an optional protocol-relative URL. Must be at the beginning of the string or start with a non-word character (handled later) - domainNameRegex.source + '\\.', - tldRegex.source, - ')', - ')', - - '(?:' + urlSuffixRegex.source + ')?' // match for path, query string, and/or hash anchor - optional - ].join( "" ), 'gi' ); - } )(), - - - /** - * A regular expression to use to check the character before a protocol-relative - * URL match. We don't want to match a protocol-relative URL if it is part - * of another word. - * - * For example, we want to match something like "Go to: //google.com", - * but we don't want to match something like "abc//google.com" - * - * This regular expression is used to test the character before the '//'. - * - * @private - * @type {RegExp} wordCharRegExp - */ - wordCharRegExp : /\w/, - - - /** - * The regular expression to match opening parenthesis in a URL match. - * - * This is to determine if we have unbalanced parenthesis in the URL, and to - * drop the final parenthesis that was matched if so. - * - * Ex: The text "(check out: wikipedia.com/something_(disambiguation))" - * should only autolink the inner "wikipedia.com/something_(disambiguation)" - * part, so if we find that we have unbalanced parenthesis, we will drop the - * last one for the match. - * - * @private - * @property {RegExp} - */ - openParensRe : /\(/g, - - /** - * The regular expression to match closing parenthesis in a URL match. See - * {@link #openParensRe} for more information. - * - * @private - * @property {RegExp} - */ - closeParensRe : /\)/g, - - - /** - * @constructor - * @param {Object} cfg The configuration properties for the Match instance, - * specified in an Object (map). - */ - constructor : function( cfg ) { - Autolinker.matcher.Matcher.prototype.constructor.call( this, cfg ); - - this.stripPrefix = cfg.stripPrefix; - - if( this.stripPrefix == null ) throw new Error( '`stripPrefix` cfg required' ); - }, - - - /** - * @inheritdoc - */ - parseMatches : function( text ) { - var matcherRegex = this.matcherRegex, - stripPrefix = this.stripPrefix, - tagBuilder = this.tagBuilder, - matches = [], - match; - - while( ( match = matcherRegex.exec( text ) ) !== null ) { - var matchStr = match[ 0 ], - schemeUrlMatch = match[ 1 ], - wwwUrlMatch = match[ 2 ], - wwwProtocolRelativeMatch = match[ 3 ], - //tldUrlMatch = match[ 4 ], -- not needed at the moment - tldProtocolRelativeMatch = match[ 5 ], - offset = match.index, - protocolRelativeMatch = wwwProtocolRelativeMatch || tldProtocolRelativeMatch, - prevChar = text.charAt( offset - 1 ); - - if( !Autolinker.matcher.UrlMatchValidator.isValid( matchStr, schemeUrlMatch ) ) { - continue; - } - - // If the match is preceded by an '@' character, then it is either - // an email address or a username. Skip these types of matches. - if( offset > 0 && prevChar === '@' ) { - continue; - } - - // If it's a protocol-relative '//' match, but the character before the '//' - // was a word character (i.e. a letter/number), then we found the '//' in the - // middle of another word (such as "asdf//asdf.com"). In this case, skip the - // match. - if( offset > 0 && protocolRelativeMatch && this.wordCharRegExp.test( prevChar ) ) { - continue; - } - - // Handle a closing parenthesis at the end of the match, and exclude - // it if there is not a matching open parenthesis in the match - // itself. - if( this.matchHasUnbalancedClosingParen( matchStr ) ) { - matchStr = matchStr.substr( 0, matchStr.length - 1 ); // remove the trailing ")" - } else { - // Handle an invalid character after the TLD - var pos = this.matchHasInvalidCharAfterTld( matchStr, schemeUrlMatch ); - if( pos > -1 ) { - matchStr = matchStr.substr( 0, pos ); // remove the trailing invalid chars - } - } - - var urlMatchType = schemeUrlMatch ? 'scheme' : ( wwwUrlMatch ? 'www' : 'tld' ), - protocolUrlMatch = !!schemeUrlMatch; - - matches.push( new Autolinker.match.Url( { - tagBuilder : tagBuilder, - matchedText : matchStr, - offset : offset, - urlMatchType : urlMatchType, - url : matchStr, - protocolUrlMatch : protocolUrlMatch, - protocolRelativeMatch : !!protocolRelativeMatch, - stripPrefix : stripPrefix - } ) ); - } - - return matches; - }, - - - /** - * Determines if a match found has an unmatched closing parenthesis. If so, - * this parenthesis will be removed from the match itself, and appended - * after the generated anchor tag. - * - * A match may have an extra closing parenthesis at the end of the match - * because the regular expression must include parenthesis for URLs such as - * "wikipedia.com/something_(disambiguation)", which should be auto-linked. - * - * However, an extra parenthesis *will* be included when the URL itself is - * wrapped in parenthesis, such as in the case of "(wikipedia.com/something_(disambiguation))". - * In this case, the last closing parenthesis should *not* be part of the - * URL itself, and this method will return `true`. - * - * @private - * @param {String} matchStr The full match string from the {@link #matcherRegex}. - * @return {Boolean} `true` if there is an unbalanced closing parenthesis at - * the end of the `matchStr`, `false` otherwise. - */ - matchHasUnbalancedClosingParen : function( matchStr ) { - var lastChar = matchStr.charAt( matchStr.length - 1 ); - - if( lastChar === ')' ) { - var openParensMatch = matchStr.match( this.openParensRe ), - closeParensMatch = matchStr.match( this.closeParensRe ), - numOpenParens = ( openParensMatch && openParensMatch.length ) || 0, - numCloseParens = ( closeParensMatch && closeParensMatch.length ) || 0; - - if( numOpenParens < numCloseParens ) { - return true; - } - } - - return false; - }, - - - /** - * Determine if there's an invalid character after the TLD in a URL. Valid - * characters after TLD are ':/?#'. Exclude scheme matched URLs from this - * check. - * - * @private - * @param {String} urlMatch The matched URL, if there was one. Will be an - * empty string if the match is not a URL match. - * @param {String} schemeUrlMatch The match URL string for a scheme - * match. Ex: 'http://yahoo.com'. This is used to match something like - * 'http://localhost', where we won't double check that the domain name - * has at least one '.' in it. - * @return {Number} the position where the invalid character was found. If - * no such character was found, returns -1 - */ - matchHasInvalidCharAfterTld : function( urlMatch, schemeUrlMatch ) { - if( !urlMatch ) { - return -1; - } - - var offset = 0; - if ( schemeUrlMatch ) { - offset = urlMatch.indexOf(':'); - urlMatch = urlMatch.slice(offset); - } - - var re = /^((.?\/\/)?[A-Za-z0-9\u00C0-\u017F\.\-]*[A-Za-z0-9\u00C0-\u017F\-]\.[A-Za-z]+)/; - var res = re.exec( urlMatch ); - if ( res === null ) { - return -1; - } - - offset += res[1].length; - urlMatch = urlMatch.slice(res[1].length); - if (/^[^.A-Za-z:\/?#]/.test(urlMatch)) { - return offset; - } - - return -1; - } - -} ); -/*global Autolinker */ -/*jshint scripturl:true */ -/** - * @private - * @class Autolinker.matcher.UrlMatchValidator - * @singleton - * - * Used by Autolinker to filter out false URL positives from the - * {@link Autolinker.matcher.Url UrlMatcher}. - * - * Due to the limitations of regular expressions (including the missing feature - * of look-behinds in JS regular expressions), we cannot always determine the - * validity of a given match. This class applies a bit of additional logic to - * filter out any false positives that have been matched by the - * {@link Autolinker.matcher.Url UrlMatcher}. - */ -Autolinker.matcher.UrlMatchValidator = { - - /** - * Regex to test for a full protocol, with the two trailing slashes. Ex: 'http://' - * - * @private - * @property {RegExp} hasFullProtocolRegex - */ - hasFullProtocolRegex : /^[A-Za-z][-.+A-Za-z0-9]*:\/\//, - - /** - * Regex to find the URI scheme, such as 'mailto:'. - * - * This is used to filter out 'javascript:' and 'vbscript:' schemes. - * - * @private - * @property {RegExp} uriSchemeRegex - */ - uriSchemeRegex : /^[A-Za-z][-.+A-Za-z0-9]*:/, - - /** - * Regex to determine if at least one word char exists after the protocol (i.e. after the ':') - * - * @private - * @property {RegExp} hasWordCharAfterProtocolRegex - */ - hasWordCharAfterProtocolRegex : /:[^\s]*?[A-Za-z\u00C0-\u017F]/, - - /** - * Regex to determine if the string is a valid IP address - * - * @private - * @property {RegExp} ipRegex - */ - ipRegex: /[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?\.[0-9][0-9]?[0-9]?(:[0-9]*)?\/?$/, - - /** - * Determines if a given URL match found by the {@link Autolinker.matcher.Url UrlMatcher} - * is valid. Will return `false` for: - * - * 1) URL matches which do not have at least have one period ('.') in the - * domain name (effectively skipping over matches like "abc:def"). - * However, URL matches with a protocol will be allowed (ex: 'http://localhost') - * 2) URL matches which do not have at least one word character in the - * domain name (effectively skipping over matches like "git:1.0"). - * 3) A protocol-relative url match (a URL beginning with '//') whose - * previous character is a word character (effectively skipping over - * strings like "abc//google.com") - * - * Otherwise, returns `true`. - * - * @param {String} urlMatch The matched URL, if there was one. Will be an - * empty string if the match is not a URL match. - * @param {String} protocolUrlMatch The match URL string for a protocol - * match. Ex: 'http://yahoo.com'. This is used to match something like - * 'http://localhost', where we won't double check that the domain name - * has at least one '.' in it. - * @return {Boolean} `true` if the match given is valid and should be - * processed, or `false` if the match is invalid and/or should just not be - * processed. - */ - isValid : function( urlMatch, protocolUrlMatch ) { - if( - ( protocolUrlMatch && !this.isValidUriScheme( protocolUrlMatch ) ) || - this.urlMatchDoesNotHaveProtocolOrDot( urlMatch, protocolUrlMatch ) || // At least one period ('.') must exist in the URL match for us to consider it an actual URL, *unless* it was a full protocol match (like 'http://localhost') - (this.urlMatchDoesNotHaveAtLeastOneWordChar( urlMatch, protocolUrlMatch ) && // At least one letter character must exist in the domain name after a protocol match. Ex: skip over something like "git:1.0" - !this.isValidIpAddress( urlMatch ) // Except if it's an IP address - ) - ) { - return false; - } - - return true; - }, - - - isValidIpAddress : function ( uriSchemeMatch ) { - var newRegex = new RegExp(this.hasFullProtocolRegex.source + this.ipRegex.source); - var uriScheme = uriSchemeMatch.match( newRegex ); - - return uriScheme !== null; - }, - - /** - * Determines if the URI scheme is a valid scheme to be autolinked. Returns - * `false` if the scheme is 'javascript:' or 'vbscript:' - * - * @private - * @param {String} uriSchemeMatch The match URL string for a full URI scheme - * match. Ex: 'http://yahoo.com' or 'mailto:a@a.com'. - * @return {Boolean} `true` if the scheme is a valid one, `false` otherwise. - */ - isValidUriScheme : function( uriSchemeMatch ) { - var uriScheme = uriSchemeMatch.match( this.uriSchemeRegex )[ 0 ].toLowerCase(); - - return ( uriScheme !== 'javascript:' && uriScheme !== 'vbscript:' ); - }, - - - /** - * Determines if a URL match does not have either: - * - * a) a full protocol (i.e. 'http://'), or - * b) at least one dot ('.') in the domain name (for a non-full-protocol - * match). - * - * Either situation is considered an invalid URL (ex: 'git:d' does not have - * either the '://' part, or at least one dot in the domain name. If the - * match was 'git:abc.com', we would consider this valid.) - * - * @private - * @param {String} urlMatch The matched URL, if there was one. Will be an - * empty string if the match is not a URL match. - * @param {String} protocolUrlMatch The match URL string for a protocol - * match. Ex: 'http://yahoo.com'. This is used to match something like - * 'http://localhost', where we won't double check that the domain name - * has at least one '.' in it. - * @return {Boolean} `true` if the URL match does not have a full protocol, - * or at least one dot ('.') in a non-full-protocol match. - */ - urlMatchDoesNotHaveProtocolOrDot : function( urlMatch, protocolUrlMatch ) { - return ( !!urlMatch && ( !protocolUrlMatch || !this.hasFullProtocolRegex.test( protocolUrlMatch ) ) && urlMatch.indexOf( '.' ) === -1 ); - }, - - - /** - * Determines if a URL match does not have at least one word character after - * the protocol (i.e. in the domain name). - * - * At least one letter character must exist in the domain name after a - * protocol match. Ex: skip over something like "git:1.0" - * - * @private - * @param {String} urlMatch The matched URL, if there was one. Will be an - * empty string if the match is not a URL match. - * @param {String} protocolUrlMatch The match URL string for a protocol - * match. Ex: 'http://yahoo.com'. This is used to know whether or not we - * have a protocol in the URL string, in order to check for a word - * character after the protocol separator (':'). - * @return {Boolean} `true` if the URL match does not have at least one word - * character in it after the protocol, `false` otherwise. - */ - urlMatchDoesNotHaveAtLeastOneWordChar : function( urlMatch, protocolUrlMatch ) { - if( urlMatch && protocolUrlMatch ) { - return !this.hasWordCharAfterProtocolRegex.test( urlMatch ); - } else { - return false; - } - } - -}; -/*global Autolinker */ -/** - * A truncation feature where the ellipsis will be placed at the end of the URL. - * - * @param {String} anchorText - * @param {Number} truncateLen The maximum length of the truncated output URL string. - * @param {String} ellipsisChars The characters to place within the url, e.g. "..". - * @return {String} The truncated URL. - */ -Autolinker.truncate.TruncateEnd = function(anchorText, truncateLen, ellipsisChars){ - return Autolinker.Util.ellipsis( anchorText, truncateLen, ellipsisChars ); -}; - -/*global Autolinker */ -/** - * Date: 2015-10-05 - * Author: Kasper Søfren (https://github.com/kafoso) - * - * A truncation feature, where the ellipsis will be placed in the dead-center of the URL. - * - * @param {String} url A URL. - * @param {Number} truncateLen The maximum length of the truncated output URL string. - * @param {String} ellipsisChars The characters to place within the url, e.g. "..". - * @return {String} The truncated URL. - */ -Autolinker.truncate.TruncateMiddle = function(url, truncateLen, ellipsisChars){ - if (url.length <= truncateLen) { - return url; - } - var availableLength = truncateLen - ellipsisChars.length; - var end = ""; - if (availableLength > 0) { - end = url.substr((-1)*Math.floor(availableLength/2)); - } - return (url.substr(0, Math.ceil(availableLength/2)) + ellipsisChars + end).substr(0, truncateLen); -}; - -/*global Autolinker */ -/** - * Date: 2015-10-05 - * Author: Kasper Søfren (https://github.com/kafoso) - * - * A truncation feature, where the ellipsis will be placed at a section within - * the URL making it still somewhat human readable. - * - * @param {String} url A URL. - * @param {Number} truncateLen The maximum length of the truncated output URL string. - * @param {String} ellipsisChars The characters to place within the url, e.g. "..". - * @return {String} The truncated URL. - */ -Autolinker.truncate.TruncateSmart = function(url, truncateLen, ellipsisChars){ - var parse_url = function(url){ // Functionality inspired by PHP function of same name - var urlObj = {}; - var urlSub = url; - var match = urlSub.match(/^([a-z]+):\/\//i); - if (match) { - urlObj.scheme = match[1]; - urlSub = urlSub.substr(match[0].length); - } - match = urlSub.match(/^(.*?)(?=(\?|#|\/|$))/i); - if (match) { - urlObj.host = match[1]; - urlSub = urlSub.substr(match[0].length); - } - match = urlSub.match(/^\/(.*?)(?=(\?|#|$))/i); - if (match) { - urlObj.path = match[1]; - urlSub = urlSub.substr(match[0].length); - } - match = urlSub.match(/^\?(.*?)(?=(#|$))/i); - if (match) { - urlObj.query = match[1]; - urlSub = urlSub.substr(match[0].length); - } - match = urlSub.match(/^#(.*?)$/i); - if (match) { - urlObj.fragment = match[1]; - //urlSub = urlSub.substr(match[0].length); -- not used. Uncomment if adding another block. - } - return urlObj; - }; - - var buildUrl = function(urlObj){ - var url = ""; - if (urlObj.scheme && urlObj.host) { - url += urlObj.scheme + "://"; - } - if (urlObj.host) { - url += urlObj.host; - } - if (urlObj.path) { - url += "/" + urlObj.path; - } - if (urlObj.query) { - url += "?" + urlObj.query; - } - if (urlObj.fragment) { - url += "#" + urlObj.fragment; - } - return url; - }; - - var buildSegment = function(segment, remainingAvailableLength){ - var remainingAvailableLengthHalf = remainingAvailableLength/ 2, - startOffset = Math.ceil(remainingAvailableLengthHalf), - endOffset = (-1)*Math.floor(remainingAvailableLengthHalf), - end = ""; - if (endOffset < 0) { - end = segment.substr(endOffset); - } - return segment.substr(0, startOffset) + ellipsisChars + end; - }; - if (url.length <= truncateLen) { - return url; - } - var availableLength = truncateLen - ellipsisChars.length; - var urlObj = parse_url(url); - // Clean up the URL - if (urlObj.query) { - var matchQuery = urlObj.query.match(/^(.*?)(?=(\?|\#))(.*?)$/i); - if (matchQuery) { - // Malformed URL; two or more "?". Removed any content behind the 2nd. - urlObj.query = urlObj.query.substr(0, matchQuery[1].length); - url = buildUrl(urlObj); - } - } - if (url.length <= truncateLen) { - return url; - } - if (urlObj.host) { - urlObj.host = urlObj.host.replace(/^www\./, ""); - url = buildUrl(urlObj); - } - if (url.length <= truncateLen) { - return url; - } - // Process and build the URL - var str = ""; - if (urlObj.host) { - str += urlObj.host; - } - if (str.length >= availableLength) { - if (urlObj.host.length == truncateLen) { - return (urlObj.host.substr(0, (truncateLen - ellipsisChars.length)) + ellipsisChars).substr(0, truncateLen); - } - return buildSegment(str, availableLength).substr(0, truncateLen); - } - var pathAndQuery = ""; - if (urlObj.path) { - pathAndQuery += "/" + urlObj.path; - } - if (urlObj.query) { - pathAndQuery += "?" + urlObj.query; - } - if (pathAndQuery) { - if ((str+pathAndQuery).length >= availableLength) { - if ((str+pathAndQuery).length == truncateLen) { - return (str + pathAndQuery).substr(0, truncateLen); - } - var remainingAvailableLength = availableLength - str.length; - return (str + buildSegment(pathAndQuery, remainingAvailableLength)).substr(0, truncateLen); - } else { - str += pathAndQuery; - } - } - if (urlObj.fragment) { - var fragment = "#"+urlObj.fragment; - if ((str+fragment).length >= availableLength) { - if ((str+fragment).length == truncateLen) { - return (str + fragment).substr(0, truncateLen); - } - var remainingAvailableLength2 = availableLength - str.length; - return (str + buildSegment(fragment, remainingAvailableLength2)).substr(0, truncateLen); - } else { - str += fragment; - } - } - if (urlObj.scheme && urlObj.host) { - var scheme = urlObj.scheme + "://"; - if ((str+scheme).length < availableLength) { - return (scheme + str).substr(0, truncateLen); - } - } - if (str.length <= truncateLen) { - return str; - } - var end = ""; - if (availableLength > 0) { - end = str.substr((-1)*Math.floor(availableLength/2)); - } - return (str.substr(0, Math.ceil(availableLength/2)) + ellipsisChars + end).substr(0, truncateLen); -}; - -return Autolinker; -})); diff --git a/node_modules/autolinker/dist/Autolinker.min.js b/node_modules/autolinker/dist/Autolinker.min.js deleted file mode 100644 index fb80ada47017537022aed6e19c712e96ea787404..0000000000000000000000000000000000000000 --- a/node_modules/autolinker/dist/Autolinker.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/*! - * Autolinker.js - * 0.28.1 - * - * Copyright(c) 2016 Gregory Jacobs - * MIT License - * - * https://github.com/gregjacobs/Autolinker.js - */ -!function(t,e){"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?module.exports=e():t.Autolinker=e()}(this,function(){var t=function(e){e=e||{},this.version=t.version,this.urls=this.normalizeUrlsCfg(e.urls),this.email="boolean"!=typeof e.email||e.email,this.twitter="boolean"!=typeof e.twitter||e.twitter,this.phone="boolean"!=typeof e.phone||e.phone,this.hashtag=e.hashtag||!1,this.newWindow="boolean"!=typeof e.newWindow||e.newWindow,this.stripPrefix="boolean"!=typeof e.stripPrefix||e.stripPrefix;var r=this.hashtag;if(r!==!1&&"twitter"!==r&&"facebook"!==r&&"instagram"!==r)throw new Error("invalid `hashtag` cfg - see docs");this.truncate=this.normalizeTruncateCfg(e.truncate),this.className=e.className||"",this.replaceFn=e.replaceFn||null,this.htmlParser=null,this.matchers=null,this.tagBuilder=null};return t.link=function(e,r){var a=new t(r);return a.link(e)},t.version="0.28.1",t.prototype={constructor:t,normalizeUrlsCfg:function(t){return null==t&&(t=!0),"boolean"==typeof t?{schemeMatches:t,wwwMatches:t,tldMatches:t}:{schemeMatches:"boolean"!=typeof t.schemeMatches||t.schemeMatches,wwwMatches:"boolean"!=typeof t.wwwMatches||t.wwwMatches,tldMatches:"boolean"!=typeof t.tldMatches||t.tldMatches}},normalizeTruncateCfg:function(e){return"number"==typeof e?{length:e,location:"end"}:t.Util.defaults(e||{},{length:Number.POSITIVE_INFINITY,location:"end"})},parse:function(t){for(var e=this.getHtmlParser(),r=e.parse(t),a=0,n=[],i=0,s=r.length;ie&&(r=null==r?"..":r,t=t.substring(0,e-r.length)+r),t},indexOf:function(t,e){if(Array.prototype.indexOf)return t.indexOf(e);for(var r=0,a=t.length;r=0;r--)e(t[r])===!0&&t.splice(r,1)},splitAndCapture:function(t,e){for(var r,a=[],n=0;r=e.exec(t);)a.push(t.substring(n,r.index)),a.push(r[0]),n=r.index+r[0].length;return a.push(t.substring(n)),a},trim:function(t){return t.replace(this.trimRegex,"")}},t.HtmlTag=t.Util.extend(Object,{whitespaceRegex:/\s+/,constructor:function(e){t.Util.assign(this,e),this.innerHtml=this.innerHtml||this.innerHTML},setTagName:function(t){return this.tagName=t,this},getTagName:function(){return this.tagName||""},setAttr:function(t,e){var r=this.getAttrs();return r[t]=e,this},getAttr:function(t){return this.getAttrs()[t]},setAttrs:function(e){var r=this.getAttrs();return t.Util.assign(r,e),this},getAttrs:function(){return this.attrs||(this.attrs={})},setClass:function(t){return this.setAttr("class",t)},addClass:function(e){for(var r,a=this.getClass(),n=this.whitespaceRegex,i=t.Util.indexOf,s=a?a.split(n):[],o=e.split(n);r=o.shift();)i(s,r)===-1&&s.push(r);return this.getAttrs()["class"]=s.join(" "),this},removeClass:function(e){for(var r,a=this.getClass(),n=this.whitespaceRegex,i=t.Util.indexOf,s=a?a.split(n):[],o=e.split(n);s.length&&(r=o.shift());){var c=i(s,r);c!==-1&&s.splice(c,1)}return this.getAttrs()["class"]=s.join(" "),this},getClass:function(){return this.getAttrs()["class"]||""},hasClass:function(t){return(" "+this.getClass()+" ").indexOf(" "+t+" ")!==-1},setInnerHtml:function(t){return this.innerHtml=t,this},getInnerHtml:function(){return this.innerHtml||""},toAnchorString:function(){var t=this.getTagName(),e=this.buildAttrsStr();return e=e?" "+e:"",["<",t,e,">",this.getInnerHtml(),""].join("")},buildAttrsStr:function(){if(!this.attrs)return"";var t=this.getAttrs(),e=[];for(var r in t)t.hasOwnProperty(r)&&e.push(r+'="'+t[r]+'"');return e.join(" ")}}),t.RegexLib=function(){var t="A-Za-z\\xAA\\xB5\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠ-ࢴऄ-हऽॐक़-ॡॱ-ঀঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡૹଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-హఽౘ-ౚౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎↃↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ々〆〱-〵〻〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꩾ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ",e="0-9٠-٩۰-۹߀-߉०-९০-৯੦-੯૦-૯୦-୯௦-௯౦-౯೦-೯൦-൯෦-෯๐-๙໐-໙༠-༩၀-၉႐-႙០-៩᠐-᠙᥆-᥏᧐-᧙᪀-᪉᪐-᪙᭐-᭙᮰-᮹᱀-᱉᱐-᱙꘠-꘩꣐-꣙꤀-꤉꧐-꧙꧰-꧹꩐-꩙꯰-꯹0-9",r=t+e,a=new RegExp("["+r+".\\-]*["+r+"\\-]"),n=/(?:travelersinsurance|sandvikcoromant|kerryproperties|cancerresearch|weatherchannel|kerrylogistics|spreadbetting|international|wolterskluwer|lifeinsurance|construction|pamperedchef|scholarships|versicherung|bridgestone|creditunion|kerryhotels|investments|productions|blackfriday|enterprises|lamborghini|photography|motorcycles|williamhill|playstation|contractors|barclaycard|accountants|redumbrella|engineering|management|telefonica|protection|consulting|tatamotors|creditcard|vlaanderen|schaeffler|associates|properties|foundation|republican|bnpparibas|boehringer|eurovision|extraspace|industries|immobilien|university|technology|volkswagen|healthcare|restaurant|cuisinella|vistaprint|apartments|accountant|travelers|homedepot|institute|vacations|furniture|fresenius|insurance|christmas|bloomberg|solutions|barcelona|firestone|financial|kuokgroup|fairwinds|community|passagens|goldpoint|equipment|lifestyle|yodobashi|aquarelle|marketing|analytics|education|amsterdam|statefarm|melbourne|allfinanz|directory|microsoft|stockholm|montblanc|accenture|lancaster|landrover|everbank|istanbul|graphics|grainger|ipiranga|softbank|attorney|pharmacy|saarland|catering|airforce|yokohama|mortgage|frontier|mutuelle|stcgroup|memorial|pictures|football|symantec|cipriani|ventures|telecity|cityeats|verisign|flsmidth|boutique|cleaning|firmdale|clinique|clothing|redstone|infiniti|deloitte|feedback|services|broadway|plumbing|commbank|training|barclays|exchange|computer|brussels|software|delivery|barefoot|builders|business|bargains|engineer|holdings|download|security|helsinki|lighting|movistar|discount|hdfcbank|supplies|marriott|property|diamonds|capetown|partners|democrat|jpmorgan|bradesco|budapest|rexroth|zuerich|shriram|academy|science|support|youtube|singles|surgery|alibaba|statoil|dentist|schwarz|android|cruises|cricket|digital|markets|starhub|systems|courses|coupons|netbank|country|domains|corsica|network|neustar|realtor|lincoln|limited|schmidt|yamaxun|cooking|contact|auction|spiegel|liaison|leclerc|latrobe|lasalle|abogado|compare|lanxess|exposed|express|company|cologne|college|avianca|lacaixa|fashion|recipes|ferrero|komatsu|storage|wanggou|clubmed|sandvik|fishing|fitness|bauhaus|kitchen|flights|florist|flowers|watches|weather|temasek|samsung|bentley|forsale|channel|theater|frogans|theatre|okinawa|website|tickets|jewelry|gallery|tiffany|iselect|shiksha|brother|organic|wedding|genting|toshiba|origins|philips|hyundai|hotmail|hoteles|hosting|rentals|windows|cartier|bugatti|holiday|careers|whoswho|hitachi|panerai|caravan|reviews|guitars|capital|trading|hamburg|hangout|finance|stream|family|abbott|health|review|travel|report|hermes|hiphop|gratis|career|toyota|hockey|dating|repair|google|social|soccer|reisen|global|otsuka|giving|unicom|casino|photos|center|broker|rocher|orange|bostik|garden|insure|ryukyu|bharti|safety|physio|sakura|oracle|online|jaguar|gallup|piaget|tienda|futbol|pictet|joburg|webcam|berlin|office|juegos|kaufen|chanel|chrome|xihuan|church|tennis|circle|kinder|flickr|bayern|claims|clinic|viajes|nowruz|xperia|norton|yachts|studio|coffee|camera|sanofi|nissan|author|expert|events|comsec|lawyer|tattoo|viking|estate|villas|condos|realty|yandex|energy|emerck|virgin|vision|durban|living|school|coupon|london|taobao|natura|taipei|nagoya|luxury|walter|aramco|sydney|madrid|credit|maison|makeup|schule|market|anquan|direct|design|swatch|suzuki|alsace|vuelos|dental|alipay|voyage|shouji|voting|airtel|mutual|degree|supply|agency|museum|mobily|dealer|monash|select|mormon|active|moscow|racing|datsun|quebec|nissay|rodeo|email|gifts|works|photo|chloe|edeka|cheap|earth|vista|tushu|koeln|glass|shoes|globo|tunes|gmail|nokia|space|kyoto|black|ricoh|seven|lamer|sener|epson|cisco|praxi|trust|citic|crown|shell|lease|green|legal|lexus|ninja|tatar|gripe|nikon|group|video|wales|autos|gucci|party|nexus|guide|linde|adult|parts|amica|lixil|boats|azure|loans|locus|cymru|lotte|lotto|stada|click|poker|quest|dabur|lupin|nadex|paris|faith|dance|canon|place|gives|trade|skype|rocks|mango|cloud|boots|smile|final|swiss|homes|honda|media|horse|cards|deals|watch|bosch|house|pizza|miami|osaka|tours|total|xerox|coach|sucks|style|delta|toray|iinet|tools|money|codes|beats|tokyo|salon|archi|movie|baidu|study|actor|yahoo|store|apple|world|forex|today|bible|tmall|tirol|irish|tires|forum|reise|vegas|vodka|sharp|omega|weber|jetzt|audio|promo|build|bingo|chase|gallo|drive|dubai|rehab|press|solar|sale|beer|bbva|bank|band|auto|sapo|sarl|saxo|audi|asia|arte|arpa|army|yoga|ally|zara|scor|scot|sexy|seat|zero|seek|aero|adac|zone|aarp|maif|meet|meme|menu|surf|mini|mobi|mtpc|porn|desi|star|ltda|name|talk|navy|love|loan|live|link|news|limo|like|spot|life|nico|lidl|lgbt|land|taxi|team|tech|kred|kpmg|sony|song|kiwi|kddi|jprs|jobs|sohu|java|itau|tips|info|immo|icbc|hsbc|town|host|page|toys|here|help|pars|haus|guru|guge|tube|goog|golf|gold|sncf|gmbh|gift|ggee|gent|gbiz|game|vana|pics|fund|ford|ping|pink|fish|film|fast|farm|play|fans|fail|plus|skin|pohl|fage|moda|post|erni|dvag|prod|doha|prof|docs|viva|diet|luxe|site|dell|sina|dclk|show|qpon|date|vote|cyou|voto|read|coop|cool|wang|club|city|chat|cern|cash|reit|rent|casa|cars|care|camp|rest|call|cafe|weir|wien|rich|wiki|buzz|wine|book|bond|room|work|rsvp|shia|ruhr|blue|bing|shaw|bike|safe|xbox|best|pwc|mtn|lds|aig|boo|fyi|nra|nrw|ntt|car|gal|obi|zip|aeg|vin|how|one|ong|onl|dad|ooo|bet|esq|org|htc|bar|uol|ibm|ovh|gdn|ice|icu|uno|gea|ifm|bot|top|wtf|lol|day|pet|eus|wtc|ubs|tvs|aco|ing|ltd|ink|tab|abb|afl|cat|int|pid|pin|bid|cba|gle|com|cbn|ads|man|wed|ceb|gmo|sky|ist|gmx|tui|mba|fan|ski|iwc|app|pro|med|ceo|jcb|jcp|goo|dev|men|aaa|meo|pub|jlc|bom|jll|gop|jmp|mil|got|gov|win|jot|mma|joy|trv|red|cfa|cfd|bio|moe|moi|mom|ren|biz|aws|xin|bbc|dnp|buy|kfh|mov|thd|xyz|fit|kia|rio|rip|kim|dog|vet|nyc|bcg|mtr|bcn|bms|bmw|run|bzh|rwe|tel|stc|axa|kpn|fly|krd|cab|bnl|foo|crs|eat|tci|sap|srl|nec|sas|net|cal|sbs|sfr|sca|scb|csc|edu|new|xxx|hiv|fox|wme|ngo|nhk|vip|sex|frl|lat|yun|law|you|tax|soy|sew|om|ac|hu|se|sc|sg|sh|sb|sa|rw|ru|rs|ro|re|qa|py|si|pw|pt|ps|sj|sk|pr|pn|pm|pl|sl|sm|pk|sn|ph|so|pg|pf|pe|pa|zw|nz|nu|nr|np|no|nl|ni|ng|nf|sr|ne|st|nc|na|mz|my|mx|mw|mv|mu|mt|ms|mr|mq|mp|mo|su|mn|mm|ml|mk|mh|mg|me|sv|md|mc|sx|sy|ma|ly|lv|sz|lu|lt|ls|lr|lk|li|lc|lb|la|tc|kz|td|ky|kw|kr|kp|kn|km|ki|kh|tf|tg|th|kg|ke|jp|jo|jm|je|it|is|ir|tj|tk|tl|tm|iq|tn|to|io|in|im|il|ie|ad|sd|ht|hr|hn|hm|tr|hk|gy|gw|gu|gt|gs|gr|gq|tt|gp|gn|gm|gl|tv|gi|tw|tz|ua|gh|ug|uk|gg|gf|ge|gd|us|uy|uz|va|gb|ga|vc|ve|fr|fo|fm|fk|fj|vg|vi|fi|eu|et|es|er|eg|ee|ec|dz|do|dm|dk|vn|dj|de|cz|cy|cx|cw|vu|cv|cu|cr|co|cn|cm|cl|ck|ci|ch|cg|cf|cd|cc|ca|wf|bz|by|bw|bv|bt|bs|br|bo|bn|bm|bj|bi|ws|bh|bg|bf|be|bd|bb|ba|az|ax|aw|au|at|as|ye|ar|aq|ao|am|al|yt|ai|za|ag|af|ae|zm|id)\b/;return{alphaNumericCharsStr:r,domainNameRegex:a,tldRegex:n}}(),t.AnchorTagBuilder=t.Util.extend(Object,{constructor:function(e){t.Util.assign(this,e)},build:function(e){return new t.HtmlTag({tagName:"a",attrs:this.createAttrs(e.getType(),e.getAnchorHref()),innerHtml:this.processAnchorText(e.getAnchorText())})},createAttrs:function(t,e){var r={href:e},a=this.createCssClass(t);return a&&(r["class"]=a),this.newWindow&&(r.target="_blank",r.rel="noopener noreferrer"),r},createCssClass:function(t){var e=this.className;return e?e+" "+e+"-"+t:""},processAnchorText:function(t){return t=this.doTruncate(t)},doTruncate:function(e){var r=this.truncate;if(!r||!r.length)return e;var a=r.length,n=r.location;return"smart"===n?t.truncate.TruncateSmart(e,a,".."):"middle"===n?t.truncate.TruncateMiddle(e,a,".."):t.truncate.TruncateEnd(e,a,"..")}}),t.htmlParser.HtmlParser=t.Util.extend(Object,{htmlRegex:function(){var t=/!--([\s\S]+?)--/,e=/[0-9a-zA-Z][0-9a-zA-Z:]*/,r=/[^\s"'>\/=\x00-\x1F\x7F]+/,a=/(?:"[^"]*?"|'[^']*?'|[^'"=<>`\s]+)/,n=r.source+"(?:\\s*=\\s*"+a.source+")?";return new RegExp(["(?:","<(!DOCTYPE)","(?:","\\s+","(?:",n,"|",a.source+")",")*",">",")","|","(?:","<(/)?","(?:",t.source,"|","(?:","("+e.source+")","(?:","(?:\\s+|\\b)",n,")*","\\s*/?",")",")",">",")"].join(""),"gi")}(),htmlCharacterEntitiesRegex:/( | |<|<|>|>|"|"|')/gi,parse:function(t){for(var e,r,a=this.htmlRegex,n=0,i=[];null!==(e=a.exec(t));){var s=e[0],o=e[3],c=e[1]||e[4],h=!!e[2],l=e.index,u=t.substring(n,l);u&&(r=this.parseTextAndEntityNodes(n,u),i.push.apply(i,r)),o?i.push(this.createCommentNode(l,s,o)):i.push(this.createElementNode(l,s,c,h)),n=l+s.length}if(n0&&"@"===f||g>0&&m&&this.wordCharRegExp.test(f))){if(this.matchHasUnbalancedClosingParen(o))o=o.substr(0,o.length-1);else{var p=this.matchHasInvalidCharAfterTld(o,c);p>-1&&(o=o.substr(0,p))}var d=c?"scheme":h?"www":"tld",b=!!c;s.push(new t.match.Url({tagBuilder:i,matchedText:o,offset:g,urlMatchType:d,url:o,protocolUrlMatch:b,protocolRelativeMatch:!!m,stripPrefix:n}))}}return s},matchHasUnbalancedClosingParen:function(t){var e=t.charAt(t.length-1);if(")"===e){var r=t.match(this.openParensRe),a=t.match(this.closeParensRe),n=r&&r.length||0,i=a&&a.length||0;if(n0&&(n=t.substr(-1*Math.floor(a/2))),(t.substr(0,Math.ceil(a/2))+r+n).substr(0,e)},t.truncate.TruncateSmart=function(t,e,r){var a=function(t){var e={},r=t,a=r.match(/^([a-z]+):\/\//i);return a&&(e.scheme=a[1],r=r.substr(a[0].length)),a=r.match(/^(.*?)(?=(\?|#|\/|$))/i),a&&(e.host=a[1],r=r.substr(a[0].length)),a=r.match(/^\/(.*?)(?=(\?|#|$))/i),a&&(e.path=a[1],r=r.substr(a[0].length)),a=r.match(/^\?(.*?)(?=(#|$))/i),a&&(e.query=a[1],r=r.substr(a[0].length)),a=r.match(/^#(.*?)$/i),a&&(e.fragment=a[1]),e},n=function(t){var e="";return t.scheme&&t.host&&(e+=t.scheme+"://"),t.host&&(e+=t.host),t.path&&(e+="/"+t.path),t.query&&(e+="?"+t.query),t.fragment&&(e+="#"+t.fragment),e},i=function(t,e){var a=e/2,n=Math.ceil(a),i=-1*Math.floor(a),s="";return i<0&&(s=t.substr(i)),t.substr(0,n)+r+s};if(t.length<=e)return t;var s=e-r.length,o=a(t);if(o.query){var c=o.query.match(/^(.*?)(?=(\?|\#))(.*?)$/i);c&&(o.query=o.query.substr(0,c[1].length),t=n(o))}if(t.length<=e)return t;if(o.host&&(o.host=o.host.replace(/^www\./,""),t=n(o)),t.length<=e)return t;var h="";if(o.host&&(h+=o.host),h.length>=s)return o.host.length==e?(o.host.substr(0,e-r.length)+r).substr(0,e):i(h,s).substr(0,e);var l="";if(o.path&&(l+="/"+o.path),o.query&&(l+="?"+o.query),l){if((h+l).length>=s){if((h+l).length==e)return(h+l).substr(0,e);var u=s-h.length;return(h+i(l,u)).substr(0,e)}h+=l}if(o.fragment){var g="#"+o.fragment;if((h+g).length>=s){if((h+g).length==e)return(h+g).substr(0,e);var m=s-h.length;return(h+i(g,m)).substr(0,e)}h+=g}if(o.scheme&&o.host){var f=o.scheme+"://";if((h+f).length0&&(p=h.substr(-1*Math.floor(s/2))),(h.substr(0,Math.ceil(s/2))+r+p).substr(0,e)},t}); \ No newline at end of file diff --git a/node_modules/autolinker/package.json b/node_modules/autolinker/package.json deleted file mode 100644 index d577922bfb5c9f7c52c86340bcc1a9b08869c94f..0000000000000000000000000000000000000000 --- a/node_modules/autolinker/package.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "_args": [ - [ - { - "name": "autolinker", - "raw": "autolinker@~0.28.0", - "rawSpec": "~0.28.0", - "scope": null, - "spec": ">=0.28.0 <0.29.0", - "type": "range" - }, - "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/remarkable" - ] - ], - "_from": "autolinker@>=0.28.0 <0.29.0", - "_id": "autolinker@0.28.1", - "_inCache": true, - "_installable": true, - "_location": "/autolinker", - "_nodeVersion": "5.10.0", - "_npmOperationalInternal": { - "host": "packages-12-west.internal.npmjs.com", - "tmp": "tmp/autolinker-0.28.1.tgz_1473119637218_0.16458595311269164" - }, - "_npmUser": { - "email": "greg@greg-jacobs.com", - "name": "gregjacobs" - }, - "_npmVersion": "3.8.3", - "_phantomChildren": {}, - "_requested": { - "name": "autolinker", - "raw": "autolinker@~0.28.0", - "rawSpec": "~0.28.0", - "scope": null, - "spec": ">=0.28.0 <0.29.0", - "type": "range" - }, - "_requiredBy": [ - "/remarkable" - ], - "_resolved": "https://registry.npmjs.org/autolinker/-/autolinker-0.28.1.tgz", - "_shasum": "0652b491881879f0775dace0cdca3233942a4e47", - "_shrinkwrap": null, - "_spec": "autolinker@~0.28.0", - "_where": "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/remarkable", - "author": { - "email": "greg@greg-jacobs.com", - "name": "Gregory Jacobs" - }, - "bugs": { - "url": "https://github.com/gregjacobs/Autolinker.js/issues" - }, - "dependencies": { - "gulp-header": "^1.7.1" - }, - "description": "Utility to automatically link the URLs, email addresses, and Twitter handles in a given block of text/HTML", - "devDependencies": { - "gulp": "^3.9.1", - "gulp-clone": "^1.0.0", - "gulp-concat": "^2.6.0", - "gulp-connect": "^3.0.0", - "gulp-jasmine": "^2.3.0", - "gulp-jsduck": "^0.3.0", - "gulp-jshint": "^2.0.0", - "gulp-preprocess": "^2.0.0", - "gulp-rename": "^1.2.2", - "gulp-typescript": "^2.13.0", - "gulp-uglify": "^1.5.3", - "gulp-umd": "^0.2.0", - "jasmine-core": "^2.4.1", - "jshint": "^2.9.1", - "jshint-stylish": "^2.1.0", - "karma": "^0.13.21", - "karma-jasmine": "^0.3.7", - "karma-phantomjs-launcher": "^1.0.0", - "karma-spec-reporter": "0.0.24", - "lodash": "^4.3.0", - "merge-stream": "^1.0.0", - "phantomjs-prebuilt": "^2.1.4", - "requirejs": "^2.1.11", - "through2": "^2.0.1" - }, - "directories": { - "test": "tests" - }, - "dist": { - "shasum": "0652b491881879f0775dace0cdca3233942a4e47", - "tarball": "https://registry.npmjs.org/autolinker/-/autolinker-0.28.1.tgz" - }, - "files": [ - "dist" - ], - "gitHead": "e6634b3736d462b60df5ee10d9e8c3c21a45f8e6", - "homepage": "https://github.com/gregjacobs/Autolinker.js", - "keywords": [ - "auto", - "link", - "autolink", - "url", - "urls", - "anchor" - ], - "license": "MIT", - "main": "dist/Autolinker.js", - "maintainers": [ - { - "email": "greg@greg-jacobs.com", - "name": "gregjacobs" - } - ], - "name": "autolinker", - "optionalDependencies": {}, - "readme": "ERROR: No README data found!", - "repository": { - "type": "git", - "url": "git://github.com/gregjacobs/Autolinker.js.git" - }, - "scripts": { - "test": "gulp" - }, - "version": "0.28.1" -} diff --git a/node_modules/boolbase/README.md b/node_modules/boolbase/README.md deleted file mode 100644 index 85eefa5e5048913b08ec4eb37d0a78473f88505d..0000000000000000000000000000000000000000 --- a/node_modules/boolbase/README.md +++ /dev/null @@ -1,10 +0,0 @@ -#boolbase -This very simple module provides two basic functions, one that always returns true (`trueFunc`) and one that always returns false (`falseFunc`). - -###WTF? - -By having only a single instance of these functions around, it's possible to do some nice optimizations. Eg. [`CSSselect`](https://github.com/fb55/CSSselect) uses these functions to determine whether a selector won't match any elements. If that's the case, the DOM doesn't even have to be touched. - -###And why is this a separate module? - -I'm trying to modularize `CSSselect` and most modules depend on these functions. IMHO, having a separate module is the easiest solution to this problem. \ No newline at end of file diff --git a/node_modules/boolbase/index.js b/node_modules/boolbase/index.js deleted file mode 100644 index 8799fd95dbe31a85c48b956eb19f3625da9f8fb1..0000000000000000000000000000000000000000 --- a/node_modules/boolbase/index.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - trueFunc: function trueFunc(){ - return true; - }, - falseFunc: function falseFunc(){ - return false; - } -}; \ No newline at end of file diff --git a/node_modules/boolbase/package.json b/node_modules/boolbase/package.json deleted file mode 100644 index 03ea9db2868421dd24320b72d7e0990bb472ff59..0000000000000000000000000000000000000000 --- a/node_modules/boolbase/package.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "_args": [ - [ - { - "name": "boolbase", - "raw": "boolbase@~1.0.0", - "rawSpec": "~1.0.0", - "scope": null, - "spec": ">=1.0.0 <1.1.0", - "type": "range" - }, - "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/css-select" - ] - ], - "_from": "boolbase@>=1.0.0 <1.1.0", - "_id": "boolbase@1.0.0", - "_inCache": true, - "_installable": true, - "_location": "/boolbase", - "_npmUser": { - "email": "me@feedic.com", - "name": "feedic" - }, - "_npmVersion": "1.4.2", - "_phantomChildren": {}, - "_requested": { - "name": "boolbase", - "raw": "boolbase@~1.0.0", - "rawSpec": "~1.0.0", - "scope": null, - "spec": ">=1.0.0 <1.1.0", - "type": "range" - }, - "_requiredBy": [ - "/css-select", - "/nth-check" - ], - "_resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "_shasum": "68dff5fbe60c51eb37725ea9e3ed310dcc1e776e", - "_shrinkwrap": null, - "_spec": "boolbase@~1.0.0", - "_where": "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/css-select", - "author": { - "email": "me@feedic.com", - "name": "Felix Boehm" - }, - "bugs": { - "url": "https://github.com/fb55/boolbase/issues" - }, - "dependencies": {}, - "description": "two functions: One that returns true, one that returns false", - "devDependencies": {}, - "directories": {}, - "dist": { - "shasum": "68dff5fbe60c51eb37725ea9e3ed310dcc1e776e", - "tarball": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" - }, - "homepage": "https://github.com/fb55/boolbase", - "keywords": [ - "boolean", - "function" - ], - "license": "ISC", - "main": "index.js", - "maintainers": [ - { - "email": "me@feedic.com", - "name": "feedic" - } - ], - "name": "boolbase", - "optionalDependencies": {}, - "readme": "ERROR: No README data found!", - "repository": { - "type": "git", - "url": "git+https://github.com/fb55/boolbase.git" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "version": "1.0.0" -} diff --git a/node_modules/buffer-from/LICENSE b/node_modules/buffer-from/LICENSE deleted file mode 100644 index e4bf1d69b1bb0df5acf1278e583264acdc1eefc5..0000000000000000000000000000000000000000 --- a/node_modules/buffer-from/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2016, 2018 Linus Unnebäck - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/node_modules/buffer-from/index.js b/node_modules/buffer-from/index.js deleted file mode 100644 index d92a83d01fd8b5ce1fcbdf92e72e234672d09d15..0000000000000000000000000000000000000000 --- a/node_modules/buffer-from/index.js +++ /dev/null @@ -1,69 +0,0 @@ -var toString = Object.prototype.toString - -var isModern = ( - typeof Buffer.alloc === 'function' && - typeof Buffer.allocUnsafe === 'function' && - typeof Buffer.from === 'function' -) - -function isArrayBuffer (input) { - return toString.call(input).slice(8, -1) === 'ArrayBuffer' -} - -function fromArrayBuffer (obj, byteOffset, length) { - byteOffset >>>= 0 - - var maxLength = obj.byteLength - byteOffset - - if (maxLength < 0) { - throw new RangeError("'offset' is out of bounds") - } - - if (length === undefined) { - length = maxLength - } else { - length >>>= 0 - - if (length > maxLength) { - throw new RangeError("'length' is out of bounds") - } - } - - return isModern - ? Buffer.from(obj.slice(byteOffset, byteOffset + length)) - : new Buffer(new Uint8Array(obj.slice(byteOffset, byteOffset + length))) -} - -function fromString (string, encoding) { - if (typeof encoding !== 'string' || encoding === '') { - encoding = 'utf8' - } - - if (!Buffer.isEncoding(encoding)) { - throw new TypeError('"encoding" must be a valid string encoding') - } - - return isModern - ? Buffer.from(string, encoding) - : new Buffer(string, encoding) -} - -function bufferFrom (value, encodingOrOffset, length) { - if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number') - } - - if (isArrayBuffer(value)) { - return fromArrayBuffer(value, encodingOrOffset, length) - } - - if (typeof value === 'string') { - return fromString(value, encodingOrOffset) - } - - return isModern - ? Buffer.from(value) - : new Buffer(value) -} - -module.exports = bufferFrom diff --git a/node_modules/buffer-from/package.json b/node_modules/buffer-from/package.json deleted file mode 100644 index 1168d85bd9cded90f27c8a7fc6b656892a3d8ed7..0000000000000000000000000000000000000000 --- a/node_modules/buffer-from/package.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "_args": [ - [ - { - "name": "buffer-from", - "raw": "buffer-from@^1.0.0", - "rawSpec": "^1.0.0", - "scope": null, - "spec": ">=1.0.0 <2.0.0", - "type": "range" - }, - "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/concat-stream" - ] - ], - "_from": "buffer-from@>=1.0.0 <2.0.0", - "_id": "buffer-from@1.1.1", - "_inCache": true, - "_installable": true, - "_location": "/buffer-from", - "_nodeVersion": "10.5.0", - "_npmOperationalInternal": { - "host": "s3://npm-registry-packages", - "tmp": "tmp/buffer-from_1.1.1_1533048083841_0.2458068233892754" - }, - "_npmUser": { - "email": "linus@folkdatorn.se", - "name": "linusu" - }, - "_npmVersion": "6.1.0", - "_phantomChildren": {}, - "_requested": { - "name": "buffer-from", - "raw": "buffer-from@^1.0.0", - "rawSpec": "^1.0.0", - "scope": null, - "spec": ">=1.0.0 <2.0.0", - "type": "range" - }, - "_requiredBy": [ - "/concat-stream" - ], - "_resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "_shasum": "32713bc028f75c02fdb710d7c7bcec1f2c6070ef", - "_shrinkwrap": null, - "_spec": "buffer-from@^1.0.0", - "_where": "/Users/xxm/Documents/gitlab/codechina-docs/node_modules/concat-stream", - "bugs": { - "url": "https://github.com/LinusU/buffer-from/issues" - }, - "dependencies": {}, - "description": "A [ponyfill](https://ponyfill.com) for `Buffer.from`, uses native implementation if available.", - "devDependencies": { - "standard": "^7.1.2" - }, - "directories": {}, - "dist": { - "fileCount": 4, - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbYHUTCRA9TVsSAnZWagAAgoQP/1LXApc57d1uAc/0mnLq\nCI87dq7EtKS4lG7EjFY3yzxIZxlq1++vH0/sWe0V8je9sHhrm/AkSxlcplEV\nWELPjRwIY4h3LP6U5ppG7XAVGmbipkIAGhiRaJtqGfI/TgPRiB3QcrqanlRG\nBf4oDubBJ2vK8dh5Gd0AhAkkTOsIcf4b5uC64A5GUtMoPOrko+zyRYM8IrRo\n7kDspGfsk3YYxyB/L0APD4AIC8vYz2Gin2ca+zJBZH6cvfThhFWbSnCFfVuW\nxXcheune4boTojusOn5dm4LxzFyMgbeibDZTaq+Yod3RuuUVaSCXWNITcT6g\nIlP7wdbBFGx7Ik5hKEtAGtsCdWshzg9YxHR7g7CPe+0xIeb0zNeKBlxFF2jT\niPeiI+JGlMZuH2Qu+284T9WWom/j0NcbZuWmrV5E1GUimVJqtgqD3S3ivc4y\n6fS6OTIemRUmWwmS7farPxzTs34QkUp0vH/dhuvNeZKockTjLvlveHlOtC4m\nhGp5UdiwrsV7Xqqy/RHlACxPjexkDfhwi0FSeY799VkzbgrPm7Npwn8HwMDI\nv6qpaxPbruRJx65zp1J4DqWlhYENreSFOaXGY/t34GIQ1yNHXGg4Z2ltshPi\nb3lJuLEolQYK5GAcryVnAGusAisYQDfygT1BPxYsVT2ZWYmicpHs7UD+70ya\nfbJa\r\n=YgJu\r\n-----END PGP SIGNATURE-----\r\n", - "shasum": "32713bc028f75c02fdb710d7c7bcec1f2c6070ef", - "tarball": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "unpackedSize": 4966 - }, - "files": [ - "index.js" - ], - "gitHead": "53f464194ae30e806f6faef635202b4dfd404ed5", - "homepage": "https://github.com/LinusU/buffer-from#readme", - "keywords": [ - "buffer", - "buffer from" - ], - "license": "MIT", - "maintainers": [ - { - "email": "linus@folkdatorn.se", - "name": "linusu" - } - ], - "name": "buffer-from", - "optionalDependencies": {}, - "readme": "ERROR: No README data found!", - "repository": { - "type": "git", - "url": "git+https://github.com/LinusU/buffer-from.git" - }, - "scripts": { - "test": "standard && node test" - }, - "version": "1.1.1" -} diff --git a/node_modules/buffer-from/readme.md b/node_modules/buffer-from/readme.md deleted file mode 100644 index 9880a558a7c91fefb0e6908318fbd991b6b93dcf..0000000000000000000000000000000000000000 --- a/node_modules/buffer-from/readme.md +++ /dev/null @@ -1,69 +0,0 @@ -# Buffer From - -A [ponyfill](https://ponyfill.com) for `Buffer.from`, uses native implementation if available. - -## Installation - -```sh -npm install --save buffer-from -``` - -## Usage - -```js -const bufferFrom = require('buffer-from') - -console.log(bufferFrom([1, 2, 3, 4])) -//=> - -const arr = new Uint8Array([1, 2, 3, 4]) -console.log(bufferFrom(arr.buffer, 1, 2)) -//=> - -console.log(bufferFrom('test', 'utf8')) -//=> - -const buf = bufferFrom('test') -console.log(bufferFrom(buf)) -//=> -``` - -## API - -### bufferFrom(array) - -- `array` <Array> - -Allocates a new `Buffer` using an `array` of octets. - -### bufferFrom(arrayBuffer[, byteOffset[, length]]) - -- `arrayBuffer` <ArrayBuffer> The `.buffer` property of a TypedArray or ArrayBuffer -- `byteOffset` <Integer> Where to start copying from `arrayBuffer`. **Default:** `0` -- `length` <Integer> How many bytes to copy from `arrayBuffer`. **Default:** `arrayBuffer.length - byteOffset` - -When passed a reference to the `.buffer` property of a TypedArray instance, the -newly created `Buffer` will share the same allocated memory as the TypedArray. - -The optional `byteOffset` and `length` arguments specify a memory range within -the `arrayBuffer` that will be shared by the `Buffer`. - -### bufferFrom(buffer) - -- `buffer` <Buffer> An existing `Buffer` to copy data from - -Copies the passed `buffer` data onto a new `Buffer` instance. - -### bufferFrom(string[, encoding]) - -- `string` <String> A string to encode. -- `encoding` <String> The encoding of `string`. **Default:** `'utf8'` - -Creates a new `Buffer` containing the given JavaScript string `string`. If -provided, the `encoding` parameter identifies the character encoding of -`string`. - -## See also - -- [buffer-alloc](https://github.com/LinusU/buffer-alloc) A ponyfill for `Buffer.alloc` -- [buffer-alloc-unsafe](https://github.com/LinusU/buffer-alloc-unsafe) A ponyfill for `Buffer.allocUnsafe` diff --git a/node_modules/cheerio/History.md b/node_modules/cheerio/History.md deleted file mode 100644 index c7e38e66a76870ecc8741b553590d8792b697731..0000000000000000000000000000000000000000 --- a/node_modules/cheerio/History.md +++ /dev/null @@ -1,576 +0,0 @@ - -0.22.0 / 2016-08-23 -================== - - * Return undefined in .prop if given an invalid element or tag (#880) - * Merge pull request #884 from cheeriojs/readme-cleanup - * readme updates - * Merge pull request #881 from piamancini/patch-1 - * Added backers and sponsors from OpenCollective - * Use jQuery from the jquery module in benchmarks (#871) - * Document, test, and extend static `$.text` method (#855) - * Fix typo on calling _.extend (#861) - * Update versions (#870) - * Use individual lodash functions (#864) - * Added `.serialize()` support. Fixes #69 (#827) - * Update Readme.md (#857) - * add extension for JSON require call - * remove gittask badge - * Merge pull request #672 from underdogio/dev/checkbox.radio.values.sqwished - * Added default value for checkboxes/radios - -0.20.0 / 2016-02-01 -================== - - * Add coveralls badge, remove link to old report (Felix Böhm) - * Update lodash dependeny to 4.1.0 (leif.hanack) - * Fix PR #726 adding 'appendTo()' and 'prependTo()' (Delgan) - * Added appendTo and prependTo with tests #641 (digihaven) - * Fix #780 by changing options context in '.find()' (Felix Böhm) - * Add an unit test checking the query of child (Delgan) - * fix #667: attr({foo: null}) removes attribute foo, like attr('foo', null) (Ray Waldin) - * Include reference to dedicated "Loading" section (Mike Pennisi) - * Added load method to $ (alanev) - * update css-select to 1.2.0 (Felix Böhm) - * Fixing Grammatical Error (Dan Corman) - * Test against node v0.12 --> v4.2 (Jason Kurian) - * Correct output in example (Felix Böhm) - * Fix npm files filter (Bogdan Chadkin) - * Enable setting data on all elements in selection (Mike Pennisi) - * Reinstate `$.fn.toArray` (Mike Pennisi) - * update css-select to 1.1.0 (Thomas Shafer) - * Complete implementation of `wrap` (Mike Pennisi) - * Correct name of unit test (Mike Pennisi) - * Correct grammar in test titles (Mike Pennisi) - * Normalize whitespace (Mike Pennisi) - * Insert omitted assertion (Mike Pennisi) - * Update invocation of `children` (Mike Pennisi) - * Begin implementation of `wrap` method (Dandlezzz) - * Update Readme.md (Sven Slootweg) - * fix document's mistake in Readme.md (exoticknight) - * Add tests for setting text and html as non-strings (Ryc O'Chet) - * Fix for passing non-string values to .html or .text (Ryc O'Chet) - * use a selector to filter form elements (fb55) - * fix README.md typo (Yutian Li) - * README: fix spelling (Chris Rebert) - * Added support for options without a `value` attribute. Fixes #633 (Todd Wolfson) - * responding to pull request feedback - remove item() method and related tests (Ray Waldin) - * add length property and item method to object returned by prop('style'), plus tests (Ray Waldin) - * Added .prop method to readme (Artem Burtsev) - * Added .prop method (Artem Burtsev) - * Added Gitter badge (The Gitter Badger) - -0.19.0 / 2015-03-21 -================== - - * fixed allignment (fb55) - * added test case for malformed json in data attributes (fb55) - * fix: handle some extreme cases like `data-custom="{{templatevar}}"`. There is possibility error while parsing json . (Harish.K) - * Add missing optional selector doc for {prev,next}{All,Until} (Jérémie Astori) - * update to dom-serializer@0.1.0 (Felix Böhm) - * Document `Cheerio#serialzeArray` (Mike Pennisi) - * Fixed up `serializeArray()` and added multiple support (Todd Wolfson) - * Implement serializeArray() (Jarno Leppänen) - * recognize options in $.xml() (fb55) - * lib/static.js: text(): rm errant space before ++ (Chris Rebert) - * Do not expose internal `children` array (Mike Pennisi) - * Change lodash dependencies to ^3.1.0 (Samy Pessé) - * Update lodash@3.1.0 (Samy Pessé) - * Updates Readme.md: .not(function (index, elem)) (Patrick Ward) - * update to css-select@1.0.0 (fb55) - * Allow failures in Node.js v0.11 (Mike Pennisi) - * Added: Gittask badge (Matthew Mueller) - * Isolate prototypes of functions created via `load` (Mike Pennisi) - * Updates Readme.md: adds JS syntax highlighting (frankcash) - * #608 -- Add support for insertBefore/insertAfter syntax. Supports target types of: $, [$], selector (both single and multiple results) (Ben Cochran) - * Clone input nodes when inserting over a set (Mike Pennisi) - * Move unit test files (Mike Pennisi) - * remove unnecessarily tricky code (David Chambers) - * pass options to $.html in toString (fb55) - * add license info to package.json (Chris Rebert) - * xyz@~0.5.0 (David Chambers) - * Remove unofficial signature of `children` (Mike Pennisi) - * Fix bug in `css` method (Mike Pennisi) - * Correct bug in implementation of `Cheerio#val` (Mike Pennisi) - -0.18.0 / 2014-11-06 -================== - - * bump htmlparser2 dependency to ~3.8.1 (Chris Rebert) - * Correct unit test titles (Mike Pennisi) - * Correct behavior of `after` and `before` (Mike Pennisi) - * implement jQuery's .has() (Chris Rebert) - * Update repository url (haqii) - * attr() should return undefined or name for booleans (Raoul Millais) - * Update Readme.md (Ryan Breen) - * Implement `Cheerio#not` (Mike Pennisi) - * Clone nodes according to original parsing options (Mike Pennisi) - * fix lint error (David Chambers) - * Add explicit tests for DOM level 1 API (Mike Pennisi) - * Expose DOM level 1 API for Node-like objects (Mike Pennisi) - * Correct error in documentation (Mike Pennisi) - * Return a fully-qualified Function from `$.load` (Mike Pennisi) - * Update tests to avoid duck typing (Mike Pennisi) - * Alter "loaded" functions to produce true instances (Mike Pennisi) - * Organize tests for `cheerio.load` (Mike Pennisi) - * Complete `$.prototype.find` (Mike Pennisi) - * Use JSHint's `extends` option (Mike Pennisi) - * Remove aliases for exported methods (Mike Pennisi) - * Disallow unused variables (Mike Pennisi) - * Remove unused internal variables (Mike Pennisi) - * Remove unused variables from unit tests (Mike Pennisi) - * Remove unused API method references (Mike Pennisi) - * Move tests for `contains` method (Mike Pennisi) - * xyz@0.4.0 (David Chambers) - * Created a wiki for companies using cheerio in production (Matthew Mueller) - * Implement `$.prototype.index` (Mike Pennisi) - * Implement `$.prototype.addBack` (Mike Pennisi) - * Added double quotes to radio attribute name to account for characters such as brackets (akant10) - * Update History.md (Gabriel Falkenberg) - * add 0.17.0 changelog (David Chambers) - * exit prepublish script if tag not found (David Chambers) - * alphabetize devDependencies (fb55) - * ignore coverage dir (fb55) - * submit coverage to coveralls (fb55) - * replace jscoverage with istanbul (fb55) - -0.17.0 / 2014-06-10 -================== - - * Fix bug in internal `uniqueSplice` function (Mike Pennisi) - * accept buffer argument to cheerio.load (David Chambers) - * Respect options on the element level (Alex Indigo) - * Change state definition to more readable (Artem Burtsev) - * added test (0xBADC0FFEE) - * add class only if doesn't exist (Artem Burtsev) - * Made it less insane. (Alex Indigo) - * Implement `Cheerio#add` (Mike Pennisi) - * Use "loaded" instance of Cheerio in unit tests (Mike Pennisi) - * Be more strict with object check. (Alex Indigo) - * Added options argument to .html() static method. (Alex Indigo) - * Fixed encoding mishaps. Adjusted tests. (Alex Indigo) - * use dom-serializer module (fb55) - * don't test on 0.8, don't ignore 0.11 (Felix Böhm) - * parse: rm unused variables (coderaiser) - * cheerio: rm unused variable (coderaiser) - * Fixed test (Avi Kohn) - * Added test (Avi Kohn) - * Changed == to === (Avi Kohn) - * Fixed a bug in removing type="hidden" attr (Avi Kohn) - * sorted (Alexey Raspopov) - * add `muted` attr to booleanAttributes (Alexey Raspopov) - * fixed context of `this` in .html (Felix Böhm) - * append new elements for each element in selection (fb55) - -0.16.0 / 2014-05-08 -================== - - * fix `make bench` (David Chambers) - * makefile: add release-* targets (David Chambers) - * alphabetize dependencies (David Chambers) - * Rewrite `data` internals with caching behavior (Mike Pennisi) - * Fence .val example as js (Kevin Sawicki) - * Fixed typos. Deleted trailing whitespace from test/render.js (Nattaphoom Ch) - * Fix manipulation APIs with removed elements (kpdecker) - * Perform manual string parsing for hasClass (kpdecker) - * Fix existing element removal (kpdecker) - * update render tests (Felix Böhm) - * fixed cheerio path (Felix Böhm) - * use `entities.escape` for attribute values (Felix Böhm) - * bump entities version (Felix Böhm) - * remove lowerCaseTags option from readme (Felix Böhm) - * added test case for .html in xmlMode (fb55) - * render xml in `html()` when `xmlMode: true` (fb55) - * use a map for booleanAttributes (fb55) - * update singleTags, use utils.isTag (fb55) - * update travis badge URL (Felix Böhm) - * use typeof instead of _.isString and _.isNumber (fb55) - * use Array.isArray instead of _.isArray (fb55) - * replace _.isFunction with typeof (fb55) - * removed unnecessary error message (fb55) - * decode entities in htmlparser2 (fb55) - * pass options object to CSSselect (fb55) - -0.15.0 / 2014-04-08 -================== - - * Update callbacks to pass element per docs (@kpdecker) - * preserve options (@fb55) - * Use SVG travis badge (@t3chnoboy) - * only use static requires (@fb55) - * Optimize manipulation methods (@kpdecker) - * Optimize add and remove class cases (@kpdecker) - * accept dom of DomHandler to cheerio.load (@nleush) - * added parentsUntil method (@finspin) - * Add performance optimization and bug fix `empty` method (@kpdecker) - -0.14.0 / 2014-04-01 -================== - - * call encodeXML and directly expose decodeHTML (@fb55) - * use latest htmlparser2 and entities versions (@fb55) - * Deprecate `$.fn.toArray` (@jugglinmike) - * Implement `$.fn.get` (@jugglinmike) - * .replaceWith now replaces all selected elements. (@xavi-) - * Correct arguments for 'replaceWith' callback (@jugglinmike) - * switch to lodash (@fb55) - * update to entities@0.5.0 (@fb55) - * Fix attr when $ collection contains text modules (@kpdecker) - * Update to latest version of expect.js (@jugglinmike) - * Remove nodes from their previous structures (@jugglinmike) - * Update render.js (@stevenvachon) - * CDATA test (@stevenvachon) - * only ever one child index for cdata (@stevenvachon) - * don't loop through cdata children array (@stevenvachon) - * proper rendering of CDATA (@stevenvachon) - * Add cheerio-only bench option (@kpdecker) - * Avoid delete operations (@kpdecker) - * Add independent html benchmark (@kpdecker) - * Cache tag check in render (@kpdecker) - * Simplify attribute rendering step (@kpdecker) - * Add html rendering bench case (@kpdecker) - * Remove unnecessary check from removeAttr (@kpdecker) - * Remove unnecessary encoding step for attrs (@kpdecker) - * Add test for removeAttr+attr on boolean attributes (@kpdecker) - * Add single element benchmark case (@kpdecker) - * Optimize filter with selector (@kpdecker) - * Fix passing context as dom node (@alfred-nsh) - * Fix bug in `nextUntil` (@jugglinmike) - * Fix bug in `nextAll` (@jugglinmike) - * Implement `selector` argument of `next` method (@jugglinmike) - * Fix bug in `prevUntil` (@jugglinmike) - * Implement `selector` argument of `prev` method (@jugglinmike) - * Fix bug in `prevAll` (@jugglinmike) - * Fix bug in `siblings` (@jugglinmike) - * Avoid unnecessary indexOf from toggleClass (@kpdecker) - * Use strict equality rather than falsy check in eq (@kpdecker) - * Add benchmark coverage for all $ APIs (@kpdecker) - * Optimize filter Cheerio intermediate creation (@kpdecker) - * Optimize siblings cheerio instance creation (@kpdecker) - * Optimize identity cases for first/last/eq (@kpdecker) - * Use domEach for traversal (@kpdecker) - * Inline children lookup in find (@kpdecker) - * Use domEach in data accessor (@kpdecker) - * Avoid cheerio creation in add/remove/toggleClass (@kpdecker) - * Implement getAttr local helper (@kpdecker) - -0.13.1 / 2014-01-07 -================== - - * Fix select with context in Cheerio function (@jugglinmike) - * Remove unecessary DOM maintenance logic (@jugglinmike) - * Deprecate support for node 0.6 - -0.13.0 / 2013-12-30 -================== - - * Remove "root" node (@jugglinmike) - * Fix bug in `prevAll`, `prev`, `nextAll`, `next`, `prevUntil`, `nextUntil` (@jugglinmike) - * Fix `replaceWith` method (@jugglinmike) - * added nextUntil() and prevUntil() (@finspin) - * Remove internal `connect` function (@jugglinmike) - * Rename `Cheerio#make` to document private status (@jugginmike) - * Remove extraneous call to `_.uniq` (@jugglinmike) - * Use CSSselect library directly (@jugglinmike) - * Run CI against Node v0.11 as an allowed failure (@jugginmike) - * Correct bug in `Cheerio#parents` (@jugglinmike) - * Implement `$.fn.end` (@jugginmike) - * Ignore colons inside of url(.*) when parsing css (@Meekohi) - * Introduce rudimentary benchmark suite (@jugglinmike) - * Update HtmlParser2 version (@jugglinmike) - * Correct inconsistency in `$.fn.map` (@jugglinmike) - * fixed traversing tests (@finspin) - * Simplify `make` method (@jugglinmike) - * Avoid shadowing instance methods from arrays (@jugglinmike) - -0.12.4 / 2013-11-12 -================== - - * Coerce JSON values returned by `data` (@jugglinmike) - * issue #284: when rendering HTML, use original data attributes (@Trott) - * Introduce JSHint for automated code linting (@jugglinmike) - * Prevent `find` from returning duplicate elements (@jugglinmike) - * Implement function signature of `replaceWith` (@jugglinmike) - * Implement function signature of `before` (@jugglinmike) - * Implement function signature of `after` (@jugglinmike) - * Implement function signature of `append`/`prepend` (@jugglinmike) - * Extend iteration methods to accept nodes (@jugglinmike) - * Improve `removeClass` (@jugglinmike) - * Complete function signature of `addClass` (@jugglinmike) - * Fix bug in `removeClass` (@jugglinmike) - * Improve contributing.md (@jugglinmike) - * Fix and document .css() (@jugglinmike) - -0.12.3 / 2013-10-04 -=================== - - * Add .toggleClass() function (@cyberthom) - * Add contributing guidelines (@jugglinmike) - * Fix bug in `siblings` (@jugglinmike) - * Correct the implementation `filter` and `is` (@jugglinmike) - * add .data() function (@andi-neck) - * add .css() (@yields) - * Implements contents() (@jlep) - -0.12.2 / 2013-09-04 -================== - - * Correct implementation of `$.fn.text` (@jugglinmike) - * Refactor Cheerio array creation (@jugglinmike) - * Extend manipulation methods to accept Arrays (@jugglinmike) - * support .attr(attributeName, function(index, attr)) (@xiaohwan) - -0.12.1 / 2013-07-30 -================== - - * Correct behavior of `Cheerio#parents` (@jugglinmike) - * Double quotes inside attributes kills HTML (@khoomeister) - * Making next({}) and prev({}) return empty object (@absentTelegraph) - * Implement $.parseHTML (@jugglinmike) - * Correct bug in jQuery.fn.closest (@jugglinmike) - * Correct behavior of $.fn.val on 'option' elements (@jugglinmike) - -0.12.0 / 2013-06-09 -=================== - - * Breaking Change: Changed context from parent to the actual passed one (@swissmanu) - * Fixed: jquery checkbox val behavior (@jhubble) - * Added: output xml with $.xml() (@Maciek416) - * Bumped: htmlparser2 to 3.1.1 - * Fixed: bug in attr(key, val) on empty objects (@farhadi) - * Added: prevAll, nextAll (@lessmind) - * Fixed: Safety check in parents and closest (@zero21xxx) - * Added: .is(sel) (@zero21xxx) - -0.11.0 / 2013-04-22 -================== - -* Added: .closest() (@jeremy-dentel) -* Added: .parents() (@zero21xxx) -* Added: .val() (@rschmukler & @leahciMic) -* Added: Travis support for node 0.10.0 (@jeremy-dentel) -* Fixed: .find() if no selector (@davidchambers) -* Fixed: Propagate syntax errors caused by invalid selectors (@davidchambers) - -0.10.8 / 2013-03-11 -================== - -* Add slice method (SBoudrias) - -0.10.7 / 2013-02-10 -================== - -* Code & doc cleanup (davidchambers) -* Fixed bug in filter (jugglinmike) - -0.10.6 / 2013-01-29 -================== - -* Added `$.contains(...)` (jugglinmike) -* formatting cleanup (davidchambers) -* Bug fix for `.children()` (jugglinmike & davidchambers) -* Remove global `render` bug (wvl) - -0.10.5 / 2012-12-18 -=================== - -* Fixed botched publish from 0.10.4 - changes should now be present - -0.10.4 / 2012-12-16 -================== - -* $.find should query descendants only (@jugglinmike) -* Tighter underscore dependency - -0.10.3 / 2012-11-18 -=================== - -* fixed outer html bug -* Updated documentation for $(...).html() and $.html() - -0.10.2 / 2012-11-17 -=================== - -* Added a toString() method (@bensheldon) -* use `_.each` and `_.map` to simplify cheerio namesakes (@davidchambers) -* Added filter() with tests and updated readme (@bensheldon & @davidchambers) -* Added spaces between attributes rewritten by removeClass (@jos3000) -* updated docs to remove reference to size method (@ironchefpython) -* removed HTML tidy/pretty print from cheerio - -0.10.1 / 2012-10-04 -=================== - -* Fixed regression, filtering with a context (#106) - -0.10.0 / 2012-09-24 -=================== - -* Greatly simplified and reorganized the library, reducing the loc by 30% -* Now supports mocha's test-coverage -* Deprecated self-closing tags (HTML5 doesn't require them) -* Fixed error thrown in removeClass(...) @robashton - -0.9.2 / 2012-08-10 -================== - -* added $(...).map(fn) -* manipulation: refactor `makeCheerioArray` -* make .removeClass() remove *all* occurrences (#64) - -0.9.1 / 2012-08-03 -================== - -* fixed bug causing options not to make it to the parser - -0.9.0 / 2012-07-24 -================== - -* Added node 8.x support -* Removed node 4.x support -* Add html(dom) support (@wvl) -* fixed xss vulnerabilities on .attr(), .text(), & .html() (@benatkin, @FB55) -* Rewrote tests into javascript, removing coffeescript dependency (@davidchambers) -* Tons of cleanup (@davidchambers) - -0.8.3 / 2012-06-12 -================== - -* Fixed minor package regression (closes #60) - -0.8.2 / 2012-06-11 -================== - -* Now fails gracefully in cases that involve special chars, which is inline with jQuery (closes #59) -* text() now decode special entities (closes #52) -* updated travis.yml to test node 4.x - -0.8.1 / 2012-06-02 -================== - -* fixed regression where if you created an element, it would update the root -* compatible with node 4.x (again) - -0.8.0 / 2012-05-27 -================== - -* Updated CSS parser to use FB55/CSSselect. Cheerio now supports most CSS3 psuedo selectors thanks to @FB55. -* ignoreWhitespace now on by default again. See #55 for context. -* Changed $(':root') to $.root(), cleaned up $.clone() -* Support for .eq(i) thanks to @alexbardas -* Removed support for node 0.4.x -* Fixed memory leak where package.json was continually loaded -* Tons more tests - -0.7.0 / 2012-04-08 -================== - -* Now testing with node v0.7.7 -* Added travis-ci integration -* Replaced should.js with expect.js. Browser testing to come -* Fixed spacing between attributes and their values -* Added HTML tidy/pretty print -* Exposed node-htmlparser2 parsing options -* Revert .replaceWith(...) to be consistent with jQuery - -0.6.2 / 2012-02-12 -================== - -* Fixed .replaceWith(...) regression - -0.6.1 / 2012-02-12 -================== - -* Added .first(), .last(), and .clone() commands. -* Option to parse using whitespace added to `.load`. -* Many bug fixes to make cheerio more aligned with jQuery. -* Added $(':root') to select the highest level element. - -Many thanks to the contributors that made this release happen: @ironchefpython and @siddMahen - -0.6.0 / 2012-02-07 -================== - -* *Important:* `$(...).html()` now returns inner HTML, which is in line with the jQuery spec -* `$.html()` returns the full HTML string. `$.html([cheerioObject])` will return the outer(selected element's tag) and inner HTML of that object -* Fixed bug that prevented HTML strings with depth (eg. `append('
')`) from getting `parent`, `next`, `prev` attributes. -* Halted [htmlparser2](https://github.com/FB55/node-htmlparser) at v2.2.2 until single attributes bug gets fixed. - -0.5.1 / 2012-02-05 -================== - -* Fixed minor regression: $(...).text(fn) would fail - -0.5.1 / 2012-02-05 -================== - -* Fixed regression: HTML pages with comments would fail - -0.5.0 / 2012-02-04 -================== - -* Transitioned from Coffeescript back to Javascript -* Parser now ignores whitespace -* Fixed issue with double slashes on self-enclosing tags -* Added boolean attributes to html rendering - -0.4.2 / 2012-01-16 -================== - -* Multiple selectors support: $('.apple, .orange'). Thanks @siddMahen! -* Update package.json to always use latest cheerio-soupselect -* Fix memory leak in index.js - -0.4.1 / 2011-12-19 -================== -* Minor packaging changes to allow `make test` to work from npm installation - -0.4.0 / 2011-12-19 -================== - -* Rewrote all unit tests as cheerio transitioned from vows -> mocha -* Internally, renderer.render -> render(...), parser.parse -> parse(...) -* Append, prepend, html, before, after all work with only text (no tags) -* Bugfix: Attributes can now be removed from script and style tags -* Added yield as a single tag -* Cheerio now compatible with node >=0.4.7 - -0.3.2 / 2011-12-1 -================= - -* Fixed $(...).text(...) to work with "root" element - -0.3.1 / 2011-11-25 -================== - -* Now relying on cheerio-soupselect instead of node-soupselect -* Removed all lingering htmlparser dependencies -* parser now returns parent "root" element. Root now never needs to be updated when there is multiple roots. This fixes ongoing issues with before(...), after(...) and other manipulation functions -* Added jQuery's $(...).replaceWith(...) - -0.3.0 / 2011-11-19 -================== - -* Now using htmlparser2 for parsing (2x speed increase, cleaner, actively developed) -* Added benchmark directory for future speed tests -* $('...').dom() was funky, so it was removed in favor of $('...').get(). $.dom() still works the same. -* $.root now correctly static across all instances of $ -* Added a screencast - -0.2.2 / 2011-11-9 -================= - -* Traversing will select `", - "expected": [ - { - "type": "tag", - "name": "head", - "attribs": {}, - "children": [ - { - "type": "script", - "name": "script", - "attribs": { - "language": "Javascript" - }, - "children": [ - { - "data": "var foo = \"\"; alert(2 > foo); var baz = 10 << 2; var zip = 10 >> 1; var yap = \"<<>>>><<\";", - "type": "text" - } - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/node_modules/domhandler/test/cases/05-tags_in_comment.json b/node_modules/domhandler/test/cases/05-tags_in_comment.json deleted file mode 100644 index 2d22d9e1d8f6f49019c280246346346ae6821a11..0000000000000000000000000000000000000000 --- a/node_modules/domhandler/test/cases/05-tags_in_comment.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "Special char in comment", - "options": {}, - "html": "", - "expected": [ - { - "type": "tag", - "name": "head", - "attribs": {}, - "children": [ - { - "data": " commented out tags Test", - "type": "comment" - } - ] - } - ] -} \ No newline at end of file diff --git a/node_modules/domhandler/test/cases/06-comment_in_script.json b/node_modules/domhandler/test/cases/06-comment_in_script.json deleted file mode 100644 index 9a21cdabf8b262829273ab0f326a53c6d76d1d92..0000000000000000000000000000000000000000 --- a/node_modules/domhandler/test/cases/06-comment_in_script.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "Script source in comment", - "options": {}, - "html": "", - "expected": [ - { - "type": "script", - "name": "script", - "attribs": {}, - "children": [ - { - "data": "", - "type": "text" - } - ] - } - ] -} \ No newline at end of file diff --git a/node_modules/domhandler/test/cases/07-unescaped_in_style.json b/node_modules/domhandler/test/cases/07-unescaped_in_style.json deleted file mode 100644 index 77438fdc1d5b1d2db0e1279f6adc67467426cadc..0000000000000000000000000000000000000000 --- a/node_modules/domhandler/test/cases/07-unescaped_in_style.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "Unescaped chars in style", - "options": {}, - "html": "", - "expected": [ - { - "type": "style", - "name": "style", - "attribs": { - "type": "text/css" - }, - "children": [ - { - "data": "\n body > p\n\t{ font-weight: bold; }", - "type": "text" - } - ] - } - ] -} \ No newline at end of file diff --git a/node_modules/domhandler/test/cases/08-extra_spaces_in_tag.json b/node_modules/domhandler/test/cases/08-extra_spaces_in_tag.json deleted file mode 100644 index 5c2492e222f138b2aa28237f74555beb0a34a03d..0000000000000000000000000000000000000000 --- a/node_modules/domhandler/test/cases/08-extra_spaces_in_tag.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "Extra spaces in tag", - "options": {}, - "html": "the text", - "expected": [ - { - "type": "tag", - "name": "font", - "attribs": { - "size": "14" - }, - "children": [ - { - "data": "the text", - "type": "text" - } - ] - } - ] -} \ No newline at end of file diff --git a/node_modules/domhandler/test/cases/09-unquoted_attrib.json b/node_modules/domhandler/test/cases/09-unquoted_attrib.json deleted file mode 100644 index 543cceeed7b5cff975d62399d8dc279d409209f0..0000000000000000000000000000000000000000 --- a/node_modules/domhandler/test/cases/09-unquoted_attrib.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "Unquoted attributes", - "options": {}, - "html": "the text", - "expected": [ - { - "type": "tag", - "name": "font", - "attribs": { - "size": "14" - }, - "children": [ - { - "data": "the text", - "type": "text" - } - ] - } - ] -} \ No newline at end of file diff --git a/node_modules/domhandler/test/cases/10-singular_attribute.json b/node_modules/domhandler/test/cases/10-singular_attribute.json deleted file mode 100644 index 544636e49eb7f6213d2f56cdbcfcd6d083178911..0000000000000000000000000000000000000000 --- a/node_modules/domhandler/test/cases/10-singular_attribute.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "Singular attribute", - "options": {}, - "html": "