From f5ec0e5db4e8606e8627e5cabca3c79ea33ce5f7 Mon Sep 17 00:00:00 2001 From: Rajakavitha1 Date: Fri, 12 Jun 2020 12:48:12 +0530 Subject: [PATCH 01/99] Removing Rajakavitha1 from the approvers list It has been a pleasure working with the SIG-Docs team. --- OWNERS_ALIASES | 4 ---- 1 file changed, 4 deletions(-) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 34c36cee81..03f8f79b8a 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -46,7 +46,6 @@ aliases: - kbhawkey - makoscafee - onlydole - - Rajakavitha1 - savitharaghunathan - sftim - steveperry-53 @@ -63,7 +62,6 @@ aliases: - kbhawkey - makoscafee - onlydole - - rajakavitha1 - rajeshdeshpande02 - sftim - steveperry-53 @@ -111,12 +109,10 @@ aliases: - avidLearnerInProgress - daminisatya - mittalyashu - - Rajakavitha1 sig-docs-hi-reviews: # PR reviews for Hindi content - avidLearnerInProgress - daminisatya - mittalyashu - - Rajakavitha1 sig-docs-id-owners: # Admins for Indonesian content - girikuncoro - irvifa From 05843a7f9e60ee9edbfcf6417ee3aa4daf5b07f4 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Fri, 19 Jun 2020 22:19:21 +0800 Subject: [PATCH 02/99] [zh] Sync control-plane-node-communication The original master-node-communication page was renamed with some new text added about Konnectivity. This PR resync the Chinese localization. --- .../control-plane-node-communication.md | 181 ++++++++++++++++++ .../architecture/master-node-communication.md | 69 ------- 2 files changed, 181 insertions(+), 69 deletions(-) create mode 100644 content/zh/docs/concepts/architecture/control-plane-node-communication.md delete mode 100644 content/zh/docs/concepts/architecture/master-node-communication.md diff --git a/content/zh/docs/concepts/architecture/control-plane-node-communication.md b/content/zh/docs/concepts/architecture/control-plane-node-communication.md new file mode 100644 index 0000000000..eafa80f804 --- /dev/null +++ b/content/zh/docs/concepts/architecture/control-plane-node-communication.md @@ -0,0 +1,181 @@ +--- +title: 控制面到节点通信 +content_type: concept +weight: 20 +--- + + + + + + + +本文对控制面节点(确切说是 apiserver)和 Kubernetes 集群之间的通信路径进行了分类。 +目的是为了让用户能够自定义他们的安装,以实现对网络配置的加固,使得集群能够在不可信的网络上 +(或者在一个云服务商完全公开的 IP 上)运行。 + + + + +## 节点到控制面 + +Kubernetes 采用的是中心辐射型(Hub-and-Spoke)API 模式。 +所有从集群(或所运行的 Pods)发出的 API 调用都终止于 apiserver(其它控制面组件都没有被设计为可暴露远程服务)。 +apiserver 被配置为在一个安全的 HTTPS 端口(443)上监听远程连接请求, +并启用一种或多种形式的客户端[身份认证](/docs/reference/access-authn-authz/authentication/)机制。 +一种或多种客户端[鉴权机制](/docs/reference/access-authn-authz/authorization/)应该被启用, +特别是在允许使用[匿名请求](/docs/reference/access-authn-autha/authentication/#anonymous-requests) +或[服务账号令牌](/docs/reference/access-authn-authz/authentication/#service-account-tokens)的时候。 + + + +应该使用集群的公共根证书开通节点,这样它们就能够基于有效的客户端凭据安全地连接 apiserver。 +例如:在一个默认的 GCE 部署中,客户端凭据以客户端证书的形式提供给 kubelet。 +请查看 [kubelet TLS 启动引导](/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/) +以了解如何自动提供 kubelet 客户端证书。 + + + +想要连接到 apiserver 的 Pod 可以使用服务账号安全地进行连接。 +当 Pod 被实例化时,Kubernetes 自动把公共根证书和一个有效的持有者令牌注入到 Pod 里。 +`kubernetes` 服务(位于所有名字空间中)配置了一个虚拟 IP 地址,用于(通过 kube-proxy)转发 +请求到 apiserver 的 HTTPS 末端。 + +控制面组件也通过安全端口与集群的 apiserver 通信。 + + + +这样,从集群节点和节点上运行的 Pod 到控制面的连接的缺省操作模式即是安全的,能够在不可信的网络或公网上运行。 + + + +## 控制面到节点 + +从控制面(apiserver)到节点有两种主要的通信路径。 +第一种是从 apiserver 到集群中每个节点上运行的 kubelet 进程。 +第二种是从 apiserver 通过它的代理功能连接到任何节点、Pod 或者服务。 + + + +### apiserver 到 kubelet + +从 apiserver 到 kubelet 的连接用于: + +* 获取 Pod 日志 +* 挂接(通过 kubectl)到运行中的 Pod +* 提供 kubelet 的端口转发功能。 + +这些连接终止于 kubelet 的 HTTPS 末端。 +默认情况下,apiserver 不检查 kubelet 的服务证书。这使得此类连接容易受到中间人攻击, +在非受信网络或公开网络上运行也是 **不安全的**。 + + + +为了对这个连接进行认证,使用 `--kubelet-certificate-authority` 标志给 apiserver +提供一个根证书包,用于 kubelet 的服务证书。 + +如果无法实现这点,又要求避免在非受信网络或公共网络上进行连接,可在 apiserver 和 +kubelet 之间使用 [SSH 隧道](#ssh-tunnels)。 + +最后,应该启用 [Kubelet 用户认证和/或鉴权](/docs/admin/kubelet-authentication-authorization/)来保护 kubelet API。 + + + +### apiserver 到节点、Pod 和服务 + +从 apiserver 到节点、Pod 或服务的连接默认为纯 HTTP 方式,因此既没有认证,也没有加密。 +这些连接可通过给 API URL 中的节点、Pod 或服务名称添加前缀 `https:` 来运行在安全的 HTTPS 连接上。 +不过这些连接既不会验证 HTTPS 末端提供的证书,也不会提供客户端证书。 +因此,虽然连接是加密的,仍无法提供任何完整性保证。 +这些连接 **目前还不能安全地** 在非受信网络或公共网络上运行。 + + + +### SSH 隧道 {#ssh-tunnels} + +Kubernetes 支持使用 SSH 隧道来保护从控制面到节点的通信路径。在这种配置下,apiserver +建立一个到集群中各节点的 SSH 隧道(连接到在 22 端口监听的 SSH 服务) +并通过这个隧道传输所有到 kubelet、节点、Pod 或服务的请求。 +这一隧道保证通信不会被暴露到集群节点所运行的网络之外。 + +SSH 隧道目前已被废弃。除非你了解个中细节,否则不应使用。 +Konnectivity 服务是对此通信通道的替代品。 + + + +### Konnectivity 服务 + +{{< feature-state for_k8s_version="v1.18" state="beta" >}} + +作为 SSH 隧道的替代方案,Konnectivity 服务提供 TCP 层的代理,以便支持从控制面到集群的通信。 +Konnectivity 服务包含两个部分:Konnectivity 服务器和 Konnectivity 代理,分别运行在 +控制面网络和节点网络中。Konnectivity 代理建立并维持到 Konnectivity 服务器的网络连接。 +启用 Konnectivity 服务之后,所有控制面到节点的通信都通过这些连接传输。 + +请浏览 [Konnectivity 服务任务](/docs/tasks/extend-kubernetes/setup-konnectivity/) +在你的集群中配置 Konnectivity 服务。 diff --git a/content/zh/docs/concepts/architecture/master-node-communication.md b/content/zh/docs/concepts/architecture/master-node-communication.md deleted file mode 100644 index d0357fb3cb..0000000000 --- a/content/zh/docs/concepts/architecture/master-node-communication.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -approvers: -- dchen1107 -- liggitt - -title: Master 节点通信 ---- - -{{< toc >}} - - -## 概览 - - -本文对 Master 节点(确切说是 apiserver)和 Kubernetes 集群之间的通信路径进行了分类。目的是为了让用户能够自定义他们的安装,对网络配置进行加固,使得集群能够在不可信的网络上(或者在一个云服务商完全公共的 IP 上)运行。 - - -## Cluster -> Master - - -所有从集群到 master 的通信路径都终止于 apiserver(其它 master 组件没有被设计为可暴露远程服务)。在一个典型的部署中,apiserver 被配置为在一个安全的 HTTPS 端口(443)上监听远程连接并启用一种或多种形式的客户端[身份认证](/docs/admin/authentication/)机制。一种或多种客户端[身份认证](/docs/admin/authentication/)机制应该被启用,特别是在允许使用 [匿名请求](/docs/admin/authentication/#anonymous-requests) 或 [service account tokens](/docs/admin/authentication/#service-account-tokens) 的时候。 - - -应该使用集群的公共根证书开通节点,如此它们就能够基于有效的客户端凭据安全的连接 apiserver。例如:在一个默认的 GCE 部署中,客户端凭据以客户端证书的形式提供给 kubelet。请查看 [kubelet TLS bootstrapping](/docs/admin/kubelet-tls-bootstrapping/) 获取如何自动提供 kubelet 客户端证书。 - - -想要连接到 apiserver 的 Pods 可以使用一个 service account 安全的进行连接。这种情况下,当 Pods 被实例化时 Kubernetes 将自动的把公共根证书和一个有效的不记名令牌注入到 pod 里。`kubernetes` service (所有 namespaces 中)都配置了一个虚拟 IP 地址,用于转发(通过 kube-proxy)请求到 apiserver 的 HTTPS endpoint。 - - -Master 组件通过非安全(没有加密或认证)端口和集群的 apiserver 通信。这个端口通常只在 master 节点的 localhost 接口暴露,这样,所有在相同机器上运行的 master 组件就能和集群的 apiserver 通信。一段时间以后,master 组件将变为使用带身份认证和权限验证的安全端口(查看[#13598](https://github.com/kubernetes/kubernetes/issues/13598))。 - - -这样的结果使得从集群(在节点上运行的 nodes 和 pods)到 master 的缺省连接操作模式默认被保护,能够在不可信或公网中运行。 - - -## Master -> Cluster - - -从 master(apiserver)到集群有两种主要的通信路径。第一种是从 apiserver 到集群中每个节点上运行的 kubelet 进程。第二种是从 apiserver 通过它的代理功能到任何 node、pod 或者 service。 - - -## apiserver -> kubelet - - -从 apiserver 到 kubelet 的连接用于获取 pods 日志、连接(通过 kubectl)运行中的 pods,以及使用 kubelet 的端口转发功能。这些连接终止于 kubelet 的 HTTPS endpoint。 - - -默认的,apiserver 不会验证 kubelet 的服务证书,这会导致连接遭到中间人攻击,因而在不可信或公共网络上是不安全的。 - - -为了对这个连接进行认证,请使用 `--kubelet-certificate-authority` 标记给 apiserver 提供一个根证书捆绑,用于 kubelet 的服务证书。 - - -如果这样不可能,又要求避免在不可信的或公共的网络上进行连接,请在 apiserver 和 kubelet 之间使用 [SSH 隧道](/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)。 - - -最后,应该启用 [Kubelet 用户认证和/或权限认证](/docs/admin/kubelet-authentication-authorization/)来保护 kubelet API。 - - -## apiserver -> nodes, pods, and services - - -从 apiserver 到 node、pod 或者 service 的连接默认为纯 HTTP 方式,因此既没有认证,也没有加密。他们能够通过给 API URL 中的 node、pod 或 service 名称添加前缀 `https:` 来运行在安全的 HTTPS 连接上。但他们即不会认证 HTTPS endpoint 提供的证书,也不会提供客户端证书。这样虽然连接是加密的,但它不会提供任何完整性保证。这些连接**目前还不能安全的**在不可信的或公共的网络上运行。 - - -## SSH 隧道 - - -[Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine/docs/) 使用 SSH 隧道保护 Master -> Cluster 通信路径。在这种配置下,apiserver 发起一个到集群中每个节点的 SSH 隧道(连接到在 22 端口监听的 ssh 服务)并通过这个隧道传输所有到 kubelet、node、pod 或者 service 的流量。这个隧道保证流量不会在集群运行的私有 GCE 网络之外暴露。 From bf53749cf640ca22f32fa43f1c5e438df75d6312 Mon Sep 17 00:00:00 2001 From: Zhang Yong Date: Mon, 29 Jun 2020 11:17:33 +0800 Subject: [PATCH 03/99] Remove invalid /static/images/metadocs/ --- .../metadocs/jekyll-tags-glossary-injector.gif | Bin 41295 -> 0 bytes .../metadocs/jekyll-tags-glossary-tooltip.png | Bin 37485 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 static/images/metadocs/jekyll-tags-glossary-injector.gif delete mode 100644 static/images/metadocs/jekyll-tags-glossary-tooltip.png diff --git a/static/images/metadocs/jekyll-tags-glossary-injector.gif b/static/images/metadocs/jekyll-tags-glossary-injector.gif deleted file mode 100644 index 8392c567ef3ac92bd68e1ed75f104247b04b0ded..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41295 zcmb@tcUTk8*EhWBp$DW37>a=O-b?7AS1Afe?CYbYU9K|nyT(4?tI?;uJSM5=%S zh7JOXieLkt_$|NR{oL2{$NR@S*R`{sJ#*&F=bW9{%*<}|^mP>!owp#rfFs~fqM@OI z!w_H?6BQ%lnKNhD*w~m^Sy41d0RSWegCN9Nq$L@6d3i-dLwQP)!5 z!be+M+sMes($exWIoViQ7@PW98;7`98r%3?@(4BcjBs^z_4W1j^KcId4vCJAjtGso z>Ko+i;Fjpak`}_A6~dMr$wLgZNs90wh6M)`rLM=`NKF#XPd=ZYBSy?qC@hf7&6i3@ zlYLZh;Ze3gUWLl73e}c}q7N$++a61|H7eCq%M`?(8)}susFRu*QW@)2JUx~;JytpW zE%yBjQ(>b__Ol&kj$wyguY)jc{xBRa!x3>V%Rym_NHGo`oj zPG@1${N1X_`l`{+w#oLI!NIQ4&po3r8~VowCa1?nKMxId_RQBlnD2hE+&;MY^}zD< z_~PlY?csMT01?Z|PY{zOs%oXF>1OI0q+YbUt#6v;;E@w?Ez!ffz$+p@DE#KNh=+ke z#qrUp-U)ZY67!;^XYNj>G6~0@%H<5y%mpoD;fuyT82BjCtHSR>tBp@yl+yv z85$by?VBDMeLFZZ_iA!+dV2cZyLXdQ@7|3Mtj`XuEzF#rjGdkg?yb&!-F)|QZu8y3 z+RXggyOr&w4`0^S)>hYcc6N5Rw>H1-t{!~cK0Vp^aj?6)_jzsa+s@aYJ712->DSM1 z2Zukt{rr7;divw&;IE$k|H!z1K#^`_Irk}*iH?<}mWG**l$Znr^tVV~OUpt}Q%_Pt zQtA`{=p>wRI6p870Q>_&g2)AETf0kW#4-Q|XaN>-4H0M8V4Q}TnbDty{yqP}|4oN) zfIqf@DbYW+{wx3ggy`MegIxgtWJcC@aSL|!C*wu{fU>&cg2-bAHcFQBhK1n%;C(V? z3?dT*066py_WT>O{=qJPW0AjftSq$1Iv4;zQad{bc>)0KAO7fTuAXE&w0}5C1h{#h z29PiAk}uR;y`0Grqg^0l5r6+cGNwb4v7pQUFy#3^u(Pwve~daid;SOi?F_jlxn*td zV4RgL(C`nYCgaWk7ZX!5W+3AsZ?Z@K z;J03(*o$OL);|U9x&~{JqX{qrU&Y+A1vh@L`HvA0GoJ+=v)1R zU4jBF{%HVwEx^y@PlW&2N%C^n{}MhWIP`1Yx#%6A3IBtURr<_AgK7RT`loUt z&hM}8PObpC@9wAfM^273q&E1P<-e6DLxQaS$jMQJtoS$^{OP`b8au>=nEeS5nH&@h z7y(*1ZrW4kT8@qeU$*A*rI+WfJ4?XMcXzy=xnL)oEfP-UnQImeI>DX0Qe5kQ~* z-6)#wU!rgwxHcRM*M(pBR|2?_Y5S3nAi(?oAu}YGxs%-sBIg1BI`Ln7unpJ*Yy~z0 zBf;hYYhdj!EC0B9#XBzOe^EyR#sGlXQ5 z{u_$_+YI`Dlz0PfWG%!0tqDnjG(ZL+&mqH*PDl%YhCG9`LPjB7fABw~b^i*F=YLwW z_=}q_*$MA|btE21Y)kz9NB>_}oynztnEkm0!6EM9A>`f%Xa(XTg1kMwLeLuIN3uIw zKfqN?1T7^YDGvaD9`Jv3$m4(i^0OP<6@Q&Ow)`1;hA2=f&xIHplDD$C>4|iDgYIOsz7z1 zHqdj>FlYia4_XFogT8=He}W-kYA_?16U+}52P=Rzz=mKeumji=d=(rCP5|Eo=YvbY zkHO90=im|W444Go0e^!45Gn{Wgc~9XQGjScOd*#b9*`i&bw~;%7g7SLfwYtF^b~{y z*@gUo!l7rNXs9T;dt#v%p{~%Y(Cg4NXaTem+6?W3PC=KU`_K~@4U7XO3{!&X!)#%m zurOF6EEiS|Yl8KYht4|e5Dtek!v)~-1j@eDDESVw$EQX$VFrI5PFOUM9Z95NSKjqFBFA~%u0C{PsVPbrir zOex$bA}BH_$|%|?UQ?`7{Gz0%6rfb4w4(H(jHS${tfB0uT%i0)MMcF!rATE?-K8?PbewcoX0l~n}pu^zCkibyN(95uT26Be?jMf>~Gx2B2&h(#IXM{5f zFzPeY*t4b7&*=F4`At%Yro9m+1mZq6RYexJRcefKQmS>>~? zXH(ABpMA>#<`Ckr;E3WVvI0$BE;-!`aKZ%f-xv;qu|i;p*nvK6mDv+BxrY zIp?08`+#ObYoPtm`RG3MJ~sz9mOGTYn0t)-7monXMV>gGr#y?il)MVO9=ticFL?L) z&hZ)ZMe{x4dwZVZyux{}^Lgh7&mZv%@Z0bc`CIt61Xu<11tJ9=2`mWG2&xNS6)X{) zz5u_VaKZP&y$j<)U?Eu{FQG!A*TP_7Ibm<%d%_bUFcC$O0Fe@rSy5_HjZ@KUqK`zE z#hAs6#NxzS#6F7iiC+@GB|a#AA|Wf`Cs8KxPLe^=Kr&9UUGj^Rkd&)bq13cAjkK=x z4e3_t&oaU??lSjf=48*v8p{%8U&tQI$;$=F)yQqj^T|8O-<6+LU{o+uNK+V6geht& z-camR{GlYL6rxnG^hsG%*;lz*c}qn=#a*RLWmT0&)mgPzm86DNb5bi(BdK$%JFAzd zuV8pFZkTe+rp5&gAC1QvA2lU3gEX5okF=DuVzhd+A=-M{DcWN?3_2He3Uroqd2~H> zAL;Jv$?8Sv^9@0~bBXge7k!tzF8i)pu6eFIZWy;5w{3S- z_bm5K4^@vWk1bDC&uq_aFLke6uU&5~?*i}7K3JazK1aT$z7@Wwel~tj{gM7o{%rva z0loo!fn0&%ffG1kTq2HiRq5*OtNTHQLFK`qV29w=5JvKJXEapsG?Wm!d`<0I;kEB! z)?p3d^x*;FqY*+8$q}28x{(i~pi!<-FQU1lW22X2G-8UcgRZ+=e{qBNM#7DCydJ(X zmNM2i_EnrjTvpscyiI(20%rm~VU?gqc$7$+7?e0mR3<)1f+l$S@_&x*`i%{I<%&Ozs-l+^$y>i%sameyb5LtH4C5K<+z)C_voJ6y~+ES`!x?ZAEZ9` zS>#M7ZLPJgC`Nq3VXPQ!)LCq1( z`z>BAq*lAui8h0_7wyXJO&ww#6`kCjgwG6 zy|%s6edc{*{f7NR1G)pfgBpX+hE#_-hn0rgUMjq78Ic=l9+e$!dL{d+X-sac`L+D( z)^Wx0_6e1V?n(8@=Tq8K1JnA`BQqv56K^iQnVYqrCC$0bZO!}5e|~%I?XP$E1=vE$ zB5E;riDRkc{e|~WNphsFW$oqB70Z=(tFEg%Yr$*3*Aq5qHgY%5oo-fbNo{p*>u!&K zxcpe_t!rMeLnq?_Lc2x#evMhi*IJ%mJa<7e;uWK zXZv3HL*d8ZPn(~czrubae&-)wIBq{NJXtvPKRv}c2RZ*WCxDQ1um^bq-^~2&w%hUJI@DM64qt@Ex-lQ|aj-#!0tAm-mhWCx`+^cgLkYah4 zb|-lARh}x5mgeo(&8c$pY_%?S+08d)ms9T_x6AoY)%sUh$0*AOysruTDkjPygPU(B zcH};3I|^7Cw_7z?w3q*~^~lw-wxb|>ak$J0J`iM!Gvd}dK^>G}`zK~e(9T97^F3q`nN z#BQe*^;zFC=N0zzx%u!E{`*NKDdIIlE@>jo3Z%YQm{NJ(&6nGrWm%f- zd=HYD*#(Qk-eA3RqCBdrDl_?$9AcO=Db^GtCWvW$#tF| z8&C4Z*mrKqls`}8=5C)(XTPZ}yw^Bw?Yq}B=kaK-G2L%Rw0ZH`jz90pb>EL|Tjh^F zwy&4J6YKb7@hhNnr@%0|YB^KP;ML`;49;%0(y{qWBcj-X-Qry^o)+?!ESqcV9$^`oL!M1o(5 zKJW{Esort->yXGh4(V}90a2+5@%Np?@3Ra8!m<{IQ8B;I(c=uv{UYN)H&m@caEoi-%0qeCko5< z?`f{h`w-JxSA6B~f1iw86$x7nI1{5Vt!3D)uytMdRm=Eofu*C(aNqli8z!svKNl;X zoyZK-r;7dDYOZh$+YEY7+d=BwT$0`7h#Iw!_h!6uMCv#_{(Ufg>UjKZ&hz!PgSTOU z$5S0qpHz=tq&`sn;aB)n_2=ZHE2=*~W;_f3{`r~ujpLPu4E4jGp8`*hPFCL^zhvnF z1w6%1?VJNsAk;RwYh(5<7lC*MpF`woFAqmie2tV-y?Jpz9!}VEcvQ_LF9NOPE@|tDU<}opdR!m{C|^;6iR4!G6v8aEw(~(C2fSw-JebHUF7n z)~%c2Di1jI@(0!U$5Tgq@1HZo4$9R8W(rL6ek0lH=)&o5nFp6~Zwu=0Do!TmQ9JQV zR$;LpaoNJqH3N*CzUj5voN}Y{XUwY%%&MhsJxyCblPWlJ$@=x}&u1PQ;2FZO98c`VN;3^!FSt@hT*^F2OYVBVo$A> zRgPQDJXacu!;LDnsE`x78=vpJJbNBRA!MAa_JxprP)Vcp(;%yQvTR{(3)`P(cB?w% z25U^RyxdQV0=CBT!A@tLs$|o=@`(xscOJ8N_QCvt>`JV$4~ST8l`q*;WtLv8*l~Np zVbZEv?)JL$PS})AcSwaxw5#z0p%*pRYI6gj!tAmatf5&=k3XhbW6Z(zn_WyUQ&$&mzxR*_R$O_24u&KFKK6v7qMq zyrxH9oQ2wh*O?pB6`oko{j%(7KTJ-DIT6)Zr+h7bT_!cVzhIkHSQURvOU(4Yye`K4 zeEH|iSPfqmi1UW6FPnJMaMN8YSK)UbE*-VctI8Lg>t;(I=Z} zzXCu>dW>^NgHQNpD0lqO~LH~&K^OrCw_|k)q{M> zF4w`?f7Ro1mFsnj7D5xvntz1=QcR)xRdI6xt5c(GPxlaST#-%jkRkMUd8pcHF1=qXT_wWiy+iyATD+dB!38Lgv&OT zXAHd+eMbY9ii4u7ac*$8=biCR8k{wLNs~p#w z?AlB!nP9qbC+N9aEi`ujgT<9tI-^YRowIc?#)VkQr-vA-OQcwRs?URu9ZKxl=EiZf z-v&+k#d4|My82mPEV5y8Vg>f$+IKZT7GBVE3}}M--B=3fempOE0>U^xPwxrz07{+E z3v0_u(Un(Q;M{S-eKyoUW*l!b4m_$9M@I<&Tz&%|g@HIao^d=6@-s-BZ)Is&wilke z@I+k1i9Wp&+;Rc~;ly)(K&(yt=^o+0YFovW;Cz{LfjL5a$ptN^h1d`h9+W>sJd51 zIjN3me(-I_;NV2(y(5Fg7xDUcA2k#76=Jf9snlh9S_sV|*w-)IP!TT;V(>9i`}?U+ z+F<1QuP_cgGF#8ijUS07!QC@KF*qEvL{z#NGNK2WfQ}-Xxj@UWG7ULit_7u=!KrH9 z+~fknosji<-WQ8ta=~y29+6-M3hY6C?e{I4y-Kx@U(@tR#DJ4$MPr>nq5H^PCc9_= zjKl$9IQIkqJOH;?YVljKv2c?oyn@;$v=d4U`+X_k29rmbb z9oixU;C!`_Q$*scewbh_GHeiGI1bMMz)mE{euE@3xq`Mh7&Iv9+N{qq5;XOBv zGQ+jCJct;u6Unh}Fhevr0ZQ^=mH@7sA(=?mZ=#X5D(i-Z7Z^6=6>UoKLZ}!nBGR-aVZS+&+ZLQLo`6RNB6@Bb zlVDY$vTn?H)vqw&9y#an$BDhIowgZRUcMrgp!2?nZgoKJRf148k$i1b=0m05{321Yd~84rLx zS?{gY!vGA-4g+(*!Fh^&zrTQeeUrcjz^&1#X+?0RT9EC2>7^c|OA#o^Nm?<_%d`UQ zga$)vaq^T8)!TC=h%l=nKp@jgnh5rwEK90|ab$XR!huK$4-+P^ZKilE8n}RmNmIgO z$Dy~{!cXXDouhR@H;)Pe5N@kl4t!;mblTRmO4pfx8fX5zBogc&0u#*+f%{)Ve7K$G zf`M6~;UVRS0E|;48g4j%a0PiSo zy)R>`LorT#gO9Ekz>-MSIic`!rPwHmQd_f%GlFpIo<|Qa9_U?0Gv`t+NBmD!Hc{?dTb>DkCcG_*siK<4tK%j->%jLowc0}t@_Albx|;#Ei(Ou ztUa@g_+YQXgHolAi%J)H#lJJywZqg@OU3W6)@4oCaZyQdp4A*us1^Jb^P^E)pzx$# z&rXLSMW3~rLAqaZ&8^~ne1o{vrHoK4p-8p*qP)7Hc9KlhYp=!v*=v#=CN~XC;mX+C zWm=*gchZ#_z~@cTGL3qSjrSgEX`F3b>uX~CX>6$6Y$MpDJaDaXTleCls)gJBx7l;t zcl5@-H?DZLFt1zBB8=NYv=CGlZEOsVTlLDR+Ls6|h#4z^)K=(P{o~u$%)M-5sTh_r z;T+nnKV(|2!P@d4X`ae7-5W{6o^9uKYZ9EuDKKnzDQo8+X`kzFJ;`oA%BgzWS8IOT z1bApsFMR3InsMz;JK=2mr)k=zjt)A5#vWlkkIhicrkLShogA`l=O%LI%G63vsJbGi zZJwoei7D$2oNZ$$tL;c=l5OnrOSRo7Y?aOKegkVCKC6+{*DbHBqkO)5ZlFu)u**6> z=1ZZbaca!f>1Wz}U0lxTFUp?X7V3GbV~b3CHrU*c%e+)hdNNtIFMy^m5uIIGz!K%U&VCxY7EcxT{`2yOeJH@>tOI$wxBee z$5+*XT3&y(PVG#;7qwzTaQ~IwfjVA$6=}EU4Fg51{R=DoBj1$6rTdu-~#Sck0sP?&Qm>8+@KEg&WG}OBeM@4Jg6&ZY>qJ&9H_h=X} zN>lE;IFLrISiL*&nn^q-t^dN*K#sIZWLdw5k=(dWe|E4!m67r_4&7;&K8IF#hrM}3 zexrDEeS#&y!peS5(5_3Qb|h3=>rs8Q%AlF0?v3nGsbKxP`c0v0+AsXNI`68gzk4;( ziHX>HHPt!t&QFz#aqKg7!^&taW20Q@yWZ*Fy+`(SXU>YP{eIP-Gu&Acjg4g;sn?61V`5dT6L1oVUj;)QZW5wl4oy1m~-;{ z;-u)4$#Y$kGWRCsp1>tJr}&>t$uCZ+9Zzz;nvy!6;uW3N-kVZPpU{t)){U7qc`|)r zaoYHJTETe6I%dY!c+yaHhW&WTFlI_NecDd-jlJp{wCJ>R%p|cEKKg}Wcbo>tIUA%p z8{#l~EoL_S-fU#oZ1m#n_2XGQ=UklXT!O<~V$599y}9T;nv})4^jC8?Ip?!f=W`t9 za~EebW9AFG=I<`fCmE;b(7!EFeOu=6wtVqSkw1NvD*Yo-)+fgFPmL$4kD2Q@8Jp6X zTVA2s_UJo|*}7iQKZ|+$LUkd6exWaB0qVRk)U`0WxG;9SFwVI+d7`>F?XdVJW^wM` z;@hspg~i3C<3$qZ(u(TRn#0mY%+l7qr4L<8yNgR7kC*m2-+xhkf8g-`Fy{UDd+&dC zz5l)V{^a;Qz(oS9k)Vzw_;nKUK8doMM7>0!Jt3jEmKoHR86B6IuP?LSUuN%K=2%+h zI$1_@t?;O=@HwvVUtbZtzd}>905_*oSY8q0T9qmUazK3!9*w!_$65!2+)D zq@3)IJ2Jfk5V|JmQ8m>1TrjK|w4rD_e{5}sM5*rty^Ep!x=*R(1gXN%9v0C)ae`{2 zDRtFQq#nvu3DmU!y7vGAi}|=pT6sQBC80*$F#hpL5v4kc%FHBv7eKsnqWel(dDcUL zI;GM_!L*C0B*ti1Z%|fAKm$%F+fjRbS5Ced)zN$j*va6cIs|Cdim3PZY1Hx5hp5d0 zHN;&r+C36w{yy#YIAtM@wv`J}gs0s>Axdh#eBFmOkyiHhp)YF>?(Wkr(?WGmDC>aL zGgs(H7*Jj&%{Fe8=F`q0n(hgP@^GI@W}Nz{h(;B+xkrN3;c2%e5Mrc_J`y$mv!m$1 zcZU*tGh(P0_`|0FCD@$qEdV_zqPc^idj~*w1L*elA#|ryF9PTWQP8hyKV~qfUKF&T zhDKwbwigX85JQ&2ytv@$cc8PhvumhWL4rvq&R92fbQd{%RjAr zD1yFPIvRTLTN(6SUX0rAL>-|~OVxs>dJI56*V3e`Q!6-8wMrbb)KVYrQ`VwU&zvA_ zxRVw$Fr7MTXCLDHk<#lEWwko$nFQsdK&l$k&+k#NHPS9bk`ACp3{_d;v@bRcis~yy zec7!Vk@?8-B=T^#DOK~;itbHL)$33;i#2T4dE@)qcP!Qoaz!1w6WA;_j0$A^m-_Bl zZkpUzjX8m`%Xs$tTe4a=&Q`xsQ7p!P{?KGtpz42T3uZY<<@412<1R(~#m_dV%AUrO z2HU#(!ghN_Dh-hbd(u_uT*KwG8RpS$HyeFoe|wpw|E+e} zPFBJh5v#8rWA{{VoWMCR9e7PXG=89aPf5^R;ihQZ&cx^vhdUS1y;?r)jA}-=i`{P~ zpZ!69-Duh7BT8mHn`eZ1O#_ka_kyvU0V334uKj^J5|@9=tu0EJVc&88sJV0;dAPUu zjCk(KN%YTe>MZX0`$Sw+pI7vI54LKY?;v6ey#sq=gXm< zB5%v#^VjKl?x(KJ^*!b5`|QP~P+;y`8nH14y&vf)@~M!@?U6wK>8{40@UQDoDJ(aU zuO7>rp&isftusux&ErBpaX-RwVmbG6O68v1VB=?QM*9+^`v{c_+u(iYNCj9PpT*}} zrB~qCPb{2XZ6^fcB_Rt$3SU7d{&`@QU_)s{N#-kFToDP%q7Ww-eE&*N(faLk_C0>I zc3FKgmd5hyjh3eBFxiLKYHsPWd-bu6-S=&LSzZ!at0BbMP!>B_64AJQ{#jt|vOD{d z-)h;L^w#Z%d438hxICZk=L7enYQ3j)0{9PxIGwJ=4#=i9&iAujty$hY)-e6#r7&hLz8L&U`pRO-b>WnI zA@f&SZhsq}dOH-d5cug{>4c)D(9Cm%a{=Ki4yIgXZ~eu+L$(Q@RK8DZyg!cIpc!*G zTD}#=d2r)No>c#bUV#TSUo$q3kKVpN_4@gygKqoB{JV;0-`C%%w?-f7Mc&^7hu=Fn zHVG3_ocnr0si6L~i7yt-c4e1R0dw#$Fg$+Z+_y=D%IVCfFt*WiCz|qVClO{*yfWn7 zA*?#{wQ{a6cxP&NWN*~yc%oz(Le&kM!T!c9QT4!?IzGJj><1iCMaG5pQ*mzul0F%m zuzV(uwVzvPB1yZ?h5k{i_PHZED60Re;@j0slS|WLyV$@OWYo1N?io~*@_LZ@TEOkac`n`OuOD`sKtrm*eEt7Tq zJf!Ys<+usveIK^2{+heqsdwR9>&vSpS;V!nO_4=?o#^_k!e2(~@~PjkeAmm9-|nvR zF}07&)kqev-*r~%{ce_M&6pq0C9MY>)%5fINjshVGYiJy9Ra?Qn~r z0I6zThia`rg=wj31|mkb+U!-nW$IYNJ&Twsn&C@&K|Hc44*tTX@hLiwg-iwQp9o4$ z6`YtSzm$C}0uvTGQkqK23aO2c-f^D4WN}sL_JboUKR3_zH;w!<<%FDFuJ^4IqRq0k zM1Oa>W1%^t$hx|>Y0DZQJF6j!?CKVg4Y{@?!~2uD+22C;EPq@u5o?ya)imSfCH-R_ zU7cG~L{s4@ZHQgIf0$;#5n%Js&^X>ByEG?#GpOmT-D<#W$NQ!&Pejzz`WWOX3HCHt z`mMu3^K92Mrl)f9RF}R`=l6_5Jd@%~8cv-GAcFYga!Cos!g&*hm<_Fc+vA@XyX zYYu{VPL<_h_-y^>CpcaAmn3PEmL7(3T#{$LQ`5;y0_#U{cO4@v>gim+_`uVY#nhD( zLJ;eK{J_M4I6H{f@kr;#j3DZy}xUs?yVg zo(D|zH0Pr|&lcFcw&0gBNL|=e5-*sLNDD5~8P!6oNA~3|1(xV6pp3%aPCbB!RthY* z7?1Q$NIyQvHofO={n+c6LFoh5GirfNLie zb}x4V!fFEZKRBJ4co&#^kT+<*7yik1;W$8|omUu#XR$91;dhIpSn`|^i+&my()zqb zsW0kW{+#m7@DAyZzR9Ugt8%}^gINp)v|pDd^3(BT>vL#RpB5Gu`wKJAvVYy1w0{{L zAo#>#=}O^^=%;7TwbtAavn%@bo50d?ME#^Q+l$E7BXjM1*^cBli9yR3pGVX5x4j+4 ztM3e>P99#mGPY9l@m-JVr+u6BJ*S!vEjsX<2iBqvS0ALZ_vj3MQN{4ChV-#W$}WVl zv|XnQ;e&HZ7!#FSO|-%o)joS|u2Y3ojdhA;am73%4hwYKI#q}6C=B|soqhI3f%(LG z!Y|ajE-LkBzb{isJM_0_>HXktDcL%GS=VK%PqeSJek_IS1%}0n(}}Kze(yg$`1Hzn zv**J&*92NqCTa0?%UcM$b}M{xFw)?n_9{@%n|ydbtBrjH#zTU8>Q~HlAi~f+ zHgDTlgAf7ir8hnZa=gTpuJ9MW>>1V)@(SWBEO^-Sq5Fwzm7))EK3=A_T4+5;l#=nn zyKKajaS$&$?sTgAO=)vFdpF*-^{i#Ld2cHxm7;XL8bBfp_6V9t%RZlj0ZAwD3lnOi z6pbtNr7SNApM8@edlE03!2ktt+e%3a7J*QJX%r}Va(DZ-6088g8uKvS?0i%a;^G{v z3B~t(NS>|W)?OyJidD-d1n&q)tVL+KloCg_i$^h(K_Bk1GEft}c-}fcGE5LyX+YWo zc#qH87q&HsBch!S*u-Ob6E8J_bqW!Bn z)b-l)cQn7&-(E5-)kx^A+EI0#R!*%f)*aQ^eAE|-PrQtQ0sF8Ed}y>)lSg(fk8*d} zt6ZpC24 zRZ?Pj2_|?P#L)u}QRqx*C352-GI!e}`{0~d*b?hdoQzNumdJr6q>LBGj>4lKBPcuJ z5OiE0Y9R8vUVqV}U_li>EMirPm^7^xj750kH0^SV2c!{Ee8j-;V*a=KA>qX@gkOez zhX-#xdDz)HvU96Mn>t!$s4q#-kVo$BC=Ak?nAl3Z7eZvwObf)S1SlX@ei`_o)!#;` zh7I)uqlgV_55riA!6ele4TkM&hWtT@U@t?xHTtWqhK-H-9Wt_;%EYct9RtIm;8vcf zd?U*!9m+N$nM{)r;;Jnotw8^)W?FFV;OpqVlNa^vckbSL?q{&x0BzXMqUS9z3fXfXpAU=HDa7{*n5G=95SF3Zm72_wqZeMp^q?G@zo+All zpHK8nQXA1GShXS?0X)wfh{FsPA|dXF0dow2F7^z5l!@aQk3G0cbR3W6=mC)x9E-R^ z=3rFKNdh<%RsO$8C{t+R357y{3D?5Uyoai7`_ zWP%4n;GT;W)<#_1isev<^G!Mt2yud0DZn6GvA*buy2nIyef7{srK>8ivw#J{D>uXz z#?ceY>y_)UWzM4jc;spa*tq zcfxB62DB0)C5Rke6ZQabF_Y-qL*PWeaRjhL41!YuTx-DuMaQ`pXQXZrNJRi1YaxxoZ0O)M1U+39K(Ca8#fmf0D4irFon1*Q8S1ab5aC$iQTRn%+W^V+PDXyt`>OoDS_z+t3!)ZC(v6Pzs{7NvmDeVFJT z9&1{Q@W6vio#3|NAW$(Jn@_l!4`V~2u2v=(I3>D;$F3_N^!F3|S{*>2VE`ULB;m9A z;T#fisqO?`9R7w3-m*1OsuS)9;P;{Ui`Y1he3ZSPjkg!x3iB3dec=V*EhP{kmjRjnro9zig9%RWFGaa97$i9>wp zd_n1P<~at;Q-oD4K!lNEO)JHt%m`qGDJ07D0RbM;n%KO~eWx$>=3_)828Kw2ha@E; zu&~iK^35kSW)dyE@TwnO`xY;F{z%})P$4!5NwS0#)R;pif)D4Wy-P^M2<*fIS9?r@ zonV$|1S)+BTarVFv@I*H_zE0#q7#4mhpJ0b4c-M{woNU;&zL;S` zMd4wFMTQ==iNX1a#-Rw~q-g`&#H%NnvA(tr4wZv?{wmmUXg8l@gi|8xI5MmjYFtDN zc1pydh~#}g@=MJ0T4G=>an>PGs2fTcNOVNQ9i8p`hCq%ziO3|lV-F};P|F)f^z{NR zCarq4!jY};D`+P_&A0Acw~06Tn>B@Zo4)ue z9MO@>RM-z`ZM!Zs9g7TqkCZ^z+pb#_G=xgT@n8_L>{w2GJo0=ApH3>pMOc^u3>X3- zhd?RrFIUq5YZA>#2s#eF1w!`3o_AYafY}sM0wCNA2v&eu_P~8U!YF#+qY<{Mp~$d& zg26b{xYlzdfsj6sU|74vipq?z_3Rh6(yvWmEh0pe6M`$D4n>K{j)|<532aFTtVvMD zVz?n5YFKnJ3VD_OHou(q%D>a28pqe(|Yh<#;)u7uV( zkw|F=uSzY;${;`2S;B#0YW+#@t#>!;Tom@!^sLbBLT6 zLdu-8^;WFnx#5d~ZWJVfm#yuEC&-XW&?OXg2sVz31hc#a_amj>>ZJ0%`Zga!9oPVmOUKH(VCg@iSVAp)f!8yRydpNZJrZTqC;)0WLdz@ z#$nnkJA_$a2y0xiyP_p)T%UCsMF=spXvAM0xPBw>RFz=y;0r%zTp;;H-yGH+mk4Gx zi~`_Y*9Bkrc5=lQ6Y{W6E8)nzEQ-NRJItsdo)D1;qcu&Wt4NG{L-5H=^e%$8Ya99G z!?3nDDOb=J=~ZC`}Q<8qtY_MvuNqmjMUW4o2|4c4$Qu*%KnS<^=4C z4w>D3t%)=k*urC{u9_n+oZVLw>ga>{D%Q|PqS|2+1SG)n;C45!mrn$G{bFvQ67D$3>bsx zT>iGgLzg?96%D)FDH^XFr5jCLr?Xg^vsF59+oG;=bewWm7iyh@2cPuS_@Ts4a2 z1g8wpHd%jVS6z*Du8-#=eh zyg%2i9{#OIpyRVqQ$C?3_Z{}cZLSgwep-qDFL`Xl@S2-90gy) zrK=vTf$_9j0B%GJ$#e@sJAt&N6F(8zz>N?TNKQQvdRAvzi}&;Kv_b&&EeKErb+@2b zVns2@C`fE$pysXdWAp&(RfG8shJlva`KCC?DL9pOjuoV5NWW&*m+JGd7a{~K zW#`bN@_9*BY;9VvRS%}M%%Mg1$sfAXYZq7wcbtNMrMrEGbIsqWo%r4ZS~N?B7+&Se`>=h=ewFMaIciRaJNW|)zZ)Gndm z%Sv+1P{_jYe4=t#lukWq&c=RWQEljR8a|)N$7`yp%PnXEblIO__abkZQUW>$IE>6( z0<(im8#dEK^`l#3y~>8$LuFN`^i`SAP*{m#E5on%&#BA=ny z=@w=x(-jS25O2XijAf2+y{R&-q!%=?2iR;wu~^@b44IbinkK3hV_K#%Eemlgo?ZJd zQa3e+Ipwik-)UM^G&F*##AY#R#^PN-?}*s=;|7#?HBLYt`zSb%OR1;!CQZW^zfLXj zw*9!9Z*!`_C&rJy<;SPKAHkI#hJ|XuX_O|0>|e`wR8CU8oWtFqIa+#V5+frd0Ben6 zc$gh8^mxqSwQSoi4~>lA>xMG5#8Aq56sMxfYs4BVVY1Wp)NETWY{PRlANp>k)fw?7 z3QqUaz!-CUMtRuYgeMg)<Dhqd3IeM_f9}8C%KdES2y;vP{MOM&9 z{@$~?^-f1-msurvT9k7(Q&&HL0TWU-c)l~Alb!qU&gWukf5)?h=lUT&tW$qk7Uqgys=xy*^Ewj*qd}v_WM?Kv>?O z^_6jMsfd9j#lc8YvQ(%=9fE~dPASX@!UV^dM@*hMi_~As!(OG6|5ch>+9zPWtda6K zC1lj)WhwT8MWLFn-N?0|wfvEA4Y{SZm$QtNw+SCS^{5X}+%w<_$4TrZB&I z+&Q6wzrzLoVacV(s`+5W)8OJy3!#F}wOJ=2%cO~r^6kd$NX#9%125wW$^Pvdcp*7c zhNcsLTWM1UZn^fTOsQn?^OTQQu8q9ZuUBbp^s#W!Dzd)7q>}N=gqK${L#M9q(PYkt zNWLn1%_`9{cKtO=n`9c6&pe^_2SRdoxjB|PvSlBlcfwXutiH^h;i*z~yO{l=|F*GL z;th&jo8%WWVjpK}SLp>}Yvt#WssZ_=*xUT8i04nM1nNl|FnW95c}*oI-Z-WYXo8aE zgD+Oic}@P8nsVpveq?Tmokm8b2rVF99n}1Y5REE%$@N_Arqs|AQ>)v)3qMu(-7aTe z4te1Fpd)hg;nJOtVIL!Dua28*mO{kcDX6UKm=9}A7*inL!j?b8^14AUF9pW@vOJcO z@;&J}E}i@Bd!>x_yI-$rZJb}V!%2Blq1)yCD34*MC#pvehqZ+wZ&5DS4nOJDjyNAJ zr?PCgk*5mdl1#CDyuw80FZL0eSUloVlN>(qTeL3ShQsw_;m}WE>2>n_*VUs&*&!I$ z7cG^u4|q#OhhUmg*YAp8i(NkTi;dN#oTjde2HzQx9q`TD{(9+xbpEKDbntvPhezX2 z&ryk{FR`yv`edit#+FR4LisD z2DRxeOmWMl?9=q8J(0&!nbYB%=It(QzoHLDy?j5NbUuJQX$wH@voN2cuI(Y8{|-9f zt9(ltj!=0kSR9f%D@I}Pd)<2(5qS6gyPQ8ID($~Ux4n~`H9t4q7(BWA$zC*16E0^o z!2T(8x!$?w^=HSXZ&ru!_l5V>e?7KTT|(;hqh=-EXNS7AAGW+M932@N_#n0SnMKS+ zL)VPm-Wj@xwDcbqe80YxJ zEU<*m{E2U3`i$7nBMJX8`9n5s^p76c94R@i)J$2St`m#GmnRofAr>>Eu zY;JFHbKsHGO#Sac)W`b+G4`=G)z7H7ZDZz_V{*T~5^vs&^UOXTGH(f$_;+gBdH!0* z75{JC>Ke&TpFMn^E`D*<-Lq7F=R6O4I11{I?Z|f9SJukw8f%XI`RL`~Vd%e~ug_hN z+N`$tY&W()@3uYD{0i45%XKo6&2wP<>gJF7W*dvq)<2i|s^`Z4w$rWp%x-tWdK+hd zYfXP=AGf?|M;pqao@;x2lLKQQ5clQcu&66A@szgoqT4P%C$(g`J;>c7f=GMI{YSvW zS04)e5+&}`6{?;0=J@G$QDNxYrwsh=2yO8GBiN7j#pf4hb|1MdfJ)v}Q>cbBR71o! zbvRq7b)vz@ftIzTPYH)?ukuYx_FIAr;&3)u2zzh|d$5O9dWn3{$^qy+SEL}%vl7ly zLEica9(p!zrezE10aa0hi+=?99tv{Kl;|5EIK~7y%{;z6UlC9c5{N932q+Pl7ZkEB z<#iPjoDpQ>Smog_<;_~Tbgfi4RZu8vh5xaqgsrCtR7gNlC~3RmyMYxqwdT&MA)ARCAA*zf5{IcYl;C2bmP^prv@a65& z%QK}(n6(5GVY!(SWm#dRi4`6*PvH$usbDX*rZTk-VN_okYD`#trc8ZFSYxA1V^3J~ zXPG8d7!55)Gl^(%lxy*eXkRMVmKD)Kmg{JUVD!o{W+J+_<+`pSdcNg)!6N#R<@&co z3{uMtvP29YmKzp}7(FXDsueMADmU&BG3hHe851#`DK}jbG219N+Y>SWS#C}h!9pvr zOrjPX6&C!WmX|6lWks!!6;>Le)_N7zW}-H>6*jJ-w!Rg%!J>AN6?V5o?Ncl4vqT*p zRyY)kIzFp#tQB=?s&MKMb?&Qh9usw$sc>1MR$QGaQILg8W_c)Vi@HLexiekz;CSZ2 zf64RGGqZ=5A{;q<9Hl&}z7mFzzyeEeOJAY-2_MNzev!}oWRD=t_`C zPYk%##a8f4g81zEEt+d%bwWUr0-mchZle@&^B=y&epZ z77IgGhG~d}>s5xERfcZ>H-y9@eJdl4e8PFrv}dQGT=?iLzv!&Wn8$uG#bU7!Dr0N? z;<7er#RpMAVmD_hZ_ ze$R3}qg6a>V=J_4iv{d*k19@p2B4R!vN$Bt&HS_JpFfb5$e9qn&n=N_RGBO}7=e7A z=PL2AV@?kh5SA)-8%avm@Bqr44aPAk7HCSS*o0lT_ z=$v>#)|XpMq&g(&)&@XjCA^Rwp=ATm@v34Enj~J@zHA&4&rc0d8cBi!Xz4jxl~W)r zRpKlspnfVD#t&5NZMDjZi4(ie189Z1?l*c;w=?`-xW4Szle!uD{5i5)6-&A_m84n# z0O>SRXXi5DP8oYZg4``9O?w#w3WI9N8R$smJ_o=cIZSs=sJ6;nxBM|)c0s3I<7@%6 zlHa9_)+L-abR{{Y{i< z(Npcwl2MUrC=JYPt)6xb^3-?^6uh{iSghVg1BeHXaR55)@`8VdPOmVG4Hdk_N(StOIq<&UgXEq_KxJyt!R( zW&M<@yT#hNRlm~6=F+Nt)kd*&hbjcp5NMWZ@CpUhz}!xYrNl~8?M_$4ifWR2gZ9Tn zSs-(F?2n}Q@ph=Hj%qp0sAu<80_|lA4eFEzKy8Pv?!MaARx7M-u-w`)llxIzv4W&M zE8?g5q$S5BRXk~IK8g2h?Gg=1rKkD^!g6H5 zwC$^ZR5?4>eRVEr7831Q?G)x{FIRP`rSI?6c1sQH$ph#sbF}j5iAwQ0bm6;l)apdF zI-S4sNl0h3!blSJ#a?KJe+rE}Lo?2ryH+7SiSAfToYXB3)>0`qQ7xxs3#3skPg0xe zMyBsDS|{!Q)uvg%E0Hp;)+JVCbgQ={N*Cy~mExXD4(_(pafE!c9QzU)J5(fF$#{SV zOz^BMT3`x^76mY&0amVruGB9qT%hN&n*cb0b!0nq1K=}9GaZ<`qp2+ky)4LCZyx)t z6^ee`Bo)55d21p7Kz$G80EB7L#B-86-1V12Ld{|?11$LG=c+*1P*A#9^iQ$q$Dys< z=;+X`na2wFrce<(1%M*u9;zU_`Q0!$prXlN^xyZeiO_W4dRfjl)XPuG#q^&m%+??A zzqz9MM*q^Gf{sMCp0J|Z6{O~Rso53fS9|G8p~$p1D(A};qr$REw^b_NsOE&pJvmf3 zta8lVQXRjd{@yD*Hx#t~Mq~eq=C3!J|E{26ikgQb%Cm2@E{3BdE7hJHGF8iKYbs(s zJ=T^}ROSrFxGCzr<5JCq`h+*=d(rAA9qEUK8{Ag($qm;}Q#8tHFm&r)@>VqIKhmqM zHkoZOl@l_Z4ChD`Qu!6`x}=DOHDZ~SEI1o2E-G1yHCoCkSt&PKX)0OkH(Hx3+1NGO zxGCBCHQI(K*+n(l-Bz+sYqZZ+a>#FVc&g-B+35I6$*H-~={<*%bAO}rxRT3kqsy|A z>t>_tzLMjaG<61Q(RrWAa%Z5{e|pw`de(n>)>%;gKRxR|J?noJs{Yfn{?oJm)3g55 zv;Nbw{?oJm)3g55v;Nbw{?oJmH*NU;ww{%Crf7j^80hKg>HbH$qy@vyv$3&pb90}u z?eynaWEfyDDRu=}HenHADJdyMMa46&T}4?%T0xnWTilQZgjJ+>yvnL*BO+#e(bj;& z#*96{fX?5JJ+3r^J6l`ZSQ=r29L=!y*KE8ayuG~x0|Udu!{g%Oq9Y?i0wcq{U96G1 z=@Gn{A)IM(!ig?o8PT{DU*m{7m(x=u^6y+q&sTnsuk<`$^37w(%KPH^&ro;EQ7siR z&nuN1Un(^>sa3yHElj-F-+~-`qwwz^=-)rikuLR_KDB>TssBOP|EWH%ML%!VX=>Ac zm=a!bKd!k~?{%-x0LsP@p5(bOl?xoQ2+A9W9wF(22==GU=b*Nnbw7@w)@M_Y#f zsM@E8XX?7)uU{scUoCeItq*@#pZv7=@%xNiKYJX096SB{>-FdNwXL1#e}8YD{D|B+ zxHi8LLwb(};0dxyDV(AyY6f>rEC@~kIe|9_k+IK$a3yEf89jXKg2V)@xxttKn|TX}2=c!WNVLSE5rNMWj54OQ{G=A52P0%FN76 zOH0qo%R5ur^YinwGYM4%sZ~#M-c>$)Q}*EDqvksgY93WK=T_F2m6f0Q?3K?dDqE{w zyl5}4Y(ej){Vntox|PT-6JC-gZ;gIL$i~UlM4$A(=(qYKakhw$M-hoKQ4S8oZVbl-Co%I zAGdw|^Z&T*TbpNM`_A$Ao$cN4Ul0GBS?zyMfBrc6d&cPg{PpW__cLW_ zxc&cE^tk-P#Q#tAxVQD6hYPM;UmAJ)W^kmwjU)FQ5dJ>;=t!)E7=h^!{|NPK7^2_IZ z_f(0E0`G?b8;|^-J>Pg7*z{%NiPO;Q5yEZn`)Rz<8_ze3<9~kHe2RxkZV{6?u5Fd1 zUwW}snu*-rDkJDgeksqjz4oP|!1u+MXN4Pdu=1yp+%GDNhAvAMS7yxnzsTJ1=q;os z_a4G{W2YYL*EB6%ld5gqzOnPF?a$D4{`Q}(JFj|HTX*W;{&`$o+ov5DSl=mWTvInK z56z_(vRcLJL?>ZO8OhUQOdJ1Apn z)ouN&PI7OLYwzwgtO|`(x2|QK>^C3T?u5Lh-(=W(e_`{bY(K4&v;2FQ)7=~Ic7(3K z>N{~X2_=2Y;5`^-eo`nu#GvW4-wyfpq?UBKS?#cgGh`v;4Jt&scKo|`{80nzCzJZ2 zZl<=QAsywwu<46#E;oh+#o8g&NrSDr&0n6?{G1PL-u?Lr*T4Id&wn`R*JAW$%`fUw z{IA_#%XpaVF(sKZ_;@8{Q+e-rjiBGr#P2|mDX4BRs{OrD7`69%lbCkq!2S&}`-=;COti#j*8%;9>b$ITz4syMqH9dUN>{y9jaYUU>WNQPq; zdJpjGnY{cN13i~izlCAqSJ%wM+x}W$GYC$r-&Rx7q-vRhOy1>jyq7=WanBsn@TpQTFDVG|t`4zP&)hd&|c_QMEoc z(c77~Dhk7V=|gaEozBWpRkKGIRzyKbpEU*IhH4qT{xMA2d zs&FsprBCZT8rJ?+i!pX;Rc7%SOp#dcWXIJl81Sf8^m_tV0-W=5)@zt2D=Sk^OUjjX zY;&~wj-Tc`JN_n;spoFVlcjaL%ct%y{g~Fc#tyoRj&KN1a9Bt;HNITq*GHt%pU*d= z!gOE-xL(vxnWwnJJT_UPuDW{yC_I{$c8Fl)*;s;zJ|wYTYwS@I7X*y`b##CC4W@3N z3%+pxXuUVA&T%|K^k^r-w^>xw>q=-m$T~b@#I&nbig~efiI<5h47!qQ=Ux@)T)iVY zWlZj(&-rRAT=S^bJYv}T204ir03kHJWtr}pa2C&`ni}I*ZE*ltQN-hp3AU6yj*_H= zF0u9#%uTqzzIpt8NV((O_$%HcKerLv529uufT2o9`H*5*9AFt_;Zr>y9s^VBx}4P! z`sG}XKw`hDBJK6`Zmun|jOoUQicn$~B=&-A>o+OpY*DH$^TRq5C6EKkrJt~M1(2>4f@$vEt+t+>q-CQ?6IR>#FGI_BCoY!-QT^+Gy&hftV zJ~@NV(b|LSeicUX-88JkQkyFjp3Kt80Mj@EneSF#di{r(RyRS<5|f_9n+dv8`qPdX z-=cH%Gdb-tQzcNlh6C35gpuKypP>!&L=0>2ci>UsrU~llTJE)frRs8_+(}-55~cWuJb1H z$yZD|!D85FX7|xF=QFjKqoTFha#<3^#b=nzk4aQk6gE*b@;-u_sKZ-KPLNoIh1@wxf_}GRebIr)PcJTb~~qqQMzME3g*P8D0Vj&k_w{4))j1&wG?6rIG;G z=PKhVlwTKuJ^H}auERzs^t+H>rrxM%#1zg;LtdAn_b7%|xT^ADe-1x&IrSZuAbwaFVPk*|3SzwFUwEr|P`O}ox<75_sJsoh6cpeZ)MI8gQSaBLaew!A+tkBT|cvd1h z;oR4iI-LR<*jb22?uZCnZ%Klo@emO(nlZEr4V03>t($^$xAx=d{9~o0y@^agaQuZm z;%{*Q5TF@ML)%482C!3hegZVKL|mE_fTy#qhIxty66i^_@#BKnvxw_#+(OL)5#6(IZ83g14^x2iP z+-zr&@fIzR3k!^gCAKaf)|>~k2Y|g_aZzMiPI>4-7 zEHwQvz(qisP9;Qx1!xa<3MTD|HJWROrDCQcstP@eHR zdzcdukxfC^xFhbP8GiqSH^?*ILo={$z#GU6*+d3BneHCI*okGl$3ovu42eb~3Rvi6 z?dba583`2nF*JgCGc=b4uIJCtPJx$T?X;8-kVwWH7Ptd3%v=<9(Uwk;lO9uUMdgtP z+tq>Y{D86((|P5=aX_rY4447!Xn+TW$wNQ@#2ko=M1yE?V0nnXyT0~HL`I~Qp?J6< zuG=Ao07bY5q4hv2mtY1g5IbUQ#{@`+jFQEE<3Z8#5CNh+oqdkJ#P$$&j;<4DDHaCYe@<05ihU6qoDz)kSq!f<5q%{7Rdz;(;Bjw4yjE zx(l~Cv9NfY{m8)WAS}q21PgHod9uKG@lLD#V914F4S6cKSplL~XXS^71-ajim51yf z$6UfEa1rh8aCd&TKw|~&szgdPu|u06abgb8NG!;U1hd8wAQCz7k2yULpmu0j=mD6; zMoPPv?j9LV#KXd{$@%zXa1(tm#o7iPmWM_ZvCzjIz{vR2LNdK00X8E*mw<&V9Kdgp z81GRKVFDgO>2zIKNIMzMSBc1?Fhp=YYQ~y&2*GC1blNuVHdsWVJKb9{1DPcy4)Dax z>iSb+f?1%E?sr^cAP{$GP?{0{u@^5166Frk!^3W{JNp3h71c;}fn% zA3}KqX#8*xdbCsK4~J_+nBx>!kVo+7D>&r2Bty6aECUH3Uow<~ zWEFq~NnChJnWoiukGkv+!q%D0J`55=16Oq+!f3~p3%8fIuq==gmt1Jq9T{DBuq&Eq zjDrZGVZm4sTSbxakqgIwToktW(piI2tkl(fx(D)%*$4DEB4h|nH%5SfHyDO-bbR@+ z1uWeVk?sM&NF}4`O5_oR2iCC!hKGcQ3j%ZjbMS`%<3r$4500(_fXyDjOVCvo_6RaS zSAt{sCHk(#@ct13Fv~gsg9h{00e%Fq zItIQlx zl&J(W1!(#)rQsA>3nF$k2C}aL5hP~5@wei@LbFuB!PuuB#0RbfSQv%Ym<0XnC{;L} z}a#zDQ%&>(^=>JBW+K8o!z$m0O4z9nTqBoH3Tvd>c?TrG}` z+7Paxl7KLX$Dn<5ol8av%upVDiQ5SBvE=EjuhAdh6V)}P=sAx)zlj<|JqphH{oc=rr{8MgA}aV@FMUTtgjfM*fivwla~BT<|!g0}BboG3K!#9<$JQ5)gwFM5PhK z&F43w>mUOHbhi%jNrW?C9g%=TWIlq-9KbpA5uKE?*Be2SXDp@9*7Q%##nL^((c$Uf zkI@W?1uz`e?Sp%IjSnmcfbfzljO1y2@DMM+%19pU7!J8cMaDYG7k$u$hLfRu1S{bb zjrok4bshteH#+p^IG5&;j@|@UN0>dnd}TFVHU_3ihIpf+1dKr@EHLjEV6l^u;|!xO zL$7=Z&^kL41EV^3q?46#dkBU0N}lvH&ewnMcuC~loS=>$2^$Mqy>EV2_)f< zw?9oAtCQ{lC_O_wXc6+nQ=;YRN4jh*Y={h}cF4m9fq{@O^szXPl7km{0&PPqh@a2i z-g2OesDsP{t>-ovY9AvK(C!Tc$bkGK2QqAs0-JWHi|IzU~Olfzr#rS`q4my#RFNtGV*PG-&WOZb$e_?0!p5r1Trb#=F~wpii5$ z4DK`+1QNsCK^rRGdVSHC0ASgm6Hx~ZA;xZ{b^iAErbW|eV(}{v@MqCNWhEjQ?{tF* zCOrlTQlLZnMaAV0Hs)f!W>P_i4@)B^!8;=$P8LTa0)VLl8E4!oS+}x(R4?abS|8JM z{_}efX)N3i#&$QGj~*<02g)u_yx|Aal?TMgpK(QxR2cPo7Z<1zjEv7jb%w7DM61s}UMFGpf@(_!<*WvQ3CpV!TKNnw(F3IbbTrz_WL44s^ zu>u-P#_LcoqG2Gx#EJw&|!#Z(@brFoVBI2M|PLv;#Brw62K}kYeNiWF+VwYDEp~di3 z$zZET9ShI+wX2WKcV26z=xEVdp_6mXDCJiICS|51m9=Q~W>Sj&f@QjUbYJPp^ss&P z#K^upmR(7{-2MQHVS$EFJ}{e^e8K3C(!dhj87AEs#t#rR?hK6wh$hPJD)r2`W0;g@ zoT%HSxb8I`(2wKxK4~y6QxUI-yGLVtKl%42>-Ls3_P;LeZ7$VTeHt7++xveERU1tHA0Kgr+XCl{i%?9;+_LTJBV3p4-9Lsb?sule0$DCFiT zE$6zT9WJA(9BDPmq3JT+i(FxcnGr$U08L@j_a?UQQcc7-7DPqdk-^g=qxVN9%V)DR zkFfhkV??)R%ZZ$b!$8`@X9dWG<~yGf^krRKPq>Qe&R0v zx>F7bb^8^0`&abSUpVt$x7lpnZf|p&>-e5kjO}>ye20>aOV@<`J8k934vhPyZw8Z= zE!xUi?=SO-etYA3WmRP7_P^iuY(FC}|0KS`6y+!`uRFTv>@?MWJ<|TFn&Z%!RF$jK40d_?@6|tt6%w@5P$zYdp?J2NW`#__~6vm5sr{DI5d+$slWf325 zI1ip{r|B!a>i@AbQtZqRD^fn%%E~i+%zsa{;@U(_Nxf{0!(rfj;UVvC=1G&*BAnsp zj5^nG@KW!ci@dT6(R-`ycm5$e+OCFv>8Oy3+H3oBnEbIUWOm5~74>=H`TmT?g6i-6 z!B@?<$Ehtb`-h{;uz!DVMW<|!!~U6T{(7;K*|Byid_dYg*CX3{ur0;X^=(LstV&;L zj8g}$AXwCo*RNo85ISG6+N_)l=4jZDC(K&3at$Hqa~CqRud=x0vMPV{U%OnVxn3nP zAP{oCen9AsqQc-~g7t$zks`%&MxvGFp@WhYZ0CjrE2k8OB;TBd4qtlOreGrZ?sU{d z@xAjK6XdALl@Vl3JoTKR;(mC}FsdIFX0C9uZe^yjnQ3LJ*$%cg*E!GF@IjN=#+s}v z2+8@N&!@{aW^!5mJ6Wb<`?7WYpDIrV8MDzi0r;uJHJC_?3 zO0%v}5Tw0FnrM@~SGLO!JMVnchaVk_Qjm@Tl@(2n*I)G_or0P_H#vp8=d*Rdh1Aek zTZ}JOKk_N?Xm*KOPEmG^+5A8BxL==}-ERMbsJJJ-p~G@#MIKe&YzrILgsF#r&=+eDpETE3kC?XeYmb<9OH+^h z=vUbu`6;AdJ!&y(vps70HcTUWB~7d&dd)6>Gx~GBA2q!6Nt#CNmr72h;?3v%8gaY# z%rw62HN!OHzuBaU@r9qIQ>vo-K5WE2ns)Hx3tzbKk}qiD!r9o3Ut-tUd5p9mOs?Ou zVw~l~#&uGesPNDZyTP* zf-31OPWCzvHgN+pq|*l;VGDfs0|5o3)_d1nOZLlKP?SB0md{#;|C<4X(f1ofm%M-GF!X|= zs3qw!;=<5p1YL=oetLUU2z!l+2(x5#Ki@5y)I%_7W$&x-AFFKQ>CIc8Ue zqh_X_HQx0z3x1AB-VC1s>k)SQL(;k3?Eop^Ef zeyyZ10Ug%Mh5dR~^bAGSiPf$@?x?r}3=Shg@GA%IEHfASd2*8~7q6!Y)kjmUI)1W8 zUiA@E(9p_uX>n&O=h9_~{Wu zJ|=u~5ZIL+cx>+fvx|K&?4p9ZJA?C9DfeD_KWm8!b96ZkPrHgPV&^_Bb65APe%;zH zq1z_p+Aj7Z|1{O5`x-VwNu1?47^?hJmP%~HP?`6Htsmh(e_i0gp@yncovnj(2JK*bUp@R z=+6HuI#dMHtK3$?z~3emqmOx|j=!1>KF5Mk+=8mwfAbW(MZ-6TNst&}WqP|O5;MRB zWH1yMs(1t2NW38H^06KZJvJ+PA@Q+> zUU(@hXSQp4DO;IJigM%xlTCagTP3ATC0L6TS=}{JG51m>ltTaKCM`Rm5yB9bIbPVH z!=Z8vmi#&7-z#*OwK@RFe6Pj8<#pwaN|o-f?UD>$qBh5CQjKKCOMhSGcQ+2?_sofl zIsTi;{O!KqHDYM888?$Zp;~`}A|`_T@;@!4bT?rU&vlBZBpqIbf}OXY)%U;N@q%gd zUSN$d3c2-5Eo^?e`8`Afm&mz5f$2wgv3KB7l^0f+)1rGsHEv|sEv$0(NB1dp+{lVr zSi1;|8PL@TeUQJfE~XzdWYZD)uzBILTw2VCk4D(z*@X?|{+O|djh&>R6ib`jgKjFi6%`J?e}LB zzdm*Q)pe14RBV2_NgFaxzU}(wgh_o>^l8j{PTXmS-^r(T&8Q{h(x?54&7XGMf~r^B z+onU*c6K^e&R2}^w70Ekc1ykb!_!RD)jk_ny!h_j$`wsWCOX6kJvZ6b>ec>bhkxUp zXxAYU7}5B2z4_axX2#^Sj_c_8^Qg`o*e^l!#7iWo4Y?E0G5O^E$Lk&2@7{mx?&Pd~ zH|EqywnCM5qJ*qF5eW3;{JSFy4e=4Qh{<~q6Y6{3Ou-I@Hr#dPlb32gt=d@1+dq4$ z{k@LjUwHUs+OOilC*oDJxb)sa3BajJ(^)D6Vwsl{Uqllx4;y^$=s=GOh1 zB686f-38%SRwDggCVEB-z43~AR@BTMqp6-Ck%8OZy-W+bo(*~-@qI~%KI^Y~PRUI% zBRwgZx;`fQ!GW0MDg9J$y{su+&2^oOWHn-mo;AiW++;8>vp=_7|6%f=miJ(Obzeb) zq0dzRlO9Z7?qFW|U|6!@{gJ*Rwlg4U&~HjdA=A)pYVc8Ye_`ODk$0OmqMsOU^fYj& zdTOZV)UZ~>D0g9?6g(WTFjVz*DE4%yxM!d~a3~*TT%0^ym1`VtZCuwj)Pym3=WU!H zINW|T+-frXUV89pjBzKgarc5|H_D{9XOQGQQZGGX%4_rnWAqfI7prKLTR7AhKQaOy z$+YepjUV|SGCILKT8HVQK9$z{a5_AoI69j=`Y73Gcxou8e5fbWv}eS0K7OS1#^@q= zjKVfHacWA;99|DIDfS*3;~jg_F#0xdY%6o{Pu$o{wdwfO;3~?jI(O{L`q-9<$wKnT zE7Wjvyz#fMV@F5BtF+ud!pDEbo6L9{A6e^9=bAraGu$jR(pVVJU>kWMjXq|>J}Dmu zLCg-XV6COe;Pzq4l-XoFwzJI~%5GL-Xh!cd(&bG4x-h=HfPFGz0_+;MNRKmoHce<4 zTB#lbbd3+e28SnD1mh44(|-meqcGT4J%eq@`mCa3cY4fD*|1`~<6X`cxtSLEPHlJjTbXO`aG_E}H&cH<(+{tq>XIR~LRU_2G3PSzFPfA>Ojx z*=i$xNZVwj_G|ZO;i$yDiLWDlD2T;Eu7;qGq2ymH<99v^Ar(tBbjllC^x^L|MGip^0hG!jO5MgWhE0iWQ4qXWF90k0ZZv6d>%3^pZ*OtXK5eFT_DFZPO3S7+-IwJ9AWrjiY#bK zPF$R;#aJgLJJ9&pcAjFN1{pEPI8u&24mmrX#ye_H8@ox{wIN0n|Bk8^TD>eZ87;IJ zKeT=FdBi_&RBrdy3p2Hgahxo4dOk{SO&Q;Hsu)blAQh5S&)#>Ho(Olj%D zJqo^P;<}P$rHFgJk9*vyJCfI9dvt6*d}&ph%%`^qLoV#}II!2aG2Zg%;+ucxLiL=N z@i@-(EL)r)3Jxil4%N3e9iM)3Ekd@Bbnx0*tFKQCRJi3wn6+P@-H9+CwQ++7+mvTo zG=o>>ewg{Bw2498cq%3&X4X{xu91AkpT0H>FMx!Q#v=s=uC=6mHL^qIX)X=PMju11 z(o^gysRIj82m3TD_MT`o%oqs?B3dcUScU}7HWa1>6+j{gu;}>DicPNng6wZWK1REL zmU6Nij32o1cfi=%USY96B)-?1*Y^eclGnPdO0jX4%xA5_G@MF`v7UFj$qX857dW$V zX=!8O$ZKwLuoE(k1Mtr7Xn%%Ip5!z+94Lat)Bg}^$~{Uo2Zl(p$46F4v+9)lL?u=kQ_+H z!}r=p{{OBxIsAQ}8X;%j=x?$vb7$(Eg8Fn$VSs%_H>V2=KHWb(XZQGkK-Gc+7IC zwSRQPk7GKOv(C?fI40L&c7bn&ySOQ5&)3{#<>;oj_{pN-@Tb^@P*G+mraGW2iAq^%Ed5GAKA*8_TVB^EJOuA{Da2kVknKw+=&W@G=a?0(W z>)2k?Nh@zdMVUq>o0%NQSuFc|VJ(e!`^mzpfs25qcN^6(>r3*@uSsT4345FDY`f@i zn2b_QN9q^oZg&ieE-blyenaPMi*w0%PR7EJFLdTL%0{2T7D{!Nn~F!X(&kew7}-X{ zZmI1hdLxjfHjK+L_PrfmI>og;qUv9Jn0mNswsIq`1$S7O^M)wgnu@wKdgQx0Z|WGS zL@sEb3TZN9sBsBl0nW_P5P=jYJPaofi7QBpP=N&FVbFrco9K^05Ro5SKdINUd9jsTE%4Cve>z=Gz1+}P8we?TY#X+vDBCo@L*qCcz{gML) zWao=h9p6La!qdK8i;S*IvsaOJP>~LCM+K2UeEvSsEvfoC&v;rOZyrvDh(q|eAh>i` z1p3n2A1F)zo&)}ya6d$js+{704v&VzjQcP>}m}b9W?9L5i8#hr_0Q$joAh z+3{qdopkCPP0;a1ZnT-{MvO|JGaAN;18Mg|0D@w8%Vx}(O4yQMiNkYmtq0-oas?1h zEO?Lpi-kA@5QoHzUFSqs-%^$hC+-y54mtsNUak~qdO|xg1uCCnDUWx;X-AwvoZ?*} zI1rD)Gj1-q=xqE&=I=2qf2_`~*$Yy1i?+B`An<|jA~1j#9%q5`D|rvH#^D>7`y!+N zM?(bczj0yH?ls3&*usMB<2Y3SUI1`NPqPQ`3^e%HZax4xjwc-wK}vwND1@iudF)A_ zlG3Qo^1m(9@zAYJ2Nu9eJm$iy1ekn0Ps>TTKpK<~53d4+t1PgeI$i&CT2zqAjt1Kq zB(t>$U&n&%(xEzMckWfGZ1&08^2xeb(DeeC6BguRmk?mT_xWk6sXb^bB!%4|*%k}J zke&tr% zmkAQlRR9GzScT$ohpVG6RhV5-aZ0WO^{limC|=bLcL0`-jwAHD_m5 zuOm|0vDR<0K4|CX?o=agvn%gpT6VE5O6L3S&M!F%DG^4SI;(hnlE`ZGu_~dqv(te+Q^jm1M)uuaJuY=rI7ZFHOz-k1mN$-{Th+R@Um`Zbf+pd8mq-ZdbYUm1A2K6-)-7xICZE_~35s28_>SzkE*3CZSqj~g8anuG2O zVyzhCRU5Z!`=rBI2`=y4LpXq?9xr~`1QiULaU$jxvUN4dBOA;nLGgOiJ-dNfH|^gnLK6_#J||19rrh0JDTS~$bZK2c;htJ@OIMLpN=r@_eJ%MgOJ;h& zOZ4htc#gKxk^PklH8RU86DmcTCRZt?T*r)loLt5ve1~+NN%C32xnc27(P5p)*%q{! zgi5t=sp?VB#H7Sy*{xB~UO>|D^Ois;1^GQ%nB+6ki%(+6c`j^>-1QGn(k|`$K1%y3 zP=#6LYz(FK>w4>kF$QE6?YK15#CF+EeLF&?smbS^O!H#wiHy^XD+7Pa=he^CZ|BZ6 z$-didb$Zfbsl=YG%nHa)=oVfTxPKKoa*kO-uIh?8HK~3bn!t!8$xkT5{H>tcGxD2c4|l+)VHeswzP6jr>n?uLK6OuvXm+KLsONV==0S` zS^O1xi4_t>yGtYN{I+TtvW{_>k;KwTOX-;;Fx_JZvkjN$$l-{k4vZwNSF41f0`4q5>9Rl-_|6aI=_u3_p@@<*e5IxBw;cB6`9>3BiJ^lI&e ziMrJJE+fyj4|tw4ByO1qmyOlFFgzgaPJ5C{>wSZXYYNR_HU&}T{#iHvJjwh>-qQhh zcxE;yY*6z$*Mjz!V18Jof2Kb zlaNEd7>{DQAxEzHGwJ2dXjh7zh8_WtEUo7E4~bTk`Cs0&*|^Q z6PDC39!exaGz6%;Eh?mjKuU9lJ90xKg zP9cY&iEP_jQ$hB&Nq!|lG&}NXuO(L*gH?L@XJ7iy3yyFRARZS=nn9QW!jufxj1`#x5x37982S z8F+=C`kHp=3;BLU_`;ZRBRoecSdS@?Ov{_@ZmD|K7#)KWhKyVID{rlc5nF_w?rrfQ zM=|0$tWw=ubI^?L62@=3?mStas>G2I%83Cwd=)I)Rs09?+t_5GBY=RJD!I35FoU@u zIpbsB_mW4d&Q%f$D6D%Fi%bgVLe;F_KvT20z3i&x!b|M%tDo6|fA}_Q&9;zvyA-k= zQZ_vgoyH_Lua4{R2Nb1crE3$uywLG|YHx352*PtKf*Z6xe)4c*sdR>;VT^+kdIS(Y z+2s$ho*4kd+R62uYMq*3_;$Wu6zI#dX6o+Bo^jq8-CUK0f7%0w7hdKu!K7}xt~pvtl`leiXD3{QxgaKH5<_;NCox_@p%aO6gr|X)a z_zvn)=-u-ZGlwNMq(geG%=*)HS!gynO0s-Gqw$oSI~p*~d?*#q;EH=hC!Vrrmk|mSi0BA>B!EZC6>!SeCL>Ylq<7fB+qi?AQ9z*o3=I4Msd~ z2YSW5Z}4u%(^}TorP(xDWLUN!CHDsUwigc>twVB@rQM+jSMvxs@o* zcTSn&iY@38hZB(kI;vlvp5Amj8$f`nPLj<`l!&HPAGoNDJ)6kg)lH;5Taw^8WkMWAjX5G#mrcR8izak~I!mUy+3qkK94qG| zhYpOc#Dr(jjS=0dvo6^l313}l6#lBc3CANLDkuv=|MBBe=PKqapUgSRa4s4CoK{(d zB*B}@l`44a(W4-eCtZ=SH9|niGS5TAsV$Hw%Dn)6D1@|yv=w}myrk!OnylhMQKw?E z8`oqdOFc|5Dl~TgO8{&Oll0KQgD3(;D$b&q;m~0K1&_hYH8Nyk)W$UyV^IKwxIITk z_F|o3Br#IN01n<pk_-sE7Yq*kaRO=`tO?qpbm z%y+aSQM!fSAtFPH+YO)uOEw}{5Tgk-Wd+X;#EN z)?{dIMPG(RW)>braOP@y)g-FRwq%iP>cvCOrexLy2<0Yka@A|nWpJuc-aW8fA2TXIE_1QEF9rZsl~UMS3>g zZCaHW9%MNxr)iF-ecmTq;6-5KXSpb*Ns<|2UMGK6;(!)txww#FGG{K*Cr)aofkNVg z3Z8&QC~Hn=w|M7xQm1qpsD@IghxX=e{xGOpzGR1fD2G~(Rt%?!+GbjAVu`M3wpgfo z=I2+aXe0tCjRIwkl0{@jBm#Ei_|OiHSr z(&Sohs;9<~rhclZjwhrN=Wtr;IJNxS zWm>%>wq`3=jH|6aA>(D$u9_=djH?E+tF$_vN&>4}uxq(uYhR9OxYX-d*{fyNtGHaw zXo{;`vSh%5Q0^gV!nW%>Ud39XV`CqyFPN&e~!^=Q9xYq?G=wZLmu77kjzzJqshe^w)q?G}5bcJFMb45Z z*7hvao^8=qZCu2Qq?-P%+Y+GI+HKh8t=noPf{txFPNU7zXKeZf&<$>16s}nrF5#jk zU?8qvDDKZO?q4`=SwU{(+SlS@?hIM3cS&yMaxP(jZbeY;;d*Ya0)=3ZZsiUJ&}r^p zh;HecE?|hR>RvAFnic8>M(wf-?Cx%z$!@!}?(Oyk=nC&A7BBFQZt@;4>n^YFhHmq^ zuI;v^?>_Hf^se)oF7`^V@^UYol@4jvsd$Ag?F&nqB8^19e$FUsGF&)>j9p5n?mlZtV!X>>C z9Qkn{ztJrK@*Dl(APX`fA95i3u_FKRAbUn0N3tYOvJ}IE&)f?pXR;=5GADPkCx3D$ z+raQrGAWm`Dc3MO*hB*u04uk$E59-<$FeNXGA+Au12DuX=dv#E@(j~M%^ZLL1hX&? zGcgyl{xKgjGAHve9{@viA}>EPG)FTCrx5@c04QHGHfOUZGcyiIvp0V;I8QKo001*< zvpJvhCv!9ShBG_2vpf5*FOxGm&oe#W3pc+rKIgMO&u=^#QnNy9vH={x0NhIeG=M*EaspuVKMTMCBtRz*v_zjYN~bgp zjdMj~vH)aq0uVp|%(Nzx^u4^aITwHfAOKDSfK6*MH#@UR4>eI2bwYP?13Ul$BtS+> z00?AsMhn0I3;+$7f&~CTN4s=JWAXq5vrhv6PS1cT$Urq~vOqg@QKz+9OY~7^vHL1Wi8P@}bOm$!MJazAUbNCUttsDmoFLp#iM0hGfypmsI1gAn{S zJbVMp%yl-z!#5-%UO5xc~3ZnM>21NwQv60**xrm zg9AV}tV0G205xznEX>0y0KjkW!h}g$BFF$Z^(~h;JHW#@$ago4Lk0lAh|7R9(1Qm601LPSGQ7fp_f$NHLz1KR1SmoVv;aMD zI4Hn_j$`s||2Uebc@~dzYeRU3gTZWz0|fv8eOCaJ!-Ehs_g}MsIUvI{$b&d+LpUHq zDPRL}1He`z!aF2`Y}0m!k2emG+jGs6F=zt51c&gKYH-JG4yaR`OLXJN=SD(41|2nV}vHp+!vZiZxJOlw= zm%}`y!Yj;!IA{Y!IQcx(gEnAH5KO>1$OAHTgFLXp47@`--~!%#0SmkXJb=Mxm$^MR zbFjC&y9@D!4**<;gJ{n{IV3|2P(v(*!#1FRC!p9mpo1#R^bB-EI;2A~pa1}T0ywP0 zH{5jryn;Kdf(~p$s<(86hw-~_Jjd7Yh2Jz+x4DCFbtX5!R+n=F=yh3xnnsUyPxthW zOL)i6Jk7uG$8$1iGxaAMz)PF_y|A`C+p_=!0LgoDgx5UMCp`+^JXq`e&s(!d^Sm_= zKmv#~0+77b_w+@#wn)FU0Tg}AE4|o{eFys(*t9f5r@fi;{y5pUz1v4{rmMZ&uRQ|2 zz1`nE12g^H*YnZiz2E=+0PFqU)3dJwzTqD}{k})g4}RJgKH@(<)LK zRAYYSTmI!sHKJ=iqFeswQ-0_JKme?_%tyZJufF+?a|0kY?8m>^lJ4 zvp(Ra%MwL31YE`ROv1Zk} zm1|e8U%`eIJCtc5U0Y hap%^(n|E*DzkvrAKAd=Qm1X^<~!H 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 PMR_#UbXD;xFT(!^f@r$w From 5f48a54bcd20a9cf58786def615fd40853ed6347 Mon Sep 17 00:00:00 2001 From: ZhiFeng1993 Date: Mon, 29 Jun 2020 22:33:00 -0700 Subject: [PATCH 04/99] Clean up style user joutneys css file --- static/css/style_user_journeys.css | 848 ----------------------------- 1 file changed, 848 deletions(-) delete mode 100644 static/css/style_user_journeys.css diff --git a/static/css/style_user_journeys.css b/static/css/style_user_journeys.css deleted file mode 100644 index aa21c87851..0000000000 --- a/static/css/style_user_journeys.css +++ /dev/null @@ -1,848 +0,0 @@ -@font-face { - font-family: 'Material Icons'; - font-style: normal; - font-weight: 400; - src: url(iconfont/MaterialIcons-Regular.eot); /* For IE6-8 */ - src: local('Material Icons'), - local('MaterialIcons-Regular'), - url('../fonts/MaterialIcons-Regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ - url('../fonts/MaterialIcons-Regular.woff2') format('woff2'), /* Super Modern Browsers */ - url('../fonts/MaterialIcons-Regular.woff') format('woff'), /* Modern Browsers */ - url('../fonts/MaterialIcons-Regular.svg#MaterialIcons-Regular') format('svg'), /* Legacy iOS */ - url('../fonts/MaterialIcons-Regular.ttf') format('truetype'); /* Safari, Android, iOS */ -} - -.material-icons { - font-family: 'Material Icons'; - font-weight: normal; - font-style: normal; - font-size: 24px; /* Preferred icon size */ - display: inline-block; - line-height: 1; - text-transform: none; - letter-spacing: normal; - word-wrap: normal; - white-space: nowrap; - direction: ltr; - - /* Support for all WebKit browsers. */ - -webkit-font-smoothing: antialiased; - /* Support for Safari and Chrome. */ - text-rendering: optimizeLegibility; - - /* Support for Firefox. */ - -moz-osx-font-smoothing: grayscale; - - /* Support for IE. */ - font-feature-settings: 'liga'; -} - -body { - margin:0 auto; -} - -.infobarWrapper a { - color:#303030; -} - -#encyclopedia { - padding: 0px !important; -} - -span .editthispage { - display: -webkit-inline-box !important; -} - -.editthispage { - display: -webkit-inline-box !important; -} - -h1 { - padding-top: 3% !important; - padding-bottom: 1.5% !important; - padding-left: 3% !important; - padding-right: 3% !important; - text-align: center !important; - font-size: 22pt !important; - font-weight:normal; - color:#303030; -} - -.container { - width:80%; -} - -.issue-button-container { - width: 75%; - margin-left: 15%; - padding-left: 1.5%; - padding-bottom: 2%; -} - -.anchor { - display: block; - position: relative; - top: -50px; - visibility: hidden; -} - -.pages a { - font-family: 'roboto'; - font-size:11pt; - text-decoration:none !important; - letter-spacing:0.03em; - color:#606060; -} - -.pages a:hover{ - color:black; -} - -.docstitle a{ - font-family: 'roboto'; - font-size:16pt; - margin-bottom:50px !important; - color:#3371e3 !important; - text-decoration:none !important; -} - -.docstitle { - margin-bottom:10px !important; -} - -.emphasize-box { - background-color: #dde1e4; - margin: 2% 10%; - padding-top: 20px; - padding-bottom: 5px; -} - -.emphasize-box li { - font-size: 14px !important; -} - -.browsedocs { - font-family: 'roboto' !important; - width:75%; - margin-top:2%; - margin-bottom:5%; - margin-left:15%; - line-height:2em; -} - -.browsecolumn { - float:left; - width: 33%; -} - -.browsesection { - float:left; - display:block; - width:100%; - margin:2%; -} - -.pages { - width:100%; - color:#606060 !important; -} - -.browseheader { - font-family: 'roboto'; - text-align:center; - padding:1%; - color:white !important; - font-weight:100; - font-size:18px; - text-transform:uppercase; - font-weight:400; - background-color:#303030; - letter-spacing:0.08em; - background-repeat:repeat; - background-size:contain; - background-position:center; -} - -.browseheader a{ - color:white !important; -} - -.topheader { - background-color: white !important; - color:#303030; - font-family: 'roboto'; - text-align:center; - padding:3%; - font-weight:300; - font-size:24pt; - letter-spacing:0.06em; -} - -.docssectionheaders { - background-color: #eeeeee !important; - color:#3371e3; - font-family: 'roboto'; - text-align:center; - padding: 3%; - margin: 6% 0% 2% 0%; - font-weight:300; - font-size:18pt; - letter-spacing:0.06em; -} - -.docscols { - width:100%; - float:left; -} - -.section1 { - width:100%; - float:left; -} - -.docscol1 { - background-color:#eeeeee; - padding:2%; - margin-right:2%; - width:28% !important; - display:inline-block; - float:left; -} - -.docscol2 { - background-color:#ffffff; - border:1px solid #aaaaaa; - padding:2%; - width:27% !important; - float:left; - margin-right:2%; - display:inline-block; -} - -.docscol3 { - background-color:#ffffff; - padding:1.5%; - width:27% !important; - display:inline-block; - float:right; - border:1px solid blue; -} - -.docscoltitle { - float:left; - padding-top:0; - margin-right:2%; - padding-bottom:3%; - font-size:16pt; - line-height:20pt; - font-weight:400; - color:#3371e3; -} - -.docsfullcol1 { - width:95%; - padding:2%; - margin:3%; -} - -.docsfullcol2 { - width:95%; - padding:2%; - background-color:#eeeeee; - margin:3%; -} - -.docsfullcol3 { - background-color:#ffffff; - padding:2%; - width:95%; - display:inline-block; - border:1px solid blue; - margin:3%; -} - -.docsfullcol1icon { - width:5%; - padding:2%; -} - -.docstitle2 { - padding:0%; - padding-bottom:3%; - font-size:16pt; - text-align:center; - font-weight:400; - padding-top:2%; - color:#3371e3; -} - -.docsButton { - background-color:#3371e3; - color:white; - border: 2px solid #ffffff; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; /* future proofing */ - -khtml-border-radius: 5px; /* for old Konqueror browsers */ - border: 2px solid #ffffff; - padding:1%; - text-decoration:none; - margin:0%; -} - -.material-icons { - font-size:50pt !important; - color:#3371e3; -} - -.paths { - padding:1%; - background-color:#3371e3; - text-align:center; -} - -.display-bar { - padding:1%; - background-color:#303030; - text-align:center; - font-size:18px; - font-family: 'roboto'; - text-transform:uppercase; - text-align:center; - letter-spacing:0.1em; - color:#ffffff; -} - -.cards { - padding:3%; - width:80%; - margin-left:10%; - background-color:#ffffff; - text-align:center; - font-family: 'roboto'; - text-transform:uppercase; - text-align:center; - letter-spacing:0.1em; -} - -.cards > div { - display: none; -} - -button { - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; /* future proofing */ - -khtml-border-radius: 5px; /* for old Konqueror browsers */ - border: 2px solid #ffffff; - padding:1%; - margin:1%; - color:#ffffff; - font-family: 'roboto'; - text-transform:uppercase; - text-align:center; - letter-spacing:0.1em; - display: inline-block; -} - -.navButton { - white-space:nowrap; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; /* future proofing */ - -khtml-border-radius: 5px; /* for old Konqueror browsers */ - border: 2px solid #ffffff; - padding:1%; - margin:1%; - color:#3371e3; - background-color:white; - font-family: 'roboto'; - text-transform:uppercase; - text-align:center; - letter-spacing:0.1em; - display: inline-block; - cursor: pointer; -} - -.navButton:active { - background-color:#3371e3; - color:white; - border: 2px solid #ffffff; -} - -.navButton:visited { - background-color:#3371e3; - color:white; - border: 2px solid #ffffff; -} - -.navButton:focus { - background-color:#3371e3 !important; - color:white; - border: 2px solid #ffffff; -} - -.navButton:hover, .keepShow { - background-color:#3371e3; - color:white; - border: 2px solid #ffffff; -} - -.buttons { - background-color:#3371e3; - white-space:nowrap; - cursor:pointer; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; /* future proofing */ - -khtml-border-radius: 5px; /* for old Konqueror browsers */ - border: 2px solid #ffffff; - padding: 2%; - margin:1%; - color:#ffffff; - font-family: 'roboto'; - text-transform:uppercase; - text-align:center; - letter-spacing:0.1em; - display: inline-block; - vertical-align:middle; - line-height:1.3em; -} - -.buttonoption1 { - background-color:#3371e3; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; /* future proofing */ - -khtml-border-radius: 5px; /* for old Konqueror browsers */ - border: 2px solid #ffffff; - padding:2%; - margin:1%; - color:#ffffff; - font-family: 'roboto'; - text-transform:uppercase; - text-align:center; - letter-spacing:0.1em; - display: inline-block; - width:250px; - vertical-align:middle; -} - -.buttons:active .active{ - background-color:white; - color:#3371e3; - border: 2px solid #3371e3; -} - -.buttons:hover { - background-color:white; - color:#3371e3; - border: 2px solid #3371e3; - cursor: pointer; -} - -.buttons:target { - background-color:white; - color:#3371e3; - border: 2px solid #3371e3; -} - -.buttons:visited { - background-color:white; - color:#3371e3; - border: 2px solid #3371e3; -} - -.buttons.selected { - background-color:white; - color:#3371e3; - border: 2px solid #3371e3; -} - -/*.keepShow { - background-color:white; - color:#3371e3; - border: 2px solid white; -}*/ - -.level { - background-color:#ffffff; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; /* future proofing */ - -khtml-border-radius: 5px; /* for old Konqueror browsers */ - border: 2px solid #303030; - padding:0%; - padding-top:3%; - margin:1%; - margin-top:4%; - color:#303030; - font-family: 'roboto'; - font-weight:100; - text-transform:none; - text-align:center; - letter-spacing:0.1em; - display: inline-block; - width:250px; cursor: pointer; - cursor: pointer; -} - -.level:hover, .level.selected { - background-color:#dddddd; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; /* future proofing */ - -khtml-border-radius: 5px; /* for old Konqueror browsers */ - border: 2px solid #303030; - cursor: pointer; -} - -.tab1text{ - padding:5%; - color:#303030; - font-size:15px; - line-height:22px; -} - -.tabbottom { - background-color:#303030; - color:#ffffff;; - font-family:'roboto'; - width:100%; - margin:0px; - font-size:34 !important; -} - -i { - font-size:44px !important; - text-align:center; - color:#000066; -} - -.infobarWrapper { - visibility: hidden; - margin-bottom:5%; -} - -.infobar { - padding:0%; - background-color:#3371e3; - text-align:center; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; /* future proofing */ - -khtml-border-radius: 5px; /* for old Konqueror browsers */ - border: 2px solid #ffffff; - padding:2%; - font-size:22px; - line-height:30px; - letter-spacing:0.07em; - text-transform:uppercase; - margin:3%; - font-weight:bold; - color:#ffffff; - font-family: 'roboto'; - width:70%; - margin-left:15%; - margin-bottom:3%; -} - -.whitebar { - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; /* future proofing */ - -khtml-border-radius: 5px; /* for old Konqueror browsers */ - background-color:#ffffff; - text-transform:none; - padding:3%; - letter-spacing:0.6pt; - font-size:15px; - z-index:99; - font-weight:400; - line-height:18pt; - color:#606060; - margin:1%; - text-align:left; -} - -.whitebararrow{ - float:right; - padding:3%; - font-size:15px; - z-index:99; - font-weight:100; - line-height:18pt; - color:#606060; - margin:1%; - text-align:right; -} - -.hide { - float:left; - font-size:16px; - padding-left:2%; - padding-bottom:5%; -} - -.fa { - line-height:0.7em !important; -} - -.infoicon { - float:left; - padding-bottom:2%; - padding-right:2%; - margin-bottom:10%; - color:#3371e3 !important; -} - -.numberCircle { - display:inline-block; - line-height:0px; - border-radius:5px; - border:2px solid; - font-weight:300; - font-size:24px; -} - -.numberCircle span { - display:inline-block; - padding-top:50%; padding-bottom:50%; - margin-left:12px; - margin-right:12px; -} - -.docButton { - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; /* future proofing */ - -khtml-border-radius: 5px; /* for old Konqueror browsers */ - border: 1.5px solid #3371e3; - padding:1%; - background-color:#eeeeee; - font-size:13px; - margin:.5%; - color:#3371e3; - font-family: 'roboto'; - text-transform:uppercase; - text-align:center; - letter-spacing:0.1em; - display: inline-block; -} - -.docButton:hover { - border: 1.5px solid #3371e3; - background-color:#3371e3; - font-size:13px; - color:#eeeeee; -} - -.tablebar { - text-align:center; - background-color:#eeeeee; - padding:1.5%; -} - -.aboutsection { - background-color:white; - font-family: 'roboto'; - font-weight:300 !important; - font-size:14px; - letter-spacing:0.05em; - line-height:22px; - width:70%; - margin-left:15%; - padding-bottom:5%; -} - -.aboutsection p { - font-size: 16px; - text-align:center; - font-weight:300; - line-height: 1.75em; - letter-spacing: 0.1px; - margin-bottom: 0.75em; -} - -.aboutsection a { - text-decoration: underline; - color:#3371e3; - font-weight:400; -} - -.aboutcolumn { - float:left; - width: 50%; - text-align: center; -} - -.docsection1 { - background-color:white; - font-family: 'roboto'; - font-weight:300 !important; - font-size:14px; - letter-spacing:0.05em; - line-height:22px; - width:65%; - margin-left:17%; - margin-top : 10%; - padding:4%; -} - -#persona-definition { - visibility: hidden; -} - -.about-k8s-content { - width: 100%; - float: right; -} - -.docsection1 a { - text-decoration: underline; -} - -.docsection1 p { - font-size: 16px; - font-weight:300; - line-height: 1.75em; - letter-spacing: 0.1px; - margin-bottom: 0.75em; -} - -.docsection1 li { - margin-bottom: 0.75em; - margin-left: 3em; - font-size: 16px; - font-weight:300; - line-height: 1.75em; - letter-spacing: 0.1px; -} - -.docsection1 ol li { - list-style: decimal; -} - -.docsection1 ul li { - list-style: disc; -} - -.docsection1 code { - font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; - font-size: 90%; - padding: 2px 4px; - color: #c7254e; - border-radius: 4px; - background-color: #f9f2f4; -} - -.intro { - background-color:white; - font-family: 'roboto'; - padding:3%; - font-weight:100; - font-size:14px; - letter-spacing:0.05em; - line-height:22px; - width:100%; - margin-left:10%; -} - -.introtext { - float:right; - background-color:white; - font-family: 'roboto'; - padding:3%; - font-weight:100; - font-size:14px; - letter-spacing:0.05em; - line-height:22px; - width:50%; - margin-left:10%; -} - -.track { - background-color:#3371e3; - font-family: 'roboto'; - padding:1%; - color:white; - font-weight:500; - text-align:center; - text-transform:uppercase; - font-size:16px; - letter-spacing:0.05em; - line-height:22px; - width:100%; -} - -.sections { - background-color:#303030; - font-family: 'roboto'; - padding:1%; - color:white; - font-weight:500; - text-align:center; - text-transform:uppercase; - font-size:18px; - letter-spacing:0.05em; - line-height:22px; - width:100%; -} - -.quotedocs { - line-height:26pt; - font-size:16pt; -} - -table { - width: 100%; - border: 1px solid #ccc; - border-spacing: 0; - margin-top: 30px; - margin-bottom: 30px; -} - -thead, tr:nth-child(even) { - background-color: light-grey; -} - -thead { - background-color: #555; - color: white; -} - -th, td { - padding: 8px; - text-align: left; - margin: 0; - border: 1px solid #ccc; -} - -th { - font-weight: normal; -} - -@media screen and (max-width: 640px) { - - .browsecolumn { - width: 95%; - } - - .paths { - margin-top : 10%; - padding:4%; - } - - .navButton { - padding:2%; - } - - .buttons { - padding:4%; - } - - .whitebar { - padding:5%; - } -} - From 9626db512167b437b75885b020755961088a79b7 Mon Sep 17 00:00:00 2001 From: Arhell Date: Thu, 2 Jul 2020 00:55:50 +0300 Subject: [PATCH 05/99] fix table content --- assets/scss/_custom.scss | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/assets/scss/_custom.scss b/assets/scss/_custom.scss index f02d6d908b..d040211f79 100644 --- a/assets/scss/_custom.scss +++ b/assets/scss/_custom.scss @@ -264,6 +264,14 @@ footer { } } +main { + .td-content table code, + .td-content>table td { + word-break: break-word; + } +} + + // blockquotes and callouts blockquote { From 4ddc1663f2181511a2eb2575b41c3a7c3acf7dc7 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Thu, 2 Jul 2020 16:30:52 +0800 Subject: [PATCH 06/99] Add a kubectl tip for working with keys with dots --- content/en/docs/reference/kubectl/cheatsheet.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/en/docs/reference/kubectl/cheatsheet.md b/content/en/docs/reference/kubectl/cheatsheet.md index 36629d2c29..dda75574a9 100644 --- a/content/en/docs/reference/kubectl/cheatsheet.md +++ b/content/en/docs/reference/kubectl/cheatsheet.md @@ -166,6 +166,10 @@ kubectl get pv --sort-by=.spec.capacity.storage kubectl get pods --selector=app=cassandra -o \ jsonpath='{.items[*].metadata.labels.version}' +# Retrieve the value of a key with dots, e.g. 'ca.crt' +kubectl get configmap myconfig \ + -o jsonpath='{.data.ca\.crt}' + # Get all worker nodes (use a selector to exclude results that have a label # named 'node-role.kubernetes.io/master') kubectl get node --selector='!node-role.kubernetes.io/master' From f34fe97ba0da469cb3fb521369a3811578d2e0cf Mon Sep 17 00:00:00 2001 From: Jorge Gallegos Date: Thu, 2 Jul 2020 12:12:15 -0500 Subject: [PATCH 07/99] Removing duplicate custom-jekyll js After docsy theme got merged these scripts aren't needed anymore. Confirmed after removing it (and all ` - {{ with .Params.js }}{{ range (split . ",") }} {{ end }}{{ else }}{{ end }} \ No newline at end of file diff --git a/static/js/custom-jekyll/tags.js b/static/js/custom-jekyll/tags.js deleted file mode 100644 index d99660ee60..0000000000 --- a/static/js/custom-jekyll/tags.js +++ /dev/null @@ -1,15 +0,0 @@ -$( document ).ready(function() { - // Shows permalink when term name is hovered over - $(".glossary-injector").each(function() { - var placeholder = $("#" + $(this).data("placeholder-id")); - var originalContent = placeholder.html(); - - var glossaryDef = $($(this).find(".injector-def")[0]).html(); - - $(this).mouseenter(function() { - placeholder.html(glossaryDef); - }).mouseleave(function(){ - placeholder.html(originalContent); - }); - }); -}); From 25e76c02737957fe9c415dcaa76f1faeaeedaf26 Mon Sep 17 00:00:00 2001 From: Celeste Horgan Date: Thu, 2 Jul 2020 10:39:21 -0700 Subject: [PATCH 08/99] Add page for PR wranglers --- content/en/docs/contribute/advanced.md | 65 +---------------- .../contribute/participate/pr-wranglers.md | 69 +++++++++++++++++++ .../participate/roles-and-responsibilties.md | 10 ++- 3 files changed, 78 insertions(+), 66 deletions(-) create mode 100644 content/en/docs/contribute/participate/pr-wranglers.md diff --git a/content/en/docs/contribute/advanced.md b/content/en/docs/contribute/advanced.md index 594816a2b5..44c72916d9 100644 --- a/content/en/docs/contribute/advanced.md +++ b/content/en/docs/contribute/advanced.md @@ -17,67 +17,6 @@ client and other tools for some of these tasks. -## Be the PR Wrangler for a week - -SIG Docs [approvers](/docs/contribute/participating/#approvers) take week-long turns [wrangling PRs](https://github.com/kubernetes/website/wiki/PR-Wranglers) for the repository. - -The PR wrangler’s duties include: - -- Review [open pull requests](https://github.com/kubernetes/website/pulls) daily for quality and adherence to the [Style](/docs/contribute/style/style-guide/) and [Content](/docs/contribute/style/content-guide/) guides. - - Review the smallest PRs (`size/XS`) first, then iterate towards the largest (`size/XXL`). - - Review as many PRs as you can. -- Ensure that the CLA is signed by each contributor. - - Help new contributors sign the [CLA](https://github.com/kubernetes/community/blob/master/CLA.md). - - Use [this](https://github.com/zparnold/k8s-docs-pr-botherer) script to automatically remind contributors that haven’t signed the CLA to sign the CLA. -- Provide feedback on proposed changes and help facilitate technical reviews from members of other SIGs. - - Provide inline suggestions on the PR for the proposed content changes. - - If you need to verify content, comment on the PR and request more details. - - Assign relevant `sig/` label(s). - - If needed, assign reviewers from the `reviewers:` block in the file's front matter. - - Assign `Docs Review` and `Tech Review` labels to indicate the PR's review status. - - Assign `Needs Doc Review` or `Needs Tech Review` for PRs that haven't yet been reviewed. - - Assign `Doc Review: Open Issues` or `Tech Review: Open Issues` for PRs that have been reviewed and require further input or action before merging. - - Assign `/lgtm` and `/approve` labels to PRs that can be merged. -- Merge PRs when they are ready, or close PRs that shouldn’t be accepted. - - Consider accepting accurate technical content even if the content meets only some of the docs' [style guidelines](/docs/contribute/style/style-guide/). Open a new issue with the label `good first issue` to address style concerns. -- Triage and tag incoming issues daily. See [Triage and categorize issues](/docs/contribute/review/for-approvers/#triage-and-categorize-issues) for guidelines on how SIG Docs uses metadata. - -### Helpful GitHub queries for wranglers - -The following queries are helpful when wrangling. After working through these queries, the remaining list of PRs to be -reviewed is usually small. These queries specifically exclude localization PRs, and only include the `master` branch (except for the last one). - -- [No CLA, not eligible to merge](https://github.com/kubernetes/website/pulls?q=is%3Aopen+is%3Apr+label%3A%22cncf-cla%3A+no%22+-label%3Ado-not-merge+label%3Alanguage%2Fen): - Remind the contributor to sign the CLA. If they have already been reminded by both the bot and a human, close - the PR and remind them that they can open it after signing the CLA. - **Do not review PRs whose authors have not signed the CLA!** -- [Needs LGTM](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+-label%3Algtm+): - If it needs technical review, loop in one of the reviewers suggested by the bot. If it needs docs review - or copy-editing, either suggest changes or add a copyedit commit to the PR to move it along. -- [Has LGTM, needs docs approval](https://github.com/kubernetes/website/pulls?q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+label%3Algtm): - Determine whether any additional changes or updates need to be made for the PR to be merged. If you think the PR is ready to be merged, comment `/approve`. -- [Quick Wins](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+base%3Amaster+-label%3A%22do-not-merge%2Fwork-in-progress%22+-label%3A%22do-not-merge%2Fhold%22+label%3A%22cncf-cla%3A+yes%22+label%3A%22size%2FXS%22+label%3A%22language%2Fen%22+): If it’s a small PR against master with no clear blockers. (change "XS" in the size label as you work through the PRs [XS, S, M, L, XL, XXL]). -- [Not against master](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+-base%3Amaster): If it's against a `dev-` branch, it's for an upcoming release. Make sure the [release meister](https://github.com/kubernetes/sig-release/tree/master/release-team) knows about it by adding a comment with `/assign @`. If it's against an old branch, help the PR author figure out whether it's targeted against the best branch. - -### When to close Pull Requests - -Reviews and approvals are one tool to keep our PR queue short and current. Another tool is closure. - -- Close any PR where the CLA hasn’t been signed for two weeks. -PR authors can reopen the PR after signing the CLA, so this is a low-risk way to make sure nothing gets merged without a signed CLA. - -- Close any PR where the author has not responded to comments or feedback in 2 or more weeks. - -Don't be afraid to close pull requests. Contributors can easily reopen and resume works in progress. Oftentimes a closure notice is what spurs an author to resume and finish their contribution. - -To close a pull request, leave a `/close` comment on the PR. - -{{< note >}} - -An automated service, [`fejta-bot`](https://github.com/fejta-bot) automatically marks issues as stale after 90 days of inactivity, then closes them after an additional 30 days of inactivity when they become rotten. PR wranglers should close issues after 14-30 days of inactivity. - -{{< /note >}} - ## Propose improvements SIG Docs [members](/docs/contribute/participating/#members) can propose improvements. @@ -244,6 +183,4 @@ When you’re ready to start the recording, click Record to Cloud. When you’re ready to stop recording, click Stop. -The video uploads automatically to YouTube. - - +The video uploads automatically to YouTube. \ No newline at end of file diff --git a/content/en/docs/contribute/participate/pr-wranglers.md b/content/en/docs/contribute/participate/pr-wranglers.md new file mode 100644 index 0000000000..6538e813df --- /dev/null +++ b/content/en/docs/contribute/participate/pr-wranglers.md @@ -0,0 +1,69 @@ +--- +title: PR wranglers +content_type: concept +weight: 20 +--- + + + +SIG Docs [approvers](/docs/contribute/participating/roles-and-responsibilites/#approvers) take week-long shifts [managing pull requests](https://github.com/kubernetes/website/wiki/PR-Wranglers) for the repository. + +This section covers the duties of a PR wrangler. For more information on giving good reviews, see [Reviewing changes](/docs/contribute/review/). + + + +## Duties + +Each day in a week-long shift as PR Wrangler: + +- Triage and tag incoming issues daily. See [Triage and categorize issues](/docs/contribute/review/for-approvers/#triage-and-categorize-issues) for guidelines on how SIG Docs uses metadata. +- Review [open pull requests](https://github.com/kubernetes/website/pulls) for quality and adherence to the [Style](/docs/contribute/style/style-guide/) and [Content](/docs/contribute/style/content-guide/) guides. + - Start with the smallest PRs (`size/XS`) first, and end with the largest (`size/XXL`). Review as many PRs as you can. +- Make sure PR contributors sign the [CLA](https://github.com/kubernetes/community/blob/master/CLA.md). + - Use [this](https://github.com/zparnold/k8s-docs-pr-botherer) script to remind contributors that haven’t signed the CLA to do so. +- Provide feedback on changes and ask for technical reviews from members of other SIGs. + - Provide inline suggestions on the PR for the proposed content changes. + - If you need to verify content, comment on the PR and request more details. + - Assign relevant `sig/` label(s). + - If needed, assign reviewers from the `reviewers:` block in the file's front matter. +- Use the `/approve` comment to approve a PR for merging. Merge the PR when ready. + - PRs should have a `/lgtm` comment from another member before merging. + - Consider accepting technically accurate content that doesn't meet the [style guidelines](/docs/contribute/style/style-guide/). Open a new issue with the label `good first issue` to address style concerns. + +### Helpful GitHub queries for wranglers + +The following queries are helpful when wrangling. +After working through these queries, the remaining list of PRs to review is usually small. +These queries exclude localization PRs. All queries are against the main branch except the last one. + +- [No CLA, not eligible to merge](https://github.com/kubernetes/website/pulls?q=is%3Aopen+is%3Apr+label%3A%22cncf-cla%3A+no%22+-label%3Ado-not-merge+label%3Alanguage%2Fen): + Remind the contributor to sign the CLA. If both the bot and a human have reminded them, close + the PR and remind them that they can open it after signing the CLA. + **Do not review PRs whose authors have not signed the CLA!** +- [Needs LGTM](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+-label%3Algtm+): + Lists PRs that need an LGTM from a member. If the PR needs technical review, loop in one of the reviewers suggested by the bot. If the content needs work, add suggestions and feedback in-line. +- [Has LGTM, needs docs approval](https://github.com/kubernetes/website/pulls?q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+label%3Algtm): + Lists PRs that need an `/approve` comment to merge. +- [Quick Wins](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+base%3Amaster+-label%3A%22do-not-merge%2Fwork-in-progress%22+-label%3A%22do-not-merge%2Fhold%22+label%3A%22cncf-cla%3A+yes%22+label%3A%22size%2FXS%22+label%3A%22language%2Fen%22+): Lists PRs against the main branch with no clear blockers. (change "XS" in the size label as you work through the PRs [XS, S, M, L, XL, XXL]). +- [Not against the main branch](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+-base%3Amaster): If the PR is against a `dev-` branch, it's for an upcoming release. Assign the [docs release manager](https://github.com/kubernetes/sig-release/tree/master/release-team#kubernetes-release-team-roles) using: `/assign @`. If the PR is against an old branch, help the author figure out whether it's targeted against the best branch. + +### When to close Pull Requests + +Reviews and approvals are one tool to keep our PR queue short and current. Another tool is closure. + +Close PRs where: +- The author hasn't signed the CLA for two weeks. + + Authors can reopen the PR after signing the CLA. This is a low-risk way to make sure nothing gets merged without a signed CLA. + +- The author has not responded to comments or feedback in 2 or more weeks. + +Don't be afraid to close pull requests. Contributors can easily reopen and resume works in progress. Often a closure notice is what spurs an author to resume and finish their contribution. + +To close a pull request, leave a `/close` comment on the PR. + +{{< note >}} + +The [`fejta-bot`](https://github.com/fejta-bot) bot marks issues as stale after 90 days of inactivity. After 30 more days it marks issues as rotten and closes them. PR wranglers should close issues after 14-30 days of inactivity. + +{{< /note >}} \ No newline at end of file diff --git a/content/en/docs/contribute/participate/roles-and-responsibilties.md b/content/en/docs/contribute/participate/roles-and-responsibilties.md index b01beec352..179acf0009 100644 --- a/content/en/docs/contribute/participate/roles-and-responsibilties.md +++ b/content/en/docs/contribute/participate/roles-and-responsibilties.md @@ -171,7 +171,7 @@ Approvers and SIG Docs leads are the only ones who can merge pull requests into - Visit the Netlify page preview for a PR to make sure things look good before approving. - Participate in the [PR Wrangler rotation schedule](https://github.com/kubernetes/website/wiki/PR-Wranglers) for weekly rotations. SIG Docs expects all approvers to participate in this -rotation. See [Be the PR Wrangler for a week](/docs/contribute/advanced#be-the-pr-wrangler-for-a-week) +rotation. See [PR wranglers](/docs/contribute/participating/pr-wranglers) for more details. ### Becoming an approver @@ -188,4 +188,10 @@ To apply: 2. Assign the PR to one or more current SIG Docs approvers. -If approved, a SIG Docs lead adds you to the appropriate GitHub team. Once added, [K8s-ci-robot](https://github.com/kubernetes/test-infra/tree/master/prow#bots-home) assigns and suggests you as a reviewer on new pull requests. \ No newline at end of file +If approved, a SIG Docs lead adds you to the appropriate GitHub team. Once added, [K8s-ci-robot](https://github.com/kubernetes/test-infra/tree/master/prow#bots-home) assigns and suggests you as a reviewer on new pull requests. + +## {{% heading "whatsnext" %}} + +Learn about specialized roles in SIG Docs: + +- [PR wranglers](/docs/contribute/participating/pr-wranglers) \ No newline at end of file From 9aad658f6a7db56e6b1c9ae20777b104f07bc785 Mon Sep 17 00:00:00 2001 From: Saba Zubair Date: Fri, 3 Jul 2020 21:12:27 -0400 Subject: [PATCH 09/99] =?UTF-8?q?removed=20anchor-4.1.1-min.js=20file=20fr?= =?UTF-8?q?om=20static/js/anchor-4.1.1=20and=20the=20corresponding=20call?= =?UTF-8?q?=20in=20/layouts/partial/head.html#L77.=20This=20completes=20#2?= =?UTF-8?q?2040=20and=20serves=20as=20my=20first=20contribution=20to=20an?= =?UTF-8?q?=20OS=20project.=20=F0=9F=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- layouts/partials/head.html | 1 - static/js/anchor-4.1.1.min.js | 6 ------ 2 files changed, 7 deletions(-) delete mode 100644 static/js/anchor-4.1.1.min.js diff --git a/layouts/partials/head.html b/layouts/partials/head.html index 43d1a91c67..d0a2eb064f 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -74,7 +74,6 @@ {{ end }} - diff --git a/static/js/anchor-4.1.1.min.js b/static/js/anchor-4.1.1.min.js deleted file mode 100644 index 29a64acae6..0000000000 --- a/static/js/anchor-4.1.1.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * AnchorJS - v4.1.1 - 2018-07-01 - * https://github.com/bryanbraun/anchorjs - * Copyright (c) 2018 Bryan Braun; Licensed MIT - */ -!function(A,e){"use strict";"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():(A.AnchorJS=e(),A.anchors=new A.AnchorJS)}(this,function(){"use strict";return function(A){function d(A){A.icon=A.hasOwnProperty("icon")?A.icon:"",A.visible=A.hasOwnProperty("visible")?A.visible:"hover",A.placement=A.hasOwnProperty("placement")?A.placement:"right",A.ariaLabel=A.hasOwnProperty("ariaLabel")?A.ariaLabel:"Anchor",A.class=A.hasOwnProperty("class")?A.class:"",A.truncate=A.hasOwnProperty("truncate")?Math.floor(A.truncate):64}function f(A){var e;if("string"==typeof A||A instanceof String)e=[].slice.call(document.querySelectorAll(A));else{if(!(Array.isArray(A)||A instanceof NodeList))throw new Error("The selector provided to AnchorJS was invalid.");e=[].slice.call(A)}return e}this.options=A||{},this.elements=[],d(this.options),this.isTouchDevice=function(){return!!("ontouchstart"in window||window.DocumentTouch&&document instanceof DocumentTouch)},this.add=function(A){var e,t,i,n,o,s,r,a,c,h,l,u=[];if(d(this.options),"touch"===(l=this.options.visible)&&(l=this.isTouchDevice()?"always":"hover"),A||(A="h2, h3, h4, h5, h6"),0===(e=f(A)).length)return this;for(function(){if(null===document.head.querySelector("style.anchorjs")){var A,e=document.createElement("style");e.className="anchorjs",e.appendChild(document.createTextNode("")),void 0===(A=document.head.querySelector('[rel="stylesheet"], style'))?document.head.appendChild(e):document.head.insertBefore(e,A),e.sheet.insertRule(" .anchorjs-link { opacity: 0; text-decoration: none; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }",e.sheet.cssRules.length),e.sheet.insertRule(" *:hover > .anchorjs-link, .anchorjs-link:focus { opacity: 1; }",e.sheet.cssRules.length),e.sheet.insertRule(" [data-anchorjs-icon]::after { content: attr(data-anchorjs-icon); }",e.sheet.cssRules.length),e.sheet.insertRule(' @font-face { font-family: "anchorjs-icons"; src: url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype"); }',e.sheet.cssRules.length)}}(),t=document.querySelectorAll("[id]"),i=[].map.call(t,function(A){return A.id}),o=0;o\]\.\/\(\)\*\\\n\t\b\v]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),t=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||t||!1}}}); \ No newline at end of file From cf1cc32b84d8c8b1eec3f1ad5703c5a5f0a3d682 Mon Sep 17 00:00:00 2001 From: Arhell Date: Sat, 4 Jul 2020 12:35:28 +0300 Subject: [PATCH 10/99] fix heading text --- assets/scss/_custom.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/scss/_custom.scss b/assets/scss/_custom.scss index f02d6d908b..98a0b7ddff 100644 --- a/assets/scss/_custom.scss +++ b/assets/scss/_custom.scss @@ -118,7 +118,7 @@ section { } @media only screen and (min-width: 1075px) { - margin-top: 1.5rem !important; + margin-top: 1rem !important; } } From 393c40c680e5e63e8cbbc83c107e89c4fd98bf2d Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Sat, 30 May 2020 14:27:39 +0800 Subject: [PATCH 11/99] [zh] Synchronize the README file --- README-zh.md | 256 +++++++++++++++++++++++---------------------------- 1 file changed, 117 insertions(+), 139 deletions(-) diff --git a/README-zh.md b/README-zh.md index 8a7898774a..5b4353127f 100644 --- a/README-zh.md +++ b/README-zh.md @@ -1,74 +1,139 @@ # Kubernetes 文档 + +--> -[![Build Status](https://api.travis-ci.org/kubernetes/website.svg?branch=master)](https://travis-ci.org/kubernetes/website) -[![GitHub release](https://img.shields.io/github/release/kubernetes/website.svg)](https://github.com/kubernetes/website/releases/latest) +[![Netlify Status](https://api.netlify.com/api/v1/badges/be93b718-a6df-402a-b4a4-855ba186c97d/deploy-status)](https://app.netlify.com/sites/kubernetes-io-master-staging/deploys) [![GitHub release](https://img.shields.io/github/release/kubernetes/website.svg)](https://github.com/kubernetes/website/releases/latest) -欢迎!本仓库包含了所有用于构建 [Kubernetes 网站和文档](https://kubernetes.io/)的内容。 +This repository contains the assets required to build the [Kubernetes website and documentation](https://kubernetes.io/). We're glad that you want to contribute! +--> +本仓库包含了所有用于构建 [Kubernetes 网站和文档](https://kubernetes.io/) 的软件资产。 我们非常高兴您想要参与贡献! + +## 在本地使用 Hugo 来运行网站 + +请参考 [Hugo 的官方文档](https://gohugo.io/getting-started/installing/)了解 Hugo 的安装指令。 +请确保安装的是 [`netlify.toml`](netlify.toml#L10) 文件中环境变量 `HUGO_VERSION` 所指定的 +Hugo 扩展版本。 + + +在构造网站之前,先克隆 Kubernetes website 仓库: + +```bash +git clone https://github.com/kubernetes/website.git +cd website +git submodule update --init --recursive +``` + + +**注意:** Kubernetes 网站要部署 [Docsy Hugo 主题](https://github.com/google/docsy#readme). +如果你还没有更新你本地的 website 仓库,目录 `website/themes/docsy` +会是空目录。 +在本地没有主题副本的情况下,网站无法正常构造。 + +使用下面的命令更新网站主题: + +```bash +git submodule update --init --recursive --depth 1 +``` + + +若要在本地构造和测试网站,请运行: + +```bash +hugo server --buildFuture +``` + + +上述命令会在端口 1313 上启动本地 Hugo 服务器。 +启动浏览器,打开 http://localhost:1313 来查看网站。 +当你对源文件作出修改时,Hugo 会更新网站并强制浏览器执行刷新操作。 + + +## 参与 SIG Docs 工作 + +通过 [社区页面](https://github.com/kubernetes/community/tree/master/sig-docs#meetings) +进一步了解 SIG Docs Kubernetes 社区和会议信息。 + +你也可以通过以下渠道联系本项目的维护人员: + +- [Slack](https://kubernetes.slack.com/messages/sig-docs) +- [邮件列表](https://groups.google.com/forum/#!forum/kubernetes-sig-docs) + -## 贡献文档 + +You can click the **Fork** button in the upper-right area of the screen to create a copy of this repository in your GitHub account. This copy is called a *fork*. Make any changes you want in your fork, and when you are ready to send those changes to us, go to your fork and create a new pull request to let us know about it. + +Once your pull request is created, a Kubernetes reviewer will take responsibility for providing clear, actionable feedback. As the owner of the pull request, **it is your responsibility to modify your pull request to address the feedback that has been provided to you by the Kubernetes reviewer.** +--> +## 为文档做贡献 + +你也可以点击屏幕右上方区域的 **Fork** 按钮,在你自己的 GitHub +账号下创建本仓库的拷贝。此拷贝被称作 *fork*。 +你可以在自己的拷贝中任意地修改文档,并在你已准备好将所作修改提交给我们时, +在你自己的拷贝下创建一个拉取请求(Pull Request),以便让我们知道。 + +一旦你创建了拉取请求,某个 Kubernetes 评审人会负责提供明确的、可执行的反馈意见。 +作为拉取请求的拥有者,*修改拉取请求以解决 Kubernetes +评审人所提出的反馈是你的责任*。 -您可以点击屏幕右上方的 **Fork** 按钮,在您的 GitHub 账户下创建一份本仓库的副本。这个副本叫做 *fork*。您可以对 fork 副本进行任意修改, -当准备好把修改提交给我们时,您可以通过创建一个 pull request 来告知我们。 - - -创建 pull request 后,Kubernetes 审核人员将负责提供清晰且可操作的反馈。作为 pull request 的所有者,**您有责任修改 pull request 以解决 Kubernetes 审核者提供给您的反馈。** -另请注意,您最终可能会收到多个 Kubernetes 审核人员为您提供的反馈,也可能出现后面 Kubernetes 审核人员的反馈与前面审核人员的反馈不尽相同的情况。 -此外,在某些情况下,您的某位评审员可能会在需要时要求 [Kubernetes 技术评审员](https://github.com/kubernetes/website/wiki/Tech-reviewers) 进行技术评审。 -审稿人将尽最大努力及时提供反馈,但响应时间可能因情况而异。 + +Furthermore, in some cases, one of your reviewers might ask for a technical review from a Kubernetes tech reviewer when needed. Reviewers will do their best to provide feedback in a timely fashion but response time can vary based on circumstances. +--> +还要提醒的一点,有时可能会有不止一个 Kubernetes 评审人为你提供反馈意见。 +有时候,某个评审人的意见和另一个最初被指派的评审人的意见不同。 + +更进一步,在某些时候,评审人之一可能会在需要的时候请求 Kubernetes +技术评审人来执行技术评审。 +评审人会尽力及时地提供反馈意见,不过具体的响应时间可能会因时而异。 +--> 有关为 Kubernetes 文档做出贡献的更多信息,请参阅: -* [开始贡献](https://kubernetes.io/docs/contribute/start/) -* [缓存您的文档变更](http://kubernetes.io/docs/contribute/intermediate#view-your-changes-locally) -* [使用页面模版](http://kubernetes.io/docs/contribute/style/page-templates/) +* [贡献 Kubernetes 文档](https://kubernetes.io/docs/contribute/) +* [页面内容类型](http://kubernetes.io/docs/contribute/style/page-content-types/) * [文档风格指南](http://kubernetes.io/docs/contribute/style/style-guide/) * [本地化 Kubernetes 文档](https://kubernetes.io/docs/contribute/localization/) - -## `README.md` 的本地化 Kubernetes 文档 - - -### 中文 +## 中文本地化 可以通过以下方式联系中文本地化的维护人员: @@ -76,107 +141,20 @@ You can reach the maintainers of Korean localization at: * He Xiaolong ([GitHub - @markthink](https://github.com/markthink)) * [Slack channel](https://kubernetes.slack.com/messages/kubernetes-docs-zh) - -## 在本地使用 docker 运行网站 - - -在本地运行 Kubernetes 网站的推荐方法是运行包含 [Hugo](https://gohugo.io) 静态网站生成器的专用 [Docker](https://docker.com) 镜像。 - - -> 如果您使用的是 Windows,则需要一些工具,可以使用 [Chocolatey](https://chocolatey.org) 进行安装。`choco install make` - - -> 如果您更喜欢在没有 Docker 的情况下在本地运行网站,请参阅下面的[使用 Hugo 在本地运行网站](#running-the-site-locally-using-hugo) 章节。 - - -如果您已经[安装运行](https://www.docker.com/get-started)了 Docker,使用以下命令在本地构建 `kubernetes-hugo` Docker 镜像: - -```bash -make docker-image -``` - - -一旦创建了镜像,您就可以在本地运行网站了: - -```bash -make docker-serve -``` - - -打开浏览器访问 http://localhost:1313 以查看网站。当您对源文件进行更改时,Hugo 会更新网站并强制刷新浏览器。 - - -## 使用 Hugo 在本地运行网站 {#running-the-site-locally-using-hugo} - - -有关 Hugo 的安装说明,请参阅 [Hugo 官方文档](https://gohugo.io/getting-started/installing/)。 -确保安装对应版本的 Hugo,版本号由 [`netlify.toml`](netlify.toml#L9) 文件中的 `HUGO_VERSION` 环境变量指定。 - - -安装 Hugo 后,在本地运行网站: - -```bash -make serve -``` - - -这将在 1313 端口上启动本地 Hugo 服务器。打开浏览器访问 http://localhost:1313 查看网站。当您对源文件进行更改时,Hugo 会更新网站并强制刷新浏览器。 - - -## 社区、讨论、贡献和支持 - - -在[社区页面](http://kubernetes.io/community/)了解如何与 Kubernetes 社区互动。 - - -您可以通过以下方式联系该项目的维护人员: - -- [Slack](https://kubernetes.slack.com/messages/sig-docs) -- [Mailing List](https://groups.google.com/forum/#!forum/kubernetes-sig-docs) - +Participation in the Kubernetes community is governed by the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). +--> ### 行为准则 -参与 Kubernetes 社区受 [Kubernetes 行为准则](code-of-conduct.md)的约束。 +参与 Kubernetes 社区受 [CNCF 行为准则](https://github.com/cncf/foundation/blob/master/code-of-conduct.md)约束。 +--> ## 感谢! Kubernetes 因为社区的参与而蓬勃发展,感谢您对我们网站和文档的贡献! From 423f391c68100fe0576fd105fa487b566a0c870e Mon Sep 17 00:00:00 2001 From: wxsm Date: Mon, 6 Jul 2020 13:06:09 +0800 Subject: [PATCH 12/99] fix zh doc misleading to en link. fix zh doc misleading to en link. --- .../tutorials/kubernetes-basics/update/update-interactive.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/tutorials/kubernetes-basics/update/update-interactive.html b/content/zh/docs/tutorials/kubernetes-basics/update/update-interactive.html index 6f52711e17..0f9ea050c3 100644 --- a/content/zh/docs/tutorials/kubernetes-basics/update/update-interactive.html +++ b/content/zh/docs/tutorials/kubernetes-basics/update/update-interactive.html @@ -32,7 +32,7 @@ weight: 20 From 906517f3ffa708329051fab343bac44610777995 Mon Sep 17 00:00:00 2001 From: Ross Wilson Date: Mon, 6 Jul 2020 17:47:52 +0200 Subject: [PATCH 13/99] Fix erroneous RSS feed link in security.md When referring to the `kubernetes-security-announce` mailing list, an alternative RSS link is incorrectly given to `kubernetes-announce` instead. This PR updates that link. --- content/en/docs/reference/issues-security/security.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/reference/issues-security/security.md b/content/en/docs/reference/issues-security/security.md index b9b1ce7c37..2d16e37662 100644 --- a/content/en/docs/reference/issues-security/security.md +++ b/content/en/docs/reference/issues-security/security.md @@ -19,7 +19,7 @@ This page describes Kubernetes security and disclosure information. Join the [kubernetes-security-announce](https://groups.google.com/forum/#!forum/kubernetes-security-announce) group for emails about security and major API announcements. -You can also subscribe to an RSS feed of the above using [this link](https://groups.google.com/forum/feed/kubernetes-announce/msgs/rss_v2_0.xml?num=50). +You can also subscribe to an RSS feed of the above using [this link](https://groups.google.com/forum/feed/kubernetes-security-announce/msgs/rss_v2_0.xml?num=50). ## Report a Vulnerability From a6a41daee939f01b1482cdd65e985806a0d08272 Mon Sep 17 00:00:00 2001 From: Celeste Horgan Date: Mon, 6 Jul 2020 11:54:22 -0700 Subject: [PATCH 14/99] Apply suggestions from code review Co-authored-by: Tim Bannister --- .../contribute/participate/roles-and-responsibilties.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/en/docs/contribute/participate/roles-and-responsibilties.md b/content/en/docs/contribute/participate/roles-and-responsibilties.md index 179acf0009..346ce0321f 100644 --- a/content/en/docs/contribute/participate/roles-and-responsibilties.md +++ b/content/en/docs/contribute/participate/roles-and-responsibilties.md @@ -171,7 +171,7 @@ Approvers and SIG Docs leads are the only ones who can merge pull requests into - Visit the Netlify page preview for a PR to make sure things look good before approving. - Participate in the [PR Wrangler rotation schedule](https://github.com/kubernetes/website/wiki/PR-Wranglers) for weekly rotations. SIG Docs expects all approvers to participate in this -rotation. See [PR wranglers](/docs/contribute/participating/pr-wranglers) +rotation. See [PR wranglers](/docs/contribute/participating/pr-wranglers/). for more details. ### Becoming an approver @@ -188,10 +188,10 @@ To apply: 2. Assign the PR to one or more current SIG Docs approvers. -If approved, a SIG Docs lead adds you to the appropriate GitHub team. Once added, [K8s-ci-robot](https://github.com/kubernetes/test-infra/tree/master/prow#bots-home) assigns and suggests you as a reviewer on new pull requests. +If approved, a SIG Docs lead adds you to the appropriate GitHub team. Once added, [@k8s-ci-robot](https://github.com/kubernetes/test-infra/tree/master/prow#bots-home) assigns and suggests you as a reviewer on new pull requests. ## {{% heading "whatsnext" %}} Learn about specialized roles in SIG Docs: -- [PR wranglers](/docs/contribute/participating/pr-wranglers) \ No newline at end of file +- [PR wranglers](/docs/contribute/participating/pr-wranglers) From 52f2920d5f7fcef706ab0d9130c3dcbe04843fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Raymond=20Maug=C3=A9?= Date: Mon, 6 Jul 2020 18:03:45 -0400 Subject: [PATCH 15/99] Updates minor spelling correction "can not" to "cannot" --- .../docs/concepts/overview/working-with-objects/namespaces.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/overview/working-with-objects/namespaces.md b/content/en/docs/concepts/overview/working-with-objects/namespaces.md index 07e7dac726..59b1763450 100644 --- a/content/en/docs/concepts/overview/working-with-objects/namespaces.md +++ b/content/en/docs/concepts/overview/working-with-objects/namespaces.md @@ -26,7 +26,7 @@ need to create or think about namespaces at all. Start using namespaces when yo need the features they provide. Namespaces provide a scope for names. Names of resources need to be unique within a namespace, -but not across namespaces. Namespaces can not be nested inside one another and each Kubernetes +but not across namespaces. Namespaces cannot be nested inside one another and each Kubernetes resource can only be in one namespace. Namespaces are a way to divide cluster resources between multiple users (via [resource quota](/docs/concepts/policy/resource-quotas/)). From b05f9569c7c0e69a5adda09dcc8de822be19bea6 Mon Sep 17 00:00:00 2001 From: Celeste Horgan Date: Mon, 6 Jul 2020 15:56:46 -0700 Subject: [PATCH 16/99] Address feedback --- .../docs/contribute/participate/roles-and-responsibilties.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/content/en/docs/contribute/participate/roles-and-responsibilties.md b/content/en/docs/contribute/participate/roles-and-responsibilties.md index 346ce0321f..7536464ce0 100644 --- a/content/en/docs/contribute/participate/roles-and-responsibilties.md +++ b/content/en/docs/contribute/participate/roles-and-responsibilties.md @@ -192,6 +192,4 @@ If approved, a SIG Docs lead adds you to the appropriate GitHub team. Once added ## {{% heading "whatsnext" %}} -Learn about specialized roles in SIG Docs: - -- [PR wranglers](/docs/contribute/participating/pr-wranglers) +- Read about [PR wrangling](/docs/contribute/participating/pr-wranglers), a role all approvers take on rotation. \ No newline at end of file From e8aa06428937113429a9fd206c72d0a73121a087 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Tue, 23 Jun 2020 10:46:27 +0800 Subject: [PATCH 17/99] [zh] Sync contribution guidelines (2) This PR is about the changes to reference generation. --- .../contribute/generate-ref-docs/_index.md | 17 +- .../generate-ref-docs/contribute-upstream.md | 221 +++++----- .../contribute/generate-ref-docs/kubectl.md | 319 ++++++-------- .../generate-ref-docs/kubernetes-api.md | 307 ++++++------- .../kubernetes-components.md | 403 +---------------- .../prerequisites-ref-docs.md | 45 ++ .../generate-ref-docs/quickstart.md | 405 ++++++++++++++++++ 7 files changed, 845 insertions(+), 872 deletions(-) create mode 100644 content/zh/docs/contribute/generate-ref-docs/prerequisites-ref-docs.md create mode 100644 content/zh/docs/contribute/generate-ref-docs/quickstart.md diff --git a/content/zh/docs/contribute/generate-ref-docs/_index.md b/content/zh/docs/contribute/generate-ref-docs/_index.md index ac5f61a40f..7afd3743f5 100644 --- a/content/zh/docs/contribute/generate-ref-docs/_index.md +++ b/content/zh/docs/contribute/generate-ref-docs/_index.md @@ -5,17 +5,22 @@ weight: 80 --- -许多 Kubernetes 参考文档都是使用脚本从 Kubernetes 源代码生成的。本节的主题是如何生成这种类型的文档。 +本节的主题是描述如何生成 Kubernetes 参考指南。 +要生成参考文档,请参考下面的指南: + +* [生成参考文档快速入门](/docs/contribute/generate-ref-docs/quickstart/) + diff --git a/content/zh/docs/contribute/generate-ref-docs/contribute-upstream.md b/content/zh/docs/contribute/generate-ref-docs/contribute-upstream.md index f71871b296..4bfa40f0a8 100644 --- a/content/zh/docs/contribute/generate-ref-docs/contribute-upstream.md +++ b/content/zh/docs/contribute/generate-ref-docs/contribute-upstream.md @@ -1,12 +1,12 @@ --- title: 为上游 Kubernetes 代码库做出贡献 content_type: task +weight: 20 --- @@ -16,93 +16,83 @@ This page shows how to contribute to the upstream kubernetes/kubernetes project to fix bugs found in the Kubernetes API documentation or the `kube-*` components such as `kube-apiserver`, `kube-controller-manager`, etc. --> -此页面描述如何为上游 kubernetes/kubernetes 项目做出贡献,如修复 Kubernetes API 文档或 `kube-*` 组件(例如 kube-apiserver、kube-controller-manager 等)中发现的错误。 +此页面描述如何为上游 `kubernetes/kubernetes` 项目做出贡献,如修复 Kubernetes API +文档或 Kubernetes 组件(例如 `kubeadm`、`kube-apiserver`、`kube-controller-manager` 等) +中发现的错误。 -相反,如果您想从上游代码重新生成 Kubernetes API 或 `kube-*` 组件的参考文档。请参考以下说明: - +如果您仅想从上游代码重新生成 Kubernetes API 或 `kube-*` 组件的参考文档。请参考以下说明: + - [生成 Kubernetes API 的参考文档](/docs/contribute/generate-ref-docs/kubernetes-api/) - [生成 Kubernetes 组件和工具的参考文档](/docs/contribute/generate-ref-docs/kubernetes-components/) - - - ## {{% heading "prerequisites" %}} - -您需要安装以下工具: +- 你需要安装以下工具: + + - [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) + - [Golang](https://golang.org/doc/install) 的 1.13 版本或更高 + - [Docker](https://docs.docker.com/engine/installation/) + - [etcd](https://github.com/coreos/etcd/) -* [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) -* [Golang](https://golang.org/doc/install) Go 版本大于 1.9.1 -* [Docker](https://docs.docker.com/engine/installation/) -* [etcd](https://github.com/coreos/etcd/) +- 你必须设置 `GOPATH` 环境变量,并且 `etcd` 的位置必须在 `PATH` 环境变量中。 -必须设置 $GOPATH 环境变量,并且 `etcd` 的位置必须在 $PATH 环境变量中。 - - -您需要知道如何创建对 GitHub 代码仓库的拉取请求(Pull Request)。 -通常,这涉及创建代码仓库的分支。要获取更多的信息请参考[创建 PR](https://help.github.com/articles/creating-a-pull-request/) 和 -[GitHub 标准 Fork 和 PR 工作流程](https://gist.github.com/Chaser324/ce0505fbed06b947d962)。 - - - - +- 您需要知道如何创建对 GitHub 代码仓库的拉取请求(Pull Request)。 + 通常,这涉及创建代码仓库的派生副本。 + 要获取更多的信息请参考[创建 PR](https://help.github.com/articles/creating-a-pull-request/) 和 + [GitHub 标准派生和 PR 工作流程](https://gist.github.com/Chaser324/ce0505fbed06b947d962)。 -## 基本原则 - -Kubernetes API 和 `kube-*` 组件(例如 `kube-apiserver`、`kube-controller-manager`)的参考文档是根据[上游 Kubernetes](https://github.com/kubernetes/kubernetes/) 中的源代码自动生成的。 - +## 基本说明 + +Kubernetes API 和 `kube-*` 组件(例如 `kube-apiserver`、`kube-controller-manager`)的参考文档 +是根据[上游 Kubernetes](https://github.com/kubernetes/kubernetes/) 中的源代码自动生成的。 + 当您在生成的文档中看到错误时,您可能需要考虑创建一个 PR 用来在上游项目中对其进行修复。 ## 克隆 Kubernetes 代码仓库 - -如果您还没有 kubernetes/kubernetes 代码仓库,请立即参照下列命令获取: +如果您还没有 kubernetes/kubernetes 代码仓库,请参照下列命令获取: ```shell mkdir $GOPATH/src @@ -117,9 +107,10 @@ For example, if you followed the preceding step to get the repository, your base directory is `$GOPATH/src/github.com/kubernetes/kubernetes.` The remaining steps refer to your base directory as ``. --> -确定您的 [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 代码仓库克隆的基本目录。 -例如,如果按照前面的步骤获取代码仓库,则您的基本目录为 `$GOPATH/src/github.com/kubernetes/kubernetes`。 -接下来其余步骤将您的基本目录称为 ``。 +确定您的 [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 代码仓库克隆的根目录。 +例如,如果按照前面的步骤获取代码仓库,则你的根目录为 `$GOPATH/src/github.com/kubernetes/kubernetes`。 +接下来其余步骤将你的根目录称为 ``。 + -确定您的 [kubernetes-sigs/reference-docs](https://github.com/kubernetes-sigs/reference-docs) 代码仓库克隆的基本目录。 -例如,如果按照前面的步骤获取代码仓库,则您的基本目录为 `$GOPATH/src/github.com/kubernetes-sigs/reference-docs`。 -接下来其余步骤将您的基本目录称为 ``。 +确定您的 [kubernetes-sigs/reference-docs](https://github.com/kubernetes-sigs/reference-docs) +代码仓库克隆的根目录。 +例如,如果按照前面的步骤获取代码仓库,则你的根目录为 +`$GOPATH/src/github.com/kubernetes-sigs/reference-docs`。 +接下来其余步骤将你的根目录称为 ``。 -## 编辑 Kubernetes 源代码 - -Kubernetes API 参考文档是根据 OpenAPI 规范自动生成的,该规范是从 Kubernetes 源代码生成的。如果要更改 API 参考文档,第一步是更改 Kubernetes 源代码中的一个或多个注释。 +## 编辑 Kubernetes 源代码 + +Kubernetes API 参考文档是根据 OpenAPI 规范自动生成的,该规范是从 Kubernetes 源代码生成的。 +如果要更改 API 参考文档,第一步是更改 Kubernetes 源代码中的一个或多个注释。 -### 更改上游 Kubernetes 源代码 - +### 更改上游 Kubernetes 源代码 + {{< note >}} -以下步骤仅作为示例,不是一般步骤,具体情况因您而异。 +以下步骤仅作为示例,不是通用步骤,具体情况因环境而异。 {{< /note >}} -以下在 Kubernetes 源代码中编辑注释的示例。 - -在您本地的 kubernetes/kubernetes 代码仓库中,切换出本地 master 分支,并确保它是最新的: +以下在 Kubernetes 源代码中编辑注释的示例。 + +在您本地的 kubernetes/kubernetes 代码仓库中,检出 master 分支,并确保它是最新的: ```shell cd @@ -184,19 +175,18 @@ git pull https://github.com/kubernetes/kubernetes master -假设 master 分支中的此源文件的拼写错误为 "atmost": +假设 master 分支中的下面源文件中包含拼写错误 "atmost": [kubernetes/kubernetes/staging/src/k8s.io/api/apps/v1/types.go](https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/api/apps/v1/types.go) -在您的本地环境中,打开 `types.go` 文件,然后将 "atmost" 更改为 "at most"。 - -以下命令查看您已更改的文件: +在你的本地环境中,打开 `types.go` 文件,然后将 "atmost" 更改为 "at most"。 + +以下命令验证你已经更改了文件: ```shell git status @@ -216,23 +206,22 @@ On branch master -### 提交已编辑的文件 - -运行 `git add` 和 `git commit` 命令提交到目前为止所做的更改。在下一步中,您将进行第二次提交,将更改分成两个提交很重要。 +### 提交已编辑的文件 + +运行 `git add` 和 `git commit` 命令提交到目前为止所做的更改。 +在下一步中,您将进行第二次提交,将更改分成两个提交很重要。 ### 生成 OpenAPI 规范和相关文件 - 进入 `` 目录并运行以下脚本: ```shell @@ -242,12 +231,10 @@ hack/update-generated-protobuf.sh hack/update-api-reference-docs.sh ``` - -运行 `git status` 命令查看生成的东西。 + +运行 `git status` 命令查看生成的文件。 -```shell +```none On branch master ... modified: api/openapi-spec/swagger.json @@ -264,14 +251,16 @@ For example, you could run `git diff -a api/openapi-spec/swagger.json`. This is important, because `swagger.json` is the input to the second stage of the doc generation process. --> -查看 `api/openapi-spec/swagger.json` 的内容,以确保 typo 已经被修正。例如,您可以运行 `git diff -a api/openapi-spec/swagger.json` 命令。这很重要,因为 `swagger.json` 是文档生成过程中第二阶段的输入。 +查看 `api/openapi-spec/swagger.json` 的内容,以确保拼写错误已经被修正。 +例如,您可以运行 `git diff -a api/openapi-spec/swagger.json` 命令。 +这很重要,因为 `swagger.json` 是文档生成过程中第二阶段的输入。 -运行 `git add` 和 `git commit` 命令来提交您的更改。现在您有两个提交: +运行 `git add` 和 `git commit` 命令来提交您的更改。现在您有两个提交(commits): 一种包含编辑的 `types.go` 文件,另一种包含生成的 OpenAPI 规范和相关文件。 将这两个提交分开独立。也就是说,不要 squash 您的提交。 @@ -283,13 +272,16 @@ master branch of the Monitor your pull request, and respond to reviewer comments as needed. Continue to monitor your pull request until it is merged. --> -将您的更改作为 [PR](https://help.github.com/articles/creating-a-pull-request/) 提交到 [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 代码仓库的 master 分支。关注您的 PR,并根据需要回复 reviewer 的评论。继续关注您的 PR,直到 PR 被合并为止。 +将您的更改作为 [PR](https://help.github.com/articles/creating-a-pull-request/) +提交到 [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 代码仓库的 master 分支。 +关注您的 PR,并根据需要回复 reviewer 的评论。继续关注您的 PR,直到 PR 被合并为止。 -[PR 57758](https://github.com/kubernetes/kubernetes/pull/57758) 是修复 Kubernetes 源代码中的拼写错误的拉取请求的示例。 +[PR 57758](https://github.com/kubernetes/kubernetes/pull/57758) 是修复 Kubernetes +源代码中的拼写错误的拉取请求的示例。 {{< note >}} -确定要更改的正确源文件可能很棘手。在前面的示例中,官方的源文件位于 `kubernetes/kubernetes` 代码仓库的 `staging` 目录中。但是根据您的情况,`staging` 目录可能不是找到官方源文件的地方。根据指导原则,请检查 [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes/tree/master/staging) 代码仓库和相关代码仓库(例如 [kubernetes/apiserver](https://github.com/kubernetes/apiserver/blob/master/README.md))中的 `README` 文件。 +确定要更改的正确源文件可能很棘手。在前面的示例中,官方的源文件位于 `kubernetes/kubernetes` +代码仓库的 `staging` 目录中。但是根据您的情况,`staging` 目录可能不是找到官方源文件的地方。 +如果需要帮助,请阅读 +[kubernetes/kubernetes](https://github.com/kubernetes/kubernetes/tree/master/staging) +代码仓库和相关代码仓库 +(例如 [kubernetes/apiserver](https://github.com/kubernetes/apiserver/blob/master/README.md)) +中的 `README` 文件。 {{< /note >}} -### Cherry Pick 将您的提交纳入发布分支 - -在上一节中,您在 master 分支中编辑了一个文件,然后运行了脚本用来生成 OpenAPI 规范和相关文件。然后将您的更改提交到 kubernetes/kubernetes 代码仓库的 master 分支的 pull request 中。 现在,需要将您的更改反向移植到已经 release 的分支。例如,假设使用 master 分支来开发 Kubernetes 1.10 版,并且您想将更改反向移植到 release-1.9 分支。 +### 将你的提交 Cherrypick 到发布分支 + +在上一节中,你在 master 分支中编辑了一个文件,然后运行了脚本用来生成 OpenAPI 规范和相关文件。 +然后用 PR 将你的更改提交到 kubernetes/kubernetes 代码仓库的 master 分支中。 +现在,需要将你的更改反向移植到已经发布的分支。 +例如,假设 master 分支被用来开发 Kubernetes 1.10 版,并且你想将更改反向移植到 release-1.9 分支。 -回想一下,您的 pull request 有两个提交:一个用于编辑 `types.go`,一个用于由脚本生成的文件。下一步的目的是对您的第一次提交 cherry pick 到 release-1.9 分支。这个想法是 cherry pick 编辑了 types.go 的提交,但不是具有运行脚本结果的提交。有关说明,请参见[提出 Cherry Pick](https://git.k8s.io/community/contributors/devel/sig-release/cherry-picks.md)。 +回想一下,您的 PR 有两个提交:一个用于编辑 `types.go`,一个用于由脚本生成的文件。 +下一步是将你的第一次提交 cherrypick 到 release-1.9 分支。这样做的原因是仅 cherrypick 编辑了 types.go 的提交, +而不是具有脚本运行结果的提交。 +有关说明,请参见[提出 Cherry Pick](https://git.k8s.io/community/contributors/devel/sig-release/cherry-picks.md)。 {{< note >}} -提出 cherry pick 要求您有权在 pull request 中设置标签和里程碑。如果您没有这些权限,则需要与可以为您设置标签和里程碑的人员合作。 +提出 Cherry Pick 要求你有权在 PR 中设置标签和里程碑。如果您没有这些权限, +则需要与可以为你设置标签和里程碑的人员合作。 {{< /note >}} -当您提出一个 pull request,希望将您的一个提交 cherry pick 到 release-1.9 分支中时,下一步是在本地环境的 release-1.9 分支中运行这些脚本。 +当你发起 PR 将你的一个提交 cherry pick 到 release-1.9 分支中时,下一步是在本地环境的 release-1.9 +分支中运行如下脚本。 ```shell hack/update-generated-swagger-docs.sh @@ -354,7 +359,8 @@ hack/update-api-reference-docs.sh Now add a commit to your cherry-pick pull request that has the recently generated OpenAPI spec and related files. Monitor your pull request until it gets merged into the release-1.9 branch. --> -现在将提交添加到您的 Cherry-pick pull request 中,该请求具有最近生成的 OpenAPI 规范和相关文件。关注您的 pull request 请求,直到其合并到 release-1.9 分支中为止。 +现在将提交添加到您的 Cherry-Pick PR 中,该 PR 中包含最新生成的 OpenAPI 规范和相关文件。 +关注你的 PR,直到其合并到 release-1.9 分支中为止。 -此时,master 分支和 release-1.9 分支都具有更新的 `types.go` 文件和一组生成的文件,这些文件反映了您对 `types.go` 所做的更改。请注意,生成的 OpenAPI 规范和其他 release-1.9 分支中生成的文件不一定与 master 分支中生成的文件相同。release-1.9 分支中生成的文件仅包含来自 Kubernetes 1.9 的 API 元素。master 分支中生成的文件可能包含不在 1.9 中但正在为 1.10 开发的 API 元素。 - +此时,master 分支和 release-1.9 分支都具有更新的 `types.go` 文件和一组生成的文件, +这些文件反映了对 `types.go` 所做的更改。 +请注意,生成的 OpenAPI 规范和其他 release-1.9 分支中生成的文件不一定与 master 分支中生成的文件相同。 +release-1.9 分支中生成的文件仅包含来自 Kubernetes 1.9 的 API 元素。 +master 分支中生成的文件可能包含不在 1.9 中但正在为 1.10 开发的 API 元素。 -## 生成已发布的参考文档 - -上一节显示了如何编辑源文件然后生成多个文件,包括在 `kubernetes/kubernetes` 代码仓库中的 `api/openapi-spec/swagger.json`。 -`swagger.json` 文件是 OpenAPI 定义文件,可用于生成 API 参考文档。 +## 生成已发布的参考文档 + +上一节显示了如何编辑源文件然后生成多个文件,包括在 `kubernetes/kubernetes` 代码仓库中的 +`api/openapi-spec/swagger.json`。`swagger.json` 文件是 OpenAPI 定义文件,可用于生成 API 参考文档。 -现在,您可以按照[生成 Kubernetes API 的参考文档](/docs/contribute/generate-ref-docs/kubernetes-api/)指南来生成 +现在,您可以按照 +[生成 Kubernetes API 的参考文档](/docs/contribute/generate-ref-docs/kubernetes-api/) +指南来生成 [已发布的 Kubernetes API 参考文档](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/)。 - - ## {{% heading "whatsnext" %}} - -该页面显示了如何自动生成 `kubectl` 工具提供的命令的参考页面。 +本页面描述了如何生成 `kubectl` 命令参考。 -{{< note >}} -本主题展示了如何为 [kubectl 命令集](/docs/reference/generated/kubectl/kubectl-commands) 生成参考文档,如 [kubectl apply](/docs/reference/generated/kubectl/kubectl-commands#apply) 和 [kubectl taint](/docs/reference/generated/kubectl/kubectl-commands#taint)。 - -本主题没有展示如何生成 [kubectl](/docs/reference/generated/kubectl/kubectl/) 组件的参考页面。相关说明请参见[为 Kubernetes 组件和工具生成参考页面](/docs/home/contribute/generated-reference/kubernetes-components/)。 + +{{< note >}} +本主题描述了如何为 [kubectl 命令](/docs/reference/generated/kubectl/kubectl-commands) +生成参考文档,如 [kubectl apply](/docs/reference/generated/kubectl/kubectl-commands#apply) 和 +[kubectl taint](/docs/reference/generated/kubectl/kubectl-commands#taint)。 +本主题没有讨论如何生成 [kubectl](/docs/reference/generated/kubectl/kubectl/) 组件选项的参考页面。 +相关说明请参见[为 Kubernetes 组件和工具生成参考页面](/docs/home/contribute/generated-reference/kubernetes-components/)。 {{< /note >}} - - - ## {{% heading "prerequisites" %}} - - - -* 你需要安装 [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)。 - - - -* 你需要安装 1.9.1 或更高版本的 [Golang](https://golang.org/doc/install), 并在环境变量中设置 `$GOPATH`。 - - - -* 你需要安装 [Docker](https://docs.docker.com/engine/installation/)。 - - - -* 你需要知道如何在一个 GitHub 项目仓库中创建一个 PR。一般来说,这涉及到创建仓库的一个分支。想了解更多信息,请参见[创建一个文档 PR](/docs/home/contribute/create-pull-request/) 和 [GitHub 标准 Fork & PR 工作流](https://gist.github.com/Chaser324/ce0505fbed06b947d962)。 - - - +{{< include "prerequisites-ref-docs.md" >}} -## 设置本地仓库 - -创建本地工作区并设置您的 `GOPATH`。 +## 配置本地仓库 + +创建本地工作区并设置你的 `GOPATH`。 ```shell mkdir -p $HOME/ - export GOPATH=$HOME/ ``` - + 获取以下仓库的本地克隆: ```shell @@ -113,16 +72,14 @@ go get -u kubernetes-incubator/reference-docs -如果您还没有下载过 `kubernetes/website` 仓库,现在下载: +如果您还没有获取过 `kubernetes/website` 仓库,现在获取之: ```shell git clone https://github.com//website $GOPATH/src/github.com//website ``` - -克隆下载 kubernetes/kubernetes 仓库,并作为 k8s.io/kubernetes: + +克隆 kubernetes/kubernetes 仓库作为 k8s.io/kubernetes: ```shell git clone https://github.com/kubernetes/kubernetes $GOPATH/src/k8s.io/kubernetes @@ -131,18 +88,15 @@ git clone https://github.com/kubernetes/kubernetes $GOPATH/src/k8s.io/kubernetes -从 `$GOPATH/src/k8s.io/kubernetes/vendor/github.com` 中卸载 spf13 软件包。 +从 `$GOPATH/src/k8s.io/kubernetes/vendor/github.com` 中移除 spf13 软件包。 ```shell rm -rf $GOPATH/src/k8s.io/kubernetes/vendor/github.com/spf13 ``` - + kubernetes/kubernetes 仓库提供对 kubectl 和 kustomize 源代码的访问。 - -确定 [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 仓库的本地主目录。例如,如果按照前面的步骤来获取该仓库,则主目录是 `$GOPATH/src/k8s.io/kubernetes.`。下文将该目录称为 ``。 +* 确定 [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 仓库的本地主目录。 + 例如,如果按照前面的步骤来获取该仓库,则主目录是 `$GOPATH/src/k8s.io/kubernetes.`。 + 下文将该目录称为 ``。 -确定 [kubernetes/website](https://github.com/kubernetes/website) 仓库的本地主目录。例如,如果按照前面的步骤来获取该仓库,则主目录是 `$GOPATH/src/github.com//website`。下文将该目录称为 ``。 +* 确定 [kubernetes/website](https://github.com/kubernetes/website) 仓库的本地主目录。 + 例如,如果按照前面的步骤来获取该仓库,则主目录是 `$GOPATH/src/github.com//website`。 + 下文将该目录称为 ``。 -确定 [kubernetes-incubator/reference-docs](https://github.com/kubernetes-incubator/reference-docs) 仓库的本地主目录。例如,如果按照前面的步骤来获取该仓库,则主目录是 `$GOPATH/src/github.com/kubernetes-incubator/reference-docs`。下文将该目录称为 ``。 +* 确定 [kubernetes-sigs/reference-docs](https://github.com/kubernetes-sigs/reference-docs) + 仓库的本地主目录。例如,如果按照前面的步骤来获取该仓库,则主目录是 + `$GOPATH/src/github.com/kubernetes-sigs/reference-docs`。 + 下文将该目录称为 ``。 -在您当地的 k8s.io/kubernetes 仓库中,检查感兴趣的分支并确保它是最新的。例如,如果您想要生成 Kubernetes 1.15 的文档,您可以使用以下命令: +在本地的 k8s.io/kubernetes 仓库中,检出感兴趣的分支并确保它是最新的。例如, +如果你想要生成 Kubernetes 1.17 的文档,可以使用以下命令: ```shell cd -git checkout release-1.15 -git pull https://github.com/kubernetes/kubernetes release-1.15 +git checkout v1.17.0 +git pull https://github.com/kubernetes/kubernetes v1.17.0 ``` -如果不需要编辑 kubectl 源码,请按照说明[编辑 Makefile](#editing-makefile)。 +如果不需要编辑 `kubectl` +源码,请按照说明[配置构建变量](#setting-build-variables)。 -## 编辑 kubectl 源码 - - +## 编辑 kubectl 源码 -kubectl 命令集的参考文档是基于 kubectl 源码自动生成的。如果想要修改参考文档,可以从修改 kubectl 源码中的一个或多个注释开始。在本地 kubernetes/kubernetes 仓库中进行修改,然后向 [github.com/kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 的 master 分支提交 PR。 +kubectl 命令的参考文档是基于 kubectl 源码自动生成的。如果想要修改参考文档,可以从修改 +kubectl 源码中的一个或多个注释开始。在本地 kubernetes/kubernetes 仓库中进行修改,然后向 +[github.com/kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 的 master +分支提交 PR。 -[PR 56673](https://github.com/kubernetes/kubernetes/pull/56673/files) 是一个对 kubectl 源码中的笔误进行修复的 PR 示例。 - - -跟踪你的 PR,并回应评审人的评论。继续跟踪你的 PR,直到它合入到 kubernetes/kubernetes 仓库的 master 分支中。 +[PR 56673](https://github.com/kubernetes/kubernetes/pull/56673/files) 是一个对 kubectl +源码中的笔误进行修复的 PR 示例。 + +跟踪你的 PR,并回应评审人的评论。继续跟踪你的 PR,直到它合入到 kubernetes/kubernetes 仓库的 +master 分支中。 -## 以 cherry-pick 方式将你的修改合入已发布分支 - - +## 以 cherry-pick 方式将你的修改合入已发布分支 -你的修改已合入 master 分支中,该分支用于开发下一个 Kubernetes 版本。如果你希望修改部分出现在已发布的 Kubernetes 版本文档中,则需要提议将它们以 cherry-pick 方式合入已发布分支。 +你的修改已合入 master 分支中,该分支用于开发下一个 Kubernetes 版本。 +如果你希望修改部分出现在已发布的 Kubernetes 版本文档中,则需要提议将它们以 +cherry-pick 方式合入已发布分支。 -例如,假设 master 分支正用于开发 Kubernetes 1.10 版本,而你希望将修改合入到已发布的 1.15 版本分支。相关的操作指南,请参见 [提议一个 cherry-pick 合入](https://git.k8s.io/community/contributors/devel/sig-release/cherry-picks.md)。 - - +例如,假设 master 分支正用于开发 Kubernetes 1.16 版本,而你希望将修改合入到已发布的 1.15 版本分支。 +相关的操作指南,请参见 +[提议一个 cherry-pick](https://git.k8s.io/community/contributors/devel/sig-release/cherry-picks.md)。 + 跟踪你的 cherry-pick PR,直到它合入到已发布分支中。 -{{< note >}} -提议一个 cherry-pick 合入,需要你有在 PR 中设置标签和里程碑的权限。如果你没有,你需要与有权限为你设置标签和里程碑的人合作完成。 +{{< note >}} +提议一个 cherry-pick 需要你有在 PR 中设置标签和里程碑的权限。 +如果你没有,你需要与有权限为你设置标签和里程碑的人合作完成。 {{< /note >}} +## Setting build variables -## 编辑 Makefile - - +## 设置构建变量 {#setting-build-variables} 进入 `` 目录, 打开 `Makefile` 进行编辑: -* 设置 `K8SROOT` 为 ``。 -* 设置 `WEBROOT` 为 ``。 -* 设置 `MINOR_VERSION` 为要构建的文档的次要版本。例如,如果您想为 Kubernetes 1.15 构建文档,请将 `MINOR_VERSION` 设置为 15。保存并关闭 `Makefile` 文件。 +* Set `K8S_ROOT` to ``. +* Set `K8S_WEBROOT` to ``. +* Set `K8S_RELEASE` to the version of the docs you want to build. + For example, if you want to build docs for Kubernetes 1.17, set `K8S_RELEASE` to 1.17. - -例如,更新以下变量: +* 设置 `K8S_ROOT` 为 ``。 +* 设置 `K8S_WEBROOT` 为 ``。 +* 设置 `K8S_RELEASE` 为要构建文档的版本。 + 例如,如果您想为 Kubernetes 1.17 构建文档,请将 `K8S_RELEASE` 设置为 1.17。 + +例如: ``` -WEBROOT=$(GOPATH)/src/github.com//website -K8SROOT=$(GOPATH)/src/k8s.io/kubernetes -MINOR_VERSION=15 +export K8S_WEBROOT=$(GOPATH)/src/github.com//website +export K8S_ROOT=$(GOPATH)/src/k8s.io/kubernetes +export K8S_RELEASE=1.17 ``` ## 创建版本目录 - -版本目录是 kubectl 命令集构建的临时区域。该目录中的 YAML 文件用于创建 kubectl 命令集参考的结构和导航。 +构建目标 `createversiondirs` 会生成一个版本目录并将 kubectl 参考配置文件复制到该目录中。 +版本目录的名字模式为 `v_`。 - - -在 `gen-kubectldocs/generators` 目录中,如果你还没有一个名为 `v1_MINOR_VERSION` 的目录,那么现在通过复制前一版本的目录来创建一个。例如,假设你想要为 Kubernetes 1.15 版本生成文档,但是还没有 `v1_15` 目录,这时可以通过运行以下命令来创建并填充 `v1_15` 目录: +在 `` 目录下,执行下面的命令: ```shell -cd -git checkout release-1.15 -git pull https://github.com/kubernetes/kubernetes release-1.15 +cd +make createversiondirs ``` -## 从 kubernetes/kubernetes 检出一个分支 - - +## 从 kubernetes/kubernetes 检出一个分支 -在本地 仓库中,检出你想要生成文档的、包含 Kubernetes 版本的分支。例如,如果希望为 Kubernetes 1.15 版本生成文档,请检出 1.15 分支。确保本地分支是最新的。 +在本地 `` 仓库中,检出你想要生成文档的、包含 Kubernetes 版本的分支。 +例如,如果希望为 Kubernetes 1.17 版本生成文档,请检出 `v1.17.0` 标记。 +确保本地分支是最新的。 ```shell cd -git checkout release-1.15 -git pull https://github.com/kubernetes/kubernetes release-1.15 +git checkout v1.17.0 +git pull https://github.com/kubernetes/kubernetes v1.17.0 ``` -## 运行文档生成代码 - - +## 运行文档生成代码 -在 kubernetes-incubator/reference-docs 仓库的本地目录中,构建并运行 kubectl 命令集参数生成代码。你可能需要以 root 用户运行命令: +在本地的 `` 目录下,运行 `copycli` 构建目标。此命令以 `root` 账号运行: ```shell cd @@ -361,16 +316,16 @@ make copycli The `copycli` command will clean the staging directories, generate the kubectl command files, and copy the collated kubectl reference HTML page and assets to ``. --> -`copycli` 命令将清理暂存目录,生成 kubectl 命令集文件,并将整理后的 kubectl 参考 HTML 页面和文件复制到 ``。 +`copycli` 命令将清理暂存目录,生成 kubectl 命令文件,并将整理后的 kubectl 参考 HTML 页面和 +文件复制到 ``。 ## 找到生成的文件 - 验证是否已生成以下两个文件: ```shell @@ -380,22 +335,19 @@ Verify that these two files have been generated: ## 找到复制的文件 - -确认所有生成的文件都已复制到您的 ``: +确认所有生成的文件都已复制到你的 ``: ```shell cd git status ``` - + 输出应包括修改后的文件: ``` @@ -403,10 +355,9 @@ static/docs/reference/generated/kubectl/kubectl-commands.html static/docs/reference/generated/kubectl/navData.js ``` - -此外,输出可能显示修改后的文件: + + +此外,输出可能还包含: ``` static/docs/reference/generated/kubectl/scroll.js @@ -421,12 +372,11 @@ static/docs/reference/generated/kubectl/node_modules/font-awesome/css/font-aweso ## 在本地测试文档 - 在本地 `` 中构建 Kubernetes 文档。 ```shell @@ -434,55 +384,44 @@ cd make docker-serve ``` - + 查看[本地预览](https://localhost:1313/docs/reference/generated/kubectl/kubectl-commands/)。 ## 在 kubernetes/website 中添加和提交更改 - 运行 `git add` 和 `git commit` 提交修改文件。 -## 创建 PR - -对 `kubernetes/website` 仓库创建 PR。跟踪你的 PR,并根据需要回应评审人的评论。继续跟踪你的 PR,直到它被合入。 - - +## 创建 PR + +对 `kubernetes/website` 仓库创建 PR。跟踪你的 PR,并根据需要回应评审人的评论。 +继续跟踪你的 PR,直到它被合入。 在 PR 合入的几分钟后,你更新的参考主题将出现在[已发布文档](/docs/home/)中。 - - - ## {{% heading "whatsnext" %}} - - -* [为 Kubernetes 组件和工具生成参考文档](/docs/home/contribute/generated-reference/kubernetes-components/) -* [为 Kubernetes API 生成参考文档](/docs/home/contribute/generated-reference/kubernetes-api/) -* [为 Kubernetes 联邦 API 生成参考文档](/docs/home/contribute/generated-reference/federation-api/) +* [生成参考文档快速入门](/docs/home/contribute/generate-ref-docs/quickstart/) +* [为 Kubernetes 组件和工具生成参考文档](/docs/home/contribute/generate-ref-docs/kubernetes-components/) +* [为 Kubernetes API 生成参考文档](/docs/home/contribute/generate-ref-docs/kubernetes-api/) diff --git a/content/zh/docs/contribute/generate-ref-docs/kubernetes-api.md b/content/zh/docs/contribute/generate-ref-docs/kubernetes-api.md index c31b9a2909..135f8843ef 100644 --- a/content/zh/docs/contribute/generate-ref-docs/kubernetes-api.md +++ b/content/zh/docs/contribute/generate-ref-docs/kubernetes-api.md @@ -1,21 +1,22 @@ --- title: 为 Kubernetes API 生成参考文档 content_type: task +weight: 50 --- 本页面展示了如何为 Kubernetes API 更新自动生成的参考文档。 -Kubernetes API 参考文档是从 [Kubernetes OpenAPI 规范](https://github.com/kubernetes/kubernetes/blob/master/api/openapi-spec/swagger.json)构建的,而工具是从 [kubernetes-incubator/reference-docs](https://github.com/kubernetes-incubator/reference-docs) 构建的。 - -如果您在生成的文档中发现错误,则需要[将其上游修复](/docs/contribute/generate-ref-docs/contribute-upstream/)。 - -如果您只需要从 [OpenAPI](https://github.com/OAI/OpenAPI-Specification) 规范中重新生成参考文档,请继续阅读此页面。 +Kubernetes API 参考文档是从 +[Kubernetes OpenAPI 规范](https://github.com/kubernetes/kubernetes/blob/master/api/openapi-spec/swagger.json) +构建的,而工具是从 +[kubernetes-sigs/reference-docs](https://github.com/kubernetes-sigs/reference-docs) 构建的。 +如果您在生成的文档中发现错误,则需要[在上游修复](/docs/contribute/generate-ref-docs/contribute-upstream/)。 +如果您只需要从 [OpenAPI](https://github.com/OAI/OpenAPI-Specification) 规范中重新生成参考文档,请继续阅读此页。 ## {{% heading "prerequisites" %}} - - - -你需要安装以下软件: - - - -* [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) -* 1.9.1 或更高版本的 [Golang](https://golang.org/doc/install) - - -你需要知道如何在一个 GitHub 项目仓库中创建一个 PR。一般来说,这涉及到创建仓库的 fork 分支。想了解更多信息,请参见[创建一个文档 PR](/docs/contribute/start/) 和 [GitHub 标准 Fork & PR 工作流](https://gist.github.com/Chaser324/ce0505fbed06b947d962)。 - - - +{{< include "prerequisites-ref-docs.md" >}} -## 设置本地仓库 - -创建本地工作区并设置您的 `GOPATH`。 +## 配置本地仓库 + +创建本地工作区并设置你的 `GOPATH`。 ```shell mkdir -p $HOME/ - export GOPATH=$HOME/ ``` - + 获取以下仓库的本地克隆: ```shell go get -u github.com/kubernetes-incubator/reference-docs - go get -u github.com/go-openapi/loads go get -u github.com/go-openapi/spec ``` - -如果您还没有下载过 `kubernetes/website` 仓库,现在下载: + +如果你还没有下载过 `kubernetes/website` 仓库,现在下载: ```shell git clone https://github.com//website $GOPATH/src/github.com//website ``` - -克隆下载 kubernetes/kubernetes 仓库,并作为 k8s.io/kubernetes: + +克隆 kubernetes/kubernetes 仓库作为 k8s.io/kubernetes: ```shell git clone https://github.com/kubernetes/kubernetes $GOPATH/src/k8s.io/kubernetes @@ -125,97 +94,91 @@ The remaining steps refer to your base directory as ``. repository is `$GOPATH/src/github.com/kubernetes-incubator/reference-docs.` The remaining steps refer to your base directory as ``. --> -* [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 仓库克隆后的基本目录为 `$GOPATH/src/k8s.io/kubernetes`。 -其余后续步骤将您的基本目录称为 ``。 - -* [kubernetes/website](https://github.com/kubernetes/website) 仓库克隆后的基本目录为 `$GOPATH/src/github.com//website`。 -其余后续步骤将您的基本目录称为 ``。 - -* [kubernetes-incubator/reference-docs](https://github.com/kubernetes-incubator/reference-docs) 仓库克隆后的基本目录为 `$GOPATH/src/github.com/kubernetes-incubator/reference-docs`。 -其余后续步骤将您的基本目录称为 ``。 +* [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 仓库克隆后的根目录为 + `$GOPATH/src/k8s.io/kubernetes`。 后续步骤将此目录称为 ``。 +* [kubernetes/website](https://github.com/kubernetes/website) 仓库克隆后的根目录为 + `$GOPATH/src/github.com//website`。后续步骤将此目录称为 ``。 +* [kubernetes-sigs/reference-docs](https://github.com/kubernetes-sigs/reference-docs) + 仓库克隆后的基本目录为 `$GOPATH/src/github.com/kubernetes-sigs/reference-docs`。 + 后续步骤将此目录称为 ``。 -## 生成 API 参考文档 - +## 生成 API 参考文档 + 本节说明如何生成[已发布的 Kubernetes API 参考文档](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/)。 -### 修改 Makefile 文件 +### Setting build variables - -进入 `` 目录,然后编辑 `Makefile` 文件: +### 设置构建变量 {#setting-build-variables} -* 设置 `K8SROOT` 为 ``. -* 设置 `WEBROOT` 为 ``. -* 设置 `MINOR_VERSION` 为要构建的文档的次要版本。例如,如果您想为 Kubernetes 1.15 构建文档,请将 `MINOR_VERSION` 设置为 15。保存并关闭 `Makefile` 文件。 +* 设置 `K8S_ROOT` 为 ``. +* 设置 `K8S_WEBROOT` 为 ``. +* 设置 `K8S_RELEASE` 为要构建的文档的版本。 + 例如,如果您想为 Kubernetes 1.17 构建文档,请将 `K8S_RELEASE` 设置为 1.17。 - -例如,更新以下变量: + +例如: ``` -WEBROOT=$(GOPATH)/src/github.com//website -K8SROOT=$(GOPATH)/src/k8s.io/kubernetes -MINOR_VERSION=15 +export K8S_WEBROOT=$(GOPATH)/src/github.com//website +export K8S_ROOT=$(GOPATH)/src/k8s.io/kubernetes +export K8S_RELEASE=1.17 ``` -### 复制 OpenAPI 规范 +### Creating versioned directory and fetching Open API spec - -在 `` 目录中运行以下命令: +### 创建版本目录并复制 OpenAPI 规范 + +构建目标 `updateapispec` 负责创建版本化的构建目录。 +目录创建了之后,从 `` 仓库取回 OpenAPI 规范文件。 +这些步骤确保配置文件的版本和 Kubernetes OpenAPI 规范的版本与发行版本匹配。 +版本化目录的名称形式为 `v_`。 ```shell make updateapispec ``` - -输出显示文件已被复制: - -```shell -cp ~/src/k8s.io/kubernetes/api/openapi-spec/swagger.json gen-apidocs/generators/openapi-spec/swagger.json -``` - ### 构建 API 参考文档 - +构建目标 `copyapi` 会生成 API 参考文档并将所生成文件复制到 +`` 目录中运行以下命令: ```shell -make api +cd +make copyapi ``` - + 验证是否已生成这两个文件: ```shell @@ -223,108 +186,83 @@ Verify that these two files have been generated: [ -e "/gen-apidocs/generators/build/navData.js" ] && echo "navData.js built" || echo "no navData.js" ``` - -### 创建发布文档的目录 - - -在 `` 目录中为生成的 API 参考文件创建目录: - -```shell -mkdir -p /static/docs/reference/generated/kubernetes-api/v1. -mkdir -p /static/docs/reference/generated/kubernetes-api/v1./css -mkdir -p /static/docs/reference/generated/kubernetes-api/v1./fonts -``` - - -## 将生成的文档复制到 kubernetes/website 仓库 - - -在 `` 目录中运行以下命令,将生成的文件复制到本地 kubernetes/website 仓库。 - -```shell -make copyapi -``` - - -进入 kubernetes/website 仓库的本地主目录,并查看已修改的文件: +进入本地 `` 目录,检查哪些文件被更改: ```shell cd git status ``` - -输出显示修改后的文件: + +输出类似于: ``` -static/docs/reference/generated/kubernetes-api/v1.15/css/bootstrap.min.css -static/docs/reference/generated/kubernetes-api/v1.15/css/font-awesome.min.css -static/docs/reference/generated/kubernetes-api/v1.15/css/stylesheet.css -static/docs/reference/generated/kubernetes-api/v1.15/fonts/FontAwesome.otf -static/docs/reference/generated/kubernetes-api/v1.15/fonts/fontawesome-webfont.eot -static/docs/reference/generated/kubernetes-api/v1.15/fonts/fontawesome-webfont.svg -static/docs/reference/generated/kubernetes-api/v1.15/fonts/fontawesome-webfont.ttf -static/docs/reference/generated/kubernetes-api/v1.15/fonts/fontawesome-webfont.woff -static/docs/reference/generated/kubernetes-api/v1.15/fonts/fontawesome-webfont.woff2 -static/docs/reference/generated/kubernetes-api/v1.15/index.html -static/docs/reference/generated/kubernetes-api/v1.15/jquery.scrollTo.min.js -static/docs/reference/generated/kubernetes-api/v1.15/navData.js -static/docs/reference/generated/kubernetes-api/v1.15/scroll.js +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/css/bootstrap.min.css +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/css/font-awesome.min.css +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/css/stylesheet.css +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/FontAwesome.otf +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/fontawesome-webfont.eot +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/fontawesome-webfont.svg +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/fontawesome-webfont.ttf +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/fontawesome-webfont.woff +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/fontawesome-webfont.woff2 +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/index.html +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/js/jquery.scrollTo.min.js +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/js/navData.js +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/js/scroll.js ``` ## 更新 API 参考索引页面 +在为新发行版本生成参考文档时,需要更新下面的文件,使之包含新的版本号: +`/content/en/docs/reference/kubernetes-api/api-index.md`。 - -* 打开 `/content/en/docs/reference/kubernetes-api/index.md` 文件进行编辑,并且更新 API 参考版本号。例如: +* 打开并编辑 `/content/en/docs/reference/kubernetes-api/api-index.md`, + API 参考的版本号。例如: ``` - --- - title: v1.15 - --- - - [Kubernetes API v1.15](/docs/reference/generated/kubernetes-api/v1.15/) + title: v1.17 + [Kubernetes API v1.17](/docs/reference/generated/kubernetes-api/v1.17/) ``` - - -* 打开 `/content/en/docs/reference/_index.md` 文件进行编辑,并添加新链接以获取最新的 API 参考。移除最旧的 API 参考版本。应该有五个指向最新 API 参考的链接。 - +* 打开编辑 `/content/en/docs/reference/_index.md`,添加指向最新 API 参考 + 的链接,删除最老的 API 版本。 + 通常保留最近的五个版本的 API 参考的链接。 -## 在本地测试 API 参考 - +## 在本地测试 API 参考 + 发布 API 参考的本地版本。 -验证 [本地预览](http://localhost:1313/docs/reference/generated/kubernetes-api/v1.15/)。 +检查[本地预览](http://localhost:1313/docs/reference/generated/kubernetes-api/v1.15/)。 ```shell cd @@ -333,11 +271,11 @@ make docker-serve ## 提交更改 - 在 `` 中运行 `git add` 和 `git commit` 来提交更改。 -将您的更改[创建 PR](/docs/contribute/start/) 提交到 [kubernetes/website](https://github.com/kubernetes/website) 仓库。监视您提交的 PR,并根据需要回复 reviewer 的评论。继续监视您的 PR,直到合并为止。 - - +基于你所生成的更改[创建 PR](/docs/contribute/start/), +提交到 [kubernetes/website](https://github.com/kubernetes/website) 仓库。 +监视您提交的 PR,并根据需要回复 reviewer 的评论。继续监视您的 PR,直到合并为止。 ## {{% heading "whatsnext" %}} - -* [为 Kubernetes 组件和工具生成参考文档](/docs/home/contribute/generated-reference/kubernetes-components/) -* [为 kubectl 命令集生成参考文档](/docs/home/contribute/generated-reference/kubectl/) -* [为 Kubernetes 联邦 API 生成参考文档](/docs/home/contribute/generated-reference/federation-api/) +* [生成参考文档快速入门](/docs/home/contribute/generate-ref-docs/quickstart/) +* [为 Kubernetes 组件和工具生成参考文档](/docs/home/contribute/generate-ref-docs/kubernetes-components/) +* [为 kubectl 命令集生成参考文档](/docs/home/contribute/generate-ref-docs/kubectl/) diff --git a/content/zh/docs/contribute/generate-ref-docs/kubernetes-components.md b/content/zh/docs/contribute/generate-ref-docs/kubernetes-components.md index 676575d2cc..95b2794047 100644 --- a/content/zh/docs/contribute/generate-ref-docs/kubernetes-components.md +++ b/content/zh/docs/contribute/generate-ref-docs/kubernetes-components.md @@ -1,413 +1,50 @@ --- -title: 为 Kubernetes 组件和工具生成参考页面 +title: 为 Kubernetes 组件和工具生成参考文档 content_type: task +weight: 120 --- - -本页面展示了如何使用 `update-imported-docs` 工具来为 [Kubernetes](https://github.com/kubernetes/kubernetes) 和 [Federation](https://github.com/kubernetes/federation) 仓库中的工具和组件生成参考文档。 - - +本页面描述如何构造 Kubernetes 组件和工具的参考文档。 ## {{% heading "prerequisites" %}} - - -* 你需要一个运行着 Linux 或 macOS 操作系统的机器。 - - - -* 你需要安装以下软件: - - * [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) - - * 1.9或更高版本的 [Golang](https://golang.org/doc/install) - - * [make](https://www.gnu.org/software/make/) - - * [gcc compiler/linker](https://gcc.gnu.org/) - - - -* 在环境变量中设置 `$GOPATH`。 - - - -* 你需要知道如何在一个 GitHub 项目仓库中创建一个 PR。一般来说,这涉及到创建仓库的一个分支。想了解更多信息,请参见[创建一个文档 PR](/docs/home/contribute/create-pull-request/)。 - - +阅读参考文档快速入门指南中的[准备工作](/docs/contribute/generate-ref-docs/quickstart/#before-you-begin)节。 - -## 下载两个仓库 - - - -如果你还没有下载过 `kubernetes/website` 仓库,现在下载: - -```shell -mkdir $GOPATH/src -cd $GOPATH/src -go get github.com/kubernetes/website -``` - - - -确定 [kubernetes/website](https://github.com/kubernetes/website) 仓库的本地主目录。例如,如果按照前面的步骤来获取该仓库,则主目录是 `$GOPATH/src/github.com/kubernetes/website`。下文将该目录称为 ``。 - - - -如果你想对参考文档进行修改,但是你还没下载过 `kubernetes/kubernetes` 仓库,现在下载: - -```shell -mkdir $GOPATH/src -cd $GOPATH/src -go get github.com/kubernetes/kubernetes -``` - - - -确定 [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 仓库的本地主目录。例如,如果按照前面的步骤来获取该仓库,则主目录是 `$GOPATH/src/github.com/kubernetes/kubernetes`。下文将该目录称为 ``。 - -{{< note >}} - - -如果你只想生成参考文档,而不需要修改,则不需要手动下载 `kubernetes/kubernetes` 仓库。当你运行 `update-imported-docs` 工具时,它会自动克隆 `kubernetes/kubernetes` 仓库。 -{{< /note >}} - - - -## 编辑 Kubernetes 源码 - - - -Kubernetes 组件和工具的参考文档是基于 Kubernetes 源码自动生成的。如果想要修改参考文档,可以从修改 Kubernetes 源码中的一个或多个注释开始。在本地 kubernetes/kubernetes 仓库中进行修改,然后向 [github.com/kubernetes/kubernetes](https://github.com/kubernetes/kubernetes) 的 master 分支提交 PR。 - - - -[PR 56942](https://github.com/kubernetes/kubernetes/pull/56942) 是一个对 Kubernetes 源码中的注释进行修改的 PR 示例。 - - - -跟踪你的 PR,并回应评审人的评论。继续跟踪你的 PR,直到它合入到 `kubernetes/kubernetes` 仓库的 master 分支中。 - - - -## 以 cherry-pick 方式将你的修改合入已发布分支 - - - -你的修改已合入 master 分支中,该分支用于开发下一个 Kubernetes 版本。如果你希望修改部分出现在已发布的 Kubernetes 版本文档中,则需要提议将它们以 cherry-pick 方式合入已发布分支。 - - - -例如,假设 master 分支正用于开发 Kubernetes 1.10 版本,而你希望将修改合入到已发布的 1.9 版本分支。相关的操作指南,请参见 [提议一个 cherry-pick 合入](https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md)。 - - - -跟踪你的 cherry-pick PR,直到它合入到已发布分支中。 - -{{< note >}} - - -提议一个 cherry-pick 合入,需要你有在 PR 中设置标签和里程碑的权限。如果你没有,你需要与有权限为你设置标签和里程碑的人合作完成。 -{{< /note >}} - - - -## update-imported-docs 概述 - - - -`update-imported-docs` 工具在 `kubernetes/website/update-imported-docs/` 目录下。它执行以下步骤: - - - -1. 克隆配置文件中指定的相关仓库。为了生成参考文档,默认情况下克隆的仓库是 `kubernetes-incubator/reference-docs` 和 `kubernetes/federation`。 -1. 在克隆出的仓库下运行命令来准备文档生成器,然后生成 Markdown 文件。 -1. 将生成的 Markdown 文件复制到配置文件中指定的 `kubernetes/website` 仓库的本地目录中。 - - - -当 Markdown 文件放入 `kubernetes/website` 仓库的本地目录中后,你就可以创建 [PR](/docs/home/contribute/create-pull-request/) 将它们提交到 `kubernetes/website`。 - - - -## 自定义 reference.yml 配置文件 - - - -打开 `/update-imported-docs/reference.yml` 进行编辑。不要修改 `generate-command` 条目的内容,除非你了解它的作用,并且需要修改指定的已发布分支。 - -```yaml -repos: -- name: reference-docs - remote: https://github.com/kubernetes-sigs/reference-docs.git - # This and the generate-command below needs a change when reference-docs has - # branches properly defined - branch: master - generate-command: | - cd $GOPATH - git clone https://github.com/kubernetes/kubernetes.git src/k8s.io/kubernetes - cd src/k8s.io/kubernetes - git checkout release-1.17 - make generated_files - cp -L -R vendor $GOPATH/src - rm -r vendor - cd $GOPATH - go get -v github.com/kubernetes-sigs/reference-docs/gen-compdocs - cd src/github.com/kubernetes-sigs/reference-docs/ - make comp -``` - - - -在 reference.yml 中,`files` 字段是 `src` 和 `dst` 字段的列表。`src` 字段指定生成的 Markdown 文件的位置,而 `dst` 字段指定将此文件复制到 `kubernetes/website` 仓库的本地目录的哪个位置。例如: - -```yaml -repos: -- name: reference-docs - remote: https://github.com/kubernetes-incubator/reference-docs.git - files: - - src: gen-compdocs/build/kube-apiserver.md - dst: content/en/docs/reference/command-line-tools-reference/kube-apiserver.md - ... -``` - - - -注意,当有许多文件要从同一个源目录复制到同一个目标目录时,可以使用通配符给 `src` 赋值,而使用目录名给 `dst` 赋值。例如: - -```shell - files: - - src: gen-compdocs/build/kubeadm*.md - dst: content/en/docs/reference/setup-tools/kubeadm/generated/ -``` - - - -## 运行 update-imported-docs 工具 - - - -在检查与或自定义 `reference.yaml` 文件后,运行 `update-imported-docs` 工具: - -```shell -cd /update-imported-docs -./update-imported-docs reference.yml -``` - - - -## 在 kubernetes/website 中添加和提交修改 - - - -列出生成并准备合入到 `kubernetes/website` 仓库中的文件: - -``` -cd -git status -``` - - - -输出展示了新增和修改的文件。例如,输出可能如下所示: - -```shell -... - - modified: content/en/docs/reference/command-line-tools-reference/cloud-controller-manager.md - modified: content/en/docs/reference/command-line-tools-reference/federation-apiserver.md - modified: content/en/docs/reference/command-line-tools-reference/federation-controller-manager.md - modified: content/en/docs/reference/command-line-tools-reference/kube-apiserver.md - modified: content/en/docs/reference/command-line-tools-reference/kube-controller-manager.md - modified: content/en/docs/reference/command-line-tools-reference/kube-proxy.md - modified: content/en/docs/reference/command-line-tools-reference/kube-scheduler.md -... -``` - - - -运行 `git add` 和 `git commit` 将提交上述文件。 - - - -## 创建 PR - - - -对 `kubernetes/website` 仓库创建 PR。跟踪你的 PR,并根据需要回应评审人的评论。继续跟踪你的 PR,直到它被合入。 - - - -在 PR 合入的几分钟后,你更新的参考主题将出现在[已发布文档](/docs/home/)中。 - - +按照[参考文档快速入门](/docs/contribute/generate-ref-docs/quickstart/) +指引,生成 Kubernetes 组件和工具的参考文档。 ## {{% heading "whatsnext" %}} - -* [为 kubectl 命令集生成参考文档](/docs/home/contribute/generated-reference/kubectl/) -* [为 Kubernetes API 生成参考文档](/docs/home/contribute/generated-reference/kubernetes-api/) -* [为 Kubernetes 联邦 API 生成参考文档](/docs/home/contribute/generated-reference/federation-api/) +* [生成参考文档快速入门](/docs/home/contribute/generate-ref-docs/quickstart/) +* [为 kubectll 命令生成参考文档](/docs/home/contribute/generate-ref-docs/kubectl/) +* [为 Kubernetes API 生成参考文档](/docs/home/contribute/generate-ref-docs/kubernetes-api/) +* [为上游 Kubernetes 项目做贡献以改进文档](/docs/contribute/generate-ref-docs/contribute-upstream/) diff --git a/content/zh/docs/contribute/generate-ref-docs/prerequisites-ref-docs.md b/content/zh/docs/contribute/generate-ref-docs/prerequisites-ref-docs.md new file mode 100644 index 0000000000..4a52bfa997 --- /dev/null +++ b/content/zh/docs/contribute/generate-ref-docs/prerequisites-ref-docs.md @@ -0,0 +1,45 @@ + + +### 需求 {#requirements} + +- 你需要一台 Linux 或 macOS 机器。 + +- 你需要安装以下工具: + + - [Python](https://www.python.org/downloads/) v3.7.x + - [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) + - [Golang](https://golang.org/doc/install) 1.13+ 版本 + - 用来安装 PyYAML 的 [Pip](https://pypi.org/project/pip/) + - [PyYAML](https://pyyaml.org/) v5.1.2 + - [make](https://www.gnu.org/software/make/) + - [gcc compiler/linker](https://gcc.gnu.org/) + - [Docker](https://docs.docker.com/engine/installation/) (仅用于 `kubectl` 命令参考) + + +- 你的 `PATH` 环境变量必须包含所需要的构建工具,例如 `Go` 程序和 `python`。 + +- 你需要知道如何为一个 GitHub 仓库创建拉取请求(PR)。 + 这牵涉到创建仓库的派生(fork)副本。 + 有关信息可进一步查看[基于本地副本开展工作](/docs/contribute/intermediate/#work_from_a_local_clone)。 + diff --git a/content/zh/docs/contribute/generate-ref-docs/quickstart.md b/content/zh/docs/contribute/generate-ref-docs/quickstart.md new file mode 100644 index 0000000000..4011b5f9b8 --- /dev/null +++ b/content/zh/docs/contribute/generate-ref-docs/quickstart.md @@ -0,0 +1,405 @@ +--- +title: 快速入门 +content_type: task +weight: 40 +--- + + + + + +本页讨论如何使用 `update-imported-docs` 脚本来生成 Kubernetes 参考文档。 +此脚本将构建的配置过程自动化,并为某个发行版本生成参考文档。 + +## {{% heading "prerequisites" %}} + +{{< include "prerequisites-ref-docs.md" >}} + + + +## 获取文档仓库 {#getting-the-docs-repository} + +确保你的 `website` 派生仓库与 `kubernetes/website` 主分支一致,并克隆 +你的派生仓库。 + +```shell +mkdir github.com +cd github.com +git clone git@github.com:/website.git +``` + + +确定你的克隆副本的根目录。例如,如果你按照前面的步骤获取了仓库,你的根目录 +会是 `github.com/website`。接下来的步骤中,`` 用来指代你的根目录。 + +{{< note>}} +如果你希望更改构建工具和 API 参考资料,可以阅读 +[上游贡献指南](/docs/contribute/generate-ref-docs/contribute-upstream). +{{< /note >}} + + +## update-imported-docs 的概述 + +脚本 `update-imported-docs` 位于 `/update-imported-docs/` 目录下, +能够生成以下参考文档: + +* Kubernetes 组件和工具的参考页面 +* `kubectl` 命令参考文档 +* Kubernetes API 参考文档 + + +脚本 `update-imported-docs` 基于 Kubernetes 源代码生成参考文档。 +过程中会在你的机器的 `/tmp` 目录下创建临时目录,克隆所需要的仓库 +`kubernetes/kubernetes` 和 `kubernetes-sigs/reference-docs` 到此临时目录。 +脚本会将 `GOPATH` 环境变量设置为指向此临时目录。 +此外,脚本会设置三个环境变量: + +* `K8S_RELEASE` +* `K8S_ROOT` +* `K8S_WEBROOT` + + +脚本需要两个参数才能成功运行: + +* 一个 YAML 配置文件(`reference.yml`) +* 一个发行版本字符串,例如:`1.17` + +配置文件中包含 `generate-command` 字段,其中定义了一系列来自于 +`kubernetes-sigs/reference-docs/Makefile` 的构建指令。 +变量 `K8S_RELEASE` 用来确定所针对的发行版本。 + + +脚本 `update-imported-docs` 执行以下步骤: + +1. 克隆配置文件中所指定的相关仓库。就生成参考文档这一目的而言,要克隆的 + 仓库默认为 `kubernetes-sigs/reference-docs`。 +1. 在所克隆的仓库下运行命令,准备文档生成器,之后生成 HTML 和 Markdown 文件。 +1. 将所生成的 HTML 和 Markdown 文件复制到 `` 本地克隆副本中, + 放在配置文件中所指定的目录下。 +1. 更新 `kubectl.md` 文件中对 `kubectl` 命令文档的链接,使之指向 `kubectl` + 命令参考中对应的节区。 + + +当所生成的文件已经被放到 `` 目录下,你就可以将其提交到你的派生副本中, +并基于所作提交发起[拉取请求(PR)](/docs/contribute/start/)到 k/website 仓库。 + + +## 配置文件格式 {#configuration-file-format} + +每个配置文件可以包含多个被导入的仓库。当必要时,你可以通过手工编辑此文件进行定制。 +你也可以通过创建新的配置文件来导入其他文档集合。 +下面是 YAML 配置文件的一个例子: + +```yaml +repos: +- name: community + remote: https://github.com/kubernetes/community.git + branch: master + files: + - src: contributors/devel/README.md + dst: docs/imported/community/devel.md + - src: contributors/guide/README.md + dst: docs/imported/community/guide.md +``` + + +通过工具导入的单页面的 Markdown 文档必须遵从 +[文档样式指南](/docs/contribute/style/style-guide/)。 + + + +## 定制 reference.yml + +打开 `/update-imported-docs/reference.yml` 文件进行编辑。 +在不了解参考文档构造命令的情况下,不要更改 `generate-command` 字段的内容。 +你一般不需要更新 `reference.yml` 文件。不过也有时候上游的源代码发生变化, +导致需要对配置文件进行更改(例如:Golang 版本依赖或者第三方库发生变化)。 +如果你遇到类似问题,请在 [Kubernetes Slack 的 #sig-docs 频道](https://kubernetes.slack.com) +联系 SIG-Docs 团队。 + + + +{{< note >}} +注意,`generate-command` 是一个可选项,用来运行指定命令或者短脚本以在仓库 +内生成文档。 +{{< /note >}} + +在 `reference.yml` 文件中,`files` 属性包含了一组 `src` 和 `dst` 字段。 +`src` 字段给出在所克隆的 `kubernetes-sigs/reference-docs` 构造目录中生成的 +Markdown 文件的位置,而 `dst` 字段则给出了对应文件要复制到的、所克隆的 +`kubernetes/website` 仓库中的位置。例如: + +```yaml +repos: +- name: reference-docs + remote: https://github.com/kubernetes-sigs/reference-docs.git + files: + - src: gen-compdocs/build/kube-apiserver.md + dst: content/en/docs/reference/command-line-tools-reference/kube-apiserver.md + ... +``` + + +注意,如果从同一源目录中有很多文件要复制到目标目录,你可以在为 `src` 所设置的 +值中使用通配符。这时,为 `dst` 所设置的值必须是目录名称。例如: + +```yaml + files: + - src: gen-compdocs/build/kubeadm*.md + dst: content/en/docs/reference/setup-tools/kubeadm/generated/ +``` + + +## 运行 update-imported-docs 工具 + +你可以用如下方式运行 `update-imported-docs` 工具: + +```shell +cd /update-imported-docs +./update-imported-docs +``` + + +例如: + +```shell +./update-imported-docs reference.yml 1.17 +``` + + + +## 修复链接 + +配置文件 `release.yml` 中包含用来修复相对链接的指令。 +若要修复导入文件中的相对链接,将 `gen-absolute-links` 属性设置为 `true`。 +你可以在 [`release.yml`](https://github.com/kubernetes/website/blob/master/update-imported-docs/release.yml) +文件中找到示例。 + + +## 添加并提交 kubernetes/website 中的变更 + +枚举新生成并复制到 `` 的文件: + +```shell +cd +git status +``` + + +输出显示新生成和已修改的文件。取决于上游源代码的修改多少, +所生成的输出也会不同。 + +### 生成的 Kubernetes 组件文档 + +``` +content/en/docs/reference/command-line-tools-reference/cloud-controller-manager.md +content/en/docs/reference/command-line-tools-reference/kube-apiserver.md +content/en/docs/reference/command-line-tools-reference/kube-controller-manager.md +content/en/docs/reference/command-line-tools-reference/kube-proxy.md +content/en/docs/reference/command-line-tools-reference/kube-scheduler.md +content/en/docs/reference/setup-tools/kubeadm/generated/kubeadm.md +content/en/docs/reference/kubectl/kubectl.md +``` + + +### 生成的 kubectl 命令参考文件 + +``` +static/docs/reference/generated/kubectl/kubectl-commands.html +static/docs/reference/generated/kubectl/navData.js +static/docs/reference/generated/kubectl/scroll.js +static/docs/reference/generated/kubectl/stylesheet.css +static/docs/reference/generated/kubectl/tabvisibility.js +static/docs/reference/generated/kubectl/node_modules/bootstrap/dist/css/bootstrap.min.css +static/docs/reference/generated/kubectl/node_modules/highlight.js/styles/default.css +static/docs/reference/generated/kubectl/node_modules/jquery.scrollto/jquery.scrollTo.min.js +static/docs/reference/generated/kubectl/node_modules/jquery/dist/jquery.min.js +static/docs/reference/generated/kubectl/css/font-awesome.min.css +``` + + +### 生成的 Kubernetes API 参考目录与文件 + +``` +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/index.html +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/js/navData.js +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/js/scroll.js +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/js/query.scrollTo.min.js +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/css/font-awesome.min.css +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/css/bootstrap.min.css +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/css/stylesheet.css +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/FontAwesome.otf +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/fontawesome-webfont.eot +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/fontawesome-webfont.svg +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/fontawesome-webfont.ttf +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/fontawesome-webfont.woff +static/docs/reference/generated/kubernetes-api/{{< param "version" >}}/fonts/fontawesome-webfont.woff2 +``` + + +运行 `git add` 和 `git commit` 提交文件。 + +## 创建拉取请求 {#creating-a-pull-request} + +接下来创建一个对 `kubernetes/website` 仓库的拉取请求(PR)。 +监视所创建的 PR,并根据需要对评阅意见给出反馈。 +继续监视该 PR 直到其被合并为止。 + +当你的 PR 被合并几分钟之后,你所做的对参考文档的变更就会出现 +[发布的文档](/docs/home/)上。 + +## {{% heading "whatsnext" %}} + + +要手动设置所需的构造仓库,执行构建目标,以生成各个参考文档,可参考下面的指南: + +* [为 Kubernetes 组件和工具生成参考文档](/docs/contribute/generate-ref-docs/kubernetes-components/) +* [为 kubeclt 命令生成参考文档](/docs/contribute/generate-ref-docs/kubectl/) +* [为 Kubernetes API 生成参考文档](/docs/contribute/generate-ref-docs/kubernetes-api/) + From 7eef8e73babba1a7eaf8be6d1413db3136805861 Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Tue, 23 Jun 2020 10:49:32 +0800 Subject: [PATCH 18/99] [zh] Sync contribution guidelines (5) This PR is about the reviews. --- content/zh/docs/contribute/review/_index.md | 17 + .../docs/contribute/review/for-approvers.md | 432 ++++++++++++++++++ .../docs/contribute/review/reviewing-prs.md | 202 ++++++++ 3 files changed, 651 insertions(+) create mode 100644 content/zh/docs/contribute/review/_index.md create mode 100644 content/zh/docs/contribute/review/for-approvers.md create mode 100644 content/zh/docs/contribute/review/reviewing-prs.md diff --git a/content/zh/docs/contribute/review/_index.md b/content/zh/docs/contribute/review/_index.md new file mode 100644 index 0000000000..b3401268bb --- /dev/null +++ b/content/zh/docs/contribute/review/_index.md @@ -0,0 +1,17 @@ +--- +title: 评阅变更 +weight: 30 +--- + + + + +本节描述如何对内容进行评阅。 + + + diff --git a/content/zh/docs/contribute/review/for-approvers.md b/content/zh/docs/contribute/review/for-approvers.md new file mode 100644 index 0000000000..3db894e0b4 --- /dev/null +++ b/content/zh/docs/contribute/review/for-approvers.md @@ -0,0 +1,432 @@ +--- +title: 评阅人和批准人文档 +linktitle: 评阅人和批准人 +slug: for-approvers +content_type: concept +weight: 20 +--- + + + + +SIG Docs [评阅人(Reviewers)](/docs/contribute/participating/#reviewers) +和[批准人(Approvers)](/docs/contribute/participating/#approvers) +在对变更进行评审时需要做一些额外的事情。 + +每周都有一个特定的文档批准人自愿负责对 PR 进行分类和评阅。 +此角色称作该周的“PR 管理者(PR Wrangler)”。 +相关信息可参考 [PR Wrangler 排班表](https://github.com/kubernetes/website/wiki/PR-Wranglers)。 +要成为 PR Wangler,需要参加每周的 SIG Docs 例会,并自愿报名。 +即使当前这周排班没有轮到你,你仍可以评阅那些尚未被积极评阅的 PRs。 + +除了上述的轮值安排,后台机器人也会为基于所影响的文件来为 PR +指派评阅人和批准人。 + + + +## 评阅 PR + +Kubernetes 文档遵循 [Kubernetes 代码评阅流程](https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md#the-code-review-process)。 + +[评阅 PR](/docs/contribute/review/reviewing-prs) 文档中所描述的所有规程都适用, +不过评阅人和批准人还要做以下工作: + + +- 根据需要使用 Prow 命令 `/assign` 指派特定的评阅人。如果某个 PR + 需要来自代码贡献者的技术审核时,这一点非常重要。 + + {{< note >}} + 你可以查看 Markdown 文件的文件头,其中的 `reviewers` 字段给出了哪些人可以为文档提供技术审核。 + {{< /note >}} + +- 确保 PR 遵从[内容指南](/docs/contribute/style/content-guide/)和[样式指南](/docs/contribute/style/style-guide/); + 如果 PR 没有达到要求,指引作者阅读指南中的相关部分。 +- 适当的时候使用 GitHub **Request Changes** 选项,建议 PR 作者实施所建议的修改。 +- 当你所提供的建议被采纳后,在 GitHub 中使用 `/approve` 或 `/lgtm` Prow 命令,改变评审状态。 + + +## 提交到他人的 PR + +为 PR 留下评语是很有用的,不过有时候你需要向他人的 PR 提交内容。 + +除非他人明确请求你的帮助或者你希望重启一个被放弃很久的 PR,不要“接手”他人的工作。 +尽管短期看来这样做可以提高效率,但是也剥夺了他人提交贡献的机会。 + +你所要遵循的流程取决于你需要编辑已经在 PR 范畴的文件,还是 PR 尚未触碰的文件。 + + +如果处于下列情况之一,你不可以向别人的 PR 提交内容: + +- 如果 PR 作者是直接将自己的分支提交到 + [https://github.com/kubernetes/website/](https://github.com/kubernetes/website/) + 仓库。只有具有推送权限的评阅人才可以向他人的 PR 提交内容。 + + {{< note >}} + 我们应鼓励作者下次将分支推送到自己的克隆副本之后再发起 PR。 + {{< /note >}} + +- PR 作者明确地禁止批准人编辑他/她的 PR。 + + +## 评阅用的 Prow 命令 + +[Prow](https://github.com/kubernetes/test-infra/blob/master/prow/README.md) +是基于 Kubernetes 的 CI/CD 系统,基于拉取请求(PR)的触发运行不同任务。 +Prow 使得我们可以使用会话机器人一样的命令跨整个 Kubernetes 组织处理 GitHub +动作,例如[添加和删除标签](#adding-and-removing-issue-labels)、关闭 Issues +以及指派批准人等等。你可以使用 `/<命令名称>` 的形式以 GitHub 评论的方式输入 +Prow 命令。 + +评阅人和批准人最常用的 Prow 命令有: + + +{{< table caption="评阅用 Prow 命令" >}} +Prow 命令 | 角色限制 | 描述 +:------------|:------------------|:----------- +`/lgtm` | 任何人均可使用,但只有评阅人和批准人使用此命令的时候才会触发自动化操作 | 用来表明你已经完成 PR 的评阅并对其所作变更表示满意 +`/approve` | 批准人 | 批准某 PR 可以合并 +`/assign` |评阅人或批准人 | 指派某人来评阅或批准某 PR +`/close` | 评阅人或批准人 | 关闭 Issue 或 PR +`/hold` | 任何人 | 添加 `do-not-merge/hold` 标签,用来表明 PR 不应被自动合并 +`/hold cancel` | 任何人 | 去掉 `do-not-merge/hold` 标签 +{{< /table >}} + +请参考 [Prow 命令指南](https://prow.k8s.io/command-help),了解你可以在 PR +中使用的命令的完整列表。 + + +## 对 Issue 进行诊断和分类 + +一般而言,SIG Docs 遵从 [Kubernetes issue 判定](https://github.com/kubernetes/community/blob/master/contributors/guide/issue-triage.md) 流程并使用相同的标签。 + +此 GitHub Issue +[过滤器](https://github.com/kubernetes/website/issues?q=is%3Aissue+is%3Aopen+-label%3Apriority%2Fbacklog+-label%3Apriority%2Fimportant-longterm+-label%3Apriority%2Fimportant-soon+-label%3Atriage%2Fneeds-information+-label%3Atriage%2Fsupport+sort%3Acreated-asc) +可以用来查找需要评判的 Issues。 + + + +### 评判 Issue {#triaging-an-issue} + +1. 验证 Issue 的合法性 + + - 确保 Issue 是关于网站文档的。某些 Issue 可以通过回答问题或者为报告者提供 + 资源链接来快速关闭。 + 参考[请求支持或代码缺陷报告](#support-requests-or-code-bug-reports) + 节以了解详细信息。 + - 评估该 Issue 是否有价值。 + - 如果 Issue 缺少足够的细节以至于无法采取行动,或者报告者没有通过模版提供 + 足够信息,可以添加 `triage/needs-information` 标签。 + - 如果 Issue 同时标注了 `lifecycle/stale` 和 `triage/needs-information` + 标签,可以直接关闭。 + + +2. 添加优先级标签( + [Issue 判定指南](https://github.com/kubernetes/community/blob/master/contributors/guide/issue-triage.md#define-priority)中有优先级标签的详细定义) + + {{< table caption="Issue 标签" >}} + 标签 | 描述 + :------------|:------------------ + `priority/critical-urgent` | 应马上处理 + `priority/important-soon` | 应在 3 个月内处理 + `priority/important-longterm` | 应在 6 个月内处理 + `priority/backlog` | 可无限期地推迟,可在人手充足时处理 + `priority/awaiting-more-evidence` | 占位符,标示 Issue 可能是一个不错的 Issue,避免该 Issue 被忽略或遗忘 + `help` or `good first issue` | 适合对 Kubernetes 或 SIG Docs 经验较少的贡献者来处理。更多信息可参考[需要帮助和入门候选 Issue 标签](https://github.com/kubernetes/community/blob/master/contributors/guide/help-wanted.md)。 + {{< /table >}} + + 基于你自己的判断,你可以选择某 Issue 来处理,为之发起 PR + (尤其是那些可以很快处理或与你已经在做的工作相关的 Issue)。 + +如果你对 Issue 评判有任何问题,可以在 `#sig-docs` Slack 频道或者 +[kubernetes-sig-docs 邮件列表](https://groups.google.com/forum/#!forum/kubernetes-sig-docs) +中提问。 + + +## 添加和删除 Issue 标签 {#adding-and-removing-issue-labels} + +要添加标签,可以用以下形式对 PR 进行评论: + +- `/<要添加的标签>` (例如, `/good-first-issue`) +- `/<标签类别> <要添加的标签>` (例如,`/triage needs-information` 或 `/language ja`) + +要移除某个标签,可以用以下形式对 PR 进行评论: + +- `/remove-<要移除的标签>` (例如,`/remove-help`) +- `/remove-<标签类别> <要移除的标签>` (例如,`/remove-triage needs-information`) + + +在以上两种情况下,标签都必须合法存在。如果你尝试添加一个尚不存在的标签, +对应的命令会被悄悄忽略。 + +关于所有标签的完整列表,可以参考 +[Website 仓库的标签节](https://github.com/kubernetes/website/labels)。 +实际上,SIG Docs 并没有使用全部标签。 + + +### Issue 生命周期标签 + +Issues 通常都可以快速创建并关闭。 +不过也有些时候,某个 Issue 被创建之后会长期处于非活跃状态。 +也有一些时候,即使超过 90 天,某个 Issue 仍应保持打开状态。 + +{{< table caption="Issue 生命周期标签" >}} +标签 | 描述 +:------------|:------------------ +`lifecycle/stale` | 过去 90 天内某 Issue 无人问津,会被自动标记为停滞状态。如果 Issue 没有被 `/remove-lifecycle stale` 命令重置生命期,就会被自动关闭。 +`lifecycle/frozen` | 对应的 Issue 即使超过 90 天仍无人处理也不会进入停滞状态。用户手动添加此标签给一些需要保持打开状态超过 90 天的 Issue,例如那些带有 `priority/important-longterm` 标签的 Issue。 +{{< /table >}} + + +## 处理特殊的 Issue 类型 {#handling-special-issue-types} + +SIG Docs 常常会遇到以下类型的 Issue,因此对其处理方式描述如下。 + +### 重复的 Issue {#duplicate-issues} + +如果针对同一个问题有不止一个打开的 Issue,可以将其合并为一个 Issue。 +你需要决定保留哪个 Issue 为打开状态(或者重新登记一个新的 Issue), +然后将所有相关的信息复制过去并提供对关联 Issues 的链接。 +最后,将所有其他描述同一问题的 Issue 标记为 `triage/duplicate` 并关闭之。 +保持只有一个 Issue 待处理有助于减少困惑,避免在同一问题上发生重复劳动。 + + +### 失效链接 Issues {#dead-link-issues} + +如果失效链接是关于 API 或者 `kubectl` 文档的,可以将其标记为 +`/priority critical-urgent`,直到问题原因被弄清楚为止。 +对于其他的链接失效问题,可以标记 `/priority important-longterm`, +因为这些问题都需要手动处理。 + +### 博客问题 {#blog-issues} + +我们预期 [Kubernetes 博客](https://kubernetes.io/blog/)条目随着时间推移都会过期。 +因此,我们只维护一年内的博客条目。 +如果某个 Issue 是与某个超过一年的博客条目有关的,可以直接关闭 +Issue,不必修复。 + + +### 请求支持或代码缺陷报告 {#support-requests-or-code-bug-reports} + +某些文档 Issues 实际上是关于底层代码的 Issue 或者在某方面请求协助的问题, +例如某个教程无法正常工作。 +对于与文档无关的 Issues,关闭它并打上标签 `triage/support`,可以通过评论 +告知请求者其他支持渠道(Slack、Stack Overflow)。 +如果有相关的其他仓库,可以告诉请求者应该在哪个仓库登记与功能特性相关的 Issues +(通常会是 `kubernetes/kubernetes`)。 + +下面是对支持请求的回复示例: + +```none +This issue sounds more like a request for support and less +like an issue specifically for docs. I encourage you to bring +your question to the `#kubernetes-users` channel in +[Kubernetes slack](http://slack.k8s.io/). You can also search +resources like +[Stack Overflow](http://stackoverflow.com/questions/tagged/kubernetes) +for answers to similar questions. + +You can also open issues for Kubernetes functionality in +https://github.com/kubernetes/kubernetes. + +If this is a documentation issue, please re-open this issue. +``` + + +对代码缺陷 Issue 的回复示例: + +```none +This sounds more like an issue with the code than an issue with +the documentation. Please open an issue at +https://github.com/kubernetes/kubernetes/issues. + +If this is a documentation issue, please re-open this issue. +``` + diff --git a/content/zh/docs/contribute/review/reviewing-prs.md b/content/zh/docs/contribute/review/reviewing-prs.md new file mode 100644 index 0000000000..cc93511a8b --- /dev/null +++ b/content/zh/docs/contribute/review/reviewing-prs.md @@ -0,0 +1,202 @@ +--- +title: 评阅 PRs +content_type: concept +main_menu: true +weight: 10 +--- + + + + +任何人均可评阅文档的拉取请求。访问 Kubernetes 网站仓库的 +[pull requests](https://github.com/kubernetes/website/pulls) +部分可以查看所有待处理的拉取请求(PRs)。 + +评阅文档 PR 是将你自己介绍给 Kubernetes 社区的一种很好的方式。 +它将有助于你学习代码库并与其他贡献者之间建立相互信任关系。 + +在评阅之前,可以考虑: + +- 阅读[内容指南](/docs/contribute/style/content-guide/)和 + [样式指南](/docs/contribute/style/style-guide/)以便给出有价值的评论。 +- 了解 Kubernetes 文档社区中不同的[角色和职责](/docs/contribute/participating/#roles-and-responsibilities)。 + + + +## 准备工作 {#before-you-begin} + +在你开始评阅之前: + +- 阅读 [CNCF 行为准则](https://github.com/cncf/foundation/blob/master/code-of-conduct.md) + 确保你会始终遵从其中约定; +- 保持有礼貌、体谅他人,怀助人为乐初心; +- 评论时若给出修改建议,也要兼顾 PR 的积极方面 +- 保持同理心,多考虑他人收到评阅意见时的可能反应 +- 假定大家都是好意的,通过问问题澄清意图 +- 如果你是有经验的贡献者,请考虑和新贡献者一起合作,提高其产出质量 + + +## 评阅过程 {#review-process} + +一般而言,应该使用英语来评阅 PR 的内容和样式。 + +1. 前往 [https://github.com/kubernetes/website/pulls](https://github.com/kubernetes/website/pulls), + 你会看到所有针对 Kubernetes 网站和文档的待处理 PRs。 + +2. 使用以下标签(组合)对待处理 PRs 进行过滤: + + - `cncf-cla: yes` (建议):由尚未签署 CLA 的贡献者所发起的 PRs 不可以合并。 + 参考[签署 CLA](/docs/contribute/new-content/overview/#sign-the-cla) 以了解更多信息。 + - `language/en` (建议):仅查看英语语言的 PRs。 + - `size/<尺寸>`:过滤特定尺寸(规模)的 PRs。如果你刚入门,可以从较小的 PR 开始。 + + 此外,确保 PR 没有标记为尚未完成(Work in Progress)。 + 包含 `work in progress` 的 PRs 通常还没准备好被评阅。 + + +3. 选定 PR 评阅之后,可以通过以下方式理解所作的变更: + + - 阅读 PR 描述以理解所作变更,并且阅读所有关联的 Issues + - 阅读其他评阅人给出的评论 + - 点击 **Files changed** Tab 页面,查看被改变的文件和代码行 + - 滚动到 **Conversation** Tab 页面下端的 PR 构建检查节区,点击 + **deploy/netlify** 行的 **Details** 链接,预览 Netlify + 预览构建所生成的结果 + +4. 前往 **Files changed** Tab 页面,开始你的评阅工作 + + 1. 点击你希望评论的行旁边的 `+` 号 + 2. 填写你对该行的评论,之后或者选择**Add single comment** (如果你只有一条评论) + 或者 **Start a review** (如果你还有其他评论要添加) + 3. 评论结束时,点击页面顶部的 **Review changes**。这里你可以添加你的评论结语 + (记得留下一些正能量的评论!)、根据需要批准 PR、请求作者进一步修改等等。 + 新手应该选择 **Comment**。 + + +## 评阅清单 {#reviewing-checklist} + +评阅 PR 时可以从下面的条目入手。 + +### 语言和语法 {#language-and-grammar} + +- 是否存在明显的语言或语法错误?对某事的描述有更好的方式? +- 是否存在一些过于复杂晦涩的用词,本可以用简单词汇来代替? +- 是否有些用词、术语或短语可以用不带歧视性的表达方式代替? +- 用词和大小写方面是否遵从了[样式指南](/docs/contribute/style/style-guide/)? +- 是否有些句子太长,可以改得更短、更简单? +- 是否某些段落过长,可以考虑使用列表或者表格来表达? + + +### 内容 {#content} + +- Kubernetes 网站上是否别处已经存在类似的内容? +- 内容本身是否过度依赖于网站范畴之外、独立供应商或者非开源的文档? + + +### 网站 {#Website} + +- PR 是否改变或者删除了某页面的标题、slug/别名或者链接锚点? + 如果是这样,PR 是否会导致出现新的失效链接? + 是否有其他的办法,比如改变页面标题但不改变其 slug? +- PR 是否引入新的页面?如果是: + - 该页面是否使用了正确的[页面内容类型](/docs/contribute/style/page-content-types/) + 及相关联的 Hugo 短代码(shortcodes)? + - 该页面能否在对应章节的侧面导航中显示?显示得正确么? + - 该页面是否应出现在[网站主页面](/docs/home/)的列表中? +- 变更是否正确出现在 Netlify 预览中了? + 要对列表、代码段、表格、注释和图像等元素格外留心 + +### 其他 {#other} + +对于 PR 中的小问题,例如拼写错误或者空格问题,可以在你的评论前面加上 `nit:`。 +这样做可以让作者知道该问题不是一个不得了的大问题。 + From 1822626398bc1cbdd86e830fd68afa428a98c81d Mon Sep 17 00:00:00 2001 From: Arhell Date: Wed, 8 Jul 2020 00:38:22 +0300 Subject: [PATCH 19/99] fix tooltip overflows --- static/css/custom-jekyll/tags.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/css/custom-jekyll/tags.css b/static/css/custom-jekyll/tags.css index 3b929925e8..1ff6d12e85 100644 --- a/static/css/custom-jekyll/tags.css +++ b/static/css/custom-jekyll/tags.css @@ -27,7 +27,7 @@ /* Position the tooltip text */ position: absolute; - z-index: 1; + z-index: 10; bottom: 125%; left: 50%; margin-left: -150px; From fc3c00215d2245eca67b6162d00f8c4df6aea467 Mon Sep 17 00:00:00 2001 From: Muhammad Panji Date: Wed, 8 Jul 2020 07:31:53 +0700 Subject: [PATCH 20/99] Rearrange paragraphs in iptabels bridged traffic section in install kubeadm --- .../production-environment/tools/kubeadm/install-kubeadm.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/en/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md b/content/en/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md index 1e504eb40d..2996568369 100644 --- a/content/en/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md +++ b/content/en/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md @@ -54,6 +54,8 @@ route, we recommend you add IP route(s) so Kubernetes cluster addresses go via t ## Letting iptables see bridged traffic +Make sure that the `br_netfilter` module is loaded. This can be done by running `lsmod | grep br_netfilter`. To load it explicitly call `sudo modprobe br_netfilter`. + As a requirement for your Linux Node's iptables to correctly see bridged traffic, you should ensure `net.bridge.bridge-nf-call-iptables` is set to 1 in your `sysctl` config, e.g. ```bash @@ -64,8 +66,6 @@ EOF sudo sysctl --system ``` -Make sure that the `br_netfilter` module is loaded before this step. This can be done by running `lsmod | grep br_netfilter`. To load it explicitly call `sudo modprobe br_netfilter`. - For more details please see the [Network Plugin Requirements](/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/#network-plugin-requirements) page. ## Check required ports From 0f30bc04db4187bc7f69543d4b2f82eccabb7cb8 Mon Sep 17 00:00:00 2001 From: Celeste Horgan Date: Thu, 2 Jul 2020 08:41:28 -0700 Subject: [PATCH 21/99] Fix display of dropdown on case studies --- assets/scss/_custom.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/assets/scss/_custom.scss b/assets/scss/_custom.scss index f02d6d908b..202c50393c 100644 --- a/assets/scss/_custom.scss +++ b/assets/scss/_custom.scss @@ -108,6 +108,10 @@ section { &.dropdown:hover { color: $medium-grey; + + .dropdown-menu { + display: block; + } } } } @@ -390,4 +394,4 @@ main.content { } } } -} +} \ No newline at end of file From 086e8a60f2ac87e4abe42deea1e054981c070751 Mon Sep 17 00:00:00 2001 From: Celeste Horgan Date: Tue, 7 Jul 2020 16:33:22 -0700 Subject: [PATCH 22/99] Use bootstrap right alignment --- assets/scss/_custom.scss | 12 ------------ layouts/partials/navbar-lang-selector.html | 10 ++++++++++ layouts/partials/navbar-version-selector.html | 6 +++--- 3 files changed, 13 insertions(+), 15 deletions(-) create mode 100644 layouts/partials/navbar-lang-selector.html diff --git a/assets/scss/_custom.scss b/assets/scss/_custom.scss index 202c50393c..1921e19067 100644 --- a/assets/scss/_custom.scss +++ b/assets/scss/_custom.scss @@ -101,18 +101,6 @@ section { left: 0; background: #fff; } - - .dropdown-menu { - left: -80px; - } - - &.dropdown:hover { - color: $medium-grey; - - .dropdown-menu { - display: block; - } - } } } diff --git a/layouts/partials/navbar-lang-selector.html b/layouts/partials/navbar-lang-selector.html new file mode 100644 index 0000000000..7459c621c3 --- /dev/null +++ b/layouts/partials/navbar-lang-selector.html @@ -0,0 +1,10 @@ +{{/* Link directly to documentation etc., if possible. */}} +{{ $langPage := cond (gt (len .Translations) 0) . .Site.Home }} + + \ No newline at end of file diff --git a/layouts/partials/navbar-version-selector.html b/layouts/partials/navbar-version-selector.html index dfded2b553..5a3f03e126 100644 --- a/layouts/partials/navbar-version-selector.html +++ b/layouts/partials/navbar-version-selector.html @@ -1,8 +1,8 @@ - \ No newline at end of file From f9e2439e56e078bbdbdca97cf44eec2b6057c25d Mon Sep 17 00:00:00 2001 From: Celeste Horgan Date: Tue, 7 Jul 2020 17:42:51 -0700 Subject: [PATCH 23/99] Include scripts.html in case studies template --- layouts/case-studies/single-baseof.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/layouts/case-studies/single-baseof.html b/layouts/case-studies/single-baseof.html index e97cbf934d..64b48a4e13 100644 --- a/layouts/case-studies/single-baseof.html +++ b/layouts/case-studies/single-baseof.html @@ -9,5 +9,7 @@ {{ partialCached "footer.html" . }} + {{ partialCached "scripts.html" . }} + \ No newline at end of file From 67fc065ae8ebdb8f62afcc4b17d7ee12dd04bba3 Mon Sep 17 00:00:00 2001 From: jianz Date: Wed, 8 Jul 2020 11:12:42 +0800 Subject: [PATCH 24/99] escape the angle brackets in the table. escape the angle brackets in order to to show the word inside table. --- content/en/docs/reference/using-api/api-concepts.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/en/docs/reference/using-api/api-concepts.md b/content/en/docs/reference/using-api/api-concepts.md index 3c41c70116..f2109071a1 100644 --- a/content/en/docs/reference/using-api/api-concepts.md +++ b/content/en/docs/reference/using-api/api-concepts.md @@ -726,11 +726,11 @@ For get and list, the semantics of resource version are: **List:** -| paging | resourceVersion unset | resourceVersion="0" | resourceVersion="{value other than 0}" | -|-------------------------------|-----------------------|------------------------------------------------|----------------------------------------| -| limit unset | Most Recent | Any | Not older than | -| limit="n", continue unset | Most Recent | Any | Exact | -| limit="n", continue="" | Continue Token, Exact | Invalid, but treated as Continue Token, Exact | Invalid, HTTP `400 Bad Request` | +| paging | resourceVersion unset | resourceVersion="0" | resourceVersion="{value other than 0}" | +|---------------------------------|-----------------------|------------------------------------------------|----------------------------------------| +| limit unset | Most Recent | Any | Not older than | +| limit="n", continue unset | Most Recent | Any | Exact | +| limit="n", continue="\" | Continue Token, Exact | Invalid, but treated as Continue Token, Exact | Invalid, HTTP `400 Bad Request` | The meaning of the get and list semantics are: From e3da1ce1be8698937fea30e2e361aa658569f696 Mon Sep 17 00:00:00 2001 From: Irvi Firqotul Aini Date: Mon, 6 Jul 2020 20:36:48 +0700 Subject: [PATCH 25/99] docs: Translate Add External IP Address Tutorial --- .../tutorials/stateless-application/_index.md | 5 + .../expose-external-ip-address.md | 173 ++++++++++++++++++ .../service/load-balancer-example.yaml | 21 +++ 3 files changed, 199 insertions(+) create mode 100644 content/id/docs/tutorials/stateless-application/_index.md create mode 100644 content/id/docs/tutorials/stateless-application/expose-external-ip-address.md create mode 100644 content/id/examples/service/load-balancer-example.yaml diff --git a/content/id/docs/tutorials/stateless-application/_index.md b/content/id/docs/tutorials/stateless-application/_index.md new file mode 100644 index 0000000000..6923ee8165 --- /dev/null +++ b/content/id/docs/tutorials/stateless-application/_index.md @@ -0,0 +1,5 @@ +--- +title: "Aplikasi Stateless" +weight: 40 +--- + diff --git a/content/id/docs/tutorials/stateless-application/expose-external-ip-address.md b/content/id/docs/tutorials/stateless-application/expose-external-ip-address.md new file mode 100644 index 0000000000..df297f4c63 --- /dev/null +++ b/content/id/docs/tutorials/stateless-application/expose-external-ip-address.md @@ -0,0 +1,173 @@ +--- +title: Mengekspos Alamat IP Eksternal untuk Mengakses Aplikasi di dalam Klaster +content_type: tutorial +weight: 10 +--- + + + +Dokumen ini menjelaskan bagaimana cara membuat objek Service Kubernetes +yang mengekspos alamat IP eksternal. + + + + +## {{% heading "prerequisites" %}} + + + * Instal [kubectl](/id/docs/tasks/tools/install-kubectl/). + + * Gunakan sebuah penyedia layanan cloud seperti Google Kubernetes Engine atau Amazon Web Services + untuk membuat sebuah klaster Kubernetes. Tutorial ini membuat sebuah + [_load balancer_ eksternal](/id/docs/tasks/access-application-cluster/create-external-load-balancer/), + yang membutuhkan sebuah penyedia layanan cloud. + + * Konfigurasi `kubectl` agar dapat berkomunikasi dengan Kubernetes API Server kamu. + Untuk informasi lebih lanjut, kamu dapat merujuk pada dokumentasi penyedia layanan cloud + yang kamu gunakan. + + + +## {{% heading "objectives" %}} + +* Jalankan lima buah instans dari aplikasi Hello World. +* Buatlah sebuah objek Service yang mengekspos sebuah alamat IP eksternal. +* Gunakan sebuah objek Service untuk mengakses aplikasi yang sedang dijalankan. + + + + + +## Membuat sebuah objek Service untuk sebuah aplikasi yang dijalankan pada lima buah Pod + +1. Jalankan sebuah aplikasi Hello World pada klaster kamu: + +{{< codenew file="service/load-balancer-example.yaml" >}} + +```shell +kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml +``` + + +Perintah di atas akan membuat sebuah + objek [Deployment](/id/docs/concepts/workloads/controllers/deployment/) + dan sebuah objek + [ReplicaSet](/id/docs/concepts/workloads/controllers/replicaset/) + yang diasosiasikan dengan Deployment yang dibuat. ReplicaSet memiliki lima buah + [Pod](/id/docs/concepts/workloads/pods/pod/), + yang masing-masing dari Pod tersebut menjalankan aplikasi Hello World. + +1. Tampilkan informasi mengenai Deployment: + + kubectl get deployments hello-world + kubectl describe deployments hello-world + +1. Tampilkan informasi mengenai objek ReplicaSet: + + kubectl get replicasets + kubectl describe replicasets + +1. Buatlah sebuah objek Service yang mengekspos deployment: + + kubectl expose deployment hello-world --type=LoadBalancer --name=my-service + +1. Tampilkan informasi mengenai Service: + + kubectl get services my-service + + Keluaran dari perintah di atas akan menyerupai tampilan berikut: + + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + my-service LoadBalancer 10.3.245.137 104.198.205.71 8080/TCP 54s + + {{< note >}} + + Service dengan `type=LoadBalancer` didukung oleh penyedia layanan cloud eksternal, yang tidak tercakup dalam contoh ini, silahkan merujuk pada [laman berikut](/id/docs/concepts/services-networking/service/#loadbalancer) untuk informasi lebih lanjut. + + {{< /note >}} + + {{< note >}} + + Jika sebuah alamat IP eksternal yang ditunjukkan dalam status \, tunggulah hingga satu menit kemudian masukkan perintah yang sama lagi. + + {{< /note >}} + +1. Tampilkan informasi detail mengenai Service: + + kubectl describe services my-service + + Perintah di atas akan menampilkan keluaran sebagai berikut: + + Name: my-service + Namespace: default + Labels: app.kubernetes.io/name=load-balancer-example + Annotations: + Selector: app.kubernetes.io/name=load-balancer-example + Type: LoadBalancer + IP: 10.3.245.137 + LoadBalancer Ingress: 104.198.205.71 + Port: 8080/TCP + NodePort: 32377/TCP + Endpoints: 10.0.0.6:8080,10.0.1.6:8080,10.0.1.7:8080 + 2 more... + Session Affinity: None + Events: + + Pastikan nilai dari alamat IP eksternal (`LoadBalancer Ingress`) diekspos + pada Service yang kamu buat. Pada contoh ini, alamat IP eksternal yang diberikan adalah 104.198.205.71. + Kemudian pastikan nilai dari `Port` dan `NodePort`. Pada contoh ini, `Port` + yang digunakan adalah 8080 dan `NodePort` adalah 32377. + +1. Pada keluaran perintah sebelumnya, kamu dapat melihat beberapa Service dengan beberapa endpoint: + 10.0.0.6:8080,10.0.1.6:8080,10.0.1.7:8080 + 2 lainnya. Berikut ini merupakan alamat IP dari Pod + dimana aplikasi tersebut dijalankan. Untuk melakukan verifikasi alamat-alamat IP yang digunakan oleh Pod, + masukkan perintah berikut: + + kubectl get pods --output=wide + + Keluaran yang diberikan akan menyerupai: + + NAME ... IP NODE + hello-world-2895499144-1jaz9 ... 10.0.1.6 gke-cluster-1-default-pool-e0b8d269-1afc + hello-world-2895499144-2e5uh ... 10.0.1.8 gke-cluster-1-default-pool-e0b8d269-1afc + hello-world-2895499144-9m4h1 ... 10.0.0.6 gke-cluster-1-default-pool-e0b8d269-5v7a + hello-world-2895499144-o4z13 ... 10.0.1.7 gke-cluster-1-default-pool-e0b8d269-1afc + hello-world-2895499144-segjf ... 10.0.2.5 gke-cluster-1-default-pool-e0b8d269-cpuc + +1. Gunakan alamat IP eksternal (`LoadBalancer Ingress`) untuk mengakses aplikasi Hello World: + + curl http://: + + dimana `` adalah alamat IP eksternal (`LoadBalancer Ingress`) + dari Service kamu, dan `` adalah nilai dari `Port` dari deskripsi Service kamu. + Jika kamu menggunakan minikube, menuliskan perintah `minikube service my-service` akan + secara otomatis membuka aplikasi Hello World pada _browser_. + + Respons yang diberikan apabila permintaan ini berhasil adalah sebuah pesan sapaan: + + Hello Kubernetes! + + + + +## {{% heading "cleanup" %}} + + +Untuk menghapus Service, kamu dapat menggunakan perintah ini: + + kubectl delete services my-service + +Untuk menghapus Deployment, ReplicaSet, dan Pod-Pod yang digunakan untuk +menjalankan aplikasi Hello World, kamu dapat memasukkan perintah berikut: + + kubectl delete deployment hello-world + + + + +## {{% heading "whatsnext" %}} + + +Pelajari lebih lanjut cara untuk +[menghubungkan aplikasi dengan berbagai Service](/id/docs/concepts/services-networking/connect-applications-service/). + + diff --git a/content/id/examples/service/load-balancer-example.yaml b/content/id/examples/service/load-balancer-example.yaml new file mode 100644 index 0000000000..ea88fd1548 --- /dev/null +++ b/content/id/examples/service/load-balancer-example.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: load-balancer-example + name: hello-world +spec: + replicas: 5 + selector: + matchLabels: + app.kubernetes.io/name: load-balancer-example + template: + metadata: + labels: + app.kubernetes.io/name: load-balancer-example + spec: + containers: + - image: gcr.io/google-samples/node-hello:1.0 + name: hello-world + ports: + - containerPort: 8080 From 37b1f94fe49a4956e05ae42fe1d50bf0f9fffb9f Mon Sep 17 00:00:00 2001 From: Celeste Horgan Date: Wed, 8 Jul 2020 09:48:16 -0700 Subject: [PATCH 26/99] Revert T "version_menu" --- layouts/partials/navbar-version-selector.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layouts/partials/navbar-version-selector.html b/layouts/partials/navbar-version-selector.html index 5a3f03e126..09e872053f 100644 --- a/layouts/partials/navbar-version-selector.html +++ b/layouts/partials/navbar-version-selector.html @@ -1,5 +1,5 @@
diff --git a/content/ko/docs/tutorials/kubernetes-basics/scale/scale-intro.html b/content/ko/docs/tutorials/kubernetes-basics/scale/scale-intro.html index 24405ac955..9790c1f31e 100644 --- a/content/ko/docs/tutorials/kubernetes-basics/scale/scale-intro.html +++ b/content/ko/docs/tutorials/kubernetes-basics/scale/scale-intro.html @@ -44,7 +44,7 @@ weight: 10
-

kubectl run 명령에 --replicas 파라미터를 사용해서 처음부터 복수의 인스턴스로 구동되는 +

kubectl create deployment 명령에 --replicas 파라미터를 사용해서 처음부터 복수의 인스턴스로 구동되는 디플로이먼트를 만들 수도 있다

diff --git a/content/ko/docs/tutorials/services/source-ip.md b/content/ko/docs/tutorials/services/source-ip.md index 4917fa5042..5c4d94f624 100644 --- a/content/ko/docs/tutorials/services/source-ip.md +++ b/content/ko/docs/tutorials/services/source-ip.md @@ -447,6 +447,6 @@ kubectl delete deployment source-ip-app ## {{% heading "whatsnext" %}} * [서비스를 통한 애플리케이션 연결하기](/ko/docs/concepts/services-networking/connect-applications-service/)에 더 자세히 본다. -* 어떻게 [외부 로드밸런서 생성](https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/)하는지 본다. +* 어떻게 [외부 로드밸런서 생성](/docs/tasks/access-application-cluster/create-external-load-balancer/)하는지 본다. diff --git a/content/ko/docs/tutorials/stateful-application/basic-stateful-set.md b/content/ko/docs/tutorials/stateful-application/basic-stateful-set.md index d384d07655..03cfdf88c6 100644 --- a/content/ko/docs/tutorials/stateful-application/basic-stateful-set.md +++ b/content/ko/docs/tutorials/stateful-application/basic-stateful-set.md @@ -6,9 +6,9 @@ weight: 10 --- -이 튜토리얼은 스테이트풀셋([StatefulSets](/ko/docs/concepts/workloads/controllers/statefulset/))을 이용하여 -애플리케이션을 관리하는 방법을 소개한다. 어떻게 스테이트풀셋의 파드를 생성하고 삭제하며 -스케일링하고 업데이트하는지 시연한다. +이 튜토리얼은 {{< glossary_tooltip text="스테이트풀셋(StatefulSet)" term_id="statefulset" >}}을 이용하여 +애플리케이션을 관리하는 방법을 소개한다. +어떻게 스테이트풀셋의 파드를 생성하고, 삭제하며, 스케일링하고, 업데이트하는지 시연한다. ## {{% heading "prerequisites" %}} @@ -22,13 +22,14 @@ weight: 10 * [퍼시스턴트볼륨(PersistentVolumes)](/ko/docs/concepts/storage/persistent-volumes/) * [퍼시턴트볼륨 프로비저닝](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/persistent-volume-provisioning/) * [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/) -* [kubectl CLI](/docs/user-guide/kubectl/) +* [kubectl](/docs/reference/kubectl/kubectl/) 커맨드 라인 도구 +{{< note >}} 이 튜토리얼은 클러스터가 퍼시스턴스볼륨을 동적으로 프로비저닝 하도록 설정되었다고 가정한다. 만약 클러스터가 이렇게 설정되어 있지 않다면, 튜토리얼 시작 전에 수동으로 2개의 1 GiB 볼륨을 프로비저닝해야 한다. - +{{< /note >}} ## {{% heading "objectives" %}} @@ -46,7 +47,6 @@ weight: 10 * 스테이트풀셋은 어떻게 스케일링하는지 * 스테이트풀셋의 파드는 어떻게 업데이트하는지 - ## 스테이트풀셋 생성하기 @@ -74,20 +74,24 @@ kubectl get pods -w -l app=nginx ```shell kubectl apply -f web.yaml +``` +``` service/nginx created statefulset.apps/web created ``` 상기 명령어는 [NGINX](https://www.nginx.com) 웹 서버를 -실행하는 2개의 파드를 생성한다. `nginx` 서비스와 -`web` 스테이트풀셋이 성공적으로 생성되었는지 알아보자. +실행하는 2개의 파드를 생성한다. `nginx` 서비스의 정보를 가져온다. ```shell kubectl get service nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx ClusterIP None 80/TCP 12s - +``` +그리고 `web` 스테이트풀셋 정보를 가져와서 모두 성공적으로 생성되었는지 확인한다. +```shell kubectl get statefulset web +``` NAME DESIRED CURRENT AGE web 2 1 20s ``` @@ -101,6 +105,8 @@ N개의 레플리카를 가진 스테이트풀셋은 배포 시에 ```shell kubectl get pods -w -l app=nginx +``` +``` NAME READY STATUS RESTARTS AGE web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 0s @@ -112,8 +118,8 @@ web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 18s ``` -`web-1` 파드는 `web-0` 파드가 [Running과 Ready](/ko/docs/concepts/workloads/pods/pod-lifecycle/) 상태가 되기 전에 -시작하지 않음을 주의하자. +참고로 `web-1` 파드는 `web-0` 파드가 _Running_ ([파드의 단계](/ko/docs/concepts/workloads/pods/pod-lifecycle/#파드의-단계-phase) 참고) +및 _Ready_ ([파드의 조건](/docs/concepts/workloads/pods/pod-lifecycle/#파드의-조건-condition)에서 `type` 참고) 상태가 되기 전에 시작하지 않음을 주의하자. ## 스테이트풀셋 안에 파드 @@ -125,16 +131,17 @@ web-1 1/1 Running 0 18s ```shell kubectl get pods -l app=nginx +``` +``` NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 1m web-1 1/1 Running 0 1m - ``` [스테이트풀셋](/ko/docs/concepts/workloads/controllers/statefulset/) 개념에서 언급했듯 스테이트풀셋의 파드는 끈끈하고 고유한 정체성을 가진다. -이 정체성은 스테이트풀 컨트롤러에서 각 파드에 주어지는 -고유한 순번에 기인한다. 파드의 이름의 형식은 +이 정체성은 스테이트풀셋 {{< glossary_tooltip text="컨트롤러" term_id="controller" >}}에서 +각 파드에 주어지는 고유한 순번에 기인한다. 파드의 이름의 형식은 `<스테이트풀셋 이름>-<순번>` 이다. 앞서 `web` 스테이트풀셋은 2개의 레플리카를 가졌으므로 `web-0` 과 `web-1` 2개 파드를 생성한다. @@ -145,7 +152,9 @@ web-1 1/1 Running 0 1m [`kubectl exec`](/docs/reference/generated/kubectl/kubectl-commands/#exec)를 이용하자. ```shell -for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done +for i in 0 1; do kubectl exec "web-$i" -- sh -c 'hostname'; done +``` +``` web-0 web-1 ``` @@ -157,7 +166,14 @@ web-1 ```shell kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm +``` +위 명령으로 새로운 셸을 시작한다. 새 셸에서 다음을 실행한다. +```shell +# dns-test 컨테이너 셸에서 다음을 실행한다. nslookup web-0.nginx +``` +출력 결과는 다음과 비슷하다. +``` Server: 10.0.0.10 Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local @@ -172,6 +188,8 @@ Name: web-1.nginx Address 1: 10.244.2.6 ``` +(이제 `exit` 명령으로 컨테이너 셸에서 종료한다.) + 헤드리스 서비스의 CNAME은 SRV 레코드를 지칭한다 (Running과 Ready 상태의 각 파드마다 1개). SRV 레코드는 파드의 IP 주소를 포함한 A 레코드 엔트리를 지칭한다. @@ -196,6 +214,8 @@ pod "web-1" deleted ```shell kubectl get pod -w -l app=nginx +``` +``` NAME READY STATUS RESTARTS AGE web-0 0/1 ContainerCreating 0 0s NAME READY STATUS RESTARTS AGE @@ -207,15 +227,27 @@ web-1 1/1 Running 0 34s ``` 파드의 호스트네임과 클러스터 내부 DNS 엔트리를 보기 위해 -`kubectl exec`과 `kubectl run`을 이용하자. +`kubectl exec`과 `kubectl run`을 이용하자. 먼저, 파드의 호스트네임을 확인한다. ```shell for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname'; done +``` +``` web-0 web-1 - +``` +그리고 다음을 실행한다. +``` kubectl run -i --tty --image busybox:1.28 dns-test --restart=Never --rm /bin/sh +``` +이 명령으로 새로운 셸이 시작된다. +새 셸에서 다음을 실행한다. +```shell +# dns-test 컨테이너 셸에서 이것을 실행한다. nslookup web-0.nginx +``` +출력 결과는 다음과 비슷하다. +``` Server: 10.0.0.10 Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local @@ -230,6 +262,8 @@ Name: web-1.nginx Address 1: 10.244.2.8 ``` +(이제 `exit` 명령으로 컨테이너 셸을 종료한다.) + 파드의 순번, 호스트네임, SRV 레코드와 A 레코드이름은 변경되지 않지만 파드의 IP 주소는 변경될 수 있다. 이는 튜토리얼에서 사용하는 클러스터나 다른 클러스터에도 동일하다. 따라서 다른 애플리케이션이 IP 주소로 @@ -255,12 +289,20 @@ Running과 Ready 상태의 모든 파드들을 ```shell kubectl get pvc -l app=nginx +``` +출력 결과는 다음과 비슷하다. +``` NAME STATUS VOLUME CAPACITY ACCESSMODES AGE www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 48s www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 48s ``` -스테이트풀셋 컨트롤러는 2개의 [퍼시스턴트볼륨](/ko/docs/concepts/storage/persistent-volumes/)에 -묶인 2개의 퍼시스턴트볼륨클레임을 생성했다. 본 튜토리얼에서 사용되는 클러스터는 퍼시스턴트볼륨을 동적으로 + +스테이트풀셋 컨트롤러는 2개의 +{{< glossary_tooltip text="퍼시스턴트볼륨" term_id="persistent-volume" >}}에 +묶인 2개의 +{{< glossary_tooltip text="퍼시스턴트볼륨클레임" term_id="persistent-volume-claim" >}}을 생성했다. + +본 튜토리얼에서 사용되는 클러스터는 퍼시스턴트볼륨을 동적으로 프로비저닝하도록 설정되었으므로 생성된 퍼시스턴트볼륨도 자동으로 묶인다. NGINX 웹서버는 기본 색인 파일로 @@ -272,23 +314,23 @@ NGINX 웹서버는 기본 색인 파일로 NGINX 웹서버가 해당 호스트네임을 제공하는지 확인해보자. ```shell -for i in 0 1; do kubectl exec web-$i -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done +for i in 0 1; do kubectl exec "web-$i" -- sh -c 'echo $(hostname) > /usr/share/nginx/html/index.html'; done -for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done +for i in 0 1; do kubectl exec -it "web-$i" -- curl localhost; done +``` +``` web-0 web-1 ``` {{< note >}} -위에 curl 명령어로 403 Forbidden 아닌 응답을 보려면 -`volumeMounts`로 마운트된 디렉터리의 퍼미션을 수정해야 한다 +위에 curl 명령어로 **403 Forbidden** 아닌 응답을 보려면 +다음을 실행해서 `volumeMounts`로 마운트된 디렉터리의 퍼미션을 수정해야 한다 ([hostPath 볼륨을 사용할 때에 버그](https://github.com/kubernetes/kubernetes/issues/2630)로 인함). -```shell -for i in 0 1; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; done -``` +`for i in 0 1; do kubectl exec web-$i -- chmod 755 /usr/share/nginx/html; done` -위에 curl 명령을 재시도하기 전에 +위에 `curl` 명령을 재시도하기 전에 위 명령을 실행해야 한다. {{< /note >}} 첫째 터미널에서 스테이트풀셋의 파드를 감시하자. @@ -301,6 +343,8 @@ kubectl get pod -w -l app=nginx ```shell kubectl delete pod -l app=nginx +``` +``` pod "web-0" deleted pod "web-1" deleted ``` @@ -309,6 +353,8 @@ pod "web-1" deleted ```shell kubectl get pod -w -l app=nginx +``` +``` NAME READY STATUS RESTARTS AGE web-0 0/1 ContainerCreating 0 0s NAME READY STATUS RESTARTS AGE @@ -322,7 +368,9 @@ web-1 1/1 Running 0 34s 웹서버에서 자신의 호스트네임을 계속 제공하는지 확인하자. ``` -for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done +for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done +``` +``` web-0 web-1 ``` @@ -334,6 +382,7 @@ web-1 각각의 퍼시스턴트볼륨은 적절하게 마운트된다. ## 스테이트풀셋 스케일링 + 스테이트풀셋을 스케일링하는 것은 레플리카 개수를 늘리거나 줄이는 것을 의미한다. 이것은 `replicas` 필드를 갱신하여 이뤄진다. [`kubectl scale`](/docs/reference/generated/kubectl/kubectl-commands/#scale)이나 [`kubectl patch`](/docs/reference/generated/kubectl/kubectl-commands/#patch)을 @@ -352,6 +401,8 @@ kubectl get pods -w -l app=nginx ```shell kubectl scale sts web --replicas=5 +``` +``` statefulset.apps/web scaled ``` @@ -360,6 +411,8 @@ statefulset.apps/web scaled ```shell kubectl get pods -w -l app=nginx +``` +``` NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 2h web-1 1/1 Running 0 2h @@ -392,18 +445,22 @@ web-4 1/1 Running 0 19s kubectl get pods -w -l app=nginx ``` -다른 터미널에서 `kubectl patch`으로 스테이트풀셋을 뒤로 - 3개의 레플리카로 스케일링하자. +다른 터미널에서 `kubectl patch`으로 스테이트풀셋을 다시 +3개의 레플리카로 스케일링하자. ```shell kubectl patch sts web -p '{"spec":{"replicas":3}}' +``` +``` statefulset.apps/web patched ``` `web-4`와 `web-3`이 Terminating으로 전환되기까지 기다리자. -``` +```shell kubectl get pods -w -l app=nginx +``` +``` NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 3h web-1 1/1 Running 0 3h @@ -428,6 +485,8 @@ web-3 1/1 Terminating 0 42s ```shell kubectl get pvc -l app=nginx +``` +``` NAME STATUS VOLUME CAPACITY ACCESSMODES AGE www-web-0 Bound pvc-15c268c7-b507-11e6-932f-42010a800002 1Gi RWO 13h www-web-1 Bound pvc-15c79307-b507-11e6-932f-42010a800002 1Gi RWO 13h @@ -459,6 +518,8 @@ www-web-4 Bound pvc-e11bb5f8-b508-11e6-932f-42010a800002 1Gi RWO ```shell kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}' +``` +``` statefulset.apps/web patched ``` @@ -467,13 +528,18 @@ statefulset.apps/web patched ```shell kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"gcr.io/google_containers/nginx-slim:0.8"}]' +``` +``` statefulset.apps/web patched ``` 다른 터미널창에서 스테이트풀셋의 파드를 감시하자. ```shell -kubectl get po -l app=nginx -w +kubectl get pod -l app=nginx -w +``` +출력 결과는 다음과 비슷하다. +``` NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 7m web-1 1/1 Running 0 7m @@ -512,17 +578,20 @@ web-0 1/1 Running 0 10s 이 스테이트풀셋 컨트롤러는 각 파드를 종료시키고 다음 파드를 업데이트하기 전에 그것이 Running과 Ready 상태로 전환될 때까지 기다린다. 알아둘 것은 비록 스테이트풀셋 컨트롤러에서 이전 파드가 Running과 Ready 상태가 되기까지 -다음 파드를 업데이트하지 않아도 현재 버전으로 파드를 업데이트하다 실패하면 복원한다는 것이다. +다음 파드를 업데이트하지 않아도 현재 버전으로 파드를 업데이트하다 실패하면 +복원한다는 것이다. + 업데이트를 이미 받은 파드는 업데이트된 버전으로 복원되고 아직 업데이트를 받지 못한 파드는 -이전 버전으로 복원한다. -이런 식으로 컨트롤러는 간헐적인 오류가 발생해도 +이전 버전으로 복원한다. 이런 식으로 컨트롤러는 간헐적인 오류가 발생해도 애플리케이션을 계속 건강하게 유지하고 업데이트도 일관되게 유지하려 한다. 컨테이너 이미지를 살펴보기 위해 파드를 가져오자. ```shell -for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done +for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done +``` +``` k8s.gcr.io/nginx-slim:0.8 k8s.gcr.io/nginx-slim:0.8 k8s.gcr.io/nginx-slim:0.8 @@ -531,10 +600,13 @@ k8s.gcr.io/nginx-slim:0.8 스테이트풀셋의 모든 파드가 지금은 이전 컨테이너 이미지를 실행 중이이다. -**팁** 롤링 업데이트 상황을 살펴보기 위해 `kubectl rollout status sts/` +{{< note >}} +스테이트풀셋의 롤링 업데이트 상황을 살펴보기 위해 `kubectl rollout status sts/` 명령어도 사용할 수 있다. +{{< /note >}} #### 단계적으로 업데이트 하기 {#staging-an-update} + `RollingUpdate` 업데이트 전략의 파라미터인 `partition`를 이용하여 스테이트풀셋의 단계적으로 업데이트할 수 있다. 단계적 업데이트는 스테이트풀셋의 모든 파드를 현재 버전으로 유지하면서 @@ -544,6 +616,8 @@ k8s.gcr.io/nginx-slim:0.8 ```shell kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}' +``` +``` statefulset.apps/web patched ``` @@ -551,20 +625,26 @@ statefulset.apps/web patched ```shell kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]' +``` +``` statefulset.apps/web patched ``` 스테이트풀셋의 파드를 삭제하자. ```shell -kubectl delete po web-2 +kubectl delete pod web-2 +``` +``` pod "web-2" deleted ``` 파드가 Running과 Ready 상태가 되기까지 기다리자. ```shell -kubectl get po -l app=nginx -w +kubectl get pod -l app=nginx -w +``` +``` NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 4m web-1 1/1 Running 0 4m @@ -572,12 +652,13 @@ web-2 0/1 ContainerCreating 0 11s web-2 1/1 Running 0 18s ``` -파드의 컨테이너를 가져오자. +파드의 컨테이너 이미지를 가져오자. ```shell -kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}' +kubectl get pod web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}' +``` +``` k8s.gcr.io/nginx-slim:0.8 - ``` 비록 업데이트 전략이 `RollingUpdate`이지만 스테이트풀셋은 @@ -586,6 +667,7 @@ k8s.gcr.io/nginx-slim:0.8 `파티션`보다 작기 때문이다. #### 카나리(Canary) 롤링 아웃 + [위에서](#staging-an-update) 지정한 `partition`값을 차감시키면 변경사항을 테스트하기 위해 카나리 롤아웃을 할 수 있다. @@ -593,13 +675,17 @@ k8s.gcr.io/nginx-slim:0.8 ```shell kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}' +``` +``` statefulset.apps/web patched ``` `web-2` 파드가 Running과 Ready 상태가 되기까지 기다리자. ```shell -kubectl get po -l app=nginx -w +kubectl get pod -l app=nginx -w +``` +``` NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 4m web-1 1/1 Running 0 4m @@ -611,6 +697,8 @@ web-2 1/1 Running 0 18s ```shell kubectl get po web-2 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}' +``` +``` k8s.gcr.io/nginx-slim:0.7 ``` @@ -622,14 +710,19 @@ k8s.gcr.io/nginx-slim:0.7 `web-1` 파드를 삭제하자. ```shell -kubectl delete po web-1 +kubectl delete pod web-1 +``` +``` pod "web-1" deleted ``` `web-1` 파드가 Running과 Ready 상태가 되기까지 기다리자. ```shell -kubectl get po -l app=nginx -w +kubectl get pod -l app=nginx -w +``` +출력 결과는 다음과 비슷하다. +``` NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 6m web-1 0/1 Terminating 0 6m @@ -643,12 +736,13 @@ web-1 0/1 ContainerCreating 0 0s web-1 1/1 Running 0 18s ``` -`web-1` 파드의 컨테이너를 가져오자. +`web-1` 파드의 컨테이너 이미지를 가져오자. ```shell -kubectl get po web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}' +kubectl get pod web-1 --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}' +``` +``` k8s.gcr.io/nginx-slim:0.8 - ``` `web-1` 는 원래 환경설정으로 복원되었는데 @@ -658,6 +752,7 @@ k8s.gcr.io/nginx-slim:0.8 종료되어 원래 환경설정으로 복원된다. #### 단계적 롤아웃 + [카나리 롤아웃](#카나리-canary-롤링-아웃)에서 했던 방법과 비슷하게 분할된 롤링 업데이트를 이용하여 단계적 롤아웃(e.g. 선형, 기하 또는 지수적 롤아웃)을 수행할 수 있다. 단계적 롤아웃을 수행하려면 @@ -668,13 +763,18 @@ partition은 현재 `2`이다. partition을 `0`으로 바꾸자. ```shell kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}' +``` +``` statefulset.apps/web patched ``` 스테이트풀셋의 모든 파드가 Running과 Ready 상태가 되기까지 기다리자. ```shell -kubectl get po -l app=nginx -w +kubectl get pod -l app=nginx -w +``` +출력 결과는 다음과 비슷하다. +``` NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 3m web-1 0/1 ContainerCreating 0 11s @@ -692,17 +792,19 @@ web-0 0/1 ContainerCreating 0 0s web-0 1/1 Running 0 3s ``` -파드의 컨테이너를 가져오자. +스테이트풀셋에 있는 파드의 컨테이너 이미지 상세 정보를 가져오자. ```shell -for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done +for p in 0 1 2; do kubectl get pod "web-$p" --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done +``` +``` k8s.gcr.io/nginx-slim:0.7 k8s.gcr.io/nginx-slim:0.7 k8s.gcr.io/nginx-slim:0.7 ``` -`partition`을 `0`으로 이동하여 스테이트풀셋 컨트롤러에서 계속해서 +`partition`을 `0`으로 이동하여 스테이트풀셋에서 계속해서 업데이트 처리를 하도록 허용하였다. ### 삭제 시 동작 @@ -733,6 +835,8 @@ kubectl get pods -w -l app=nginx ```shell kubectl delete statefulset web --cascade=false +``` +``` statefulset.apps "web" deleted ``` @@ -740,6 +844,8 @@ statefulset.apps "web" deleted ```shell kubectl get pods -l app=nginx +``` +``` NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 6m web-1 1/1 Running 0 7m @@ -751,6 +857,8 @@ web-2 1/1 Running 0 5m ```shell kubectl delete pod web-0 +``` +``` pod "web-0" deleted ``` @@ -758,6 +866,8 @@ pod "web-0" deleted ```shell kubectl get pods -l app=nginx +``` +``` NAME READY STATUS RESTARTS AGE web-1 1/1 Running 0 10m web-2 1/1 Running 0 7m @@ -777,17 +887,21 @@ kubectl get pods -w -l app=nginx ```shell kubectl apply -f web.yaml +``` +``` statefulset.apps/web created service/nginx unchanged ``` 이 에러는 무시하자. 이것은 다만 해당 서비스가 있더라도 -nginx 헤드리스 서비스를 생성하려고 했음을 뜻한다. +_nginx_ 헤드리스 서비스를 생성하려고 했음을 뜻한다. 첫째 터미널에서 실행 중인 `kubectl get` 명령어의 출력을 살펴보자. ```shell kubectl get pods -w -l app=nginx +``` +``` NAME READY STATUS RESTARTS AGE web-1 1/1 Running 0 16m web-2 1/1 Running 0 2m @@ -813,7 +927,9 @@ web-2 0/1 Terminating 0 3m 다른 관점으로 살펴보자. ```shell -for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done +for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done +``` +``` web-0 web-1 ``` @@ -837,6 +953,8 @@ kubectl get pods -w -l app=nginx ```shell kubectl delete statefulset web +``` +``` statefulset.apps "web" deleted ``` 첫째 터미널에서 실행 중인 `kubectl get` 명령어의 출력을 살펴보고 @@ -844,6 +962,8 @@ statefulset.apps "web" deleted ```shell kubectl get pods -w -l app=nginx +``` +``` NAME READY STATUS RESTARTS AGE web-0 1/1 Running 0 11m web-1 1/1 Running 0 27m @@ -864,12 +984,17 @@ web-1 0/1 Terminating 0 29m 스테이트풀 컨트롤러는 이전 파드가 완전히 종료되기까지 기다린다. -스테이트풀셋과 그 파드를 종속적으로 삭제하는 중에 연관된 헤드리스 서비스를 -삭제하지 않음을 주의하자. +{{< note >}} +종속적 삭제는 파드와 함께 스테이트풀셋을 제거하지만, +스테이트풀셋과 관련된 헤드리스 서비스를 삭제하지 않는다. 꼭 `nginx` 서비스를 수동으로 삭제해라. +{{< /note >}} + ```shell kubectl delete service nginx +``` +``` service "nginx" deleted ``` @@ -877,6 +1002,8 @@ service "nginx" deleted ```shell kubectl apply -f web.yaml +``` +``` service/nginx created statefulset.apps/web created ``` @@ -885,22 +1012,30 @@ statefulset.apps/web created `index.html` 파일 내용을 검색하자. ```shell -for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done +for i in 0 1; do kubectl exec -i -t "web-$i" -- curl http://localhost/; done +``` +``` web-0 web-1 ``` 스테이트풀셋과 그 내부의 모든 파드를 삭제했지만 퍼시스턴트볼륨이 마운트된 채로 -다시 생성되고 `web-0`과 `web-1`은 여전히 +다시 생성되고 `web-0`과 `web-1`은 계속 각 호스트네임을 제공한다. -최종적으로 `web` 스테이트풀셋과`nginx` 서비스를 삭제한다. +최종적으로 `web` 스테이트풀셋을 삭제한다. ```shell kubectl delete service nginx +``` +``` service "nginx" deleted - +``` +그리고 `nginx` 서비스를 삭제한다. +```shell kubectl delete statefulset web +``` +``` statefulset "web" deleted ``` @@ -934,13 +1069,15 @@ statefulset "web" deleted 터미널에서 스테이트풀셋의 파드를 감시하자. ```shell -kubectl get po -l app=nginx -w +kubectl get pod -l app=nginx -w ``` 다른 터미널에서 매니페스트 안에 스테이트풀셋과 서비스를 생성하자. ```shell kubectl apply -f web-parallel.yaml +``` +``` service/nginx created statefulset.apps/web created ``` @@ -948,7 +1085,9 @@ statefulset.apps/web created 첫째 터미널에서 실행했던 `kubectl get` 명령어의 출력을 살펴보자. ```shell -kubectl get po -l app=nginx -w +kubectl get pod -l app=nginx -w +``` +``` NAME READY STATUS RESTARTS AGE web-0 0/1 Pending 0 0s web-0 0/1 Pending 0 0s @@ -967,12 +1106,14 @@ web-1 1/1 Running 0 10s ```shell kubectl scale statefulset/web --replicas=4 +``` +``` statefulset.apps/web scaled ``` `kubectl get` 명령어를 실행 중인 터미널의 출력을 살펴보자. -```shell +``` web-3 0/1 Pending 0 0s web-3 0/1 Pending 0 0s web-3 0/1 Pending 0 7s @@ -982,18 +1123,24 @@ web-3 1/1 Running 0 26s ``` -스테이트풀 컨트롤러는 두 개의 새 파드를 시작하였다. +스테이트풀셋은 두 개의 새 파드를 시작하였다. 두 번째 것을 런칭하기 위해 먼저 런칭한 것이 Running과 Ready 상태가 될 때까지 기다리지 않는다. -이 터미널을 열어 놓고 다른 터미널에서 `web` 스테이트풀셋을 삭제하자. +## {{% heading "cleanup" %}} + +정리의 일환으로 `kubectl` 명령을 실행할 준비가 된 두 개의 터미널이 열려 +있어야 한다. ```shell kubectl delete sts web +# sts는 statefulset의 약자이다. ``` -다시 한번 다른 터미널에서 실행 중인 `kubectl get`명령의 출력을 확인해보자. - +`kubectl get` 명령으로 해당 파드가 삭제된 것을 확인할 수 있다. ```shell +kubectl get pod -l app=nginx -w +``` +``` web-3 1/1 Terminating 0 9m web-2 1/1 Terminating 0 9m web-3 1/1 Terminating 0 9m @@ -1019,7 +1166,7 @@ web-3 0/1 Terminating 0 9m web-3 0/1 Terminating 0 9m ``` -스테이트풀 컨트롤러는 모든 파드를 동시에 삭제한다. 파드를 삭제하기 전에 +삭제하는 동안, 스테이트풀셋은 모든 파드를 동시에 삭제한다. 해당 파드를 삭제하기 전에 그 파드의 순서상 후계자를 기다리지 않는다. `kubectl get` 명령어가 실행된 터미널을 닫고 @@ -1030,12 +1177,11 @@ kubectl delete svc nginx ``` -## {{% heading "cleanup" %}} - +{{< note >}} 이 튜토리얼에서 사용된 퍼시턴트볼륨을 위한 -퍼시스턴트 스토리지 미디어를 삭제해야 한다. +퍼시스턴트 스토리지 미디어도 삭제해야 한다. + + 모든 스토리지를 반환하도록 환경, 스토리지 설정과 프로비저닝 방법에 따른 단계를 따르자. - - - +{{< /note >}} diff --git a/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md b/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md index 323a087408..1e0aefd4a3 100644 --- a/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md +++ b/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md @@ -190,8 +190,8 @@ kubectl apply -k ./ 응답은 아래와 비슷해야 한다. ``` - NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE - wordpress ClusterIP 10.0.0.89 80:32406/TCP 4m + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + wordpress LoadBalancer 10.0.0.89 80:32406/TCP 4m ``` {{< note >}} @@ -237,7 +237,7 @@ kubectl apply -k ./ * [인트로스펙션과 디버깅](/docs/tasks/debug-application-cluster/debug-application-introspection/)를 알아보자. -* [잡](/ko/docs/concepts/workloads/controllers/jobs-run-to-completion/)를 알아보자. +* [잡](/ko/docs/concepts/workloads/controllers/job/)를 알아보자. * [포트 포워딩](/ko/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)를 알아보자. * 어떻게 [컨테이너에서 셸을 사용하는지](/docs/tasks/debug-application-cluster/get-shell-running-container/)를 알아보자. diff --git a/content/ko/docs/tutorials/stateful-application/zookeeper.md b/content/ko/docs/tutorials/stateful-application/zookeeper.md index bf4c2e179c..490f6ff18d 100644 --- a/content/ko/docs/tutorials/stateful-application/zookeeper.md +++ b/content/ko/docs/tutorials/stateful-application/zookeeper.md @@ -43,7 +43,7 @@ weight: 40 - 어떻게 지속적해서 컨피그맵을 이용해서 앙상블을 설정하는가. - 어떻게 ZooKeeper 서버 디플로이먼트를 앙상블 안에서 퍼뜨리는가. - 어떻게 파드디스룹션버짓을 이용하여 계획된 점검 기간 동안 서비스 가용성을 보장하는가. - + @@ -132,7 +132,7 @@ zk-2 1/1 Running 0 40s for i in 0 1 2; do kubectl exec zk-$i -- hostname; done ``` -스테이트풀셋 컨트롤러는 각 순번 인덱스에 기초하여 각 파드에 고유한 호스트네임을 부여한다. 각 호스트네임은 `<스테이트풀셋 이름>-<순번 인덱스>` 형식을 취한다. `zk` 스테이트풀셋의 `replicas` 필드는 `3`으로 설정되었기 때문에, 그 스테이트풀셋 컨트롤러는 3개 파드의 호스트네임을 `zk-0`, `zk-1`, +스테이트풀셋 컨트롤러는 각 순번 인덱스에 기초하여 각 파드에 고유한 호스트네임을 부여한다. 각 호스트네임은 `<스테이트풀셋 이름>-<순번 인덱스>` 형식을 취한다. `zk` 스테이트풀셋의 `replicas` 필드는 `3`으로 설정되었기 때문에, 그 스테이트풀셋 컨트롤러는 3개 파드의 호스트네임을 `zk-0`, `zk-1`, `zk-2`로 정한다. ```shell @@ -183,9 +183,9 @@ ZooKeeper는 그것의 애플리케이션 환경설정을 `zoo.cfg` 파일에 kubectl exec zk-0 -- cat /opt/zookeeper/conf/zoo.cfg ``` -아래 파일의 `server.1`, `server.2`, `server.3` 속성에서 -`1`, `2`, `3`은 ZooKeeper 서버의 `myid` 파일에 구분자와 -연관된다. +아래 파일의 `server.1`, `server.2`, `server.3` 속성에서 +`1`, `2`, `3`은 ZooKeeper 서버의 `myid` 파일에 구분자와 +연관된다. 이들은 `zk` 스테이트풀셋의 파드의 FQDNS을 설정한다. ```shell @@ -302,7 +302,7 @@ ZooKeeper는 모든 항목을 내구성있는 WAL에 커밋하고 메모리 상 복제된 상태 머신을 이루는 합의 프로토콜에서 이용하는 일반적인 기법이다. -[`kubectl delete`](/docs/reference/generated/kubectl/kubectl-commands/#delete) 명령을 이용하여 +[`kubectl delete`](/docs/reference/generated/kubectl/kubectl-commands/#delete) 명령을 이용하여 `zk` 스테이트풀셋을 삭제하자. ```shell @@ -448,7 +448,7 @@ ZooKeeper의 서버 디렉터리에 마운트한다. [리더 선출 촉진](#리더-선출-촉진)과 [합의 달성](#합의-달성) 섹션에서 알렸듯이, ZooKeeper 앙상블에 서버는 리더 선출과 쿼럼을 구성하기 위한 일관된 설정이 필요하다. -또한 Zab 프로토콜의 일관된 설정도 +또한 Zab 프로토콜의 일관된 설정도 네트워크에 걸쳐 올바르게 동작하기 위해서 필요하다. 이 예시에서는 메니페스트에 구성을 직접 포함시켜서 일관된 구성을 달성한다. @@ -496,7 +496,7 @@ ZooKeeper는 [Log4j](http://logging.apache.org/log4j/2.x/)를 이용하며 kubectl exec zk-0 cat /usr/etc/zookeeper/log4j.properties ``` -아래 로깅 구성은 ZooKeeper가 모든 로그를 +아래 로깅 구성은 ZooKeeper가 모든 로그를 표준 출력 스트림으로 처리하게 한다. ```shell @@ -544,7 +544,7 @@ kubectl logs zk-0 --tail 20 쿠버네티스는 더 강력하지만 조금 복잡한 로그 통합을 [스택드라이버](/docs/tasks/debug-application-cluster/logging-stackdriver/)와 -[Elasticsearch와 Kibana](/docs/tasks/debug-application-cluster/logging-elasticsearch-kibana/)를 지원한다. +[Elasticsearch와 Kibana](/ko/docs/tasks/debug-application-cluster/logging-elasticsearch-kibana/)를 지원한다. 클러스터 수준의 로그 적재(ship)와 통합을 위해서는 로그 순환과 적재를 위해 [사이드카](https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns) 컨테이너를 배포하는 것을 고려한다. @@ -564,7 +564,7 @@ securityContext: fsGroup: 1000 ``` -파드 컨테이너에서 UID 1000은 ZooKeeper 사용자이며, GID 1000은 +파드 컨테이너에서 UID 1000은 ZooKeeper 사용자이며, GID 1000은 ZooKeeper의 그룹에 해당한다. `zk-0` 파드에서 프로세스 정보를 얻어오자. @@ -866,7 +866,7 @@ kubernetes-node-2g2d kubectl get nodes ``` -[`kubectl cordon`](/docs/reference/generated/kubectl/kubectl-commands/#cordon)을 이용하여 +[`kubectl cordon`](/docs/reference/generated/kubectl/kubectl-commands/#cordon)을 이용하여 클러스터 내에 4개 노드를 제외하고 다른 모든 노드를 통제해보자. ```shell @@ -1093,7 +1093,3 @@ node "kubernetes-node-ixsl" uncordoned 퍼시스턴트 스토리지 미디어를 삭제하자. 귀하의 환경과 스토리지 구성과 프로비저닝 방법에서 필요한 절차를 따라서 모든 스토리지가 재확보되도록 하자. - - - - diff --git a/content/ko/docs/tutorials/stateless-application/expose-external-ip-address.md b/content/ko/docs/tutorials/stateless-application/expose-external-ip-address.md index 291cceba26..ec5ea3b53d 100644 --- a/content/ko/docs/tutorials/stateless-application/expose-external-ip-address.md +++ b/content/ko/docs/tutorials/stateless-application/expose-external-ip-address.md @@ -15,7 +15,7 @@ weight: 10 ## {{% heading "prerequisites" %}} - * [kubectl](/docs/tasks/tools/install-kubectl/)을 설치한다. + * [kubectl](/ko/docs/tasks/tools/install-kubectl/)을 설치한다. * Google Kubernetes Engine 또는 Amazon Web Services와 같은 클라우드 공급자를 사용하여 쿠버네티스 클러스터를 생성한다. @@ -52,10 +52,10 @@ kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml 위의 명령어는 - [디플로이먼트](/ko/docs/concepts/workloads/controllers/deployment/) + [디플로이먼트(Deployment)](/ko/docs/concepts/workloads/controllers/deployment/) 오브젝트와 관련된 - [레플리카 셋](/ko/docs/concepts/workloads/controllers/replicaset/) - 오브젝트를 생성한다. 레플리카 셋은 다섯 개의 + [레플리카셋(ReplicaSet)](/ko/docs/concepts/workloads/controllers/replicaset/) + 오브젝트를 생성한다. 레플리카셋은 다섯 개의 [파드](/ko/docs/concepts/workloads/pods/pod/)가 있으며, 각 파드는 Hello World 애플리케이션을 실행한다. @@ -64,7 +64,7 @@ kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml kubectl get deployments hello-world kubectl describe deployments hello-world -1. 레플리카 셋 오브젝트에 대한 정보를 확인한다. +1. 레플리카셋 오브젝트에 대한 정보를 확인한다. kubectl get replicasets kubectl describe replicasets @@ -160,7 +160,7 @@ kubectl apply -f https://k8s.io/examples/service/load-balancer-example.yaml kubectl delete services my-service -Hello World 애플리케이션을 실행 중인 디플로이먼트, 레플리카 셋, 파드를 삭제하려면, +Hello World 애플리케이션을 실행 중인 디플로이먼트, 레플리카셋, 파드를 삭제하려면, 아래의 명령어를 입력한다. kubectl delete deployment hello-world @@ -173,4 +173,3 @@ Hello World 애플리케이션을 실행 중인 디플로이먼트, 레플리카 [애플리케이션과 서비스 연결하기](/ko/docs/concepts/services-networking/connect-applications-service/)에 대해 더 배워 본다. - diff --git a/content/ko/docs/tutorials/stateless-application/guestbook-logs-metrics-with-elk.md b/content/ko/docs/tutorials/stateless-application/guestbook-logs-metrics-with-elk.md index cd8ff4e03f..9d5cf7713b 100644 --- a/content/ko/docs/tutorials/stateless-application/guestbook-logs-metrics-with-elk.md +++ b/content/ko/docs/tutorials/stateless-application/guestbook-logs-metrics-with-elk.md @@ -402,6 +402,6 @@ kubectl scale --replicas=3 deployment/frontend ## {{% heading "whatsnext" %}} * [리소스 모니터링 도구](/ko/docs/tasks/debug-application-cluster/resource-usage-monitoring/)를 공부한다. -* [로깅 아키텍처](/docs/concepts/cluster-administration/logging/)를 더 읽어본다. +* [로깅 아키텍처](/ko/docs/concepts/cluster-administration/logging/)를 더 읽어본다. * [애플리케이션 검사 및 디버깅](/ko/docs/tasks/debug-application-cluster/)을 더 읽어본다. * [애플리케이션 문제 해결](/ko/docs/tasks/debug-application-cluster/resource-usage-monitoring/)을 더 읽어본다. diff --git a/content/ko/docs/tutorials/stateless-application/guestbook.md b/content/ko/docs/tutorials/stateless-application/guestbook.md index 422ed877e2..cce67800a6 100644 --- a/content/ko/docs/tutorials/stateless-application/guestbook.md +++ b/content/ko/docs/tutorials/stateless-application/guestbook.md @@ -47,7 +47,7 @@ card: {{< codenew file="application/guestbook/redis-master-deployment.yaml" >}} -1. 매니페스트 파일을 다운로드한 디렉토리에서 터미널 창을 시작한다. +1. 매니페스트 파일을 다운로드한 디렉터리에서 터미널 창을 시작한다. 1. `redis-master-deployment.yaml` 파일을 통해 Redis 마스터의 디플로이먼트에 적용한다. ```shell @@ -218,7 +218,7 @@ Google Compute Engine 또는 Google Kubernetes Engine과 같은 일부 클라우 1. 서비스의 목록을 질의하여 프론트엔드 서비스가 실행 중인지 확인한다. ```shell - kubectl get services + kubectl get services ``` 결과는 아래와 같은 형태로 나타난다. @@ -320,7 +320,7 @@ Google Compute Engine 또는 Google Kubernetes Engine과 같은 일부 클라우 redis-slave-2005841000-fpvqc 1/1 Running 0 1h redis-slave-2005841000-phfv9 1/1 Running 0 1h ``` - + ## {{% heading "cleanup" %}} @@ -346,7 +346,7 @@ Google Compute Engine 또는 Google Kubernetes Engine과 같은 일부 클라우 deployment.apps "frontend" deleted service "frontend" deleted ``` - + 1. 파드의 목록을 질의하여 실행 중인 파드가 없는지 확인한다. ```shell @@ -367,5 +367,4 @@ Google Compute Engine 또는 Google Kubernetes Engine과 같은 일부 클라우 * [쿠버네티스 기초](/ko/docs/tutorials/kubernetes-basics/) 튜토리얼을 완료 * [MySQL과 Wordpress을 위한 퍼시스턴트 볼륨](/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume/#visit-your-new-wordpress-blog)을 사용하여 블로그 생성하는데 쿠버네티스 이용하기 * [애플리케이션 접속](/ko/docs/concepts/services-networking/connect-applications-service/)에 대해 더 알아보기 -* [자원 관리](/docs/concepts/cluster-administration/manage-deployment/#using-labels-effectively)에 대해 더 알아보기 - +* [자원 관리](/ko/docs/concepts/cluster-administration/manage-deployment/#효과적인-레이블-사용)에 대해 더 알아보기 diff --git a/content/ko/partners/_index.html b/content/ko/partners/_index.html index 2ac7e6945c..3bd6a375f2 100644 --- a/content/ko/partners/_index.html +++ b/content/ko/partners/_index.html @@ -7,79 +7,90 @@ cid: partners ---
-
-
쿠버네티스는 파트너와 협력하여 다양하게 보완하는 플랫폼을 지원하는 강력하고 활기찬 코드베이스를 만들어갑니다.
-
-
-
-
- 공인 쿠버네티스 서비스 공급자(Kubernetes Certified Service Providers, KCSP) -
-
기업들이 쿠버네티스를 성공적으로 채택하도록 도와주는 풍부한 경험을 가진 노련한 서비스 공급자입니다. -


- -

KCSP에 관심이 있으신가요? -
-
-
-
-
- 공인 쿠버네티스 배포, 호스트된 플랫폼 그리고 설치 프로그램 -
소프트웨어 적합성은 모든 벤더의 쿠버네티스 버전이 필요한 API를 지원하도록 보장합니다. -


- -

공인 쿠버네티스에 관심이 있으신가요? -
-
-
-
-
쿠버네티스 교육 파트너(Kubernetes Training Partners, KTP)
-
클라우드 네이티브 기술 교육 경험이 풍부하고 노련한 교육 공급자입니다. -



- -

KTP에 관심이 있으신가요? -
-
-
- - + - -
- - -
- -
+ + +
+ + +
+ +