From b8b2cc7c7443e32de70834a2b3d2186cae6eea5a Mon Sep 17 00:00:00 2001 From: LiuDui <1693291525@qq.com> Date: Wed, 25 Dec 2019 08:51:29 +0800 Subject: [PATCH] ZH-trans: merge release1.16-temporary to master (#18217) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * zh-trans:/docs/docs/concepts/workloads/pods/ephemeral-containers.md (#16948) * update zh-trans of define-environment-variable-container.md (#16999) Signed-off-by: Yixiang2019 * update chinese docs (#16985) * Fix ordered list (#16988) Signed-off-by: PingWang update Signed-off-by: PingWang * zh-trans:/docs/reference/setup-tools/kubeadm/kubeadm-upgrade-phase.md (#16951) Signed-off-by: PingWang update Signed-off-by: PingWang update Signed-off-by: PingWang * Remove redundant symbol and fix some ordered list (#17000) Signed-off-by: PingWang update Signed-off-by: PingWang * update-zh-translation/docs/reference/setup-tools/kubeadm/kubeadm-init.md (#16997) * update zh translation kubeadm-reset.md kubeadm-upgrade.md (#16992) * Create kubeadm_join_phase_control-plane-join_all.md (#16987) * Update web-ui-dashboard.md (#16976) * update format problem (#16956) Signed-off-by: PingWang update Signed-off-by: PingWang * zh-trans:/docs/docs/concepts/storage/volume-pvc-datasource.md (#17021) * update zh translation /docs/reference/access-authn-authz/webhook.md (#16860) * fix confict update zh translation (#16863) * zh-trans:/docs/concepts/workloads/pods/disruptions.md (#16983) * zh-trans:/docs/concepts/workloads/pods/disruptions.md * Update content/zh/docs/concepts/workloads/pods/disruptions.md Co-Authored-By: Qiming * update zh translation content/zh/docs/reference/command-line-tools-reference/kube-scheduler.md (#17006) * Update RC's link (#16935) Signed-off-by: PingWang Update Signed-off-by: PingWang update the style Signed-off-by: PingWang * Update the links for /zh/docs/setup (#16938) Signed-off-by: PingWang * zh-trans:/docs/docs/concepts/services-networking/dual-stack.md (#17024) * update zh translation /reference/setup-tools/kubeadm/generated/kubeadm.md (#17036) * update zh tanslation /reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubelet_config_download.md (#17037) * update zh translation -/reference/setup-tools/kubeadm/generated/kubeadm_alpha.md (#17038) * update zh translation /docs/contribute/participating.md (#17040) * Fix cri-o's links to match English docs (#16936) Signed-off-by: PingWang * update zh translation content/zh/docs/reference/kubectl/jsonpath.md (#16862) * update zh translation /docs/reference/setup-tools/kubeadm/generated/kubeadm_token_generate.md (#17049) * update Unkown -> Unknown (#17062) * zh-translation:high-availability.md (#16960) Signed-off-by: yuxiaobo * update Runnning -> Running (#17061) * zh-trans:/docs/docs/concepts/storage/volume-snapshots.md (#17054) * update zh transation /docs/reference/setup-tools/kubeadm/generated/kubeadm_reset.md (#17060) * update zh translation /docs/reference/setup-tools/kubeadm/generated/kubeadm_token_create.md (#17052) * update zh translation /docs/reference/setup-tools/kubeadm/generated/kubeadm_token.md (#17055) * update zh translation update-zh-translation-/docs/reference/setup-tools/kubeadm/generated/kubeadm_token_list.md (#17048) * update zh-translation:ha-topology.md (#17099) Signed-off-by: yuxiaobo * zh-trans /reference/setup-tools/kubeadm/generated/kubeadm_config_images_list.md (#17093) * update zh translation /reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_all.md (#17083) * Add Chinese translation for scheduler-perf-tuning (#17087) Signed-off-by: GeorgeSen Add Chinese translation for scheduler-perf-tuning Signed-off-by: GeorgeSen Add Chinese translation for scheduler-perf-tuning Signed-off-by: GeorgeSen Add Chinese translation for scheduler-perf-tuning Signed-off-by: GeorgeSen * zh trans content/zh/docs/setup/production-environment/tools/kubeadm/control-plane-flags.md (#17121) * update zh trans content/zh/docs/tasks/access-application-cluster/service-access-application-cluster.md (#17122) * zh-translation:content/zh/docs/tasks/administer-cluster/namespaces-walkthrough.md (#17105) Signed-off-by: yuxiaobo * update-zh-translation-/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_migrate.md (#17091) * update zh trans /docs/setup/learning-environment/minikube.md (#17143) * update zh trans /zh/docs/reference/_index.md (#17146) * update zh trans /docs/tasks/access-application-cluster/port-forward-access-application-cluster.md (#17134) * update zh translation 20191020-update-zh-translation-/docs/contribute/localization.md (#17046) * update zh trans /docs/reference/using-api/client-libraries.md (#17144) * update zh trans /docs/reference/setup-tools/kubeadm/generated/kubeadm_version.md (#17145) * update zh /docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade_node.md (#17131) * update zh translation /reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_front-proxy-client.md (#17081) * update zh translation /docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig.md (#17078) * add zh translation /docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-join_update-status.md (#17076) * update zh trans content/zh/docs/contribute/generate-ref-docs/kubectl.md (#17165) * update zh translation /reference/command-line-tools-reference/kube-proxy.md (#17107) * zh-trans:/docs/docs/concepts/workloads/pods/pod-topology-spread-const… (#16955) * zh-trans:/docs/docs/concepts/workloads/pods/pod-topology-spread-constraints.md * Update pod-topology-spread-constraints.md * zh-trans:/docs/concepts/configuration/scheduling-framework.md (#17088) * update zh translation /docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_upload-config_kubelet.md (#17079) * update zh translation /docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_control-plane_apiserver.md (#17077) * update zh translation /docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-join.md (#17075) * update zh translation /docs/reference/setup-tools/kubeadm/generated/kubeadm_token_delete.md (#17050) * update zh trans /docs/concepts/overview/working-with-objects/namespaces.md (#17205) * update zh trans /docs/concepts/overview/what-is-kubernetes.md (#17203) * pr_release-1.16_crictl (#17201) * update zh docs/tasks/administer-cluster/dns-debugging-resolution.md (#17186) * update zh trans content/zh/docs/concepts/overview/working-with-objects/field-selectors.md (#17191) * translate configure_upgrade_etcd (#17160) * translate kubeadm_upgrade_apply (#17159) * update zh /docs/tasks/job/coarse-parallel-processing-work-queue.md (#17155) * translate docs/setup/release/version-skew-policy.md to Chinese (#17142) * update zh trans content/zh/docs/tasks/access-application-cluster/create-external-load-balancer.md (#17124) * zh-trans replace the wrong translation (#17103) zh-trans replace the wrong translation * Merged 1.14~1.16 changes (#17117) * zh-trans:/docs/concepts/configuration/assign-pod-node.md (#17129) * update zh trans /docs/contribute/generate-ref-docs/kubernetes-api.md (#17161) * pr_release-1.16_basic-ss (#17169) * Add zh-trans of assign-cpu-resource.md (#17063) Signed-off-by: heqg Add zh-trans of assign-cpu-resource.md Signed-off-by: heqg Add zh-trans of assign-cpu-resource.md Signed-off-by: heqg Add zh-trans of assign-cpu-resource.md Signed-off-by: heqg Add zh-trans of assign-cpu-resource.md Signed-off-by: heqg * update zh trans content/zh/docs/concepts/overview/working-with-objects/common-labels.md (#17193) * update zh translation /docs/contribute/intermediate.md (#17041) * zh-trans:docs/setup/production-environment/turnkey/tencent.md (#17207) * pr_release-1.16_mysql-wordpress-pv (#17202) * pr_release-1.16_reconfig-kubelet (#17200) * zh-trans:/docs/docs/concepts/workloads/controllers/jobs-run-completio… (#17020) * zh-trans:/docs/docs/concepts/workloads/controllers/jobs-run-completion.md * Update jobs-run-completion.md * Update jobs-run-completion.md * update zh trans content/zh/docs/concepts/extend-kubernetes/extend-cluster.md (#17212) * update zh trans content/zh/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation.md (#17213) * add zh trans /docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-prepare_kubeconfig.md (#17220) kubeadm_join_phase_control-plane-prepare_download-certs.md * add zh trans /reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs.md and /reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-prepare.md (#17219) * update zh trans content/zh/docs/concepts/containers/images.md (#17216) * ZH-trans: add _index.md (#17214) * ZH-trans: add _index.md * add _index.md file * add _index.md files * pr_release-1.16_crd-versions (#17198) * update zh translation /docs/reference/setup-tools/kubeadm/generated/kubeadm_config_images_pull.md (#17092) * zh-trans /reference/setup-tools/kubeadm/generated/kubeadm_config_images.md (#17094) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_addon_kube-proxy.md and content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_sa.md (#17222) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-prepare_all.md content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-prepare_certs.md (#17221) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_addon_all.md (#17223) * 013 /docs/concepts/services networking/ingress.md (#17185) * x * update zh trans content/zh/docs/concepts/services-networking/ingress.md * zh-trans:/reference/setup-tools/kubeadm/generated/kubeadm_completion.md and kubeadm_config.md (#17097) * add zh trans reference/glossary/pod-lifecycle (#17226) * update zh-translation document (#17096) Signed-off-by: yuxiaobo * update zh-translation:setup-ha-etcd-with-kubeadm.md (#17098) Signed-off-by: yuxiaobo * add zh trans /docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_selfhosting.md and /docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubelet_config_enable-dynamic.md (#17227) * add zh trans /docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubeconfig_user.md and /docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_upload-config_kubeadm.md (#17228) * zh-translation:content/zh/docs/tasks/extend-kubectl/kubectl-plugins.md (#17089) Signed-off-by: yuxiaobo * update zh translation /docs/reference/setup-tools/kubeadm/generated/kubeadm_join.md (#17080) * update zh translation /reference/setup-tools/kubeadm/generated/kubeadm_config_view.md (#17085) * zh-translation:troubleshooting-kubeadm.md (#17069) Signed-off-by: yuxiaobo * zh-trans: docs/concepts/scheduling/kube-scheduler.md (#17067) * Add Chinese translation for kube-scheduler Signed-off-by: GeorgeSen Add Chinese translation for kube-scheduler Signed-off-by: GeorgeSen Add Chinese translation for kube-scheduler Signed-off-by: GeorgeSen Add Chinese translation for kube-scheduler Signed-off-by: GeorgeSen Add Chinese translation for kube-scheduler Signed-off-by: GeorgeSen Add Chinese translation for kube-scheduler Signed-off-by: GeorgeSen Add Chinese translation for kube-scheduler Signed-off-by: GeorgeSen Add Chinese translation for kube-scheduler Signed-off-by: GeorgeSen * Update kube-scheduler.md * Add Chinese translation for kube-scheduler * Update kube-scheduler.md * Update kube-scheduler.md * Update kube-scheduler.md * translate pods.md and init-containers.md for branch release-1.16 (#17208) * update zh translation /docs/contribute/start.md (#17039) * zh-translation:2017-10-00-Five-Days-Of-Kubernetes-18.md (#17229) Signed-off-by: yuxiaobo * translate kubeadm-certs.md (#17090) * update the Illegal comment such as : (<!--、<--) (#17266) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase.md and content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_etcd-ca.md (#17268) * update zh /docs/concepts/architecture/cloud-controller.md (#17263) * update zh /docs/concepts/cluster-administration/logging.md (#17247) * modify the show of zh translation /concepts/overview/what-is-kubernetes.md /reference/setup-tools/kubeadm/generated/kubeadm_init.md /reference/setup-tools/kubeadm/kubeadm-init.md (#17246) * zh-translation:kubeadm_init_phase_control-plane_all.md (#17243) Signed-off-by: yuxiaobo * zh-translation:kubeadm_join_phase_control-plane-join_etcd.md (#17236) Signed-off-by: yuxiaobo * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubelet-start.md and content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_upload-certs.md (#17230) * add content/zh/docs/reference/glossary/container-runtime.md file fix-up to pass the ci and trans content/zh/docs/reference/glossary/container-runtime.md、content/zh/docs/concepts/overview/components.md (#17211) * zh-translation:mirror-pod.md (#17231) Signed-off-by: yuxiaobo * zh-translation:kubeadm_init_phase_upload-config.md (#17238) Signed-off-by: yuxiaobo * update zh /docs/concepts/workloads/pods/pod-overview.md (#17239) * update the format of zh translation content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_reset.md content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade.md content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade_apply.md content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade_plan.md content/zh/docs/reference/setup-tools/kubeadm/kubeadm-config.md content/zh/docs/reference/setup-tools/kubeadm/kubeadm-reset.md content/zh/docs/reference/setup-tools/kubeadm/kubeadm-token.md content/zh/docs/reference/setup-tools/kubeadm/kubeadm-upgrade.md (#17248) * Create advanced.md (#17256) * Create advanced.md * trans the advanced.md and fix the build bugs * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_control-plane.md and content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_control-plane_scheduler.md (#17269) * zh-translation:kubelet-integration.md (#17272) Signed-off-by: yuxiaobo * pr_release-1.16_out-of-resource (#17199) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_front-proxy-ca.md and content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_control-plane_controller-manager.md (#17267) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_etcd-peer.md and content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig_admin.md (#17271) * pr_release-1.16_ext-admission-ctl (#17196) * update zh translation /docs/contribute/advanced.md (#17042) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_apiserver-etcd-client.md and content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_ca.md (#17275) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_print.md update zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_print_init-defaults.md (#17282) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated… (#17287) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_etcd.md content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_upload-config_all.md update zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_control-plane.md * Update kubeadm_init_phase_etcd.md * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/… (#17285) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_etcd-server.md content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubelet.md update zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_apiserver.md * Update kubeadm_alpha_kubelet.md * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_all.md and content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_addon.md fix-up bad comment kubeadm_alpha_certs_renew.md、kubeadm_alpha_certs_renew_apiserver-etcd-client.md、kubeadm_init_phase_addon_all.md (#17276) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/… (#17281) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_etcd_local.md and content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_print_join-defaults.md * Update kubeadm_init_phase_etcd_local.md * zh trans update-daemon-set.md (#16872) * zh trans update-daemon-set.md * Update update-daemon-set.md * managing-tls-in-a-cluster.md (#16874) * update-api-object-kubectl-patch.md (#16875) * improve the zh trans /kubeadm/generated/kubeadm_init_phase_.* 1 (#17295) * improve the zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_.* (#17294) * modify the zh translation content/zh/docs/reference/setup-tools/kubea… (#17293) * modify the zh translation content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_.* * Update kubeadm_alpha.md * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig_all.md and content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_preflight.md (#17280) * add zh /docs/reference/glossary/cgroup.md (#17291) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubelet_config.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_apiserver-kubelet-client.md (#17288) * improve zh trans of command in /kubeadm/generated/kubeadm_init_phase_.* files (#17297) * improve zh command translation /kubeadm/generated/kubeadm_init_.* files (#17298) * update zh trans in /kubeadm/generated/kubeadm_.* files (#17306) * add zh trans /reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_etcd-healthcheck-client.md、/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_etcd-peer.md、/reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubeconfig.md (#17308) * Improve previously translated documents (#17327) Signed-off-by: yuxiaobo * zh-trans: docs/setup/production-environment/turnkey/aws.md (#17320) * Update zh.toml * update zh trans /generated/kubeadm_join_phase_.* files (#17301) * Update zh.toml * add zh /docs/reference/glossary/pod-disruption-budget.md (#17344) * pr_release-1.16_config-aggregation-layer (#17197) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_controller-manager.conf.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_scheduler.conf.md (#17390) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig_scheduler.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-prepare_control-plane.md (#17381) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_apiserver-kubelet-client.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-join_mark-control-plane.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_kubelet-start.md (#17380) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_addon_coredns.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_bootstrap-token.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_apiserver.md (#17383) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_certificate-key.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_reset_phase_preflight.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_reset_phase_update-cluster-status.md (#17385) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_admin.conf.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_reset_phase.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_reset_phase_cleanup-node.md (#17387) * add zh trans content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_apiserver-kubelet-client.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_front-proxy-client.md、content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_selfhosting_pivot.md (#17384) * add zh /docs/reference/glossary/limitrange.md (#17324) * add zh trans content/zh/docs/setup/best-practices/cluster-large.md (#17321) * add zh trans content/zh/docs/setup/best-practices/cluster-large.md * Update cluster-large.md * add zh trans /docs/reference/setup-tools/kubeadm/kubeadm-alpha.md、/do… (#17403) * add zh trans /docs/reference/setup-tools/kubeadm/kubeadm-alpha.md、/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_preflight.md、/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_etcd-server.md * Update kubeadm_init_phase_certs_etcd-server.md * add zh /docs/reference/glossary/cluster-operations.md (#17300) * add zh /docs/reference/glossary/applications.md (#17419) * update zh trans kubelet (#17379) * update zh trans kubelet * update the file according to feedback from reviewer tengqm * update 1000-1757 lines * update the advice zh trans * add zh /docs/reference/glossary/static-pod.md (#17418) * add zh /docs/reference/glossary/preemption.md (#17423) * add zh /docs/reference/glossary/pod-priority.md (#17421) * add zh /docs/reference/glossary/control-plane.md (#17425) * add zh /docs/reference/glossary/cluster-infrastructure.md (#17424) * pr_release-1.16_api-overview (#17444) * pr_release-1.16_daemonset (#17435) * pr_release-1.16_gc (#17445) * pr_release-1.16_qos-class (#17442) * fix QoS Class to QoS 类 (#17464) * pr_release-1.16-abac (#17427) * zh-trans:docs/setup/production-environment/turnkey/alibaba-cloud.md (#17345) * pr_release-1.16_endpoint-slice (#17468) * pr_release-1.16_taint (#17469) * pr_release-1.16_operator-pattern (#17467) * pr_release-1.16_ss (#17433) * pr_release-1.16_admission-controller (#17440) * pr_release-1.16_containerd (#17441) * pr_release-1.16_app-container (#17466) * add zh-trans content/zh/docs/setup/_index.md、content/zh/docs/setup/release/_index.md (#17503) * pr-release-1.16_enabling-endpoint-slices (#17504) * update zh trans content/zh/docs/reference/setup-tools/kubeadm/kubeadm… (#17495) * update zh trans content/zh/docs/reference/setup-tools/kubeadm/kubeadm-upgrade-phase.md、content/zh/docs/reference/setup-tools/kubeadm/kubeadm-init-phase.md * add content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig_kubelet.md * pr-release-1.16_logging (#17491) * pr-release-1.16_cri (#17486) * add zh-trans:docs/setup/production-environment/turnkey/azure.md (#17482) * pattern translate into 模式 (#17485) * fix zk affinity description in zh trans (#17393) * pr-release-1.16_ephemeral-container (#17487) * pr-release-1.16_data-plane (#17489) * pr-release-1.16_cncf (#17490) * zh-trans add content\zh\docs\tools\install-minikube.md (#16920) * zh-trans add content\zh\docs\tools\install-minikube.md * zh-trans update content\zh\docs\tools\install-minikube.md * zh-trans update content\zh\docs\tools\install-minikube.md * update \docs\tasks\tools\install-minikube.md * update docs\concepts\workloads\controllers\deployment.md * update deployment.md * pr-release-1.16_extensions (#17492) * pr-release-1.16_toleration (#17493) * Revert "update zh trans content/zh/docs/reference/setup-tools/kubeadm/kubeadm… (#17495)" (#17521) This reverts commit 1134c14e0a39bdc3d1a920ac9797139a6dcccf4b. * motidy extensions in content/zh/docs/reference/glossary/extensions (#17524) * motidy toleration in content/zh/docs/reference/glossary/toleration.md (#17523) * motidy toleration in content/zh/docs/reference/glossary/toleration.md * Update toleration.md * improve zh-trans in content/zh/docs/setup/_index.md (#17526) * add zh-trans /zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig_kubelet.md (#17527) * Broken Link (#17546) Issue available at https://kubernetes.io/zh/docs/concepts/containers/runtime-class/ and introduced by original English documentation (see #17543) * Update trans kubeadm_upgrade_plan.md (#17395) * Update kubeadm_upgrade_plan.md * Update kubeadm_upgrade_plan.md * Update kubeadm_upgrade_plan.md * Update kubeadm_upgrade_plan.md * Update kubeadm_upgrade_plan.md * Update kubeadm_upgrade_plan.md * update zh-trans of define-command-argument-container.md (#17022) Signed-off-by: Yixiang2019 update zh-trans of define-command-argument-container.md Signed-off-by: Yixiang2019 Add back the Original English Signed-off-by: Yixiang2019 update title of define-command-argument-container.md Signed-off-by: Yixiang2019 update table title and reference Signed-off-by: Yixiang2019 update reference of define-command-argument-container.md Signed-off-by: Yixiang2019 * ZH-trans: fix multiple jump links and update files (#17603) * ZH-trans: fix multiple jump links and update files * Update _index.html * update zh trans content/zh/docs/reference/setup-tools/kubeadm/kubeadm-init-phase.md (#17528) * update zh trans /doc/concepts/architecture/nodes.md (#17617) * update zh trans content/zh/docs/concepts/architecture/nodes.md * fix-up content/zh/docs/concepts/architecture/nodes.md * add zh-trans /docs/setup/release/notes.md (#17519) * add zh-trans /docs/setup/release/notes.md update-750 * fix-up 1575 line and udpate 2483 line * update to line 2980 * update to the last line 3160 * add zh-trans:docs/setup/production-environment/turnkey/icp.md (#17568) * zh-trans: /docs/setup/production-environment/container-runtimes.md (#17646) * zh-trs:container-runtimes.md Signed-off-by: yuxiaobo * Update container-runtimes.md * Translate /docs/concepts/workloads/controllers/ttlafterfinished.md into Chinese (#17791) * Translate /docs/concepts/cluster-administration/cloud-providers.md into Chinese * Translate /docs/concepts/workloads/controllers/ttlafterfinished.md into Chinese * Sorry, wrong commit, roll back... * Translate /docs/concepts/workloads/controllers/ttlafterfinished.md * Translate /docs/concepts/workloads/controllers/ttlafterfinished.md into Chinese * Translate /docs/concepts/workloads/controllers/ttlafterfinished.md into Chinese * Create trans kubeadm_upgrade_diff.md (#17392) * Update kubeadm_upgrade_diff.md * Update kubeadm_upgrade_diff.md * Update kubeadm_upgrade_diff.md * Create _index.md (#17831) * zh-trans zh-trans-/docs/reference/command-line-tools-reference/feature-gates.md (#17658) * Update volume-snapshots.md (#17829) * Update volume-snapshots.md * Update volume-snapshots.md * Update volume-snapshots.md * Create ovirt.md (#17849) * Create ovirt.md * Update ovirt.md * Translate /docs/concepts/cluster-administration/cloud-providers.md into Chinese (#17761) * Translate /docs/concepts/cluster-administration/cloud-providers.md into Chinese * Translate /docs/concepts/workloads/controllers/ttlafterfinished.md into Chinese * Sorry, wrong commit, roll back... * Update translation after tengqm's review. * Update cloud-providers.md * Update dual-stack.md (#17836) * Update dual-stack.md * Update dual-stack.md * Update dual-stack.md * Update dual-stack.md * Create validate-dual-stack.md (#17833) * Create validate-dual-stack.md * Update validate-dual-stack.md * translation content/zh/docs/reference/setup-tools/kubeadm/ kubeadm-join-phase、kubeadm-reset-phase (#17881) * zh-trans content/zh/docs/contribute/generate-ref-docs/contribute-upstream.md (#17882) * Chinese translation /docs/tasks/administer-cluster/highly-available-master.md (#17884) * Chinese translation /docs/tasks/administer-cluster/highly-available-master.md * Apply suggestions from code review Co-Authored-By: Qiming * Fix format issue (#17921) * Create topology-manager.md (#17901) * Create topology-manager.md * Update topology-manager.md * add zh-trans:docs/setup/production-environment/windows/user-guide-windows-containers.md (#17876) * Update pod-overhead.md (#17931) * Update scheduler-perf-tuning.md (#17934) * Create dcos.md (#17932) * Create dcos.md * Update dcos.md * Update object-management.md (#17937) * zh-translation content/zh/docs/setup/production-environment/tools/kops.md (#17991) * Create imperative-config.md (#17956) * Create imperative-config.md * Update imperative-config.md * Create self-hosting.md (#17950) * Create resource-bin-packing.md (#17935) * Create nodelocaldns.md (#17938) * Update config.toml(release-1.16) for 1.17 (#18025) * Update config.toml(release-1.16) for 1.17 * Update config.toml * Remove ru language * Update the conflict and merge the two commits * add nginx-deployment.yaml file Co-authored-by: ZhongliangXiong Co-authored-by: Yixiang Wang Co-authored-by: li mengyang Co-authored-by: PingWang Co-authored-by: chentanjun Co-authored-by: Sophy417 <53026875+Sophy417@users.noreply.github.com> Co-authored-by: zhangx501 Co-authored-by: Qiming Co-authored-by: yuxiaobo96 <41496192+yuxiaobo96@users.noreply.github.com> Co-authored-by: senwang Co-authored-by: lichuqiang Co-authored-by: lpf7551321 Co-authored-by: Hongcai Ren Co-authored-by: jiajie Co-authored-by: heqg <56527988+heqg@users.noreply.github.com> Co-authored-by: IreneByron Co-authored-by: Wang Bing Co-authored-by: Damini Satya Co-authored-by: liufangwai Co-authored-by: wangcong Co-authored-by: XuefeiWang2 Co-authored-by: Kubernetes Prow Robot Co-authored-by: Ziqiu Zhu Co-authored-by: ten2ton <50288981+ten2ton@users.noreply.github.com> Co-authored-by: Oleg Butuzov Co-authored-by: jiazxjason <52809535+jiazxjason@users.noreply.github.com> Co-authored-by: Coffey Gao Co-authored-by: Bingshen Wang --- content/zh/_index.html | 75 +- .../2015-03-00-Kubernetes-Gathering-Videos.md | 27 + ...-00-Weekly-Kubernetes-Community-Hangout.md | 186 + .../2015-03-00-Welcome-To-Kubernetes-Blog.md | 62 + .../2015-04-00-Kubernetes-Release-0150.md | 176 + ...-Weekly-Kubernetes-Community-Hangout_17.md | 287 ++ ...-Weekly-Kubernetes-Community-Hangout_29.md | 143 + .../2015-05-00-Kubernetes-On-Openstack.md | 112 + ...-00-Weekly-Kubernetes-Community-Hangout.md | 121 + ...15-06-00-Slides-Cluster-Management-With.md | 25 + ...-Announcing-First-Kubernetes-Enterprise.md | 24 + ...And-Replication-Controllers-With-Puppet.md | 164 + ...-Simple-Leader-Election-With-Kubernetes.md | 303 ++ ...00-Why-Kubernetes-Doesnt-Use-Libnetwork.md | 79 + ...Kubecon-Eu-2016-Kubernetes-Community-In.md | 84 + ...2-00-Kubernetes-Community-Meeting-Notes.md | 117 + .../2016-04-Kubernetes-Network-Policy-APIs.md | 182 - .../_posts/2016-04-Kubernetes-On-Aws_15.md | 129 - ...6-07-00-Citrix-Netscaler-And-Kubernetes.md | 72 + ...-Dashboard-Web-Interface-For-Kubernetes.md | 139 + .../2016-07-00-Oh-The-Places-You-Will-Go.md | 89 + .../2017-10-00-Five-Days-Of-Kubernetes-18.md | 72 + .../2017-11-00-Autoscaling-In-Kubernetes.md | 32 + ...8-03-Principles-Of-Container-App-Design.md | 81 - .../2018-05-01-developing-on-kubernetes.md | 728 ++++ ...8-05-30-say-hello-to-discuss-kubernetes.md | 67 + .../blog/_posts/2018-06-06-4-years-of-k8s.md | 42 + .../2018-06-07-dynamic-ingress-kubernetes.md | 129 + ...ng-ci-automating-contributor-experience.md | 241 ++ .../zh/blog/_posts/2018-10-03-kubedirector.md | 306 ++ ...0-11-topology-aware-volume-provisioning.md | 268 ++ .../2018-10-15-steering-election-results.md | 73 + ...-2018-north-american-contributor-summit.md | 118 + .../2018-11-08-kubernetes-docs-update-i18n.md | 89 + .../2018-12-05-new-contributor-shanghai.md | 4 +- content/zh/case-studies/_index.html | 44 +- .../adform/adform_featured_logo.png | Bin 0 -> 7110 bytes content/zh/case-studies/adform/index.html | 118 + .../case-studies/amadeus/amadeus_featured.png | Bin 0 -> 6970 bytes .../zh/case-studies/amadeus/amadeus_logo.png | Bin 0 -> 19562 bytes content/zh/case-studies/amadeus/index.html | 105 + .../ancestry/ancestry_featured.png | Bin 0 -> 21016 bytes .../case-studies/ancestry/ancestry_logo.png | Bin 0 -> 21141 bytes content/zh/case-studies/ancestry/index.html | 117 + .../ant-financial_featured_logo.png | Bin 0 -> 10263 bytes .../zh/case-studies/ant-financial/index.html | 96 + .../appdirect/appdirect_featured_logo.png | Bin 0 -> 5645 bytes content/zh/case-studies/appdirect/index.html | 99 + .../blablacar/blablacar_featured.png | Bin 0 -> 7867 bytes .../case-studies/blablacar/blablacar_logo.png | Bin 0 -> 7841 bytes content/zh/case-studies/blablacar/index.html | 98 + .../blackrock/blackrock_featured.png | Bin 0 -> 6391 bytes .../case-studies/blackrock/blackrock_logo.png | Bin 0 -> 6430 bytes content/zh/case-studies/blackrock/index.html | 112 + .../case-studies/bose/bose_featured_logo.png | Bin 0 -> 3564 bytes content/zh/case-studies/bose/index.html | 103 + content/zh/case-studies/box/box_featured.png | Bin 0 -> 6348 bytes content/zh/case-studies/box/box_logo.png | Bin 0 -> 5988 bytes content/zh/case-studies/box/box_small.png | Bin 0 -> 8519 bytes content/zh/case-studies/box/index.html | 114 + content/zh/case-studies/box/video.png | Bin 0 -> 134595 bytes .../case-studies/buffer/buffer_featured.png | Bin 0 -> 5263 bytes .../zh/case-studies/buffer/buffer_logo.png | Bin 0 -> 4791 bytes content/zh/case-studies/buffer/index.html | 157 + .../capital-one/capitalone_featured_logo.png | Bin 0 -> 11306 bytes .../zh/case-studies/capital-one/index.html | 96 + .../zh/case-studies/ccp-games/ccp_logo.png | Bin 0 -> 20368 bytes content/zh/case-studies/ccp-games/index.html | 4 + .../case-studies/cern/cern_featured_logo.png | Bin 0 -> 2849 bytes content/zh/case-studies/cern/index.html | 93 + .../chinaunicom/chinaunicom_featured_logo.png | Bin 0 -> 11459 bytes .../zh/case-studies/chinaunicom/index.html | 99 + .../city-of-montreal_featured_logo.png | Bin 0 -> 9647 bytes .../case-studies/city-of-montreal/index.html | 99 + .../crowdfire/crowdfire_featured_logo.png | Bin 0 -> 7827 bytes content/zh/case-studies/crowdfire/index.html | 101 + .../zh/case-studies/goldman-sachs/gs_logo.png | Bin 0 -> 23083 bytes .../zh/case-studies/goldman-sachs/index.html | 4 + .../case-studies/golfnow/golfnow_featured.png | Bin 0 -> 22915 bytes .../zh/case-studies/golfnow/golfnow_logo.png | Bin 0 -> 8858 bytes content/zh/case-studies/golfnow/index.html | 125 + .../haufegroup/haufegroup_featured.png | Bin 0 -> 5841 bytes .../haufegroup/haufegroup_logo.png | Bin 0 -> 5794 bytes content/zh/case-studies/haufegroup/index.html | 112 + .../case-studies/huawei/huawei_featured.png | Bin 0 -> 14310 bytes .../zh/case-studies/huawei/huawei_logo.png | Bin 0 -> 14274 bytes content/zh/case-studies/huawei/index.html | 433 +++ .../zh/case-studies/ibm/ibm_featured_logo.png | Bin 0 -> 11298 bytes .../zh/case-studies/ibm/ibm_featured_logo.svg | 1 + content/zh/case-studies/ibm/index.html | 93 + .../zh/case-studies/ing/ing_featured_logo.png | Bin 0 -> 10305 bytes .../jd-com/jd-com_featured_logo.png | Bin 0 -> 6581 bytes content/zh/case-studies/liveperson/index.html | 4 + .../liveperson/liveperson_logo.png | Bin 0 -> 19458 bytes content/zh/case-studies/monzo/index.html | 4 + content/zh/case-studies/monzo/monzo_logo.png | Bin 0 -> 5515 bytes .../case-studies/naic/naic_featured_logo.png | Bin 0 -> 9433 bytes .../zh/case-studies/nav/nav_featured_logo.png | Bin 0 -> 4218 bytes .../nerdalize/nerdalize_featured_logo.png | Bin 0 -> 10647 bytes content/zh/case-studies/netease/index.html | 105 + .../netease/netease_featured_logo.png | Bin 0 -> 5601 bytes .../newyorktimes/newyorktimes_featured.png | Bin 0 -> 20189 bytes .../newyorktimes/newyorktimes_logo.png | Bin 0 -> 10251 bytes .../nokia/nokia_featured_logo.png | Bin 0 -> 4261 bytes content/zh/case-studies/nordstrom/index.html | 152 + .../nordstrom/nordstrom_featured_logo.png | Bin 0 -> 7352 bytes .../northwestern_featured_logo.png | Bin 0 -> 10083 bytes .../ocado/ocado_featured_logo.png | Bin 0 -> 8089 bytes .../case-studies/openAI/openai_featured.png | Bin 0 -> 12132 bytes .../zh/case-studies/openAI/openai_logo.png | Bin 0 -> 19818 bytes .../peardeck/peardeck_featured.png | Bin 0 -> 11786 bytes .../case-studies/peardeck/peardeck_logo.png | Bin 0 -> 9260 bytes .../case-studies/pearson/pearson_featured.png | Bin 0 -> 7784 bytes .../zh/case-studies/pearson/pearson_logo.png | Bin 0 -> 5123 bytes content/zh/case-studies/philips/index.html | 4 + .../zh/case-studies/philips/philips_logo.png | Bin 0 -> 3877 bytes .../pingcap/pingcap_featured_logo.png | Bin 0 -> 7082 bytes .../pinterest/pinterest_feature.png | Bin 0 -> 9118 bytes .../case-studies/pinterest/pinterest_logo.png | Bin 0 -> 9003 bytes content/zh/case-studies/pokemon-go/index.html | 4 + .../pokemon-go/pokemon_go_logo.png | Bin 0 -> 19218 bytes .../prowise/prowise_featured_logo.png | Bin 0 -> 7621 bytes .../ricardo-ch/ricardo-ch_featured_logo.png | Bin 0 -> 5248 bytes .../zh/case-studies/samsung-sds/index.html | 4 + .../zh/case-studies/samsung-sds/sds_logo.png | Bin 0 -> 22930 bytes .../slamtec/slamtec_featured_logo.png | Bin 0 -> 16423 bytes .../slingtv/slingtv_featured_logo.png | Bin 0 -> 8513 bytes .../zh/case-studies/sos/sos_featured_logo.png | Bin 0 -> 6662 bytes content/zh/case-studies/soundcloud/index.html | 4 + .../soundcloud/soundcloud_logo.png | Bin 0 -> 22800 bytes .../spotify/spotify_featured_logo.png | Bin 0 -> 6383 bytes .../zh/case-studies/squarespace/index.html | 224 ++ .../squarespace/squarespace_featured_logo.png | Bin 0 -> 4539 bytes .../thredup/thredup_featured_logo.png | Bin 0 -> 4738 bytes .../case-studies/vsco/vsco_featured_logo.png | Bin 0 -> 11065 bytes content/zh/case-studies/wepay/index.html | 4 + content/zh/case-studies/wepay/wepay_logo.png | Bin 0 -> 20277 bytes content/zh/case-studies/wikimedia/index.html | 118 + .../wikimedia/wikimedia_featured.png | Bin 0 -> 21322 bytes .../case-studies/wikimedia/wikimedia_logo.png | Bin 0 -> 7875 bytes content/zh/case-studies/wink/index.html | 146 + .../zh/case-studies/wink/wink_featured.png | Bin 0 -> 21292 bytes content/zh/case-studies/wink/wink_logo.png | Bin 0 -> 5623 bytes .../woorank/woorank_featured_logo.png | Bin 0 -> 6438 bytes content/zh/case-studies/workiva/index.html | 147 + .../workiva/workiva_featured_logo.png | Bin 0 -> 5980 bytes .../zh/case-studies/yahoo-japan/index.html | 4 + .../yahoo-japan/yahooJapan_logo.png | Bin 0 -> 7266 bytes content/zh/case-studies/ygrene/index.html | 130 + .../ygrene/ygrene_featured_logo.png | Bin 0 -> 11569 bytes content/zh/case-studies/zalando/index.html | 132 + .../zalando/zalando_feature_logo.png | Bin 0 -> 7643 bytes content/zh/case-studies/zulily/index.html | 8 +- content/zh/community/_index.html | 133 + content/zh/community/code-of-conduct.md | 44 + content/zh/community/static/README.md | 5 + .../community/static/cncf-code-of-conduct.md | 46 + content/zh/docs/.gitkeep | 0 content/zh/docs/_index.md | 6 + .../zh/docs/concepts/architecture/_index.md | 9 +- .../concepts/architecture/cloud-controller.md | 8 +- .../architecture/master-node-communication.md | 12 +- .../zh/docs/concepts/architecture/nodes.md | 571 ++- .../concepts/cluster-administration/_index.md | 9 +- .../cluster-administration/cloud-providers.md | 640 +++- .../cluster-administration-overview.md | 2 - .../controller-metrics.md | 4 - .../cluster-administration/device-plugins.md | 97 - .../kubelet-garbage-collection.md | 28 +- .../cluster-administration/logging.md | 9 +- .../manage-deployment.md | 1 - .../cluster-administration/sysctl-cluster.md | 103 - .../zh/docs/concepts/configuration/_index.md | 9 +- .../concepts/configuration/assign-pod-node.md | 690 ++++ .../manage-compute-resources-container.md | 23 +- .../organize-cluster-access-kubeconfig.md | 45 +- .../docs/concepts/configuration/overview.md | 25 +- .../concepts/configuration/pod-overhead.md | 92 + .../configuration/resource-bin-packing.md | 258 ++ .../configuration/scheduling-framework.md | 542 +++ content/zh/docs/concepts/containers/_index.md | 9 +- .../containers/container-lifecycle-hooks.md | 13 + content/zh/docs/concepts/containers/images.md | 686 +++- .../docs/concepts/containers/runtime-class.md | 257 +- .../docs/concepts/extend-kubernetes/_index.md | 9 +- .../extend-kubernetes/api-extension/_index.md | 9 +- .../api-extension/apiserver-aggregation.md | 23 +- .../compute-storage-net/_index.md | 9 +- .../compute-storage-net/network-plugins.md | 6 +- .../extend-kubernetes/extend-cluster.md | 370 ++ .../extend-kubernetes/service-catalog.md | 457 +++ content/zh/docs/concepts/overview/_index.md | 9 +- .../zh/docs/concepts/overview/components.md | 249 +- .../concepts/overview/what-is-kubernetes.md | 270 +- .../overview/working-with-objects/_index.md | 9 +- .../working-with-objects/common-labels.md | 11 +- .../working-with-objects/field-selectors.md | 34 +- .../overview/working-with-objects/labels.md | 378 ++ .../working-with-objects/namespaces.md | 94 +- .../working-with-objects/object-management.md | 40 +- content/zh/docs/concepts/scheduling/_index.md | 9 + .../concepts/scheduling/kube-scheduler.md | 319 ++ .../scheduling/scheduler-perf-tuning.md | 185 + content/zh/docs/concepts/security/_index.md | 9 + .../concepts/services-networking/_index.md | 7 + .../services-networking/dual-stack.md | 215 ++ .../ingress-controllers.md | 2 - .../concepts/services-networking/ingress.md | 379 +- .../concepts/services-networking/service.md | 24 +- content/zh/docs/concepts/storage/_index.md | 7 + .../concepts/storage/dynamic-provisioning.md | 12 + .../docs/concepts/storage/storage-classes.md | 5 - .../docs/concepts/storage/storage-limits.md | 28 +- .../concepts/storage/volume-pvc-datasource.md | 142 + .../storage/volume-snapshot-classes.md | 2 +- .../docs/concepts/storage/volume-snapshots.md | 259 ++ content/zh/docs/concepts/storage/volumes.md | 6 +- content/zh/docs/concepts/workloads/_index.md | 2 +- .../concepts/workloads/controllers/_index.md | 10 +- .../workloads/controllers/cron-jobs.md | 108 +- .../workloads/controllers/daemonset.md | 376 +- .../workloads/controllers/deployment.md | 44 +- .../controllers/garbage-collection.md | 239 +- .../controllers/jobs-run-completion.md | 868 +++++ .../workloads/controllers/replicaset.md | 416 +++ .../controllers/replicationcontroller.md | 546 +++ .../workloads/controllers/statefulset.md | 457 +++ .../workloads/controllers/ttlafterfinished.md | 120 + .../zh/docs/concepts/workloads/pods/_index.md | 11 +- .../concepts/workloads/pods/disruptions.md | 533 +++ .../workloads/pods/ephemeral-containers.md | 313 ++ .../workloads/pods/init-containers.md | 389 +- .../concepts/workloads/pods/pod-overview.md | 256 ++ .../pods/pod-topology-spread-constraints.md | 402 +++ .../zh/docs/concepts/workloads/pods/pod.md | 399 +++ .../docs/concepts/workloads/pods/podpreset.md | 139 +- content/zh/docs/contribute/_index.md | 173 + content/zh/docs/contribute/advanced.md | 473 +++ .../contribute/generate-ref-docs/_index.md | 21 + .../generate-ref-docs/contribute-upstream.md | 405 +++ .../contribute/generate-ref-docs/kubectl.md | 487 +++ .../generate-ref-docs/kubernetes-api.md | 364 ++ .../kubernetes-components.md | 412 +++ content/zh/docs/contribute/intermediate.md | 1449 ++++++++ content/zh/docs/contribute/localization.md | 559 +++ content/zh/docs/contribute/participating.md | 532 +++ content/zh/docs/contribute/start.md | 634 ++++ content/zh/docs/contribute/style/_index.md | 21 + .../contribute/style/content-organization.md | 270 ++ .../style/hugo-shortcodes/example1.md | 23 + .../style/hugo-shortcodes/example2.md | 17 + .../contribute/style/hugo-shortcodes/index.md | 272 ++ .../style/hugo-shortcodes/podtemplate.json | 22 + .../docs/contribute/style/page-templates.md | 352 ++ .../docs/contribute/style/write-new-topic.md | 346 ++ .../zh/docs/doc-contributor-tools/README.md | 7 + .../doc-contributor-tools/snippets/README.md | 84 + .../snippets/atom-snippets.cson | 226 ++ .../getting-started-guides/ubuntu/security.md | 68 - .../zh/docs/home/supported-doc-versions.md | 4 +- content/zh/docs/reference/_index.md | 9 +- .../reference/access-authn-authz/_index.md | 2 +- .../docs/reference/access-authn-authz/abac.md | 279 +- .../access-authn-authz/authorization.md | 94 +- .../access-authn-authz/bootstrap-tokens.md | 14 +- .../access-authn-authz/controlling-access.md | 72 +- .../extensible-admission-controllers.md | 2090 +++++++++++ .../docs/reference/access-authn-authz/node.md | 201 ++ .../service-accounts-admin.md | 52 +- .../reference/access-authn-authz/webhook.md | 188 +- .../command-line-tools-reference/_index.md | 10 +- .../feature-gates.md | 679 ++++ .../kube-apiserver.md | 252 +- .../kube-controller-manager.md | 818 +++++ .../kube-proxy.md | 643 ++-- .../kube-scheduler.md | 1015 +++++- .../command-line-tools-reference/kubelet.md | 2166 ++++++++++- .../glossary/admission-controller.md | 44 + .../reference/glossary/aggregation-layer.md | 45 + .../zh/docs/reference/glossary/annotation.md | 42 + .../docs/reference/glossary/app-container.md | 41 + .../glossary/application-architect.md | 37 + .../glossary/application-developer.md | 41 + .../docs/reference/glossary/applications.md | 26 + .../zh/docs/reference/glossary/approver.md | 40 + .../zh/docs/reference/glossary/certificate.md | 42 + content/zh/docs/reference/glossary/cgroup.md | 40 + content/zh/docs/reference/glossary/cla.md | 38 + .../glossary/cloud-controller-manager.md | 47 + .../docs/reference/glossary/cloud-provider.md | 38 + .../reference/glossary/cluster-architect.md | 37 + .../glossary/cluster-infrastructure.md | 31 + .../reference/glossary/cluster-operations.md | 32 + .../reference/glossary/cluster-operator.md | 44 + content/zh/docs/reference/glossary/cluster.md | 33 + content/zh/docs/reference/glossary/cncf.md | 43 + content/zh/docs/reference/glossary/cni.md | 44 + .../reference/glossary/code-contributor.md | 43 + .../zh/docs/reference/glossary/configmap.md | 41 + .../glossary/container-env-variables.md | 40 + .../glossary/container-lifecycle-hooks.md | 38 + .../reference/glossary/container-runtime.md | 45 + .../zh/docs/reference/glossary/container.md | 44 + .../zh/docs/reference/glossary/containerd.md | 39 + .../zh/docs/reference/glossary/contributor.md | 39 + .../docs/reference/glossary/control-plane.md | 31 + .../zh/docs/reference/glossary/controller.md | 40 + content/zh/docs/reference/glossary/cri-o.md | 40 + content/zh/docs/reference/glossary/cri.md | 40 + content/zh/docs/reference/glossary/cronjob.md | 43 + content/zh/docs/reference/glossary/csi.md | 48 + .../glossary/customresourcedefinition.md | 46 + .../zh/docs/reference/glossary/daemonset.md | 43 + .../zh/docs/reference/glossary/data-plane.md | 30 + .../zh/docs/reference/glossary/deployment.md | 45 + .../zh/docs/reference/glossary/developer.md | 42 + .../docs/reference/glossary/device-plugin.md | 32 + content/zh/docs/reference/glossary/docker.md | 41 + .../zh/docs/reference/glossary/downstream.md | 44 + .../glossary/dynamic-volume-provisioning.md | 44 + .../docs/reference/glossary/endpoint-slice.md | 40 + .../reference/glossary/ephemeral-container.md | 36 + content/zh/docs/reference/glossary/etcd.md | 43 + .../zh/docs/reference/glossary/extensions.md | 38 + .../zh/docs/reference/glossary/flexvolume.md | 41 + .../zh/docs/reference/glossary/helm-chart.md | 43 + .../glossary/horizontal-pod-autoscaler.md | 37 + content/zh/docs/reference/glossary/image.md | 42 + content/zh/docs/reference/glossary/index.md | 3 + content/zh/docs/reference/glossary/ingress.md | 30 +- .../docs/reference/glossary/init-container.md | 41 + content/zh/docs/reference/glossary/istio.md | 45 + content/zh/docs/reference/glossary/job.md | 45 + content/zh/docs/reference/glossary/kops.md | 63 + .../docs/reference/glossary/kube-apiserver.md | 44 + .../glossary/kube-controller-manager.md | 39 + .../zh/docs/reference/glossary/kube-proxy.md | 41 + .../docs/reference/glossary/kube-scheduler.md | 42 + content/zh/docs/reference/glossary/kubeadm.md | 43 + content/zh/docs/reference/glossary/kubectl.md | 43 + content/zh/docs/reference/glossary/kubelet.md | 40 + .../docs/reference/glossary/kubernetes-api.md | 47 + content/zh/docs/reference/glossary/label.md | 41 + .../zh/docs/reference/glossary/limitrange.md | 51 + content/zh/docs/reference/glossary/logging.md | 39 + .../reference/glossary/managed-service.md | 42 + content/zh/docs/reference/glossary/member.md | 42 + .../zh/docs/reference/glossary/minikube.md | 43 + .../zh/docs/reference/glossary/mirror-pod.md | 46 + content/zh/docs/reference/glossary/name.md | 16 + .../zh/docs/reference/glossary/namespace.md | 41 + .../docs/reference/glossary/network-policy.md | 44 + content/zh/docs/reference/glossary/node.md | 43 + .../reference/glossary/operator-pattern.md | 46 + .../glossary/persistent-volume-claim.md | 39 + .../reference/glossary/persistent-volume.md | 48 + .../reference/glossary/platform-developer.md | 42 + .../glossary/pod-disruption-budget.md | 40 + .../docs/reference/glossary/pod-lifecycle.md | 40 + .../docs/reference/glossary/pod-priority.md | 39 + .../reference/glossary/pod-security-policy.md | 46 + content/zh/docs/reference/glossary/pod.md | 43 + .../zh/docs/reference/glossary/podpreset.md | 40 + .../zh/docs/reference/glossary/preemption.md | 38 + .../zh/docs/reference/glossary/qos-class.md | 46 + .../zh/docs/reference/glossary/quantity.md | 60 + content/zh/docs/reference/glossary/rbac.md | 43 + .../zh/docs/reference/glossary/replica-set.md | 45 + .../glossary/replication-controller.md | 43 + .../docs/reference/glossary/resource-quota.md | 47 + .../zh/docs/reference/glossary/reviewer.md | 41 + content/zh/docs/reference/glossary/secret.md | 45 + .../reference/glossary/security-context.md | 43 + .../zh/docs/reference/glossary/selector.md | 42 + .../reference/glossary/service-account.md | 43 + .../docs/reference/glossary/service-broker.md | 42 + .../reference/glossary/service-catalog.md | 43 + content/zh/docs/reference/glossary/service.md | 2 +- content/zh/docs/reference/glossary/sig.md | 48 + .../zh/docs/reference/glossary/statefulset.md | 49 + .../zh/docs/reference/glossary/static-pod.md | 39 + .../docs/reference/glossary/storage-class.md | 40 + content/zh/docs/reference/glossary/sysctl.md | 51 + content/zh/docs/reference/glossary/taint.md | 39 + .../zh/docs/reference/glossary/toleration.md | 38 + content/zh/docs/reference/glossary/uid.md | 16 + .../zh/docs/reference/glossary/upstream.md | 27 + .../docs/reference/glossary/volume-plugin.md | 44 + content/zh/docs/reference/glossary/volume.md | 43 + content/zh/docs/reference/glossary/wg.md | 45 + .../zh/docs/reference/glossary/workload.md | 39 + .../docs/reference/issues-security/_index.md | 10 +- .../docs/reference/issues-security/issues.md | 16 + .../reference/issues-security/security.md | 129 + content/zh/docs/reference/kubectl/_index.md | 8 +- .../zh/docs/reference/kubectl/cheatsheet.md | 679 ++++ .../zh/docs/reference/kubectl/conventions.md | 170 + .../kubectl/docker-cli-to-kubectl.md | 392 +- content/zh/docs/reference/kubectl/jsonpath.md | 118 +- .../zh/docs/reference/kubectl/kubectl-cmds.md | 10 + .../reference/kubectl/kubectl-overview.md | 287 -- content/zh/docs/reference/kubectl/kubectl.md | 88 +- content/zh/docs/reference/kubectl/overview.md | 921 +++++ .../docs/reference/kubernetes-api/_index.md | 9 +- .../labels-annotations-taints.md | 13 +- .../setup-tools/kubeadm/generated/README.md | 1 + .../setup-tools/kubeadm/generated/kubeadm.md | 133 + .../kubeadm/generated/kubeadm_alpha.md | 86 + .../kubeadm_alpha_certs_certificate-key.md | 92 + .../kubeadm_alpha_certs_check-expiration.md | 113 + .../generated/kubeadm_alpha_certs_renew.md | 106 + .../kubeadm_alpha_certs_renew_admin.conf.md | 176 + .../kubeadm_alpha_certs_renew_all.md | 166 + ...alpha_certs_renew_apiserver-etcd-client.md | 180 + ...ha_certs_renew_apiserver-kubelet-client.md | 181 + .../kubeadm_alpha_certs_renew_apiserver.md | 180 + ...pha_certs_renew_controller-manager.conf.md | 181 + ...pha_certs_renew_etcd-healthcheck-client.md | 181 + .../kubeadm_alpha_certs_renew_etcd-peer.md | 181 + .../kubeadm_alpha_certs_renew_etcd-server.md | 181 + ...dm_alpha_certs_renew_front-proxy-client.md | 178 + ...ubeadm_alpha_certs_renew_scheduler.conf.md | 181 + .../generated/kubeadm_alpha_kubeconfig.md | 88 + .../kubeadm_alpha_kubeconfig_user.md | 181 + .../generated/kubeadm_alpha_kubelet.md | 82 + .../generated/kubeadm_alpha_kubelet_config.md | 84 + .../kubeadm_alpha_kubelet_config_download.md | 140 + ...adm_alpha_kubelet_config_enable-dynamic.md | 148 + .../generated/kubeadm_alpha_selfhosting.md | 82 + .../kubeadm_alpha_selfhosting_pivot.md | 180 + .../kubeadm/generated/kubeadm_completion.md | 161 + .../kubeadm/generated/kubeadm_config.md | 115 + .../generated/kubeadm_config_images.md | 103 + .../generated/kubeadm_config_images_list.md | 141 + .../generated/kubeadm_config_images_pull.md | 169 + .../generated/kubeadm_config_migrate.md | 144 + .../kubeadm/generated/kubeadm_config_print.md | 108 + .../kubeadm_config_print_init-defaults.md | 121 + .../kubeadm_config_print_join-defaults.md | 121 + .../kubeadm/generated/kubeadm_config_view.md | 105 + .../kubeadm/generated/kubeadm_init.md | 371 +- .../kubeadm/generated/kubeadm_init_phase.md | 102 + .../generated/kubeadm_init_phase_addon.md | 89 + .../generated/kubeadm_init_phase_addon_all.md | 245 ++ .../kubeadm_init_phase_addon_coredns.md | 192 + .../kubeadm_init_phase_addon_kube-proxy.md | 199 ++ .../kubeadm_init_phase_bootstrap-token.md | 144 + .../generated/kubeadm_init_phase_certs.md | 109 + .../generated/kubeadm_init_phase_certs_all.md | 200 ++ ..._init_phase_certs_apiserver-etcd-client.md | 165 + ...it_phase_certs_apiserver-kubelet-client.md | 164 + .../kubeadm_init_phase_certs_apiserver.md | 240 ++ .../generated/kubeadm_init_phase_certs_ca.md | 140 + .../kubeadm_init_phase_certs_etcd-ca.md | 140 + ...nit_phase_certs_etcd-healthcheck-client.md | 160 + .../kubeadm_init_phase_certs_etcd-peer.md | 170 + .../kubeadm_init_phase_certs_etcd-server.md | 169 + ...kubeadm_init_phase_certs_front-proxy-ca.md | 140 + ...adm_init_phase_certs_front-proxy-client.md | 161 + .../generated/kubeadm_init_phase_certs_sa.md | 106 + .../kubeadm_init_phase_control-plane.md | 93 + .../kubeadm_init_phase_control-plane_all.md | 290 ++ ...eadm_init_phase_control-plane_apiserver.md | 240 ++ ..._phase_control-plane_controller-manager.md | 183 + ...eadm_init_phase_control-plane_scheduler.md | 171 + .../generated/kubeadm_init_phase_etcd.md | 85 + .../kubeadm_init_phase_etcd_local.md | 162 + .../kubeadm_init_phase_kubeconfig.md | 94 + .../kubeadm_init_phase_kubeconfig_admin.md | 189 + .../kubeadm_init_phase_kubeconfig_all.md | 201 ++ ...nit_phase_kubeconfig_controller-manager.md | 183 + .../kubeadm_init_phase_kubeconfig_kubelet.md | 196 + ...kubeadm_init_phase_kubeconfig_scheduler.md | 188 + .../kubeadm_init_phase_kubelet-start.md | 132 + .../kubeadm_init_phase_mark-control-plane.md | 125 + .../generated/kubeadm_init_phase_preflight.md | 122 + .../kubeadm_init_phase_upload-certs.md | 132 + .../kubeadm_init_phase_upload-config.md | 85 + .../kubeadm_init_phase_upload-config_all.md | 114 + ...ubeadm_init_phase_upload-config_kubeadm.md | 131 + ...ubeadm_init_phase_upload-config_kubelet.md | 128 + .../kubeadm/generated/kubeadm_join.md | 369 ++ .../kubeadm/generated/kubeadm_join_phase.md | 96 + .../kubeadm_join_phase_control-plane-join.md | 107 + ...beadm_join_phase_control-plane-join_all.md | 132 + ...eadm_join_phase_control-plane-join_etcd.md | 141 + ...e_control-plane-join_mark-control-plane.md | 119 + ..._phase_control-plane-join_update-status.md | 132 + ...ubeadm_join_phase_control-plane-prepare.md | 106 + ...dm_join_phase_control-plane-prepare_all.md | 245 ++ ..._join_phase_control-plane-prepare_certs.md | 204 ++ ...ase_control-plane-prepare_control-plane.md | 149 + ...se_control-plane-prepare_download-certs.md | 192 + ..._phase_control-plane-prepare_kubeconfig.md | 192 + .../kubeadm_join_phase_kubelet-start.md | 192 + .../generated/kubeadm_join_phase_preflight.md | 269 ++ .../kubeadm/generated/kubeadm_reset.md | 178 + .../kubeadm/generated/kubeadm_reset_phase.md | 96 + .../kubeadm_reset_phase_cleanup-node.md | 114 + .../kubeadm_reset_phase_preflight.md | 108 + .../kubeadm_reset_phase_remove-etcd-member.md | 91 + ...beadm_reset_phase_update-cluster-status.md | 84 + .../kubeadm/generated/kubeadm_token.md | 164 + .../kubeadm/generated/kubeadm_token_create.md | 211 ++ .../kubeadm/generated/kubeadm_token_delete.md | 120 + .../generated/kubeadm_token_generate.md | 124 + .../kubeadm/generated/kubeadm_token_list.md | 114 + .../kubeadm/generated/kubeadm_upgrade.md | 89 + .../generated/kubeadm_upgrade_apply.md | 265 ++ .../kubeadm/generated/kubeadm_upgrade_diff.md | 150 + .../kubeadm/generated/kubeadm_upgrade_node.md | 185 + .../generated/kubeadm_upgrade_node_phase.md | 81 + ...ubeadm_upgrade_node_phase_control-plane.md | 121 + ...beadm_upgrade_node_phase_kubelet-config.md | 92 + .../kubeadm/generated/kubeadm_upgrade_plan.md | 154 + .../kubeadm/generated/kubeadm_version.md | 96 + .../setup-tools/kubeadm/kubeadm-alpha.md | 128 + .../setup-tools/kubeadm/kubeadm-config.md | 69 + .../setup-tools/kubeadm/kubeadm-init-phase.md | 274 ++ .../setup-tools/kubeadm/kubeadm-init.md | 757 ++-- .../setup-tools/kubeadm/kubeadm-join-phase.md | 97 + .../setup-tools/kubeadm/kubeadm-join.md | 399 +++ .../kubeadm/kubeadm-reset-phase.md | 95 + .../setup-tools/kubeadm/kubeadm-reset.md | 62 + .../setup-tools/kubeadm/kubeadm-token.md | 57 + .../kubeadm/kubeadm-upgrade-phase.md | 47 + .../setup-tools/kubeadm/kubeadm-upgrade.md | 75 + .../setup-tools/kubeadm/kubeadm-version.md | 22 + .../reference/setup-tools/kubeadm/kubeadm.md | 11 +- content/zh/docs/reference/tools.md | 15 +- content/zh/docs/reference/using-api/_index.md | 13 + .../docs/reference/using-api/api-overview.md | 233 ++ .../reference/using-api/client-libraries.md | 149 + content/zh/docs/search.md | 11 + content/zh/docs/setup/_index.md | 181 + .../zh/docs/setup/best-practices/_index.md | 9 + .../setup/best-practices/cluster-large.md | 259 ++ .../setup/best-practices/node-conformance.md | 177 + content/zh/docs/setup/cluster-large.md | 122 - .../independent/create-cluster-kubeadm.md | 10 +- .../docs/setup/independent/install-kubeadm.md | 2 +- .../docs/setup/learning-environment/_index.md | 11 + .../setup/learning-environment/minikube.md | 931 +++++ content/zh/docs/setup/multiple-zones.md | 291 -- content/zh/docs/setup/node-conformance.md | 84 - .../setup/production-environment/_index.md | 9 + .../container-runtimes.md | 583 +++ .../on-premises-vm/_index.md | 10 + .../on-premises-vm/dcos.md | 48 + .../on-premises-vm/ovirt.md | 135 + .../production-environment/tools/_index.md | 9 + .../production-environment/tools/kops.md | 351 ++ .../tools/kubeadm/_index.md | 9 + .../tools/kubeadm/control-plane-flags.md | 138 + .../tools/kubeadm/ha-topology.md | 140 + .../tools/kubeadm/high-availability.md | 727 ++++ .../tools/kubeadm/kubelet-integration.md | 381 ++ .../tools/kubeadm/self-hosting.md | 134 + .../kubeadm/setup-ha-etcd-with-kubeadm.md | 407 +++ .../tools/kubeadm/troubleshooting-kubeadm.md | 650 ++++ .../production-environment/turnkey/_index.md | 9 + .../turnkey/alibaba-cloud.md | 44 + .../production-environment/turnkey/aws.md | 177 + .../production-environment/turnkey/azure.md | 76 + .../production-environment/turnkey/icp.md | 162 + .../production-environment/turnkey/tencent.md | 44 + .../production-environment/windows/_index.md | 9 + .../windows/kubecluster.ps1-install.gif | Bin 0 -> 7266330 bytes .../windows/kubecluster.ps1-join.gif | Bin 0 -> 3682504 bytes .../windows/kubecluster.ps1-reset.gif | Bin 0 -> 3524074 bytes .../windows/user-guide-windows-containers.md | 244 ++ content/zh/docs/setup/release/_index.md | 11 + content/zh/docs/setup/release/notes.md | 3159 +++++++++++++++++ .../docs/setup/release/version-skew-policy.md | 278 ++ content/zh/docs/setup/salt.md | 244 -- content/zh/docs/sitemap.md | 115 + content/zh/docs/tasks/_index.md | 191 + .../access-application-cluster/_index.md | 11 + .../access-cluster.md | 13 +- .../configure-dns-cluster.md | 11 +- .../create-external-load-balancer.md | 277 +- .../list-all-running-container-images.md | 11 +- ...load-balance-access-application-cluster.md | 190 - ...port-forward-access-application-cluster.md | 92 +- .../service-access-application-cluster.md | 51 +- .../web-ui-dashboard.md | 383 ++ .../tasks/access-kubernetes-api/_index.md | 11 + .../configure-aggregation-layer.md | 541 +++ .../custom-resources/_index.md | 9 + .../custom-resource-definition-versioning.md | 1259 +++++++ .../http-proxy-access-api.md | 121 + .../setup-extension-api-server.md | 19 +- .../docs/tasks/administer-cluster/_index.md | 11 + .../administer-cluster/access-cluster-api.md | 352 ++ .../calico-network-policy.md | 75 - .../change-default-storage-class.md | 57 +- .../configure-multiple-schedulers.md | 310 ++ .../configure-upgrade-etcd.md | 480 +++ .../docs/tasks/administer-cluster/coredns.md | 190 + .../cpu-management-policies.md | 227 +- .../administer-cluster/cpu-memory-limit.md | 258 -- .../developing-cloud-controller-manager.md | 84 + .../dns-custom-nameservers.md | 576 ++- .../dns-custom-nameservers/dns.png | Bin 0 -> 28795 bytes .../dns-debugging-resolution.md | 601 ++++ .../dns-horizontal-autoscaling.md | 487 +++ .../enabling-endpoint-slices.md | 109 + .../tasks/administer-cluster/encrypt-data.md | 13 +- .../extended-resource-node.md | 371 ++ ...aranteed-scheduling-critical-addon-pods.md | 74 +- .../highly-available-master.md | 345 ++ .../tasks/administer-cluster/ip-masq-agent.md | 215 ++ .../tasks/administer-cluster/kms-provider.md | 283 ++ .../administer-cluster/kubeadm/_index.md | 11 + .../kubeadm/kubeadm-certs.md | 390 ++ .../kubeadm/kubeadm-upgrade-1-9.md | 453 --- .../kubeadm/kubeadm-upgrade.md | 547 +++ .../administer-cluster/kubelet-config-file.md | 86 +- .../limit-storage-consumption.md | 143 + .../manage-resources/_index.md | 11 +- .../cpu-constraint-namespace.md | 32 +- .../manage-resources/cpu-default-namespace.md | 28 +- .../memory-constraint-namespace.md | 17 +- .../memory-default-namespace.md | 14 +- .../quota-memory-cpu-namespace.md | 18 +- .../administer-cluster/memory-available.sh | 31 + .../namespaces-walkthrough.md | 386 ++ .../tasks/administer-cluster/namespaces.md | 569 +++ .../calico-network-policy.md | 7 +- .../weave-network-policy.md | 5 +- .../tasks/administer-cluster/nodelocaldns.md | 157 + .../administer-cluster/out-of-resource.md | 673 ++++ .../administer-cluster/quota-api-object.md | 274 ++ .../administer-cluster/reconfigure-kubelet.md | 694 ++++ .../reserve-compute-resources.md | 421 +++ .../romana-network-policy.md | 51 - .../running-cloud-controller.md | 180 + .../administer-cluster/securing-a-cluster.md | 370 ++ .../tasks/administer-cluster/static-pod.md | 125 - .../administer-cluster/topology-manager.md | 292 ++ .../weave-network-policy.md | 119 - .../tasks/administer-federation/_index.md | 12 - .../tasks/configure-pod-container/_index.md | 12 +- .../assign-cpu-resource.md | 460 +++ .../assign-pods-nodes.md | 2 +- .../attach-handler-lifecycle-event.md | 1 - .../configure-persistent-volume-storage.md | 375 ++ .../configure-pod-configmap.md | 848 +++++ .../configure-pod-initialization.md | 151 + .../configure-projected-volume-storage.md | 110 + .../configure-service-account.md | 451 +++ .../configure-volume-storage.md | 200 ++ .../extended-resource.md | 221 ++ .../pull-image-private-registry.md | 286 ++ .../quality-service-pod.md | 443 +++ .../share-process-namespace.md | 193 + .../translate-compose-kubernetes.md | 844 +++++ .../tasks/debug-application-cluster/_index.md | 11 +- .../tasks/debug-application-cluster/audit.md | 2 +- .../tasks/debug-application-cluster/crictl.md | 488 +++ .../debug-application-introspection.md | 545 +++ .../debug-init-containers.md | 224 ++ .../debug-pod-replication-controller.md | 234 +- .../debug-service.md | 1180 ++++++ .../determine-reason-pod-failure.md | 172 + .../events-stackdriver.md | 167 + .../get-shell-running-container.md | 241 ++ .../local-debugging.md | 126 + .../logging-elasticsearch-kibana.md | 193 + .../monitor-node-health.md | 315 ++ .../resource-metrics-pipeline.md | 105 + .../resource-usage-monitoring.md | 105 + .../troubleshooting.md | 220 ++ .../zh/docs/tasks/example-task-template.md | 105 + .../tasks/extend-kubectl/kubectl-plugins.md | 512 +++ content/zh/docs/tasks/federation/_index.md | 11 +- .../administer-federation/_index.md | 11 + .../administer-federation/configmap.md | 147 + .../administer-federation/daemonset.md | 135 + .../administer-federation/deployment.md | 176 + .../administer-federation/events.md | 87 + .../federation/administer-federation/job.md | 189 + .../administer-federation/namespaces.md | 157 + .../administer-federation/replicaset.md | 219 ++ .../administer-federation/secret.md | 164 + .../federation-service-discovery.md | 508 +++ content/zh/docs/tasks/federation/policy.rego | 74 + .../set-up-coredns-provider-federation.md | 252 ++ .../set-up-placement-policies-federation.md | 255 ++ .../tasks/inject-data-application/_index.md | 10 +- .../define-command-argument-container.md | 211 +- .../define-environment-variable-container.md | 91 +- ...nward-api-volume-expose-pod-information.md | 4 +- content/zh/docs/tasks/job/_index.md | 11 +- .../coarse-parallel-processing-work-queue.md | 504 +++ .../fine-parallel-processing-work-queue.md | 9 +- .../job/parallel-processing-expansion.md | 302 ++ content/zh/docs/tasks/manage-daemon/_index.md | 11 + .../tasks/manage-daemon/update-daemon-set.md | 335 ++ .../docs/tasks/manage-gpus/scheduling-gpus.md | 431 ++- .../manage-hugepages/scheduling-hugepages.md | 76 +- .../tasks/manage-kubernetes-objects/_index.md | 9 + .../imperative-config.md | 275 ++ content/zh/docs/tasks/network/_index.md | 9 + .../docs/tasks/network/validate-dual-stack.md | 197 + .../zh/docs/tasks/run-application/_index.md | 11 + .../tasks/run-application/configure-pdb.md | 334 ++ .../force-delete-stateful-set-pod.md | 158 + .../horizontal-pod-autoscale-walkthrough.md | 695 ++++ .../horizontal-pod-autoscale.md | 559 +++ .../rolling-update-replication-controller.md | 296 +- .../run-replicated-stateful-application.md | 656 ++++ ...un-single-instance-stateful-application.md | 116 +- .../update-api-object-kubectl-patch.md | 527 +++ .../zh/docs/tasks/service-catalog/_index.md | 11 + .../install-service-catalog-using-helm.md | 159 + .../install-service-catalog-using-sc.md | 128 + content/zh/docs/tasks/tls/_index.md | 4 + .../tasks/tls/managing-tls-in-a-cluster.md | 411 +++ content/zh/docs/tasks/tools/_index.md | 11 + .../zh/docs/tasks/tools/install-kubectl.md | 702 ++++ .../zh/docs/tasks/tools/install-minikube.md | 110 + .../zh/docs/templates/feature-state-alpha.txt | 7 + .../zh/docs/templates/feature-state-beta.txt | 8 + .../templates/feature-state-deprecated.txt | 2 + .../docs/templates/feature-state-stable.txt | 5 + content/zh/docs/templates/index.md | 26 + content/zh/docs/tools/install-minikube.md | 248 ++ content/zh/docs/tutorials/_index.md | 189 + .../fedora => tutorials/clusters}/_index.md | 6 +- .../zh/docs/tutorials/clusters/apparmor.md | 601 ++++ .../tutorials/clusters/deny-write.profile | 10 + .../zh/docs/tutorials/configuration/_index.md | 11 + .../configure-redis-using-configmap.md | 197 +- content/zh/docs/tutorials/hello-minikube.md | 524 +++ .../tutorials/kubernetes-basics/_index.html | 36 +- .../kubernetes-basics/cluster-intro.html | 107 - .../create-cluster/_index.md | 11 + .../cluster-interactive.html | 22 +- .../create-cluster/cluster-intro.html | 108 + .../kubernetes-basics/deploy-app/_index.md | 11 + .../deploy-app/deploy-interactive.html | 45 + .../deploy-app/deploy-intro.html | 136 + .../kubernetes-basics/deploy-intro.html | 108 - .../kubernetes-basics/explore-intro.html | 142 - .../kubernetes-basics/explore/_index.md | 9 + .../{ => explore}/explore-interactive.html | 19 +- .../explore/explore-intro.html | 222 ++ .../kubernetes-basics/expose-intro.html | 119 - .../kubernetes-basics/expose/_index.md | 11 + .../{ => expose}/expose-interactive.html | 18 +- .../expose/expose-intro.html | 114 + .../kubernetes-basics/scale-intro.html | 123 - .../kubernetes-basics/scale/_index.md | 11 + .../{ => scale}/scale-interactive.html | 20 +- .../kubernetes-basics/scale/scale-intro.html | 10 +- .../kubernetes-basics/update-interactive.html | 31 - .../kubernetes-basics/update-intro.html | 135 - .../kubernetes-basics/update/_index.md | 11 + .../update-interactive.html} | 24 +- .../update/update-intro.html | 190 + .../imperative-object-management-command.md | 137 - .../object-management.md | 153 - .../docs/tutorials/online-training/_index.md | 11 + .../tutorials/online-training/overview.md | 170 + content/zh/docs/tutorials/services/_index.md | 11 + .../tutorials/stateful-application/Dockerfile | 17 - .../tutorials/stateful-application/FETCH_HEAD | 0 .../tutorials/stateful-application/_index.md | 11 + .../basic-stateful-set.md | 761 +++- .../stateful-application/cassandra.md | 3 +- .../docs/tutorials/stateful-application/dev | 0 .../mysql-wordpress-persistent-volume.md | 295 +- .../stateful-application/zookeeper.md | 4 +- .../tutorials/stateless-application/_index.md | 11 + .../expose-external-ip-address.md | 257 ++ .../stateless-application/guestbook.md | 622 ++++ content/zh/docs/update-user-guide-links.py | 85 + .../users/app-developer/advanced.md | 280 ++ .../users/cluster-operator/foundational.md | 194 + .../users/cluster-operator/intermediate.md | 221 ++ content/zh/examples/README.md | 17 + .../zh/examples/admin/cloud/ccm-example.yaml | 69 + content/zh/examples/admin/dns/busybox.yaml | 14 + .../admin/dns/dns-horizontal-autoscaler.yaml | 33 + content/zh/examples/admin/namespace-dev.json | 10 + content/zh/examples/admin/namespace-prod.json | 10 + .../resource/limit-mem-cpu-container.yaml | 19 + .../admin/resource/limit-mem-cpu-pod.yaml | 10 + .../resource/limit-memory-ratio-pod.yaml | 9 + .../admin/resource/limit-range-pod-1.yaml | 37 + .../admin/resource/limit-range-pod-2.yaml | 37 + .../admin/resource/limit-range-pod-3.yaml | 13 + .../admin/resource/pvc-limit-greater.yaml | 10 + .../admin/resource/pvc-limit-lower.yaml | 10 + .../admin/resource/quota-objects-pvc-2.yaml | 11 + .../admin/resource/quota-objects-pvc.yaml | 11 + .../admin/resource/quota-objects.yaml | 9 + .../admin/resource/storagelimits.yaml | 11 + .../zh/examples/admin/sched/my-scheduler.yaml | 67 + content/zh/examples/admin/sched/pod1.yaml | 10 + content/zh/examples/admin/sched/pod2.yaml | 11 + content/zh/examples/admin/sched/pod3.yaml | 11 + .../application/deployment-patch.yaml | 21 + .../guestbook/frontend-deployment.yaml | 38 + .../guestbook/frontend-service.yaml | 18 + .../guestbook/redis-master-deployment.yaml | 29 + .../guestbook/redis-master-service.yaml | 16 + .../guestbook/redis-slave-deployment.yaml | 40 + .../guestbook/redis-slave-service.yaml | 15 + .../examples/application/hpa/php-apache.yaml | 13 + .../zh/examples/application/job/job-tmpl.yaml | 18 + .../application/job/rabbitmq/Dockerfile | 10 + .../application/job/rabbitmq/job.yaml | 20 + .../application/job/rabbitmq/worker.py | 7 + .../examples/application/job/redis/Dockerfile | 6 + .../application/job/redis/redis-pod.yaml | 15 + .../application/job/redis/redis-service.yaml | 10 + .../examples/application/job/redis/rediswq.py | 130 + .../application/mysql/mysql-configmap.yaml | 16 + .../examples/application/mysql/mysql-pv.yaml | 2 +- .../application/mysql/mysql-services.yaml | 30 + .../application/mysql/mysql-statefulset.yaml | 167 + .../application/nginx-with-request.yaml | 23 + .../application/nginx/nginx-deployment.yaml | 19 + .../examples/application/nginx/nginx-svc.yaml | 12 + .../zh/examples/application/shell-demo.yaml | 14 + .../application/simple_deployment.yaml | 19 + .../application/update_deployment.yaml | 18 + .../application/zookeeper/zookeeper.yaml | 2 +- .../configmap/configmap-multikeys.yaml | 8 + content/zh/examples/configmap/configmaps.yaml | 15 + .../configmap/game-env-file.properties | 5 + content/zh/examples/configmap/game.properties | 7 + .../examples/configmap/ui-env-file.properties | 3 + content/zh/examples/configmap/ui.properties | 4 + .../zh/examples/controllers/daemonset.yaml | 42 + content/zh/examples/controllers/frontend.yaml | 38 + content/zh/examples/controllers/hpa-rs.yaml | 11 + content/zh/examples/controllers/job.yaml | 14 + .../controllers/nginx-deployment.yaml | 2 +- .../controllers/replication-nginx-1.7.9.yaml | 16 + .../controllers/replication-nginx-1.9.2.yaml | 21 + .../zh/examples/controllers/replication.yaml | 19 + content/zh/examples/debug/event-exporter.yaml | 47 + .../examples/debug/fluentd-gcp-configmap.yaml | 379 ++ content/zh/examples/debug/fluentd-gcp-ds.yaml | 113 + .../node-problem-detector-configmap.yaml | 49 + .../examples/debug/node-problem-detector.yaml | 43 + content/zh/examples/debug/termination.yaml | 10 + content/zh/examples/examples.go | 17 + content/zh/examples/examples_test.go | 634 ++++ .../federation/policy-engine-deployment.yaml | 37 + .../federation/policy-engine-service.yaml | 13 + .../federation/replicaset-example-policy.yaml | 21 + .../scheduling-policy-admission.yaml | 29 + content/zh/examples/minikube/Dockerfile | 4 + content/zh/examples/minikube/server.js | 9 + content/zh/examples/pods/config/redis-config | 2 + .../zh/examples/pods/config/redis-pod.yaml | 30 + content/zh/examples/pods/init-containers.yaml | 30 + .../pod-multiple-secret-env-variable.yaml | 19 + .../pods/inject/pod-secret-envFrom.yaml | 11 + .../pod-single-secret-env-variable.yaml | 14 + .../pods/pod-configmap-env-var-valueFrom.yaml | 21 + .../examples/pods/pod-configmap-envFrom.yaml | 13 + .../pod-configmap-volume-specific-key.yaml | 20 + .../examples/pods/pod-configmap-volume.yaml | 19 + .../pod-multiple-configmap-env-variable.yaml | 21 + .../pods/pod-nginx-specific-node.yaml | 10 + .../pods/pod-projected-svc-token.yaml | 20 + content/zh/examples/pods/pod-rs.yaml | 23 + .../pod-single-configmap-env-variable.yaml | 19 + .../examples/pods/pod-with-node-affinity.yaml | 26 + .../examples/pods/pod-with-pod-affinity.yaml | 29 + content/zh/examples/pods/private-reg-pod.yaml | 11 + .../zh/examples/pods/probe/exec-liveness.yaml | 21 + .../zh/examples/pods/probe/http-liveness.yaml | 21 + .../pods/probe/pod-with-http-healthcheck.yaml | 20 + .../pod-with-tcp-socket-healthcheck.yaml | 19 + .../pods/probe/tcp-liveness-readiness.yaml | 22 + content/zh/examples/pods/qos/qos-pod-2.yaml | 14 + content/zh/examples/pods/qos/qos-pod-3.yaml | 9 + content/zh/examples/pods/qos/qos-pod-4.yaml | 16 + content/zh/examples/pods/qos/qos-pod.yaml | 16 + .../pods/resource/cpu-request-limit-2.yaml | 17 + .../pods/resource/cpu-request-limit.yaml | 17 + .../resource/extended-resource-pod-2.yaml | 13 + .../pods/resource/extended-resource-pod.yaml | 13 + .../pods/resource/memory-request-limit-2.yaml | 16 + .../pods/resource/memory-request-limit-3.yaml | 16 + .../pods/resource/memory-request-limit.yaml | 16 + .../pods/security/hello-apparmor.yaml | 13 + .../pods/security/security-context-2.yaml | 13 + .../pods/security/security-context-3.yaml | 11 + .../pods/security/security-context-4.yaml | 11 + .../pods/security/security-context.yaml | 19 + .../pods/share-process-namespace.yaml | 17 + content/zh/examples/pods/simple-pod.yaml | 10 + .../zh/examples/pods/storage/projected.yaml | 23 + .../zh/examples/pods/storage/pv-claim.yaml | 11 + content/zh/examples/pods/storage/pv-pod.yaml | 20 + .../zh/examples/pods/storage/pv-volume.yaml | 14 + content/zh/examples/pods/storage/redis.yaml | 14 + .../one-constraint-with-nodeaffinity.yaml | 26 + .../one-constraint.yaml | 17 + .../two-constraints.yaml | 23 + .../zh/examples/policy/privileged-psp.yaml | 27 + .../zh/examples/policy/restricted-psp.yaml | 48 + ...-pod-disruption-budget-maxunavailable.yaml | 9 + ...er-pod-disruption-budget-minavailable.yaml | 9 + .../service/access/hello-service.yaml | 2 +- .../examples/service/networking/ingress.yaml | 2 +- .../zh/examples/windows/configmap-pod.yaml | 31 + content/zh/examples/windows/daemonset.yaml | 21 + .../zh/examples/windows/deploy-hyperv.yaml | 22 + .../zh/examples/windows/deploy-resource.yaml | 24 + content/zh/examples/windows/emptydir-pod.yaml | 20 + .../examples/windows/hostpath-volume-pod.yaml | 18 + .../windows/run-as-username-container.yaml | 17 + .../examples/windows/run-as-username-pod.yaml | 14 + content/zh/examples/windows/secret-pod.yaml | 32 + content/zh/examples/windows/simple-pod.yaml | 14 + .../includes/default-storage-class-prereqs.md | 5 +- .../federated-task-tutorial-prereqs.md | 16 + .../zh/includes/federation-content-moved.md | 7 - .../zh/includes/federation-current-state.md | 5 - .../federation-deprecation-warning-note.md | 8 + content/zh/includes/index.md | 3 + content/zh/includes/partner-script.js | 1609 +++++++++ content/zh/includes/partner-style.css | 202 ++ .../includes/user-guide-migration-notice.md | 1 - content/zh/partners/_index.html | 125 + 933 files changed, 113346 insertions(+), 8088 deletions(-) create mode 100644 content/zh/blog/_posts/2015-03-00-Kubernetes-Gathering-Videos.md create mode 100644 content/zh/blog/_posts/2015-03-00-Weekly-Kubernetes-Community-Hangout.md create mode 100644 content/zh/blog/_posts/2015-03-00-Welcome-To-Kubernetes-Blog.md create mode 100644 content/zh/blog/_posts/2015-04-00-Kubernetes-Release-0150.md create mode 100644 content/zh/blog/_posts/2015-04-00-Weekly-Kubernetes-Community-Hangout_17.md create mode 100644 content/zh/blog/_posts/2015-04-00-Weekly-Kubernetes-Community-Hangout_29.md create mode 100644 content/zh/blog/_posts/2015-05-00-Kubernetes-On-Openstack.md create mode 100644 content/zh/blog/_posts/2015-05-00-Weekly-Kubernetes-Community-Hangout.md create mode 100644 content/zh/blog/_posts/2015-06-00-Slides-Cluster-Management-With.md create mode 100644 content/zh/blog/_posts/2015-07-00-Announcing-First-Kubernetes-Enterprise.md create mode 100644 content/zh/blog/_posts/2015-12-00-Managing-Kubernetes-Pods-Services-And-Replication-Controllers-With-Puppet.md create mode 100644 content/zh/blog/_posts/2016-01-00-Simple-Leader-Election-With-Kubernetes.md create mode 100644 content/zh/blog/_posts/2016-01-00-Why-Kubernetes-Doesnt-Use-Libnetwork.md create mode 100644 content/zh/blog/_posts/2016-02-00-Kubecon-Eu-2016-Kubernetes-Community-In.md create mode 100644 content/zh/blog/_posts/2016-02-00-Kubernetes-Community-Meeting-Notes.md delete mode 100644 content/zh/blog/_posts/2016-04-Kubernetes-Network-Policy-APIs.md delete mode 100644 content/zh/blog/_posts/2016-04-Kubernetes-On-Aws_15.md create mode 100644 content/zh/blog/_posts/2016-07-00-Citrix-Netscaler-And-Kubernetes.md create mode 100644 content/zh/blog/_posts/2016-07-00-Dashboard-Web-Interface-For-Kubernetes.md create mode 100644 content/zh/blog/_posts/2016-07-00-Oh-The-Places-You-Will-Go.md create mode 100644 content/zh/blog/_posts/2017-10-00-Five-Days-Of-Kubernetes-18.md create mode 100644 content/zh/blog/_posts/2017-11-00-Autoscaling-In-Kubernetes.md delete mode 100644 content/zh/blog/_posts/2018-03-Principles-Of-Container-App-Design.md create mode 100644 content/zh/blog/_posts/2018-05-01-developing-on-kubernetes.md create mode 100644 content/zh/blog/_posts/2018-05-30-say-hello-to-discuss-kubernetes.md create mode 100644 content/zh/blog/_posts/2018-06-06-4-years-of-k8s.md create mode 100644 content/zh/blog/_posts/2018-06-07-dynamic-ingress-kubernetes.md create mode 100644 content/zh/blog/_posts/2018-08-29-kubernetes-testing-ci-automating-contributor-experience.md create mode 100644 content/zh/blog/_posts/2018-10-03-kubedirector.md create mode 100644 content/zh/blog/_posts/2018-10-11-topology-aware-volume-provisioning.md create mode 100644 content/zh/blog/_posts/2018-10-15-steering-election-results.md create mode 100644 content/zh/blog/_posts/2018-10-16-kubernetes-2018-north-american-contributor-summit.md create mode 100644 content/zh/blog/_posts/2018-11-08-kubernetes-docs-update-i18n.md create mode 100644 content/zh/case-studies/adform/adform_featured_logo.png create mode 100644 content/zh/case-studies/adform/index.html create mode 100644 content/zh/case-studies/amadeus/amadeus_featured.png create mode 100644 content/zh/case-studies/amadeus/amadeus_logo.png create mode 100644 content/zh/case-studies/amadeus/index.html create mode 100644 content/zh/case-studies/ancestry/ancestry_featured.png create mode 100644 content/zh/case-studies/ancestry/ancestry_logo.png create mode 100644 content/zh/case-studies/ancestry/index.html create mode 100644 content/zh/case-studies/ant-financial/ant-financial_featured_logo.png create mode 100644 content/zh/case-studies/ant-financial/index.html create mode 100644 content/zh/case-studies/appdirect/appdirect_featured_logo.png create mode 100644 content/zh/case-studies/appdirect/index.html create mode 100644 content/zh/case-studies/blablacar/blablacar_featured.png create mode 100644 content/zh/case-studies/blablacar/blablacar_logo.png create mode 100644 content/zh/case-studies/blablacar/index.html create mode 100644 content/zh/case-studies/blackrock/blackrock_featured.png create mode 100644 content/zh/case-studies/blackrock/blackrock_logo.png create mode 100644 content/zh/case-studies/blackrock/index.html create mode 100644 content/zh/case-studies/bose/bose_featured_logo.png create mode 100644 content/zh/case-studies/bose/index.html create mode 100644 content/zh/case-studies/box/box_featured.png create mode 100644 content/zh/case-studies/box/box_logo.png create mode 100644 content/zh/case-studies/box/box_small.png create mode 100644 content/zh/case-studies/box/index.html create mode 100644 content/zh/case-studies/box/video.png create mode 100644 content/zh/case-studies/buffer/buffer_featured.png create mode 100644 content/zh/case-studies/buffer/buffer_logo.png create mode 100644 content/zh/case-studies/buffer/index.html create mode 100644 content/zh/case-studies/capital-one/capitalone_featured_logo.png create mode 100644 content/zh/case-studies/capital-one/index.html create mode 100644 content/zh/case-studies/ccp-games/ccp_logo.png create mode 100644 content/zh/case-studies/ccp-games/index.html create mode 100644 content/zh/case-studies/cern/cern_featured_logo.png create mode 100644 content/zh/case-studies/cern/index.html create mode 100644 content/zh/case-studies/chinaunicom/chinaunicom_featured_logo.png create mode 100644 content/zh/case-studies/chinaunicom/index.html create mode 100644 content/zh/case-studies/city-of-montreal/city-of-montreal_featured_logo.png create mode 100644 content/zh/case-studies/city-of-montreal/index.html create mode 100644 content/zh/case-studies/crowdfire/crowdfire_featured_logo.png create mode 100644 content/zh/case-studies/crowdfire/index.html create mode 100644 content/zh/case-studies/goldman-sachs/gs_logo.png create mode 100644 content/zh/case-studies/goldman-sachs/index.html create mode 100644 content/zh/case-studies/golfnow/golfnow_featured.png create mode 100644 content/zh/case-studies/golfnow/golfnow_logo.png create mode 100644 content/zh/case-studies/golfnow/index.html create mode 100644 content/zh/case-studies/haufegroup/haufegroup_featured.png create mode 100644 content/zh/case-studies/haufegroup/haufegroup_logo.png create mode 100644 content/zh/case-studies/haufegroup/index.html create mode 100644 content/zh/case-studies/huawei/huawei_featured.png create mode 100644 content/zh/case-studies/huawei/huawei_logo.png create mode 100644 content/zh/case-studies/huawei/index.html create mode 100644 content/zh/case-studies/ibm/ibm_featured_logo.png create mode 100644 content/zh/case-studies/ibm/ibm_featured_logo.svg create mode 100644 content/zh/case-studies/ibm/index.html create mode 100644 content/zh/case-studies/ing/ing_featured_logo.png create mode 100644 content/zh/case-studies/jd-com/jd-com_featured_logo.png create mode 100644 content/zh/case-studies/liveperson/index.html create mode 100644 content/zh/case-studies/liveperson/liveperson_logo.png create mode 100644 content/zh/case-studies/monzo/index.html create mode 100644 content/zh/case-studies/monzo/monzo_logo.png create mode 100644 content/zh/case-studies/naic/naic_featured_logo.png create mode 100644 content/zh/case-studies/nav/nav_featured_logo.png create mode 100644 content/zh/case-studies/nerdalize/nerdalize_featured_logo.png create mode 100644 content/zh/case-studies/netease/index.html create mode 100644 content/zh/case-studies/netease/netease_featured_logo.png create mode 100644 content/zh/case-studies/newyorktimes/newyorktimes_featured.png create mode 100644 content/zh/case-studies/newyorktimes/newyorktimes_logo.png create mode 100644 content/zh/case-studies/nokia/nokia_featured_logo.png create mode 100644 content/zh/case-studies/nordstrom/index.html create mode 100644 content/zh/case-studies/nordstrom/nordstrom_featured_logo.png create mode 100644 content/zh/case-studies/northwestern-mutual/northwestern_featured_logo.png create mode 100644 content/zh/case-studies/ocado/ocado_featured_logo.png create mode 100644 content/zh/case-studies/openAI/openai_featured.png create mode 100644 content/zh/case-studies/openAI/openai_logo.png create mode 100644 content/zh/case-studies/peardeck/peardeck_featured.png create mode 100644 content/zh/case-studies/peardeck/peardeck_logo.png create mode 100644 content/zh/case-studies/pearson/pearson_featured.png create mode 100644 content/zh/case-studies/pearson/pearson_logo.png create mode 100644 content/zh/case-studies/philips/index.html create mode 100644 content/zh/case-studies/philips/philips_logo.png create mode 100644 content/zh/case-studies/pingcap/pingcap_featured_logo.png create mode 100644 content/zh/case-studies/pinterest/pinterest_feature.png create mode 100644 content/zh/case-studies/pinterest/pinterest_logo.png create mode 100644 content/zh/case-studies/pokemon-go/index.html create mode 100644 content/zh/case-studies/pokemon-go/pokemon_go_logo.png create mode 100644 content/zh/case-studies/prowise/prowise_featured_logo.png create mode 100644 content/zh/case-studies/ricardo-ch/ricardo-ch_featured_logo.png create mode 100644 content/zh/case-studies/samsung-sds/index.html create mode 100644 content/zh/case-studies/samsung-sds/sds_logo.png create mode 100644 content/zh/case-studies/slamtec/slamtec_featured_logo.png create mode 100644 content/zh/case-studies/slingtv/slingtv_featured_logo.png create mode 100644 content/zh/case-studies/sos/sos_featured_logo.png create mode 100644 content/zh/case-studies/soundcloud/index.html create mode 100644 content/zh/case-studies/soundcloud/soundcloud_logo.png create mode 100644 content/zh/case-studies/spotify/spotify_featured_logo.png create mode 100644 content/zh/case-studies/squarespace/index.html create mode 100644 content/zh/case-studies/squarespace/squarespace_featured_logo.png create mode 100644 content/zh/case-studies/thredup/thredup_featured_logo.png create mode 100644 content/zh/case-studies/vsco/vsco_featured_logo.png create mode 100644 content/zh/case-studies/wepay/index.html create mode 100644 content/zh/case-studies/wepay/wepay_logo.png create mode 100644 content/zh/case-studies/wikimedia/index.html create mode 100644 content/zh/case-studies/wikimedia/wikimedia_featured.png create mode 100644 content/zh/case-studies/wikimedia/wikimedia_logo.png create mode 100644 content/zh/case-studies/wink/index.html create mode 100644 content/zh/case-studies/wink/wink_featured.png create mode 100644 content/zh/case-studies/wink/wink_logo.png create mode 100644 content/zh/case-studies/woorank/woorank_featured_logo.png create mode 100644 content/zh/case-studies/workiva/index.html create mode 100644 content/zh/case-studies/workiva/workiva_featured_logo.png create mode 100644 content/zh/case-studies/yahoo-japan/index.html create mode 100644 content/zh/case-studies/yahoo-japan/yahooJapan_logo.png create mode 100644 content/zh/case-studies/ygrene/index.html create mode 100644 content/zh/case-studies/ygrene/ygrene_featured_logo.png create mode 100644 content/zh/case-studies/zalando/index.html create mode 100644 content/zh/case-studies/zalando/zalando_feature_logo.png create mode 100644 content/zh/community/_index.html create mode 100644 content/zh/community/code-of-conduct.md create mode 100644 content/zh/community/static/README.md create mode 100644 content/zh/community/static/cncf-code-of-conduct.md delete mode 100644 content/zh/docs/.gitkeep delete mode 100644 content/zh/docs/concepts/cluster-administration/device-plugins.md delete mode 100644 content/zh/docs/concepts/cluster-administration/sysctl-cluster.md create mode 100644 content/zh/docs/concepts/configuration/assign-pod-node.md create mode 100644 content/zh/docs/concepts/configuration/pod-overhead.md create mode 100644 content/zh/docs/concepts/configuration/resource-bin-packing.md create mode 100644 content/zh/docs/concepts/configuration/scheduling-framework.md create mode 100644 content/zh/docs/concepts/extend-kubernetes/extend-cluster.md create mode 100644 content/zh/docs/concepts/extend-kubernetes/service-catalog.md create mode 100644 content/zh/docs/concepts/overview/working-with-objects/labels.md create mode 100644 content/zh/docs/concepts/scheduling/_index.md create mode 100644 content/zh/docs/concepts/scheduling/kube-scheduler.md create mode 100644 content/zh/docs/concepts/scheduling/scheduler-perf-tuning.md create mode 100644 content/zh/docs/concepts/security/_index.md create mode 100644 content/zh/docs/concepts/services-networking/dual-stack.md create mode 100644 content/zh/docs/concepts/storage/volume-pvc-datasource.md create mode 100644 content/zh/docs/concepts/storage/volume-snapshots.md create mode 100644 content/zh/docs/concepts/workloads/controllers/jobs-run-completion.md create mode 100644 content/zh/docs/concepts/workloads/controllers/replicaset.md create mode 100644 content/zh/docs/concepts/workloads/controllers/replicationcontroller.md create mode 100644 content/zh/docs/concepts/workloads/controllers/statefulset.md create mode 100644 content/zh/docs/concepts/workloads/controllers/ttlafterfinished.md create mode 100644 content/zh/docs/concepts/workloads/pods/disruptions.md create mode 100644 content/zh/docs/concepts/workloads/pods/ephemeral-containers.md create mode 100644 content/zh/docs/concepts/workloads/pods/pod-overview.md create mode 100644 content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md create mode 100644 content/zh/docs/concepts/workloads/pods/pod.md create mode 100644 content/zh/docs/contribute/_index.md create mode 100644 content/zh/docs/contribute/advanced.md create mode 100644 content/zh/docs/contribute/generate-ref-docs/_index.md create mode 100644 content/zh/docs/contribute/generate-ref-docs/contribute-upstream.md create mode 100644 content/zh/docs/contribute/generate-ref-docs/kubectl.md create mode 100644 content/zh/docs/contribute/generate-ref-docs/kubernetes-api.md create mode 100644 content/zh/docs/contribute/generate-ref-docs/kubernetes-components.md create mode 100644 content/zh/docs/contribute/intermediate.md create mode 100644 content/zh/docs/contribute/localization.md create mode 100644 content/zh/docs/contribute/participating.md create mode 100644 content/zh/docs/contribute/start.md create mode 100644 content/zh/docs/contribute/style/_index.md create mode 100644 content/zh/docs/contribute/style/content-organization.md create mode 100644 content/zh/docs/contribute/style/hugo-shortcodes/example1.md create mode 100644 content/zh/docs/contribute/style/hugo-shortcodes/example2.md create mode 100644 content/zh/docs/contribute/style/hugo-shortcodes/index.md create mode 100644 content/zh/docs/contribute/style/hugo-shortcodes/podtemplate.json create mode 100644 content/zh/docs/contribute/style/page-templates.md create mode 100644 content/zh/docs/contribute/style/write-new-topic.md create mode 100644 content/zh/docs/doc-contributor-tools/README.md create mode 100644 content/zh/docs/doc-contributor-tools/snippets/README.md create mode 100644 content/zh/docs/doc-contributor-tools/snippets/atom-snippets.cson delete mode 100644 content/zh/docs/getting-started-guides/ubuntu/security.md create mode 100644 content/zh/docs/reference/access-authn-authz/extensible-admission-controllers.md create mode 100644 content/zh/docs/reference/access-authn-authz/node.md create mode 100644 content/zh/docs/reference/command-line-tools-reference/feature-gates.md create mode 100644 content/zh/docs/reference/command-line-tools-reference/kube-controller-manager.md create mode 100644 content/zh/docs/reference/glossary/admission-controller.md create mode 100644 content/zh/docs/reference/glossary/aggregation-layer.md create mode 100644 content/zh/docs/reference/glossary/annotation.md create mode 100644 content/zh/docs/reference/glossary/app-container.md create mode 100644 content/zh/docs/reference/glossary/application-architect.md create mode 100644 content/zh/docs/reference/glossary/application-developer.md create mode 100644 content/zh/docs/reference/glossary/applications.md create mode 100755 content/zh/docs/reference/glossary/approver.md create mode 100644 content/zh/docs/reference/glossary/certificate.md create mode 100644 content/zh/docs/reference/glossary/cgroup.md create mode 100644 content/zh/docs/reference/glossary/cla.md create mode 100755 content/zh/docs/reference/glossary/cloud-controller-manager.md create mode 100644 content/zh/docs/reference/glossary/cloud-provider.md create mode 100644 content/zh/docs/reference/glossary/cluster-architect.md create mode 100644 content/zh/docs/reference/glossary/cluster-infrastructure.md create mode 100644 content/zh/docs/reference/glossary/cluster-operations.md create mode 100644 content/zh/docs/reference/glossary/cluster-operator.md create mode 100644 content/zh/docs/reference/glossary/cluster.md create mode 100644 content/zh/docs/reference/glossary/cncf.md create mode 100644 content/zh/docs/reference/glossary/cni.md create mode 100644 content/zh/docs/reference/glossary/code-contributor.md create mode 100644 content/zh/docs/reference/glossary/configmap.md create mode 100644 content/zh/docs/reference/glossary/container-env-variables.md create mode 100644 content/zh/docs/reference/glossary/container-lifecycle-hooks.md create mode 100644 content/zh/docs/reference/glossary/container-runtime.md create mode 100644 content/zh/docs/reference/glossary/container.md create mode 100644 content/zh/docs/reference/glossary/containerd.md create mode 100755 content/zh/docs/reference/glossary/contributor.md create mode 100644 content/zh/docs/reference/glossary/control-plane.md create mode 100644 content/zh/docs/reference/glossary/controller.md create mode 100644 content/zh/docs/reference/glossary/cri-o.md create mode 100644 content/zh/docs/reference/glossary/cri.md create mode 100644 content/zh/docs/reference/glossary/cronjob.md create mode 100644 content/zh/docs/reference/glossary/csi.md create mode 100644 content/zh/docs/reference/glossary/customresourcedefinition.md create mode 100644 content/zh/docs/reference/glossary/daemonset.md create mode 100644 content/zh/docs/reference/glossary/data-plane.md create mode 100644 content/zh/docs/reference/glossary/deployment.md create mode 100755 content/zh/docs/reference/glossary/developer.md create mode 100644 content/zh/docs/reference/glossary/device-plugin.md create mode 100755 content/zh/docs/reference/glossary/docker.md create mode 100755 content/zh/docs/reference/glossary/downstream.md create mode 100755 content/zh/docs/reference/glossary/dynamic-volume-provisioning.md create mode 100644 content/zh/docs/reference/glossary/endpoint-slice.md create mode 100644 content/zh/docs/reference/glossary/ephemeral-container.md create mode 100644 content/zh/docs/reference/glossary/etcd.md create mode 100644 content/zh/docs/reference/glossary/extensions.md create mode 100644 content/zh/docs/reference/glossary/flexvolume.md create mode 100755 content/zh/docs/reference/glossary/helm-chart.md create mode 100755 content/zh/docs/reference/glossary/horizontal-pod-autoscaler.md create mode 100755 content/zh/docs/reference/glossary/image.md mode change 100755 => 100644 content/zh/docs/reference/glossary/ingress.md create mode 100755 content/zh/docs/reference/glossary/init-container.md create mode 100755 content/zh/docs/reference/glossary/istio.md create mode 100755 content/zh/docs/reference/glossary/job.md create mode 100755 content/zh/docs/reference/glossary/kops.md create mode 100755 content/zh/docs/reference/glossary/kube-apiserver.md create mode 100755 content/zh/docs/reference/glossary/kube-controller-manager.md create mode 100755 content/zh/docs/reference/glossary/kube-proxy.md create mode 100755 content/zh/docs/reference/glossary/kube-scheduler.md create mode 100644 content/zh/docs/reference/glossary/kubeadm.md create mode 100755 content/zh/docs/reference/glossary/kubectl.md create mode 100755 content/zh/docs/reference/glossary/kubelet.md create mode 100755 content/zh/docs/reference/glossary/kubernetes-api.md create mode 100755 content/zh/docs/reference/glossary/label.md create mode 100644 content/zh/docs/reference/glossary/limitrange.md create mode 100644 content/zh/docs/reference/glossary/logging.md create mode 100755 content/zh/docs/reference/glossary/managed-service.md create mode 100644 content/zh/docs/reference/glossary/member.md create mode 100755 content/zh/docs/reference/glossary/minikube.md create mode 100755 content/zh/docs/reference/glossary/mirror-pod.md create mode 100644 content/zh/docs/reference/glossary/namespace.md create mode 100755 content/zh/docs/reference/glossary/network-policy.md create mode 100755 content/zh/docs/reference/glossary/node.md create mode 100644 content/zh/docs/reference/glossary/operator-pattern.md create mode 100755 content/zh/docs/reference/glossary/persistent-volume-claim.md create mode 100644 content/zh/docs/reference/glossary/persistent-volume.md create mode 100755 content/zh/docs/reference/glossary/platform-developer.md create mode 100644 content/zh/docs/reference/glossary/pod-disruption-budget.md create mode 100644 content/zh/docs/reference/glossary/pod-lifecycle.md create mode 100644 content/zh/docs/reference/glossary/pod-priority.md create mode 100644 content/zh/docs/reference/glossary/pod-security-policy.md create mode 100755 content/zh/docs/reference/glossary/pod.md create mode 100755 content/zh/docs/reference/glossary/podpreset.md create mode 100644 content/zh/docs/reference/glossary/preemption.md create mode 100644 content/zh/docs/reference/glossary/qos-class.md create mode 100644 content/zh/docs/reference/glossary/quantity.md create mode 100755 content/zh/docs/reference/glossary/rbac.md create mode 100755 content/zh/docs/reference/glossary/replica-set.md create mode 100644 content/zh/docs/reference/glossary/replication-controller.md create mode 100755 content/zh/docs/reference/glossary/resource-quota.md create mode 100644 content/zh/docs/reference/glossary/reviewer.md create mode 100755 content/zh/docs/reference/glossary/secret.md create mode 100755 content/zh/docs/reference/glossary/security-context.md create mode 100644 content/zh/docs/reference/glossary/selector.md create mode 100755 content/zh/docs/reference/glossary/service-account.md create mode 100755 content/zh/docs/reference/glossary/service-broker.md create mode 100644 content/zh/docs/reference/glossary/service-catalog.md create mode 100755 content/zh/docs/reference/glossary/sig.md create mode 100644 content/zh/docs/reference/glossary/statefulset.md create mode 100644 content/zh/docs/reference/glossary/static-pod.md create mode 100644 content/zh/docs/reference/glossary/storage-class.md create mode 100644 content/zh/docs/reference/glossary/sysctl.md create mode 100644 content/zh/docs/reference/glossary/taint.md create mode 100644 content/zh/docs/reference/glossary/toleration.md create mode 100644 content/zh/docs/reference/glossary/upstream.md create mode 100755 content/zh/docs/reference/glossary/volume-plugin.md create mode 100755 content/zh/docs/reference/glossary/volume.md create mode 100644 content/zh/docs/reference/glossary/wg.md create mode 100644 content/zh/docs/reference/glossary/workload.md create mode 100644 content/zh/docs/reference/issues-security/issues.md create mode 100644 content/zh/docs/reference/issues-security/security.md create mode 100644 content/zh/docs/reference/kubectl/cheatsheet.md create mode 100644 content/zh/docs/reference/kubectl/conventions.md create mode 100644 content/zh/docs/reference/kubectl/kubectl-cmds.md delete mode 100644 content/zh/docs/reference/kubectl/kubectl-overview.md create mode 100644 content/zh/docs/reference/kubectl/overview.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/README.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_certificate-key.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_check-expiration.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_admin.conf.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_all.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_apiserver-etcd-client.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_apiserver-kubelet-client.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_apiserver.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_controller-manager.conf.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_etcd-healthcheck-client.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_etcd-peer.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_etcd-server.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_front-proxy-client.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_certs_renew_scheduler.conf.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubeconfig.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubeconfig_user.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubelet.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubelet_config.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubelet_config_download.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_kubelet_config_enable-dynamic.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_selfhosting.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_alpha_selfhosting_pivot.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_completion.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_images.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_images_list.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_images_pull.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_migrate.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_print.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_print_init-defaults.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_print_join-defaults.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_config_view.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_addon.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_addon_all.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_addon_coredns.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_addon_kube-proxy.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_bootstrap-token.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_all.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_apiserver-etcd-client.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_apiserver-kubelet-client.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_apiserver.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_ca.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_etcd-ca.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_etcd-healthcheck-client.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_etcd-peer.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_etcd-server.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_front-proxy-ca.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_front-proxy-client.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_certs_sa.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_control-plane.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_control-plane_all.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_control-plane_apiserver.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_control-plane_controller-manager.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_control-plane_scheduler.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_etcd.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_etcd_local.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig_admin.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig_all.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig_controller-manager.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig_kubelet.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubeconfig_scheduler.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_kubelet-start.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_mark-control-plane.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_preflight.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_upload-certs.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_upload-config.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_upload-config_all.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_upload-config_kubeadm.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_init_phase_upload-config_kubelet.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-join.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-join_all.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-join_etcd.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-join_mark-control-plane.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-join_update-status.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-prepare.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-prepare_all.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-prepare_certs.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-prepare_control-plane.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-prepare_download-certs.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_control-plane-prepare_kubeconfig.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_kubelet-start.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_join_phase_preflight.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_reset.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_reset_phase.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_reset_phase_cleanup-node.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_reset_phase_preflight.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_reset_phase_remove-etcd-member.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_reset_phase_update-cluster-status.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_token.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_token_create.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_token_delete.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_token_generate.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_token_list.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade_apply.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade_diff.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade_node.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade_node_phase.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade_node_phase_control-plane.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade_node_phase_kubelet-config.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_upgrade_plan.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/generated/kubeadm_version.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/kubeadm-alpha.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/kubeadm-config.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/kubeadm-init-phase.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/kubeadm-join-phase.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/kubeadm-join.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/kubeadm-reset-phase.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/kubeadm-reset.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/kubeadm-token.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/kubeadm-upgrade-phase.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/kubeadm-upgrade.md create mode 100644 content/zh/docs/reference/setup-tools/kubeadm/kubeadm-version.md create mode 100644 content/zh/docs/reference/using-api/_index.md create mode 100644 content/zh/docs/reference/using-api/api-overview.md create mode 100644 content/zh/docs/reference/using-api/client-libraries.md create mode 100644 content/zh/docs/search.md create mode 100644 content/zh/docs/setup/_index.md create mode 100644 content/zh/docs/setup/best-practices/_index.md create mode 100644 content/zh/docs/setup/best-practices/cluster-large.md create mode 100644 content/zh/docs/setup/best-practices/node-conformance.md delete mode 100644 content/zh/docs/setup/cluster-large.md create mode 100644 content/zh/docs/setup/learning-environment/_index.md create mode 100644 content/zh/docs/setup/learning-environment/minikube.md delete mode 100644 content/zh/docs/setup/multiple-zones.md delete mode 100644 content/zh/docs/setup/node-conformance.md create mode 100644 content/zh/docs/setup/production-environment/_index.md create mode 100644 content/zh/docs/setup/production-environment/container-runtimes.md create mode 100644 content/zh/docs/setup/production-environment/on-premises-vm/_index.md create mode 100644 content/zh/docs/setup/production-environment/on-premises-vm/dcos.md create mode 100644 content/zh/docs/setup/production-environment/on-premises-vm/ovirt.md create mode 100644 content/zh/docs/setup/production-environment/tools/_index.md create mode 100644 content/zh/docs/setup/production-environment/tools/kops.md create mode 100644 content/zh/docs/setup/production-environment/tools/kubeadm/_index.md create mode 100644 content/zh/docs/setup/production-environment/tools/kubeadm/control-plane-flags.md create mode 100644 content/zh/docs/setup/production-environment/tools/kubeadm/ha-topology.md create mode 100644 content/zh/docs/setup/production-environment/tools/kubeadm/high-availability.md create mode 100644 content/zh/docs/setup/production-environment/tools/kubeadm/kubelet-integration.md create mode 100644 content/zh/docs/setup/production-environment/tools/kubeadm/self-hosting.md create mode 100644 content/zh/docs/setup/production-environment/tools/kubeadm/setup-ha-etcd-with-kubeadm.md create mode 100644 content/zh/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm.md create mode 100644 content/zh/docs/setup/production-environment/turnkey/_index.md create mode 100644 content/zh/docs/setup/production-environment/turnkey/alibaba-cloud.md create mode 100644 content/zh/docs/setup/production-environment/turnkey/aws.md create mode 100644 content/zh/docs/setup/production-environment/turnkey/azure.md create mode 100644 content/zh/docs/setup/production-environment/turnkey/icp.md create mode 100644 content/zh/docs/setup/production-environment/turnkey/tencent.md create mode 100644 content/zh/docs/setup/production-environment/windows/_index.md create mode 100644 content/zh/docs/setup/production-environment/windows/kubecluster.ps1-install.gif create mode 100644 content/zh/docs/setup/production-environment/windows/kubecluster.ps1-join.gif create mode 100644 content/zh/docs/setup/production-environment/windows/kubecluster.ps1-reset.gif create mode 100644 content/zh/docs/setup/production-environment/windows/user-guide-windows-containers.md create mode 100644 content/zh/docs/setup/release/_index.md create mode 100644 content/zh/docs/setup/release/notes.md create mode 100644 content/zh/docs/setup/release/version-skew-policy.md delete mode 100755 content/zh/docs/setup/salt.md create mode 100644 content/zh/docs/sitemap.md create mode 100644 content/zh/docs/tasks/_index.md create mode 100644 content/zh/docs/tasks/access-application-cluster/_index.md delete mode 100644 content/zh/docs/tasks/access-application-cluster/load-balance-access-application-cluster.md create mode 100644 content/zh/docs/tasks/access-application-cluster/web-ui-dashboard.md create mode 100755 content/zh/docs/tasks/access-kubernetes-api/_index.md create mode 100644 content/zh/docs/tasks/access-kubernetes-api/configure-aggregation-layer.md create mode 100755 content/zh/docs/tasks/access-kubernetes-api/custom-resources/_index.md create mode 100644 content/zh/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definition-versioning.md create mode 100644 content/zh/docs/tasks/access-kubernetes-api/http-proxy-access-api.md create mode 100755 content/zh/docs/tasks/administer-cluster/_index.md create mode 100644 content/zh/docs/tasks/administer-cluster/access-cluster-api.md delete mode 100644 content/zh/docs/tasks/administer-cluster/calico-network-policy.md create mode 100644 content/zh/docs/tasks/administer-cluster/configure-multiple-schedulers.md create mode 100644 content/zh/docs/tasks/administer-cluster/configure-upgrade-etcd.md create mode 100644 content/zh/docs/tasks/administer-cluster/coredns.md delete mode 100644 content/zh/docs/tasks/administer-cluster/cpu-memory-limit.md create mode 100644 content/zh/docs/tasks/administer-cluster/developing-cloud-controller-manager.md create mode 100644 content/zh/docs/tasks/administer-cluster/dns-custom-nameservers/dns.png create mode 100644 content/zh/docs/tasks/administer-cluster/dns-debugging-resolution.md create mode 100644 content/zh/docs/tasks/administer-cluster/dns-horizontal-autoscaling.md create mode 100644 content/zh/docs/tasks/administer-cluster/enabling-endpoint-slices.md create mode 100644 content/zh/docs/tasks/administer-cluster/extended-resource-node.md create mode 100644 content/zh/docs/tasks/administer-cluster/highly-available-master.md create mode 100644 content/zh/docs/tasks/administer-cluster/ip-masq-agent.md create mode 100644 content/zh/docs/tasks/administer-cluster/kms-provider.md create mode 100644 content/zh/docs/tasks/administer-cluster/kubeadm/_index.md create mode 100644 content/zh/docs/tasks/administer-cluster/kubeadm/kubeadm-certs.md delete mode 100644 content/zh/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade-1-9.md create mode 100644 content/zh/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade.md create mode 100644 content/zh/docs/tasks/administer-cluster/limit-storage-consumption.md create mode 100644 content/zh/docs/tasks/administer-cluster/memory-available.sh create mode 100644 content/zh/docs/tasks/administer-cluster/namespaces-walkthrough.md create mode 100644 content/zh/docs/tasks/administer-cluster/namespaces.md create mode 100644 content/zh/docs/tasks/administer-cluster/nodelocaldns.md create mode 100644 content/zh/docs/tasks/administer-cluster/out-of-resource.md create mode 100644 content/zh/docs/tasks/administer-cluster/quota-api-object.md create mode 100644 content/zh/docs/tasks/administer-cluster/reconfigure-kubelet.md create mode 100644 content/zh/docs/tasks/administer-cluster/reserve-compute-resources.md delete mode 100644 content/zh/docs/tasks/administer-cluster/romana-network-policy.md create mode 100644 content/zh/docs/tasks/administer-cluster/running-cloud-controller.md create mode 100644 content/zh/docs/tasks/administer-cluster/securing-a-cluster.md delete mode 100644 content/zh/docs/tasks/administer-cluster/static-pod.md create mode 100644 content/zh/docs/tasks/administer-cluster/topology-manager.md delete mode 100644 content/zh/docs/tasks/administer-cluster/weave-network-policy.md delete mode 100644 content/zh/docs/tasks/administer-federation/_index.md create mode 100644 content/zh/docs/tasks/configure-pod-container/assign-cpu-resource.md create mode 100644 content/zh/docs/tasks/configure-pod-container/configure-persistent-volume-storage.md create mode 100644 content/zh/docs/tasks/configure-pod-container/configure-pod-configmap.md create mode 100644 content/zh/docs/tasks/configure-pod-container/configure-pod-initialization.md create mode 100644 content/zh/docs/tasks/configure-pod-container/configure-projected-volume-storage.md create mode 100644 content/zh/docs/tasks/configure-pod-container/configure-service-account.md create mode 100644 content/zh/docs/tasks/configure-pod-container/configure-volume-storage.md create mode 100644 content/zh/docs/tasks/configure-pod-container/extended-resource.md create mode 100644 content/zh/docs/tasks/configure-pod-container/pull-image-private-registry.md create mode 100644 content/zh/docs/tasks/configure-pod-container/quality-service-pod.md create mode 100644 content/zh/docs/tasks/configure-pod-container/share-process-namespace.md create mode 100644 content/zh/docs/tasks/configure-pod-container/translate-compose-kubernetes.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/crictl.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/debug-application-introspection.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/debug-init-containers.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/debug-service.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/determine-reason-pod-failure.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/events-stackdriver.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/get-shell-running-container.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/local-debugging.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/logging-elasticsearch-kibana.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/monitor-node-health.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/resource-metrics-pipeline.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/resource-usage-monitoring.md create mode 100644 content/zh/docs/tasks/debug-application-cluster/troubleshooting.md create mode 100644 content/zh/docs/tasks/example-task-template.md create mode 100644 content/zh/docs/tasks/extend-kubectl/kubectl-plugins.md mode change 100644 => 100755 content/zh/docs/tasks/federation/_index.md create mode 100644 content/zh/docs/tasks/federation/administer-federation/_index.md create mode 100644 content/zh/docs/tasks/federation/administer-federation/configmap.md create mode 100644 content/zh/docs/tasks/federation/administer-federation/daemonset.md create mode 100644 content/zh/docs/tasks/federation/administer-federation/deployment.md create mode 100644 content/zh/docs/tasks/federation/administer-federation/events.md create mode 100644 content/zh/docs/tasks/federation/administer-federation/job.md create mode 100644 content/zh/docs/tasks/federation/administer-federation/namespaces.md create mode 100644 content/zh/docs/tasks/federation/administer-federation/replicaset.md create mode 100644 content/zh/docs/tasks/federation/administer-federation/secret.md create mode 100644 content/zh/docs/tasks/federation/federation-service-discovery.md create mode 100644 content/zh/docs/tasks/federation/policy.rego create mode 100644 content/zh/docs/tasks/federation/set-up-coredns-provider-federation.md create mode 100644 content/zh/docs/tasks/federation/set-up-placement-policies-federation.md create mode 100644 content/zh/docs/tasks/job/coarse-parallel-processing-work-queue.md create mode 100644 content/zh/docs/tasks/job/parallel-processing-expansion.md create mode 100644 content/zh/docs/tasks/manage-daemon/_index.md create mode 100644 content/zh/docs/tasks/manage-daemon/update-daemon-set.md create mode 100644 content/zh/docs/tasks/manage-kubernetes-objects/_index.md create mode 100644 content/zh/docs/tasks/manage-kubernetes-objects/imperative-config.md create mode 100644 content/zh/docs/tasks/network/_index.md create mode 100644 content/zh/docs/tasks/network/validate-dual-stack.md create mode 100644 content/zh/docs/tasks/run-application/_index.md create mode 100644 content/zh/docs/tasks/run-application/configure-pdb.md create mode 100644 content/zh/docs/tasks/run-application/force-delete-stateful-set-pod.md create mode 100644 content/zh/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md create mode 100644 content/zh/docs/tasks/run-application/horizontal-pod-autoscale.md create mode 100644 content/zh/docs/tasks/run-application/run-replicated-stateful-application.md create mode 100644 content/zh/docs/tasks/run-application/update-api-object-kubectl-patch.md create mode 100644 content/zh/docs/tasks/service-catalog/_index.md create mode 100644 content/zh/docs/tasks/service-catalog/install-service-catalog-using-helm.md create mode 100644 content/zh/docs/tasks/service-catalog/install-service-catalog-using-sc.md create mode 100755 content/zh/docs/tasks/tls/_index.md create mode 100644 content/zh/docs/tasks/tls/managing-tls-in-a-cluster.md create mode 100644 content/zh/docs/tasks/tools/_index.md create mode 100644 content/zh/docs/tasks/tools/install-kubectl.md create mode 100644 content/zh/docs/tasks/tools/install-minikube.md create mode 100644 content/zh/docs/templates/feature-state-alpha.txt create mode 100644 content/zh/docs/templates/feature-state-beta.txt create mode 100644 content/zh/docs/templates/feature-state-deprecated.txt create mode 100644 content/zh/docs/templates/feature-state-stable.txt create mode 100644 content/zh/docs/tools/install-minikube.md create mode 100644 content/zh/docs/tutorials/_index.md rename content/zh/docs/{getting-started-guides/fedora => tutorials/clusters}/_index.md (51%) create mode 100644 content/zh/docs/tutorials/clusters/apparmor.md create mode 100644 content/zh/docs/tutorials/clusters/deny-write.profile create mode 100644 content/zh/docs/tutorials/configuration/_index.md create mode 100644 content/zh/docs/tutorials/hello-minikube.md delete mode 100644 content/zh/docs/tutorials/kubernetes-basics/cluster-intro.html create mode 100644 content/zh/docs/tutorials/kubernetes-basics/create-cluster/_index.md rename content/zh/docs/tutorials/kubernetes-basics/{ => create-cluster}/cluster-interactive.html (58%) create mode 100644 content/zh/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html create mode 100644 content/zh/docs/tutorials/kubernetes-basics/deploy-app/_index.md create mode 100644 content/zh/docs/tutorials/kubernetes-basics/deploy-app/deploy-interactive.html create mode 100644 content/zh/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro.html delete mode 100644 content/zh/docs/tutorials/kubernetes-basics/deploy-intro.html delete mode 100644 content/zh/docs/tutorials/kubernetes-basics/explore-intro.html create mode 100644 content/zh/docs/tutorials/kubernetes-basics/explore/_index.md rename content/zh/docs/tutorials/kubernetes-basics/{ => explore}/explore-interactive.html (67%) create mode 100644 content/zh/docs/tutorials/kubernetes-basics/explore/explore-intro.html delete mode 100644 content/zh/docs/tutorials/kubernetes-basics/expose-intro.html create mode 100644 content/zh/docs/tutorials/kubernetes-basics/expose/_index.md rename content/zh/docs/tutorials/kubernetes-basics/{ => expose}/expose-interactive.html (68%) create mode 100644 content/zh/docs/tutorials/kubernetes-basics/expose/expose-intro.html delete mode 100644 content/zh/docs/tutorials/kubernetes-basics/scale-intro.html create mode 100644 content/zh/docs/tutorials/kubernetes-basics/scale/_index.md rename content/zh/docs/tutorials/kubernetes-basics/{ => scale}/scale-interactive.html (68%) delete mode 100644 content/zh/docs/tutorials/kubernetes-basics/update-interactive.html delete mode 100644 content/zh/docs/tutorials/kubernetes-basics/update-intro.html create mode 100644 content/zh/docs/tutorials/kubernetes-basics/update/_index.md rename content/zh/docs/tutorials/kubernetes-basics/{deploy-interactive.html => update/update-interactive.html} (65%) create mode 100644 content/zh/docs/tutorials/kubernetes-basics/update/update-intro.html delete mode 100644 content/zh/docs/tutorials/object-management-kubectl/imperative-object-management-command.md delete mode 100644 content/zh/docs/tutorials/object-management-kubectl/object-management.md create mode 100644 content/zh/docs/tutorials/online-training/_index.md create mode 100644 content/zh/docs/tutorials/online-training/overview.md create mode 100644 content/zh/docs/tutorials/services/_index.md delete mode 100644 content/zh/docs/tutorials/stateful-application/Dockerfile delete mode 100644 content/zh/docs/tutorials/stateful-application/FETCH_HEAD create mode 100644 content/zh/docs/tutorials/stateful-application/_index.md delete mode 100644 content/zh/docs/tutorials/stateful-application/dev create mode 100644 content/zh/docs/tutorials/stateless-application/_index.md create mode 100644 content/zh/docs/tutorials/stateless-application/expose-external-ip-address.md create mode 100644 content/zh/docs/tutorials/stateless-application/guestbook.md create mode 100644 content/zh/docs/update-user-guide-links.py create mode 100644 content/zh/docs/user-journeys/users/app-developer/advanced.md create mode 100644 content/zh/docs/user-journeys/users/cluster-operator/foundational.md create mode 100644 content/zh/docs/user-journeys/users/cluster-operator/intermediate.md create mode 100644 content/zh/examples/README.md create mode 100644 content/zh/examples/admin/cloud/ccm-example.yaml create mode 100644 content/zh/examples/admin/dns/busybox.yaml create mode 100644 content/zh/examples/admin/dns/dns-horizontal-autoscaler.yaml create mode 100644 content/zh/examples/admin/namespace-dev.json create mode 100644 content/zh/examples/admin/namespace-prod.json create mode 100644 content/zh/examples/admin/resource/limit-mem-cpu-container.yaml create mode 100644 content/zh/examples/admin/resource/limit-mem-cpu-pod.yaml create mode 100644 content/zh/examples/admin/resource/limit-memory-ratio-pod.yaml create mode 100644 content/zh/examples/admin/resource/limit-range-pod-1.yaml create mode 100644 content/zh/examples/admin/resource/limit-range-pod-2.yaml create mode 100644 content/zh/examples/admin/resource/limit-range-pod-3.yaml create mode 100644 content/zh/examples/admin/resource/pvc-limit-greater.yaml create mode 100644 content/zh/examples/admin/resource/pvc-limit-lower.yaml create mode 100644 content/zh/examples/admin/resource/quota-objects-pvc-2.yaml create mode 100644 content/zh/examples/admin/resource/quota-objects-pvc.yaml create mode 100644 content/zh/examples/admin/resource/quota-objects.yaml create mode 100644 content/zh/examples/admin/resource/storagelimits.yaml create mode 100644 content/zh/examples/admin/sched/my-scheduler.yaml create mode 100644 content/zh/examples/admin/sched/pod1.yaml create mode 100644 content/zh/examples/admin/sched/pod2.yaml create mode 100644 content/zh/examples/admin/sched/pod3.yaml create mode 100644 content/zh/examples/application/deployment-patch.yaml create mode 100644 content/zh/examples/application/guestbook/frontend-deployment.yaml create mode 100644 content/zh/examples/application/guestbook/frontend-service.yaml create mode 100644 content/zh/examples/application/guestbook/redis-master-deployment.yaml create mode 100644 content/zh/examples/application/guestbook/redis-master-service.yaml create mode 100644 content/zh/examples/application/guestbook/redis-slave-deployment.yaml create mode 100644 content/zh/examples/application/guestbook/redis-slave-service.yaml create mode 100644 content/zh/examples/application/hpa/php-apache.yaml create mode 100644 content/zh/examples/application/job/job-tmpl.yaml create mode 100644 content/zh/examples/application/job/rabbitmq/Dockerfile create mode 100644 content/zh/examples/application/job/rabbitmq/job.yaml create mode 100644 content/zh/examples/application/job/rabbitmq/worker.py create mode 100644 content/zh/examples/application/job/redis/Dockerfile create mode 100644 content/zh/examples/application/job/redis/redis-pod.yaml create mode 100644 content/zh/examples/application/job/redis/redis-service.yaml create mode 100644 content/zh/examples/application/job/redis/rediswq.py create mode 100644 content/zh/examples/application/mysql/mysql-configmap.yaml create mode 100644 content/zh/examples/application/mysql/mysql-services.yaml create mode 100644 content/zh/examples/application/mysql/mysql-statefulset.yaml create mode 100644 content/zh/examples/application/nginx-with-request.yaml create mode 100644 content/zh/examples/application/nginx/nginx-deployment.yaml create mode 100644 content/zh/examples/application/nginx/nginx-svc.yaml create mode 100644 content/zh/examples/application/shell-demo.yaml create mode 100644 content/zh/examples/application/simple_deployment.yaml create mode 100644 content/zh/examples/application/update_deployment.yaml create mode 100644 content/zh/examples/configmap/configmap-multikeys.yaml create mode 100644 content/zh/examples/configmap/configmaps.yaml create mode 100644 content/zh/examples/configmap/game-env-file.properties create mode 100644 content/zh/examples/configmap/game.properties create mode 100644 content/zh/examples/configmap/ui-env-file.properties create mode 100644 content/zh/examples/configmap/ui.properties create mode 100644 content/zh/examples/controllers/daemonset.yaml create mode 100644 content/zh/examples/controllers/frontend.yaml create mode 100644 content/zh/examples/controllers/hpa-rs.yaml create mode 100644 content/zh/examples/controllers/job.yaml create mode 100644 content/zh/examples/controllers/replication-nginx-1.7.9.yaml create mode 100644 content/zh/examples/controllers/replication-nginx-1.9.2.yaml create mode 100644 content/zh/examples/controllers/replication.yaml create mode 100644 content/zh/examples/debug/event-exporter.yaml create mode 100644 content/zh/examples/debug/fluentd-gcp-configmap.yaml create mode 100644 content/zh/examples/debug/fluentd-gcp-ds.yaml create mode 100644 content/zh/examples/debug/node-problem-detector-configmap.yaml create mode 100644 content/zh/examples/debug/node-problem-detector.yaml create mode 100644 content/zh/examples/debug/termination.yaml create mode 100644 content/zh/examples/examples.go create mode 100644 content/zh/examples/examples_test.go create mode 100644 content/zh/examples/federation/policy-engine-deployment.yaml create mode 100644 content/zh/examples/federation/policy-engine-service.yaml create mode 100644 content/zh/examples/federation/replicaset-example-policy.yaml create mode 100644 content/zh/examples/federation/scheduling-policy-admission.yaml create mode 100644 content/zh/examples/minikube/Dockerfile create mode 100644 content/zh/examples/minikube/server.js create mode 100644 content/zh/examples/pods/config/redis-config create mode 100644 content/zh/examples/pods/config/redis-pod.yaml create mode 100644 content/zh/examples/pods/init-containers.yaml create mode 100644 content/zh/examples/pods/inject/pod-multiple-secret-env-variable.yaml create mode 100644 content/zh/examples/pods/inject/pod-secret-envFrom.yaml create mode 100644 content/zh/examples/pods/inject/pod-single-secret-env-variable.yaml create mode 100644 content/zh/examples/pods/pod-configmap-env-var-valueFrom.yaml create mode 100644 content/zh/examples/pods/pod-configmap-envFrom.yaml create mode 100644 content/zh/examples/pods/pod-configmap-volume-specific-key.yaml create mode 100644 content/zh/examples/pods/pod-configmap-volume.yaml create mode 100644 content/zh/examples/pods/pod-multiple-configmap-env-variable.yaml create mode 100644 content/zh/examples/pods/pod-nginx-specific-node.yaml create mode 100644 content/zh/examples/pods/pod-projected-svc-token.yaml create mode 100644 content/zh/examples/pods/pod-rs.yaml create mode 100644 content/zh/examples/pods/pod-single-configmap-env-variable.yaml create mode 100644 content/zh/examples/pods/pod-with-node-affinity.yaml create mode 100644 content/zh/examples/pods/pod-with-pod-affinity.yaml create mode 100644 content/zh/examples/pods/private-reg-pod.yaml create mode 100644 content/zh/examples/pods/probe/exec-liveness.yaml create mode 100644 content/zh/examples/pods/probe/http-liveness.yaml create mode 100644 content/zh/examples/pods/probe/pod-with-http-healthcheck.yaml create mode 100644 content/zh/examples/pods/probe/pod-with-tcp-socket-healthcheck.yaml create mode 100644 content/zh/examples/pods/probe/tcp-liveness-readiness.yaml create mode 100644 content/zh/examples/pods/qos/qos-pod-2.yaml create mode 100644 content/zh/examples/pods/qos/qos-pod-3.yaml create mode 100644 content/zh/examples/pods/qos/qos-pod-4.yaml create mode 100644 content/zh/examples/pods/qos/qos-pod.yaml create mode 100644 content/zh/examples/pods/resource/cpu-request-limit-2.yaml create mode 100644 content/zh/examples/pods/resource/cpu-request-limit.yaml create mode 100644 content/zh/examples/pods/resource/extended-resource-pod-2.yaml create mode 100644 content/zh/examples/pods/resource/extended-resource-pod.yaml create mode 100644 content/zh/examples/pods/resource/memory-request-limit-2.yaml create mode 100644 content/zh/examples/pods/resource/memory-request-limit-3.yaml create mode 100644 content/zh/examples/pods/resource/memory-request-limit.yaml create mode 100644 content/zh/examples/pods/security/hello-apparmor.yaml create mode 100644 content/zh/examples/pods/security/security-context-2.yaml create mode 100644 content/zh/examples/pods/security/security-context-3.yaml create mode 100644 content/zh/examples/pods/security/security-context-4.yaml create mode 100644 content/zh/examples/pods/security/security-context.yaml create mode 100644 content/zh/examples/pods/share-process-namespace.yaml create mode 100644 content/zh/examples/pods/simple-pod.yaml create mode 100644 content/zh/examples/pods/storage/projected.yaml create mode 100644 content/zh/examples/pods/storage/pv-claim.yaml create mode 100644 content/zh/examples/pods/storage/pv-pod.yaml create mode 100644 content/zh/examples/pods/storage/pv-volume.yaml create mode 100644 content/zh/examples/pods/storage/redis.yaml create mode 100644 content/zh/examples/pods/topology-spread-constraints/one-constraint-with-nodeaffinity.yaml create mode 100644 content/zh/examples/pods/topology-spread-constraints/one-constraint.yaml create mode 100644 content/zh/examples/pods/topology-spread-constraints/two-constraints.yaml create mode 100644 content/zh/examples/policy/privileged-psp.yaml create mode 100644 content/zh/examples/policy/restricted-psp.yaml create mode 100644 content/zh/examples/policy/zookeeper-pod-disruption-budget-maxunavailable.yaml create mode 100644 content/zh/examples/policy/zookeeper-pod-disruption-budget-minavailable.yaml create mode 100644 content/zh/examples/windows/configmap-pod.yaml create mode 100644 content/zh/examples/windows/daemonset.yaml create mode 100644 content/zh/examples/windows/deploy-hyperv.yaml create mode 100644 content/zh/examples/windows/deploy-resource.yaml create mode 100644 content/zh/examples/windows/emptydir-pod.yaml create mode 100644 content/zh/examples/windows/hostpath-volume-pod.yaml create mode 100644 content/zh/examples/windows/run-as-username-container.yaml create mode 100644 content/zh/examples/windows/run-as-username-pod.yaml create mode 100644 content/zh/examples/windows/secret-pod.yaml create mode 100644 content/zh/examples/windows/simple-pod.yaml create mode 100644 content/zh/includes/federated-task-tutorial-prereqs.md delete mode 100644 content/zh/includes/federation-content-moved.md delete mode 100644 content/zh/includes/federation-current-state.md create mode 100644 content/zh/includes/federation-deprecation-warning-note.md create mode 100644 content/zh/includes/index.md create mode 100644 content/zh/includes/partner-script.js create mode 100644 content/zh/includes/partner-style.css create mode 100644 content/zh/partners/_index.html diff --git a/content/zh/_index.html b/content/zh/_index.html index 9405f2de0e..1b0ff01700 100644 --- a/content/zh/_index.html +++ b/content/zh/_index.html @@ -1,61 +1,82 @@ --- title: "生产级别的容器编排系统" abstract: "自动化的容器部署、扩展和管理" -cid: "home" +cid: home --- {{< deprecationwarning >}} {{< blocks/section id="oceanNodes" >}} {{% blocks/feature image="flower" %}} -### [Kubernetes (K8s)]({{< relref "/docs/concepts/overview/what-is-kubernetes" >}}) -是一个开源系统,用于容器化应用的自动部署、扩缩和管理。 -Kubernetes 将构成应用的容器按逻辑单位进行分组以便于管理和发现。 -Kubernetes 基于 [谷歌公司在运行生产负载上的 15 年经验](http://queue.acm.org/detail.cfm?id=2898444) -打造,并融合了来自社区的最佳建议与实践。 + +### [Kubernetes]({{< relref "/docs/concepts/overview/what-is-kubernetes" >}}) 是用于自动部署,扩展和管理容器化应用程序的开源系统。 + + + +它将组成应用程序的容器组合成逻辑单元,以便于管理和服务发现。Kubernetes 源自[Google 15 年生产环境的运维经验](http://queue.acm.org/detail.cfm?id=2898444),同时凝聚了社区的最佳创意和实践。 + {{% /blocks/feature %}} {{% blocks/feature image="scalable" %}} -#### 星际规模 -基于一定的规则原理,谷歌公司每周能够运行数十亿的容器;通过遵循相同的设计, -Kubernetes 能够在保持现有运维团队规模的前提下完成集群的弹性伸缩。 + +#### 星际尺度 + + + +Google 每周运行数十亿个容器,Kubernetes 基于与之相同的原则来设计,能够在不扩张运维团队的情况下进行规模扩展。 {{% /blocks/feature %}} {{% blocks/feature image="blocks" %}} -#### 永不过时 -无论是在本地测试还是支撑全球化企业业务,Kubernetes 的灵活性使得其能够与您一起成长。 -无论您的需求多么复杂,Kubernetes 都能助您始终如一地、轻而易举地交付应用。 + +#### 处处适用 + + + +无论是本地测试,还是跨国公司,Kubernetes 的灵活性都能让你在应对复杂系统时得心应手。 {{% /blocks/feature %}} {{% blocks/feature image="suitcase" %}} -#### 随处运行 -作为一个开源系统,Kubernetes 使您能够自由地获得内部云、混合云或公有云基础设施所提供的便利, -并根据需要轻松地迁移工作负载。 + +#### 永不过时 + + + +Kubernetes 是开源系统,可以自由地部署在企业内部,私有云、混合云或公有云,让您轻松地做出合适的选择。 {{% /blocks/feature %}} {{< /blocks/section >}} {{< blocks/section id="video" background-image="kub_video_banner_homepage" >}} +
-

将超过 150 个微服务迁移到 Kubernetes 时遇到的挑战

-

Sarah Wells, Technical Director for Operations and Reliability, Financial Times

- -
-
-
- 参加 2019 年 11 月 18 日的 San Diego KubeCon -
-
-
-
- 参加 2020 年 3 月 30 日的 Amsterdam KubeCon + +

将 150+ 微服务迁移到 Kubernetes 上的挑战

+ +

Sarah Wells, 运营和可靠性技术总监, 金融时报

+ +
+
+
+ + 参加11月13日到15日的上海 KubeCon +
+
+
+
+ + 参加12月11日到13日的西雅图 KubeCon
diff --git a/content/zh/blog/_posts/2015-03-00-Kubernetes-Gathering-Videos.md b/content/zh/blog/_posts/2015-03-00-Kubernetes-Gathering-Videos.md new file mode 100644 index 0000000000..2576296c64 --- /dev/null +++ b/content/zh/blog/_posts/2015-03-00-Kubernetes-Gathering-Videos.md @@ -0,0 +1,27 @@ +--- + +title: " Kubernetes 采集视频 " +date: 2015-03-23 +slug: kubernetes-gathering-videos +url: /blog/2015/03/Kubernetes-Gathering-Videos +--- + + + + + +如果你错过了上个月在旧金山举行的 Kubernetes 大会,不要害怕!以下是在 YouTube 上组织成播放列表的晚间演示文稿中的视频。 + +[![Kubernetes Gathering](https://img.youtube.com/vi/q8lGZCKktYo/0.jpg)](https://www.youtube.com/playlist?list=PL69nYSiGNLP2FBVvSLHpJE8_6hRHW8Kxe) diff --git a/content/zh/blog/_posts/2015-03-00-Weekly-Kubernetes-Community-Hangout.md b/content/zh/blog/_posts/2015-03-00-Weekly-Kubernetes-Community-Hangout.md new file mode 100644 index 0000000000..6a345d4950 --- /dev/null +++ b/content/zh/blog/_posts/2015-03-00-Weekly-Kubernetes-Community-Hangout.md @@ -0,0 +1,186 @@ +--- +title: " Kubernetes 社区每周聚会笔记 - 2015年3月27日 " +date: 2015-03-28 +slug: weekly-kubernetes-community-hangout +url: /blog/2015/03/Weekly-Kubernetes-Community-Hangout +--- + + + + +每个星期,Kubernetes 贡献者社区几乎都会在谷歌 Hangouts 上聚会。我们希望任何对此感兴趣的人都能了解这个论坛的讨论内容。 + + +日程安排: + + + +\- Andy - 演示远程执行和端口转发 + +\- Quinton - 联邦集群 - 延迟 + +\- Clayton - 围绕 Kubernetes 的 UI 代码共享和协作 + + +从会议指出: + + + +1\. Andy 从 RedHat: + + + +* 演示远程执行 + + + + * kubectl exec -p $POD -- $CMD + + * 作为代理与主机建立连接,找出 pod 所在的节点,代理与 kubelet 的连接,这一点很有趣。通过 nsenter。 + + * 使用 SPDY 通过 HTTP 进行多路复用流式传输 + + * 还有互动模式: + + * 假设第一个容器,可以使用 -c $CONTAINER 一个特定的。 + + * 如果在容器中预先安装了 gdb,则可以交互地将其附加到正在运行的进程中 + + * backtrace、symbol tbles、print 等。 使用gdb可以做的大多数事情。 + + * 也可以用精心制作的参数在上面运行 rsync 或者在容器内设置 sshd。 + + * 一些聊天反馈: + + + +* Andy 还演示了端口转发 +* nnsenter 与 docker exec + + + + * 想要在主机的控制下注入二进制文件,类似于预启动钩子 + + * socat、nsenter,任何预启动钩子需要的 + + + +* 如果能在博客上发表这方面的文章就太好了 +* wheezy 中的 nginx 版本太旧,无法支持所需的主代理功能 + + + +2\. Clayton: 我们的社区组织在哪里,例如 kubernetes UI 组件? + +* google-containers-ui IRC 频道,邮件列表。 +* Tim: google-containers 前缀是历史的,应该只做 "kubernetes-ui" +* 也希望将设计资源投入使用,并且 bower 期望自己的仓库。 +* 通用协议 + + + +3\. Brian Grant: + +* 测试 v1beta3,准备进入。 +* Paul 力于改变命令行的内容。 +* 下周初至中旬,尝试默认启用v1beta3 ? +* 对于任何其他更改,请发出文件并抄送 thockin。 + + + +4\. 一般认为30分钟比60分钟好 + + + +* 不应该为了填满时间而人为地延长。 diff --git a/content/zh/blog/_posts/2015-03-00-Welcome-To-Kubernetes-Blog.md b/content/zh/blog/_posts/2015-03-00-Welcome-To-Kubernetes-Blog.md new file mode 100644 index 0000000000..3e3b5f6d3d --- /dev/null +++ b/content/zh/blog/_posts/2015-03-00-Welcome-To-Kubernetes-Blog.md @@ -0,0 +1,62 @@ +--- +title: 欢迎来到 Kubernetes 博客! +date: 2015-03-20 +slug: welcome-to-kubernetes-blog +url: /blog/2015/03/Welcome-To-Kubernetes-Blog +--- + + + + +欢迎来到新的 Kubernetes 博客。关注此博客,了解 Kubernetes 开源项目。我们计划不时发布发布说明,操作方法文章,活动,甚至一些非常有趣的话题。 + + +如果您正在使用 Kubernetes 或为该项目做出贡献并想要发帖子,[请告诉我](mailto:kitm@google.com)。 + + +首先,以下是 Kubernetes 最近在其他网站上发布的文章摘要: + + + +- [使用 Vitess 和 Kubernetes 在云中扩展 MySQL](http://googlecloudplatform.blogspot.com/2015/03/scaling-MySQL-in-the-cloud-with-Vitess-and-Kubernetes.html) +- [虚拟机上的容器群集](http://googlecloudplatform.blogspot.com/2015/02/container-clusters-on-vms.html) +- [想知道的关于 kubernetes 的一切,却又不敢问](http://googlecloudplatform.blogspot.com/2015/01/everything-you-wanted-to-know-about-Kubernetes-but-were-afraid-to-ask.html) +- [什么构成容器集群?](http://googlecloudplatform.blogspot.com/2015/01/what-makes-a-container-cluster.html) +- [将 OpenStack 和 Kubernetes 与 Murano 集成](https://www.mirantis.com/blog/integrating-openstack-and-kubernetes-with-murano/) +- [容器介绍,Kubernetes 以及现代云计算的发展轨迹](http://googlecloudplatform.blogspot.com/2015/01/in-coming-weeks-we-will-be-publishing.html) +- [什么是 Kubernetes 以及如何使用它?](http://www.centurylinklabs.com/what-is-kubernetes-and-how-to-use-it/) +- [OpenShift V3,Docker 和 Kubernetes 策略](https://blog.openshift.com/v3-docker-kubernetes-interview/) +- [Kubernetes 简介](https://www.digitalocean.com/community/tutorials/an-introduction-to-kubernetes) + + +快乐的云计算! + + + - Kit Merker - Google 云平台产品经理 diff --git a/content/zh/blog/_posts/2015-04-00-Kubernetes-Release-0150.md b/content/zh/blog/_posts/2015-04-00-Kubernetes-Release-0150.md new file mode 100644 index 0000000000..d7071e2377 --- /dev/null +++ b/content/zh/blog/_posts/2015-04-00-Kubernetes-Release-0150.md @@ -0,0 +1,176 @@ +--- +title: " Kubernetes Release: 0.15.0 " +date: 2015-04-16 +slug: kubernetes-release-0150 +url: /blog/2015/04/Kubernetes-Release-0150 +--- + + + +Release 说明: + + + +* 启用 1beta3 API 并将其设置为默认 API 版本 ([#6098][1]) +* 增加了多端口服务([#6182][2]) + * 新入门指南 + * 多节点本地启动指南 ([#6505][3]) + * Google 云平台上的 Mesos ([#5442][4]) + * Ansible 安装说明 ([#6237][5]) +* 添加了一个控制器框架 ([#5270][6], [#5473][7]) +* Kubelet 现在监听一个安全的 HTTPS 端口 ([#6380][8]) +* 使 kubectl 错误更加友好 ([#6338][9]) +* apiserver 现在支持客户端 cert 身份验证 ([#6190][10]) +* apiserver 现在限制了它处理的并发请求的数量 ([#6207][11]) +* 添加速度限制删除 pod ([#6355][12]) +* 将平衡资源分配算法作为优先级函数实现在调度程序包中 ([#6150][13]) +* 从主服务器启用日志收集功能 ([#6396][14]) +* 添加了一个 api 端口来从 Pod 中提取日志 ([#6497][15]) +* 为调度程序添加了延迟指标 ([#6368][16]) +* 为 REST 客户端添加了延迟指标 ([#6409][17]) + + + +* etcd 现在在 master 上的一个 pod 中运行 ([#6221][18]) +* nginx 现在在 master上的容器中运行 ([#6334][19]) +* 开始为主组件构建 Docker 镜像 ([#6326][20]) +* 更新了 GCE 程序以使用 gcloud 0.9.54 ([#6270][21]) +* 更新了 AWS 程序来修复区域与区域语义 ([#6011][22]) +* 记录镜像 GC 失败时的事件 ([#6091][23]) +* 为 kubernetes 客户端添加 QPS 限制器 ([#6203][24]) +* 减少运行 make release 所需的时间 ([#6196][25]) +* 新卷的支持 + * 添加 iscsi 卷插件 ([#5506][26]) + * 添加 glusterfs 卷插件 ([#6174][27]) + * AWS EBS 卷支持 ([#5138][28]) +* 更新到 heapster 版本到 v0.10.0 ([#6331][29]) +* 更新到 etcd 2.0.9 ([#6544][30]) +* 更新到 Kibana 到 v1.2 ([#6426][31]) +* 漏洞修复 + * 如果服务的公共 IP 发生变化,Kube-proxy现在会更新iptables规则 ([#6123][32]) + * 如果初始创建失败,则重试 kube-addons 创建 ([#6200][33]) + * 使 kube-proxy 对耗尽文件描述符更具弹性 ([#6727][34]) + + +要下载,请访问 https://github.com/GoogleCloudPlatform/kubernetes/releases/tag/v0.15.0 + + +[1]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6098 "在 master 中默认启用 v1beta3 api 版本" +[2]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6182 "实现多端口服务" +[3]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6505 "Docker 多节点" +[4]: https://github.com/GoogleCloudPlatform/kubernetes/pull/5442 "谷歌云平台上 Mesos 入门指南" +[5]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6237 "示例 ansible 设置仓库" +[6]: https://github.com/GoogleCloudPlatform/kubernetes/pull/5270 "控制器框架" +[7]: https://github.com/GoogleCloudPlatform/kubernetes/pull/5473 "添加 DeltaFIFO(控制器框架块)" +[8]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6380 "将 kubelet 配置为使用 HTTPS (获得 2)" +[9]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6338 "返回用于配置验证的类型化错误,并简化错误" +[10]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6190 "添加客户端证书认证" +[11]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6207 "为服务器处理的正在运行的请求数量添加一个限制。" +[12]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6355 "添加速度限制删除 pod" +[13]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6150 "将均衡资源分配算法作为优先级函数实现在调度程序包中。" +[14]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6396 "启用主服务器收集日志。" +[15]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6497 "pod 子日志资源" +[16]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6368 "将基本延迟指标添加到调度程序。" +[17]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6409 "向 REST 客户端添加延迟指标" +[18]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6221 "在 pod 中运行 etcd 2.0.5" +[19]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6334 "添加一个 nginx docker 镜像用于主程序。" +[20]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6326 "为主组件创建 Docker 镜像" +[21]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6270 "gcloud 0.9.54 的更新" + + +[22]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6011 "修复 AWS 区域 与 zone" +[23]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6091 "记录镜像 GC 失败时的事件。" +[24]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6203 "向 kubernetes 客户端添加 QPS 限制器。" +[25]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6196 "在 `make release` 的构建和打包阶段并行化架构" +[26]: https://github.com/GoogleCloudPlatform/kubernetes/pull/5506 "添加 iscsi 卷插件" +[27]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6174 "实现 glusterfs 卷插件" +[28]: https://github.com/GoogleCloudPlatform/kubernetes/pull/5138 "AWS EBS 卷支持" +[29]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6331 "将 heapster 版本更新到 v0.10.0" +[30]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6544 "构建 etcd 镜像(版本 2.0.9),并将 kubernetes 集群升级到新版本" +[31]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6426 "更新 Kibana 到 v1.2,它对 Elasticsearch 的位置进行了参数化" +[32]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6123 "修复了 kube-proxy 中的一个错误,如果一个服务的公共 ip 发生变化,它不会更新 iptables 规则" +[33]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6200 "如果 kube-addons 创建失败,请重试 kube-addons 创建。" +[34]: https://github.com/GoogleCloudPlatform/kubernetes/pull/6727 "pkg/proxy: fd 用完后引起恐慌" + diff --git a/content/zh/blog/_posts/2015-04-00-Weekly-Kubernetes-Community-Hangout_17.md b/content/zh/blog/_posts/2015-04-00-Weekly-Kubernetes-Community-Hangout_17.md new file mode 100644 index 0000000000..e71b8d17be --- /dev/null +++ b/content/zh/blog/_posts/2015-04-00-Weekly-Kubernetes-Community-Hangout_17.md @@ -0,0 +1,287 @@ +--- +title: " Kubernetes 社区每周聚会笔记- 2015年4月17日 " +date: 2015-04-17 +slug: weekly-kubernetes-community-hangout_17 +url: /blog/2015/04/Weekly-Kubernetes-Community-Hangout_17 +--- + + + + +每个星期,Kubernetes 贡献者社区几乎都会在谷歌 Hangouts 上聚会。我们希望任何对此感兴趣的人都能了解这个论坛的讨论内容。 + + +议程 + +* Mesos 集成 +* 高可用性(HA) +* 向 e2e 添加性能和分析详细信息以跟踪回归 +* 客户端版本化 + + +笔记 + + + +* Mesos 集成 + + * Mesos 集成提案: + + * 没有阻塞集成的因素。 + + * 文档需要更新。 + + + +* HA + + * 提案今天应该会提交。 + + * Etcd 集群。 + + * apiserver 负载均衡。 + + * 控制器管理器和其他主组件的冷备用。 + + + +* 向 e2e 添加性能和分析详细信息以跟踪回归 + + * 希望红色为性能回归 + + * 需要公共数据库才能发布数据 + + * 查看 + + * Justin 致力于多平台 e2e 仪表盘 + + + +* 客户端版本化 + + * + + * + + * 客户端库当前使用内部 API 对象。 + + * 尽管没有人反映频繁修改 `types.go` 有多痛苦,但我们很为此担心。 + + * 结构化类型在客户端中很有用。版本化的结构就可以了。 + + * 如果从 json/yaml (kubectl) 开始,则不应转换为结构化类型。使用 swagger。 + + + +* Security context + + * + + * 管理员可以限制谁可以运行特权容器或需要特定的 unix uid + + * kubelet 将能够从 apiserver 获取证书 + + * 政策提案将于下周左右出台 + + + +* 讨论用户的上游,等等进入Kubernetes,至少是可选的 +* 1.0 路线图 + + * 重点是性能,稳定性,集群升级 + + * TJ 一直在对[roadmap.md][4]进行一些编辑,但尚未发布PR +* Kubernetes UI + + * 依赖关系分解为第三方 + + * @lavalamp 是评论家 + + +[1]: http://kubernetes.io/images/nav_logo.svg +[2]: http://kubernetes.io/docs/ +[3]: https://kubernetes.io/blog/ +[4]: https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/roadmap.md +[5]: https://kubernetes.io/blog/2015/04/weekly-kubernetes-community-hangout_17 "permanent link" +[6]: https://resources.blogblog.com/img/icon18_edit_allbkg.gif +[7]: https://www.blogger.com/post-edit.g?blogID=112706738355446097&postID=630924463010638300&from=pencil "Edit Post" +[8]: https://www.blogger.com/share-post.g?blogID=112706738355446097&postID=630924463010638300&target=email "Email This" +[9]: https://www.blogger.com/share-post.g?blogID=112706738355446097&postID=630924463010638300&target=blog "BlogThis!" +[10]: https://www.blogger.com/share-post.g?blogID=112706738355446097&postID=630924463010638300&target=twitter "Share to Twitter" +[11]: https://www.blogger.com/share-post.g?blogID=112706738355446097&postID=630924463010638300&target=facebook "Share to Facebook" +[12]: https://www.blogger.com/share-post.g?blogID=112706738355446097&postID=630924463010638300&target=pinterest "Share to Pinterest" +[13]: https://kubernetes.io/blog/search/label/community%20meetings +[14]: https://kubernetes.io/blog/search/label/containers +[15]: https://kubernetes.io/blog/search/label/docker +[16]: https://kubernetes.io/blog/search/label/k8s +[17]: https://kubernetes.io/blog/search/label/kubernetes +[18]: https://kubernetes.io/blog/search/label/open%20source +[19]: https://kubernetes.io/blog/2015/04/kubernetes-and-mesosphere-dcos "Newer Post" +[20]: https://kubernetes.io/blog/2015/04/introducing-kubernetes-v1beta3 "Older Post" +[21]: https://kubernetes.io/blog/feeds/630924463010638300/comments/default +[22]: https://img2.blogblog.com/img/widgets/arrow_dropdown.gif +[23]: https://img1.blogblog.com/img/icon_feed12.png +[24]: https://img1.blogblog.com/img/widgets/subscribe-netvibes.png +[25]: https://www.netvibes.com/subscribe.php?url=http%3A%2F%2Fblog.kubernetes.io%2Ffeeds%2Fposts%2Fdefault +[26]: https://img1.blogblog.com/img/widgets/subscribe-yahoo.png +[27]: https://add.my.yahoo.com/content?url=http%3A%2F%2Fblog.kubernetes.io%2Ffeeds%2Fposts%2Fdefault +[28]: https://kubernetes.io/blog/feeds/posts/default +[29]: https://www.netvibes.com/subscribe.php?url=http%3A%2F%2Fblog.kubernetes.io%2Ffeeds%2F630924463010638300%2Fcomments%2Fdefault +[30]: https://add.my.yahoo.com/content?url=http%3A%2F%2Fblog.kubernetes.io%2Ffeeds%2F630924463010638300%2Fcomments%2Fdefault +[31]: https://resources.blogblog.com/img/icon18_wrench_allbkg.png +[32]: //www.blogger.com/rearrange?blogID=112706738355446097&widgetType=Subscribe&widgetId=Subscribe1&action=editWidget§ionId=sidebar-right-1 "Edit" +[33]: https://twitter.com/kubernetesio +[34]: https://github.com/kubernetes/kubernetes +[35]: http://slack.k8s.io/ +[36]: http://stackoverflow.com/questions/tagged/kubernetes +[37]: http://get.k8s.io/ +[38]: //www.blogger.com/rearrange?blogID=112706738355446097&widgetType=HTML&widgetId=HTML2&action=editWidget§ionId=sidebar-right-1 "Edit" +[39]: javascript:void(0) +[40]: https://kubernetes.io/blog/2018/ +[41]: https://kubernetes.io/blog/2018/01/ +[42]: https://kubernetes.io/blog/2017/ +[43]: https://kubernetes.io/blog/2017/12/ +[44]: https://kubernetes.io/blog/2017/11/ +[45]: https://kubernetes.io/blog/2017/10/ +[46]: https://kubernetes.io/blog/2017/09/ +[47]: https://kubernetes.io/blog/2017/08/ +[48]: https://kubernetes.io/blog/2017/07/ +[49]: https://kubernetes.io/blog/2017/06/ +[50]: https://kubernetes.io/blog/2017/05/ +[51]: https://kubernetes.io/blog/2017/04/ +[52]: https://kubernetes.io/blog/2017/03/ +[53]: https://kubernetes.io/blog/2017/02/ +[54]: https://kubernetes.io/blog/2017/01/ +[55]: https://kubernetes.io/blog/2016/ +[56]: https://kubernetes.io/blog/2016/12/ +[57]: https://kubernetes.io/blog/2016/11/ +[58]: https://kubernetes.io/blog/2016/10/ +[59]: https://kubernetes.io/blog/2016/09/ +[60]: https://kubernetes.io/blog/2016/08/ +[61]: https://kubernetes.io/blog/2016/07/ +[62]: https://kubernetes.io/blog/2016/06/ +[63]: https://kubernetes.io/blog/2016/05/ +[64]: https://kubernetes.io/blog/2016/04/ +[65]: https://kubernetes.io/blog/2016/03/ +[66]: https://kubernetes.io/blog/2016/02/ +[67]: https://kubernetes.io/blog/2016/01/ +[68]: https://kubernetes.io/blog/2015/ +[69]: https://kubernetes.io/blog/2015/12/ +[70]: https://kubernetes.io/blog/2015/11/ +[71]: https://kubernetes.io/blog/2015/10/ +[72]: https://kubernetes.io/blog/2015/09/ +[73]: https://kubernetes.io/blog/2015/08/ +[74]: https://kubernetes.io/blog/2015/07/ +[75]: https://kubernetes.io/blog/2015/06/ +[76]: https://kubernetes.io/blog/2015/05/ +[77]: https://kubernetes.io/blog/2015/04/ +[78]: https://kubernetes.io/blog/2015/04/weekly-kubernetes-community-hangout_29 +[79]: https://kubernetes.io/blog/2015/04/borg-predecessor-to-kubernetes +[80]: https://kubernetes.io/blog/2015/04/kubernetes-and-mesosphere-dcos +[81]: https://kubernetes.io/blog/2015/04/weekly-kubernetes-community-hangout_17 +[82]: https://kubernetes.io/blog/2015/04/introducing-kubernetes-v1beta3 +[83]: https://kubernetes.io/blog/2015/04/kubernetes-release-0150 +[84]: https://kubernetes.io/blog/2015/04/weekly-kubernetes-community-hangout_11 +[85]: https://kubernetes.io/blog/2015/04/faster-than-speeding-latte +[86]: https://kubernetes.io/blog/2015/04/weekly-kubernetes-community-hangout +[87]: https://kubernetes.io/blog/2015/03/ +[88]: //www.blogger.com/rearrange?blogID=112706738355446097&widgetType=BlogArchive&widgetId=BlogArchive1&action=editWidget§ionId=sidebar-right-1 "Edit" +[89]: //www.blogger.com/rearrange?blogID=112706738355446097&widgetType=HTML&widgetId=HTML1&action=editWidget§ionId=sidebar-right-1 "Edit" +[90]: https://www.blogger.com +[91]: //www.blogger.com/rearrange?blogID=112706738355446097&widgetType=Attribution&widgetId=Attribution1&action=editWidget§ionId=footer-3 "Edit" + + [*[3:27 PM]: 2015-04-17T15:27:00-07:00 diff --git a/content/zh/blog/_posts/2015-04-00-Weekly-Kubernetes-Community-Hangout_29.md b/content/zh/blog/_posts/2015-04-00-Weekly-Kubernetes-Community-Hangout_29.md new file mode 100644 index 0000000000..c451022671 --- /dev/null +++ b/content/zh/blog/_posts/2015-04-00-Weekly-Kubernetes-Community-Hangout_29.md @@ -0,0 +1,143 @@ +--- +title: " Kubernetes 社区每周聚会笔记- 2015年4月24日 " +date: 2015-04-30 +slug: weekly-kubernetes-community-hangout_29 +url: /blog/2015/04/Weekly-Kubernetes-Community-Hangout_29 +--- + + + + +每个星期,Kubernetes 贡献者社区几乎都会在谷歌 Hangouts 上聚会。我们希望任何对此感兴趣的人都能了解这个论坛的讨论内容。 + + +日程安排: + +* Flocker 和 Kubernetes 集成演示 + + +笔记: + +* flocker 和 kubernetes 集成演示 +* * Flocker Q/A + + * 迁移后文件是否仍存在于node1上? + + * Brendan: 有没有计划把它做成一本书?我们不需要 powerstrip? + + * Luke: 需要找出感兴趣的来决定我们是否想让它成为 kube 中的一个一流的持久性磁盘提供商。 + + * Brendan: 删除对 powerstrip 的需求会使其易于使用。完全去做。 + + * Tim: 将它添加到 kubernetes 应该不超过45分钟:) + + + + * Derek: 持久卷和请求相比呢? + + * Luke: 除了基于 ZFS 的新后端之外,差别不大。使工作负载真正可移植。 + + * Tim: 与基于网络的卷非常不同。有趣的是,它是唯一允许升级媒体的产品。 + + * Brendan: 请求,它如何查找重复请求?Cassandra 希望在底层复制数据。向上和向下扩缩是有效的。根据负载动态地创建存储。它的步骤不仅仅是快照——通过编程使用预分配创建副本。 + + * Tim: 帮助自动配置。 + + + + * Brian: flocker 是否需要其他组件? + + * Kai: Flocker 控制服务与主服务器位于同一位置。(dia 在博客上)。Powerstrip + Powerstrip Flocker。对在 etcd 中持久化状态非常有趣。它保存关于每个卷的元数据。 + + * Brendan: 在未来,flocker 可以是一个插件,我们将负责持久性。发布 v1.0。 + + * Brian: 有兴趣为 flocker 等服务添加通用插件。 + + * Luke: 当扩展到单个节点上的许多容器时,Zfs 会变得非常有价值。 + + + + * Alex: flocker 服务可以作为 pod 运行吗? + + * Kai: 是的,唯一的要求是 flocker 控制服务应该能够与 zfs 代理对话。需要在主机上安装 zfs 代理,并且需要访问 zfs 二进制文件。 + + * Brendan: 从理论上讲,所有 zfs 位都可以与设备一起放入容器中。 + + * Luke: 是的,仍然在处理跨容器安装问题。 + + * Tim: pmorie 正在通过它使 kubelet 在容器中工作。可能重复使用。 + + * Kai: Cinder 支持即将到来。几天之后。 +* Bob: 向 GKE 推送 kube 的过程是怎样的?需要更多的可见度。 + + diff --git a/content/zh/blog/_posts/2015-05-00-Kubernetes-On-Openstack.md b/content/zh/blog/_posts/2015-05-00-Kubernetes-On-Openstack.md new file mode 100644 index 0000000000..0a4ac17ef5 --- /dev/null +++ b/content/zh/blog/_posts/2015-05-00-Kubernetes-On-Openstack.md @@ -0,0 +1,112 @@ +--- +title: " OpenStack 上的 Kubernetes " +date: 2015-05-19 +slug: kubernetes-on-openstack +url: /blog/2015/05/Kubernetes-On-Openstack +--- + + + +[![](https://3.bp.blogspot.com/-EOrCHChZJZE/VVZzq43g6CI/AAAAAAAAF-E/JUilRHk369E/s400/Untitled%2Bdrawing.jpg)](https://3.bp.blogspot.com/-EOrCHChZJZE/VVZzq43g6CI/AAAAAAAAF-E/JUilRHk369E/s1600/Untitled%2Bdrawing.jpg) + + + +今天,[OpenStack 基金会](https://www.openstack.org/foundation/)通过在其[社区应用程序目录](http://apps.openstack.org/)中包含 Kubernetes,使您更容易在 OpenStack 云上部署和管理 Docker 容器集群。 +今天在温哥华 OpenStack 峰会上的主题演讲中,OpenStack 基金会的首席运营官:Mark Collier 和 [Mirantis](https://www.mirantis.com/) 产品线经理 Craig Peters 通过利用 OpenStack 云中已经存在的计算、存储、网络和标识系统,在几秒钟内启动了 Kubernetes 集群,展示了社区应用程序目录的工作流。 + + +目录中的条目不仅包括[启动 Kubernetes 集群](http://apps.openstack.org/#tab=murano-apps&asset=Kubernetes%20Cluster)的功能,还包括部署在 Kubernetes 管理的 Docker 容器中的一系列应用程序。这些应用包括: + + + + +- +Apache web 服务器 +- +Nginx web 服务器 +- +Crate - Docker的分布式数据库 +- +GlassFish - Java EE 7 应用服务器 +- +Tomcat - 一个开源的 web 服务器和 servlet 容器 +- +InfluxDB - 一个开源的、分布式的、时间序列数据库 +- +Grafana - InfluxDB 的度量仪表板 +- +Jenkins - 一个可扩展的开放源码持续集成服务器 +- +MariaDB 数据库 +- +MySql 数据库 +- +Redis - 键-值缓存和存储 +- +PostgreSQL 数据库 +- +MongoDB NoSQL 数据库 +- +Zend 服务器 - 完整的 PHP 应用程序平台 + + +此列表将会增长,并在[此处](https://github.com/openstack/murano-apps/tree/master/Docker/Kubernetes)进行策划。您可以检查(并参与)YAML 文件,该文件告诉 Murano 如何根据[此处](https://github.com/openstack/murano-apps/blob/master/Docker/Kubernetes/KubernetesCluster/package/Classes/KubernetesCluster.yaml)定义来安装和启动 ...apps/blob/master/Docker/Kubernetes/KubernetesCluster/package/Classes/KubernetesCluster.yaml)安装和启动 Kubernetes 集群。 + + +[Kubernetes 开源项目](https://github.com/GoogleCloudPlatform/kubernetes)继续受到社区的欢迎,并且势头越来越好,GitHub 上有超过 11000 个提交和 7648 颗星。从 Red Hat 和 Intel 到 CoreOS 和 Box.net,它已经代表了从企业 IT 到前沿创业企业的一系列客户。我们鼓励您尝试一下,给我们您的反馈,并参与到我们不断增长的社区中来。 + + + + +- Martin Buhr, Kubernetes 开源项目产品经理 + diff --git a/content/zh/blog/_posts/2015-05-00-Weekly-Kubernetes-Community-Hangout.md b/content/zh/blog/_posts/2015-05-00-Weekly-Kubernetes-Community-Hangout.md new file mode 100644 index 0000000000..8f60d7916b --- /dev/null +++ b/content/zh/blog/_posts/2015-05-00-Weekly-Kubernetes-Community-Hangout.md @@ -0,0 +1,121 @@ +--- +title: " Kubernetes 社区每周聚会笔记- 2015年5月1日 " +date: 2015-05-11 +slug: weekly-kubernetes-community-hangout +url: /blog/2015/05/Weekly-Kubernetes-Community-Hangout +--- + + + + +每个星期,Kubernetes 贡献者社区几乎都会在谷歌 Hangouts 上聚会。我们希望任何对此感兴趣的人都能了解这个论坛的讨论内容。 + + + +* 简单的滚动更新 - Brendan + + * 滚动更新 = RCs和Pods很好的例子。 + + * ...pause… (Brendan 需要 Kelsey 的演示恢复技巧) + + * 滚动更新具有恢复功能:取消更新并重新启动,更新从停止的地方继续。 + + * 新控制器获取旧控制器的名称,因此外观是纯粹的更新。 + + * 还可以在 update 中命名版本(最后不会重命名)。 + + + +* Rocket 演示 - CoreOS 的伙计们 + + * Rocket 和 docker 之间的主要区别: Rocket 是无守护进程和以 pod 为中心。。 + + * Rocket 具有原生的 AppContainer 格式,但也支持 docker 镜像格式。 + + * 可以在同一个 pod 中运行 AppContainer 和 docker 容器。 + + * 变更接近于合并。 + + + +* 演示 service accounts 和 secrets 被添加到 pod - Jordan + + * 问题:很难获得与API通信的令牌。 + + * 新的API对象:"ServiceAccount" + + * ServiceAccount 是命名空间,控制器确保命名空间中至少存在一个个默认 service account。 + + * 键入 "ServiceAccountToken",控制器确保至少有一个默认令牌。 + + * 演示 + + * * 可以使用 ServiceAccountToken 创建新的 service account。控制器将为它创建令牌。 + + * 可以创建一个带有 service account 的 pod, pod 将在 /var/run/secrets/kubernets.io/… + + + +* Kubelet 在容器中运行 - Paul + + * Kubelet 成功地运行了带有 secret 的 pod。 + diff --git a/content/zh/blog/_posts/2015-06-00-Slides-Cluster-Management-With.md b/content/zh/blog/_posts/2015-06-00-Slides-Cluster-Management-With.md new file mode 100644 index 0000000000..8e1c001d65 --- /dev/null +++ b/content/zh/blog/_posts/2015-06-00-Slides-Cluster-Management-With.md @@ -0,0 +1,25 @@ +--- +title: "幻灯片:Kubernetes 集群管理,爱丁堡大学演讲" +date: 2015-06-26 +slug: slides-cluster-management-with +url: /blog/2015/06/Slides-Cluster-Management-With +--- + + + + + +2015年6月5日星期五,我在爱丁堡大学给普通听众做了一个演讲,题目是[使用 Kubernetes 进行集群管理](https://docs.google.com/presentation/d/1H4ywDb4vAJeg8KEjpYfhNqFSig0Q8e_X5I36kM9S6q0/pub?start=false&loop=false&delayms=3000)。这次演讲包括一个带有 Kibana 前端 UI 的音乐存储系统的例子,以及一个基于 Elasticsearch 的后端,该后端有助于生成具体的概念,如 pods、复制控制器和服务。 + +[Kubernetes 集群管理](https://docs.google.com/presentation/d/1H4ywDb4vAJeg8KEjpYfhNqFSig0Q8e_X5I36kM9S6q0/pub?start=false&loop=false&delayms=3000)。 diff --git a/content/zh/blog/_posts/2015-07-00-Announcing-First-Kubernetes-Enterprise.md b/content/zh/blog/_posts/2015-07-00-Announcing-First-Kubernetes-Enterprise.md new file mode 100644 index 0000000000..d71f6bcc70 --- /dev/null +++ b/content/zh/blog/_posts/2015-07-00-Announcing-First-Kubernetes-Enterprise.md @@ -0,0 +1,24 @@ +--- +title: "宣布首个Kubernetes企业培训课程 " +date: 2015-07-08 +slug: announcing-first-kubernetes-enterprise +url: /blog/2015/07/Announcing-First-Kubernetes-Enterprise +--- + + + +在谷歌,我们依赖 Linux 容器应用程序去运行我们的核心基础架构。所有服务,从搜索引擎到Gmail服务,都运行在容器中。事实上,我们非常喜欢容器,甚至我们的谷歌云计算引擎虚拟机也运行在容器上!由于容器对于我们的业务至关重要,我们已经与社区合作开发许多基本的容器技术(从 cgroups 到 Docker 的 LibContainer),甚至决定去构建谷歌的下一代开源容器调度技术,Kubernetes。 + + +在 Kubernetes 项目进行一年后,在 OSCON 上发布 V1 版本的前夕,我们很高兴的宣布Kubernetes 的主要贡献者 Mesosphere 组织了有史以来第一次正规的以企业为中心的 Kubernetes 培训会议。首届会议将于 6 月 20 日在波特兰的 OSCON 举办,由来自 Mesosphere 的 Zed Shaw 和 Michael Hausenblas 演讲。[Pre-registration](https://mesosphere.com/training/kubernetes/) 对于优先注册者是免费的,但名额有限,立刻行动吧! + + +这个为期一天的课程将包涵使用 Kubernetes 构建和部署容器化应用程序的基础知识。它将通过完整的流程引导与参会者创建一个 Kubernetes 的应用程序体系结构,创建和配置 Docker 镜像,并把它们部署到 Kubernetes 集群上。用户还将了解在我们的谷歌容器引擎和 Mesosphere 的数据中心操作系统上部署 Kubernetes 应用程序和服务的基础知识。 + + +即将推出的 Kubernetes bootcamp 将是学习如何应用 Kubernetes 解决长期部署和应用程序管理问题的一个好途径。相对于我们所预期的,来自于广泛社区的众多培训项目而言,这只是其中一个。 diff --git a/content/zh/blog/_posts/2015-12-00-Managing-Kubernetes-Pods-Services-And-Replication-Controllers-With-Puppet.md b/content/zh/blog/_posts/2015-12-00-Managing-Kubernetes-Pods-Services-And-Replication-Controllers-With-Puppet.md new file mode 100644 index 0000000000..5faf838148 --- /dev/null +++ b/content/zh/blog/_posts/2015-12-00-Managing-Kubernetes-Pods-Services-And-Replication-Controllers-With-Puppet.md @@ -0,0 +1,164 @@ +--- +title: " 使用 Puppet 管理 Kubernetes Pods,Services 和 Replication Controllers " +date: 2015-12-17 +slug: managing-kubernetes-pods-services-and-replication-controllers-with-puppet +url: /blog/2015/12/Managing-Kubernetes-Pods-Services-And-Replication-Controllers-With-Puppet +--- + + + + + +_今天的嘉宾帖子是由 IT 自动化领域的领导者 Puppet Labs 的高级软件工程师 Gareth Rushgrove 撰写的。Gareth告诉我们一个新的 Puppet 模块,它帮助管理 Kubernetes 中的资源。_ + +熟悉[Puppet]的人(https://github.com/puppetlabs/puppet)可能使用它来管理主机上的文件、包和用户。但是Puppet首先是一个配置管理工具,配置管理是一个比管理主机级资源更广泛的规程。配置管理的一个很好的定义是它旨在解决四个相关的问题:标识、控制、状态核算和验证审计。这些问题存在于任何复杂系统的操作中,并且有了新的[Puppet Kubernetes module](https://forge.puppetlabs.com/garethr/kubernetes),我们开始研究如何为 Kubernetes 解决这些问题。 + + + +### Puppet Kubernetes 模块 + +Puppet kubernetes 模块目前假设您已经有一个 kubernetes 集群 [启动并运行]](http://kubernetes.io/gettingstarted/)。它的重点是管理 Kubernetes中的资源,如 Pods、Replication Controllers 和 Services,而不是(现在)管理底层的 kubelet 或 etcd services。下面是描述 Puppet’s DSL 中一个 Pod 的简短代码片段。 + + + +``` +kubernetes_pod { 'sample-pod': + ensure => present, + metadata => { + namespace => 'default', + }, + spec => { + containers => [{ + name => 'container-name', + image => 'nginx', + }] + }, +} +``` + + +如果您熟悉 YAML 文件格式,您可能会立即识别该结构。 该接口故意采取相同的格式以帮助在不同格式之间进行转换 — 事实上,为此提供支持的代码是从Kubernetes API Swagger自动生成的。 运行上面的代码,假设我们将其保存为 pod.pp,就像下面这样简单: + + +``` +puppet apply pod.pp +``` + + + +身份验证使用标准的 kubectl 配置文件。您可以在模块的自述文件中找到完整的[README](https://github.com/garethr/garethr-kubernetes/blob/master/README.md)。 + +Kubernetes 有很多资源,来自 Pods、 Services、 Replication Controllers 和 Service Accounts。您可以在[Puppet 中的 kubernetes 留言簿示例](https://puppetlabs.com/blog/kubernetes-guestbook-example-puppet)文章中看到管理这些资源的模块示例。这演示了如何将规范的 hello-world 示例转换为使用 Puppet代码。 + + + +然而,使用 Puppet 的一个主要优点是,您可以创建自己的更高级别和更特定于业务的接口,以连接 kubernetes 管理的应用程序。例如,对于留言簿,可以创建如下内容: + +``` +guestbook { 'myguestbook': + redis_slave_replicas => 2, + frontend_replicas => 3, + redis_master_image => 'redis', + redis_slave_image => 'gcr.io/google_samples/gb-redisslave:v1', + frontend_image => 'gcr.io/google_samples/gb-frontend:v3', +} +``` + + + +您可以在Puppet博客文章[在 Puppet 中为 Kubernetes 构建自己的抽象](https://puppetlabs.com/blog/building-your-own-abstractions-kubernetes-puppet)中阅读更多关于使用 Puppet 定义的类型的信息,并看到更多的代码示例。 + + +### 结论 + +使用 Puppet 而不仅仅是使用标准的 YAML 文件和 kubectl 的优点是: + + + +- 能够创建自己的抽象,以减少重复和设计更高级别的用户界面,如上面的留言簿示例。 +- 使用 Puppet 的开发工具验证代码和编写单元测试。 +- 与 Puppet Server 等其他工具配合,以确保代码中的模型与集群的状态匹配,并与 PuppetDB 配合工作,以存储报告和跟踪更改。 +- 能够针对 Kubernetes API 重复运行相同的代码,以检测任何更改或修正配置。 + + + +值得注意的是,大多数大型组织都将拥有非常异构的环境,运行各种各样的软件和操作系统。拥有统一这些离散系统的单一工具链可以使采用 Kubernetes 等新技术变得更加容易。 + + + +可以肯定地说,Kubernetes提供了一组优秀的组件来构建云原生系统。使用 Puppet,您可以解决在生产中运行任何复杂系统所带来的一些操作和配置管理问题。[告诉我们](mailto:gareth@puppetlabs.com)如果您试用了该模块,您会有什么想法,以及您希望在将来看到哪些支持。 + + +Gareth Rushgrove,Puppet Labs 高级软件工程师 + diff --git a/content/zh/blog/_posts/2016-01-00-Simple-Leader-Election-With-Kubernetes.md b/content/zh/blog/_posts/2016-01-00-Simple-Leader-Election-With-Kubernetes.md new file mode 100644 index 0000000000..bcea1c026e --- /dev/null +++ b/content/zh/blog/_posts/2016-01-00-Simple-Leader-Election-With-Kubernetes.md @@ -0,0 +1,303 @@ + + +title: "Kubernetes 和 Docker 简单的 leader election" +date: 2016-01-11 +slug: simple-leader-election-with-kubernetes +url: /blog/2016/01/Simple-Leader-Election-With-Kubernetes + + + +Kubernetes 简化了集群上运行的服务的部署和操作管理。但是,它也简化了这些服务的发展。在本文中,我们将看到如何使用 Kubernetes 在分布式应用程序中轻松地执行 leader election。分布式应用程序通常为了可靠性和可伸缩性而复制服务的任务,但通常需要指定其中一个副本作为负责所有副本之间协调的负责人。 + + + +通常在 leader election 中,会确定一组成为领导者的候选人。这些候选人都竞相宣布自己为领袖。其中一位候选人获胜并成为领袖。一旦选举获胜,领导者就会不断地“信号”以表示他们作为领导者的地位,其他候选人也会定期地做出新的尝试来成为领导者。这样可以确保在当前领导因某种原因失败时,快速确定新领导。 + + + +实现 leader election 通常需要部署 ZooKeeper、etcd 或 Consul 等软件并将其用于协商一致,或者也可以自己实现协商一致算法。我们将在下面看到,Kubernetes 使在应用程序中使用 leader election 的过程大大简化。 + +####在 Kubernetes 实施领导人选举 + + + +Leader election 的首要条件是确定候选人的人选。Kubernetes 已经使用 _Endpoints_ 来表示组成服务的一组复制 pod,因此我们将重用这个相同的对象。(旁白:您可能认为我们会使用 _ReplicationControllers_,但它们是绑定到特定的二进制文件,而且通常您希望只有一个领导者,即使您正在执行滚动更新) + +要执行 leader election,我们使用所有 Kubernetes api 对象的两个属性: + + + +* ResourceVersions - 每个 API 对象都有一个惟一的 ResourceVersion,您可以使用这些版本对 Kubernetes 对象执行比较和交换 +* Annotations - 每个 API 对象都可以用客户端使用的任意键/值对进行注释。 + +给定这些原语,使用 master election 的代码相对简单,您可以在这里找到[here][1]。我们自己来做吧。 + + + +``` +$ kubectl run leader-elector --image=gcr.io/google_containers/leader-elector:0.4 --replicas=3 -- --election=example +``` + +这将创建一个包含3个副本的 leader election 集合: + +``` +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +leader-elector-inmr1 1/1 Running 0 13s +leader-elector-qkq00 1/1 Running 0 13s +leader-elector-sgwcq 1/1 Running 0 13s +``` + + + +要查看哪个pod被选为领导,您可以访问其中一个 pod 的日志,用您自己的一个 pod 的名称替换 + +``` +${pod_name}, (e.g. leader-elector-inmr1 from the above) + +$ kubectl logs -f ${name} +leader is (leader-pod-name) +``` +…或者,可以直接检查 endpoints 对象: + + + +_'example' 是上面 kubectl run … 命令_中候选集的名称 +``` +$ kubectl get endpoints example -o yaml +``` +现在,要验证 leader election 是否实际有效,请在另一个终端运行: +``` +$ kubectl delete pods (leader-pod-name) +``` + + + +这将删除现有领导。由于 pod 集由 replication controller 管理,因此新的 pod 将替换已删除的pod,确保复制集的大小仍为3。通过 leader election,这三个pod中的一个被选为新的领导者,您应该会看到领导者故障转移到另一个pod。因为 Kubernetes 的吊舱在终止前有一个 _grace period_,这可能需要30-40秒。 + +Leader-election container 提供了一个简单的 web 服务器,可以服务于任何地址(e.g. http://localhost:4040)。您可以通过删除现有的 leader election 组并创建一个新的 leader elector 组来测试这一点,在该组中,您还可以向 leader elector 映像传递--http=(host):(port) 规范。这将导致集合中的每个成员通过 webhook 提供有关领导者的信息。 + + + +``` +# delete the old leader elector group +$ kubectl delete rc leader-elector + +# create the new group, note the --http=localhost:4040 flag +$ kubectl run leader-elector --image=gcr.io/google_containers/leader-elector:0.4 --replicas=3 -- --election=example --http=0.0.0.0:4040 + +# create a proxy to your Kubernetes api server +$ kubectl proxy +``` + + + +然后您可以访问: + + + + +http://localhost:8001/api/v1/proxy/namespaces/default/pods/(leader-pod-name):4040/ + + + + +你会看到: + +``` +{"name":"(name-of-leader-here)"} +``` +#### 有副手的 leader election + + + +好吧,那太好了,你可以通过 HTTP 进行leader election 并找到 leader,但是你如何从自己的应用程序中使用它呢?这就是 sidecar 的由来。Kubernetes 中,Pods 由一个或多个容器组成。通常情况下,这意味着您将 sidecar containers 添加到主应用程序中以组成 pod。(关于这个主题的更详细的处理,请参阅我之前的博客文章)。 +Leader-election container 可以作为一个 sidecar,您可以从自己的应用程序中使用。Pod 中任何对当前 master 感兴趣的容器都可以简单地访问http://localhost:4040,它们将返回一个包含当前 master 名称的简单 json 对象。由于 pod中 的所有容器共享相同的网络命名空间,因此不需要服务发现! + + + +例如,这里有一个简单的 Node.js 应用程序,它连接到 leader election sidecar 并打印出它当前是否是 master。默认情况下,leader election sidecar 将其标识符设置为 `hostname`。 + +``` +var http = require('http'); +// This will hold info about the current master +var master = {}; + + // The web handler for our nodejs application + var handleRequest = function(request, response) { + response.writeHead(200); + response.end("Master is " + master.name); + }; + + // A callback that is used for our outgoing client requests to the sidecar + var cb = function(response) { + var data = ''; + response.on('data', function(piece) { data = data + piece; }); + response.on('end', function() { master = JSON.parse(data); }); + }; + + // Make an async request to the sidecar at http://localhost:4040 + var updateMaster = function() { + var req = http.get({host: 'localhost', path: '/', port: 4040}, cb); + req.on('error', function(e) { console.log('problem with request: ' + e.message); }); + req.end(); + }; + + / / Set up regular updates + updateMaster(); + setInterval(updateMaster, 5000); + + // set up the web server + var www = http.createServer(handleRequest); + www.listen(8080); + ``` + 当然,您可以从任何支持 HTTP 和 JSON 的语言中使用这个 sidecar。 + + + +#### 结论 + + + 希望我已经向您展示了使用 Kubernetes 为您的分布式应用程序构建 leader election 是多么容易。在以后的部分中,我们将向您展示 Kubernetes 如何使构建分布式系统变得更加容易。同时,转到[Google Container Engine][2]或[kubernetes.io][3]开始使用Kubernetes。 + + [1]: https://github.com/kubernetes/contrib/pull/353 + [2]: https://cloud.google.com/container-engine/ + [3]: http://kubernetes.io/ \ No newline at end of file diff --git a/content/zh/blog/_posts/2016-01-00-Why-Kubernetes-Doesnt-Use-Libnetwork.md b/content/zh/blog/_posts/2016-01-00-Why-Kubernetes-Doesnt-Use-Libnetwork.md new file mode 100644 index 0000000000..424a68d077 --- /dev/null +++ b/content/zh/blog/_posts/2016-01-00-Why-Kubernetes-Doesnt-Use-Libnetwork.md @@ -0,0 +1,79 @@ +--- +title: " 为什么 Kubernetes 不用 libnetwork " +date: 2016-01-14 +slug: why-kubernetes-doesnt-use-libnetwork +url: /blog/2016/01/Why-Kubernetes-Doesnt-Use-Libnetwork +--- + + + + + +在 1.0 版本发布之前,Kubernetes 已经有了一个非常基础的网络插件形式-大约在引入 Docker’s [libnetwork](https://github.com/docker/libnetwork) 和 Container Network Model ([CNM](https://github.com/docker/libnetwork/blob/master/docs/design.md)) 的时候。与 libnetwork 不同,Kubernetes 插件系统仍然保留它的 'alpha' 名称。现在 Docker 的网络插件支持已经发布并得到支持,我们发现一个明显的问题是 Kubernetes 尚未采用它。毕竟,供应商几乎肯定会为 Docker 编写插件-我们最好还是用相同的驱动程序,对吧? + + + +在进一步说明之前,重要的是记住 Kubernetes 是一个支持多种容器运行时的系统, Docker 只是其中之一。配置网络只是每一个运行时的一个方面,所以当人们问起“ Kubernetes 会支持CNM吗?”,他们真正的意思是“ Kubernetes 会支持 Docker 运行时的 CNM 驱动吗?”如果我们能够跨运行时实现通用的网络支持会很棒,但这不是一个明确的目标。 + + + +实际上, Kubernetes 还没有为 Docker 运行时采用 CNM/libnetwork 。事实上,我们一直在研究 CoreOS 提出的替代 Container Network Interface ([CNI](https://github.com/appc/cni/blob/master/SPEC.md)) 模型以及 App Container ([appc](https://github.com/appc)) 规范的一部分。为什么我们要这么做?有很多技术和非技术的原因。 + + + +首先,Docker 的网络驱动程序设计中存在一些基本假设,这些假设会给我们带来问题。 + + + +Docker 有一个“本地”和“全局”驱动程序的概念。本地驱动程序(例如 "bridge" )以机器为中心,不进行任何跨节点协调。全局驱动程序(例如 "overlay" )依赖于 [libkv](https://github.com/docker/libkv) (一个键值存储抽象库)来协调跨机器。这个键值存储是另一个插件接口,并且是非常低级的(键和值,没有其他含义)。 要在 Kubernetes 集群中运行类似 Docker's overlay 驱动程序,我们要么需要集群管理员来运行 [consul](https://github.com/hashicorp/consul), [etcd](https://github.com/coreos/etcd) 或 [zookeeper](https://zookeeper.apache.org/) 的整个不同实例 (see [multi-host networking](https://docs.docker.com/engine/userguide/networking/get-started-overlay/)) 否则我们必须提供我们自己的 libkv 实现,那被 Kubernetes 支持。 + + + +后者听起来很有吸引力,并且我们尝试实现它,但 libkv 接口是非常低级的,并且架构在内部定义为 Docker 。我们必须直接暴露我们的底层键值存储,或者提供键值语义(在我们的结构化API之上,它本身是在键值系统上实现的)。对于性能,可伸缩性和安全性原因,这些都不是很有吸引力。最终结果是,当使用 Docker 网络的目标是简化事情时,整个系统将显得更加复杂。 + + + +对于愿意并且能够运行必需的基础架构以满足 Docker 全局驱动程序并自己配置 Docker 的用户, Docker 网络应该“正常工作。” Kubernetes 不会妨碍这样的设置,无论项目的方向如何,该选项都应该可用。但是对于默认安装,实际的结论是这对用户来说是一个不应有的负担,因此我们不能使用 Docker 的全局驱动程序(包括 "overlay" ),这消除了使用 Docker 插件的很多价值。 + + + +Docker 的网络模型做出了许多对 Kubernetes 无效的假设。在 docker 1.8 和 1.9 版本中,它包含一个从根本上有缺陷的“发现”实现,导致容器中的 `/etc/hosts` 文件损坏 ([docker #17190](https://github.com/docker/docker/issues/17190)) - 并且这不容易被关闭。在 1.10 版本中,Docker 计划 [捆绑一个新的DNS服务器](https://github.com/docker/docker/issues/17195),目前还不清楚是否可以关闭它。容器级命名不是 Kubernetes 的正确抽象 - 我们已经有了自己的服务命名,发现和绑定概念,并且我们已经有了自己的 DNS 模式和服务器(基于完善的 [SkyDNS](https://github.com/skynetservices/skydns) )。捆绑的解决方案不足以满足我们的需求,但不能禁用。 + + + +与本地/全局拆分正交, Docker 具有进程内和进程外( "remote" )插件。我们调查了是否可以绕过 libnetwork (从而跳过上面的问题)并直接驱动 Docker remote 插件。不幸的是,这意味着我们无法使用任何 Docker 进程中的插件,特别是 "bridge" 和 "overlay",这再次消除了 libnetwork 的大部分功能。 + + + +另一方面, CNI 在哲学上与 Kubernetes 更加一致。它比 CNM 简单得多,不需要守护进程,并且至少是合理的跨平台( CoreOS 的 [rkt](https://coreos.com/rkt/docs/) 容器运行时支持它)。跨平台意味着有机会启用跨运行时(例如 Docker , Rocket , Hyper )运行相同的网络配置。 它遵循 UNIX 的理念,即做好一件事。 + + + +此外,包装 CNI 插件并生成更加个性化的 CNI 插件是微不足道的 - 它可以通过简单的 shell 脚本完成。 CNM 在这方面要复杂得多。这使得 CNI 对于快速开发和迭代是有吸引力的选择。早期的原型已经证明,可以将 kubelet 中几乎 100% 的当前硬编码网络逻辑弹出到插件中。 + + + +我们调查了为 Docker [编写 "bridge" CNM驱动程序](https://groups.google.com/forum/#!topic/kubernetes-sig-network/5MWRPxsURUw) 并运行 CNI 驱动程序。事实证明这非常复杂。首先, CNM 和 CNI 模型非常不同,因此没有一种“方法”协调一致。 我们仍然有上面讨论的全球与本地和键值问题。假设这个驱动程序会声明自己是本地的,我们必须从 Kubernetes 获取有关逻辑网络的信息。 + + + +不幸的是, Docker 驱动程序很难映射到像 Kubernetes 这样的其他控制平面。具体来说,驱动程序不会被告知连接容器的网络名称 - 只是 Docker 内部分配的 ID 。这使得驱动程序很难映射回另一个系统中存在的任何网络概念。 + + + +这个问题和其他问题已由网络供应商提出给 Docker 开发人员,并且通常关闭为“按预期工作”,([libnetwork #139](https://github.com/docker/libnetwork/issues/139), [libnetwork #486](https://github.com/docker/libnetwork/issues/486), [libnetwork #514](https://github.com/docker/libnetwork/pull/514), [libnetwork #865](https://github.com/docker/libnetwork/issues/865), [docker #18864](https://github.com/docker/docker/issues/18864)),即使它们使非 Docker 第三方系统更难以与之集成。在整个调查过程中, Docker 明确表示他们对偏离当前路线或委托控制的想法不太欢迎。这对我们来说非常令人担忧,因为 Kubernetes 补充了 Docker 并增加了很多功能,但它存在于 Docker 之外。 + + + +出于所有这些原因,我们选择投资 CNI 作为 Kubernetes 插件模型。这会有一些不幸的副作用。它们中的大多数都相对较小(例如, `docker inspect` 不会显示 IP 地址),但有些是重要的。特别是,由 `docker run` 启动的容器可能无法与 Kubernetes 启动的容器通信,如果网络集成商想要与 Kubernetes 完全集成,则必须提供 CNI 驱动程序。另一方面, Kubernetes 将变得更简单,更灵活,早期引入的许多丑陋的(例如配置 Docker 使用我们的网桥)将会消失。 + + + +当我们沿着这条道路前进时,我们肯定会保持眼睛和耳朵的开放,以便更好地整合和简化。如果您对我们如何做到这一点有所想法,我们真的希望听到它们 - 在 [slack](http://slack.k8s.io/) 或者 [network SIG mailing-list](https://groups.google.com/forum/#!forum/kubernetes-sig-network) 找到我们。 + +Tim Hockin, Software Engineer, Google diff --git a/content/zh/blog/_posts/2016-02-00-Kubecon-Eu-2016-Kubernetes-Community-In.md b/content/zh/blog/_posts/2016-02-00-Kubecon-Eu-2016-Kubernetes-Community-In.md new file mode 100644 index 0000000000..d4ee22a2b1 --- /dev/null +++ b/content/zh/blog/_posts/2016-02-00-Kubecon-Eu-2016-Kubernetes-Community-In.md @@ -0,0 +1,84 @@ +--- +title: " KubeCon EU 2016:伦敦 Kubernetes 社区 " +date: 2016-02-24 +slug: kubecon-eu-2016-kubernetes-community-in +url: /blog/2016/02/Kubecon-Eu-2016-Kubernetes-Community-In +--- + + + + +KubeCon EU 2016 是首届[欧洲 Kubernetes](http://kubernetes.io/) 社区会议,紧随 2015 年 11 月召开的北美会议。KubeCon 致力于为 [Kubernetes](http://kubernetes.io/) 爱好者、产品用户和周围的生态系统提供教育和社区参与。 + + +快来加入我们在伦敦,与 Kubernetes 社区的数百人一起出去,体验各种深入的技术专家讲座和用例。 + + +不要错过这些优质的演讲: + + + +* “Kubernetes 硬件黑客:通过旋钮、推杆和滑块探索 Kubernetes API” 演讲者 Ian Lewis 和 Brian Dorsey,谷歌开发布道师* [http://sched.co/6Bl3](http://sched.co/6Bl3) + +* “rktnetes: 容器运行时和 Kubernetes 的新功能” 演讲者 Jonathan Boulle, CoreOS 的主程 -* [http://sched.co/6BY7](http://sched.co/6BY7) + +* “Kubernetes 文档:贡献、修复问题、收集奖金” 作者:John Mulhausen,首席技术作家,谷歌 -* [http://sched.co/6BUP](http://sched.co/6BUP)  +* “[OpenStack 在 Kubernetes 的世界中扮演什么角色?](https://kubeconeurope2016.sched.org/event/6BYC/what-is-openstacks-role-in-a-kubernetes-world?iframe=yes&w=i:0;&sidebar=yes&bg=no#?iframe=yes&w=i:100;&sidebar=yes&bg=no)” 作者:Thierry carez, OpenStack 基金会工程总监 -* http://sched.co/6BYC +* “容器调度的实用指南” 作者:Mandy Waite,开发者倡导者,谷歌 -* [http://sched.co/6BZa](http://sched.co/6BZa) + +* “[《纽约时报》编辑部正在制作 Kubernetes](https://kubeconeurope2016.sched.org/event/67f2/kubernetes-in-production-in-the-new-york-times-newsroom?iframe=yes&w=i:0;&sidebar=yes&bg=no#?iframe=yes&w=i:100;&sidebar=yes&bg=no)” Eric Lewis,《纽约时报》网站开发人员 -* [http://sched.co/67f2](http://sched.co/67f2) +* “[使用 NGINX 为 Kubernetes 创建一个高级负载均衡解决方案](https://kubeconeurope2016.sched.org/event/6Bc9/creating-an-advanced-load-balancing-solution-for-kubernetes-with-nginx?iframe=yes&w=i:0;&sidebar=yes&bg=no#?iframe=yes&w=i:100;&sidebar=yes&bg=no)” 作者:Andrew Hutchings, NGINX 技术产品经理 -* http://sched.co/6Bc9 +* 还有更多 http://kubeconeurope2016.sched.org/ + + +[在这里](https://ti.to/kubecon/kubecon-eu-2016)获取您的 KubeCon EU 门票。 + + +会场地址:CodeNode * 英国伦敦南广场 10 号 +酒店住宿:[酒店](https://skillsmatter.com/contact-us) +网站:[kubecon.io] (https://www.kubecon.io/) +推特:[@KubeConio] (https://twitter.com/kubeconio) +谷歌是 KubeCon EU 2016 的钻石赞助商。下个月 3 月 10 - 11 号来伦敦,参观 13 号展位,了解 Kubernetes,Google Container Engine(GKE),Google Cloud Platform 的所有信息! + + + +_KubeCon 是由 KubeAcademy、LLC 组织的,这是一个由社区驱动的开发者团体,专注于开发人员的教育和 kubernet.com 的推广 +-* Sarah Novotny, 谷歌的 Kubernetes 社区经理 + diff --git a/content/zh/blog/_posts/2016-02-00-Kubernetes-Community-Meeting-Notes.md b/content/zh/blog/_posts/2016-02-00-Kubernetes-Community-Meeting-Notes.md new file mode 100644 index 0000000000..5d1037f747 --- /dev/null +++ b/content/zh/blog/_posts/2016-02-00-Kubernetes-Community-Meeting-Notes.md @@ -0,0 +1,117 @@ +--- +title: " Kubernetes 社区会议记录 - 20160204 " +date: 2016-02-09 +slug: kubernetes-community-meeting-notes +url: /blog/2016/02/Kubernetes-Community-Meeting-Notes +--- + + +#### 2月4日 - rkt演示(祝贺 1.0 版本, CoreOS!), eBay 将 k8s 放在 Openstack 上并认为 Openstack 在 k8s, SIG 和片状测试激增方面取得了进展。 + + +Kubernetes 贡献社区在每周四 10:00 PT 开会,通过视频会议讨论项目状态。以下是最近一次会议的笔记。 + + +* 书记员:Rob Hirschfeld +* 演示视频(20分钟):CoreOS rkt + Kubernetes[Shaya Potter] + * 期待在未来几个月内看到与rkt和k8s的整合(“rkt-netes”)。 还没有集成到 v1.2版本中。 + * Shaya 做了一个演示(8分钟的会议视频参考) + * rkt的CLI显示了旋转容器 + * [注意:音频在点数上是乱码] + * 关于 k8s&rkt 整合的讨论 + * 下周 rkt 社区同步:https://groups.google.com/forum/#!topic/rkt-dev/FlwZVIEJGbY + * Dawn Chen: + * 将 rkt 与 kubernetes 集成的其余问题:1)cadivsor 2) DNS 3)与日志记录相关的错误 + * 但是需要在 e2e 测试套件上做更多的工作 + +* 用例(10分钟):在 OpenStack 上的 eBay k8s 和 k8s 上的 OpenStack [Ashwin Raveendran] + * eBay 目前正在 OpenStack 上运行 Kubernetes + * eBay 的目标是管理带有 k8s 的 OpenStack 控制平面。目标是实现升级。 + * OpenStack Kolla 为控制平面创建容器。使用 Ansible+Docker 来管理容器。 + * 致力于 k8s 控制计划管理 - Saltstack 被证明是他们想运营的规模的管理挑战。寻找 k8s 控制平面的自动化管理。 + +* SIG 报告 +* 测试更新 [Jeff, Joe, 和 Erick] + * 努力使有助于 K8s 的工作流程更容易理解 + * [pull/19714][1]有 bot 流程图来帮助用户理解 + * 需要一种一致的方法来运行测试 w/hacking 配置脚本(你现在必须伪造一个 Jenkins 进程) + * 想要创建必要的基础设施,使测试设置不那么薄弱 + * 想要将测试开始(单次或完整)与 Jenkins分离 + * 目标是指出你有一个可以指向任何集群的脚本 + * 演示包括 Google 内部视图 - 努力尝试获取外部视图。 + * 希望能够收集测试运行结果 + * Bob Wise 不赞同在 v1.3 版本进行测试方面的基础设施建设。 + * 关于测试实践的长期讨论… + * 我们希望在多个平台上进行测试的共识。 + * 为测试报告提供一个全面转储会很有帮助 + * 可以使用"phone-home"收集异常 + + + +* 1.2发布观察 +* CoC [Sarah] +* GSoC [Sarah] + + +要参与 Kubernetes 社区,请考虑加入我们的[Slack 频道][2],查看 GitHub上的 [Kubernetes 项目][3],或加入[Kubernetes-dev Google 小组][4]。如果你真的很兴奋,你可以完成上述所有工作并加入我们的下一次社区对话-2016年2月11日。请将您自己或您想要了解的主题添加到[议程][5]并通过加入[此组][6]来获取日历邀请。 + + "https://youtu.be/IScpP8Cj0hw?list=PL69nYSiGNLP1pkHsbPjzAewvMgGUpkCnJ" + + +[1]: https://github.com/kubernetes/kubernetes/pull/19714 +[2]: http://slack.k8s.io/ +[3]: https://github.com/kubernetes/ +[4]: https://groups.google.com/forum/#!forum/kubernetes-dev +[5]: https://docs.google.com/document/d/1VQDIAB0OqiSjIHI8AWMvSdceWhnz56jNpZrLs6o7NJY/edit# +[6]: https://groups.google.com/forum/#!forum/kubernetes-community-video-chat diff --git a/content/zh/blog/_posts/2016-04-Kubernetes-Network-Policy-APIs.md b/content/zh/blog/_posts/2016-04-Kubernetes-Network-Policy-APIs.md deleted file mode 100644 index 072ec679f3..0000000000 --- a/content/zh/blog/_posts/2016-04-Kubernetes-Network-Policy-APIs.md +++ /dev/null @@ -1,182 +0,0 @@ - - ---- -title: "SIG-Networking: Kubernetes Network Policy APIs Coming in 1.3 " -date: 2016-04-18 -slug: kubernetes-network-policy-apis -url: /blog/2016/04/Kubernetes-Network-Policy-APIs ---- - - - -编者按:这一周,我们的封面主题是 [Kubernetes 特别兴趣小组](https://github.com/kubernetes/kubernetes/wiki/Special-Interest-Groups-(SIGs));今天的文章由网络兴趣小组撰写,来谈谈 1.3 版本中即将出现的网络策略 API - 针对安全,隔离和多租户的策略。 - - - -自去年下半年起,[Kubernetes 网络特别兴趣小组](https://kubernetes.slack.com/messages/sig-network/)经常定期开会,讨论如何将网络策略带入到 Kubernetes 之中,现在,我们也将慢慢看到这些工作的成果。 - - - -很多用户经常会碰到的一个问题是, Kubernetes 的开放访问网络策略并不能很好地满足那些需要对 pod 或服务( service )访问进行更为精确控制的场景。今天,这个场景可以是在多层应用中,只允许临近层的访问。然而,随着组合微服务构建原生应用程序潮流的发展,如何控制流量在不同服务之间的流动会别的越发的重要。 - - - -在大多数的(公共的或私有的) IaaS 环境中,这种网络控制通常是将 VM 和“安全组”结合,其中安全组中成员的通信都是通过一个网络策略或者访问控制表( Access Control List, ACL )来定义,以及借助于网络包过滤器来实现。 - - - -“网络特别兴趣小组”刚开始的工作是确定 [特定的使用场景](https://docs.google.com/document/d/1blfqiH4L_fpn33ZrnQ11v7LcYP0lmpiJ_RaapAPBbNU/edit?pref=2&pli=1#) ,这些用例需要基本的网络隔离来提升安全性。 -让这些API恰如其分地满足简单、共通的用例尤其重要,因为它们将为那些服务于 Kubernetes 内多租户,更为复杂的网络策略奠定基础。 - - - -根据这些应用场景,我们考虑了集中不同的方法,然后定义了一个最简[策略规范](https://docs.google.com/document/d/1qAm-_oSap-f1d6a-xRTj6xaH1sYQBfK36VyjB5XOZug/edit)。 -基本的想法是,如果是根据命名空间的不同来进行隔离,那么就会根据所被允许的流量类型的不同,来选择特定的 pods 。 - - - -快速支持这个实验性 API 的办法是往 API 服务器上加入一个 `ThirdPartyResource` 扩展,这在 Kubernetes 1.2 就能办到。 - - - -如果你还不是很熟悉这其中的细节, Kubernetes API 是可以通过定义 `ThirdPartyResources` 扩展在特定的 URL 上创建一个新的 API 端点。 - -#### third-party-res-def.yaml - -``` -kind: ThirdPartyResource -apiVersion: extensions/v1beta1 -metadata: - - name: network-policy.net.alpha.kubernetes.io -description: "Network policy specification" -versions: - - name: v1alpha1 -``` - -``` -$kubectl create -f third-party-res-def.yaml -``` - - -这条命令会创建一个 API 端点(每个命名空间各一个): - -``` -/net.alpha.kubernetes.io/v1alpha1/namespace/default/networkpolicys/ -``` - - - - -第三方网络控制器可以监听这些端点,根据资源的创建,修改或者删除作出必要的响应。 -_注意:在接下来的 Kubernetes 1.3 发布中, Network Policy API 会以 beta API 的形式出现,这也就不需要像上面那样,创建一个 `ThirdPartyResource` API 端点了。_ - - - -网络隔离默认是关闭的,因而,所有的 pods 之间可以自由地通信。 -然而,很重要的一点是,一旦开通了网络隔离,所有命名空间下的所有 pods 之间的通信都会被阻断,换句话说,开通隔离会改变 pods 的行为。 - - - -网络隔离可以通过定义命名空间, `net.alpha.kubernetes.io` 里的 `network-isolation` 注释来开通关闭: - -``` -net.alpha.kubernetes.io/network-isolation: [on | off] -``` - - - -一旦开通了网络隔离,**一定需要使用** 显示的网络策略来允许 pod 间的通信。 - - - -一个策略规范可以被用到一个命名空间中,来定义策略的细节(如下所示): - -``` -POST /apis/net.alpha.kubernetes.io/v1alpha1/namespaces/tenant-a/networkpolicys/ -{ - "kind": "NetworkPolicy", - "metadata": { - "name": "pol1" - }, - "spec": { - "allowIncoming": { - "from": [ - { - "pods": { - "segment": "frontend" - } - } - ], - "toPorts": [ - { - "port": 80, - "protocol": "TCP" - } - ] - }, - "podSelector": { - "segment": "backend" - } - } -} -``` - - - -在这个例子中,**tenant-a** 空间将会使用 **pol1** 策略。 -具体而言,带有 **segment** 标签为 **backend** 的 pods 会允许 **segment** 标签为 **frontend** 的 pods 访问其端口 80 。 - - - - - -今天,[Romana](http://romana.io/), [OpenShift](https://www.openshift.com/), [OpenContrail](http://www.opencontrail.org/) 以及 [Calico](http://projectcalico.org/) 都已经支持在命名空间和pods中使用网络策略。 -而 Cisco 和 VMware 也在努力实现支持之中。 -Romana 和 Calico 已经在最近的 KubeCon 中展示了如何在 Kubernetes 1.2 下使用这些功能。 -你可以在这里看到他们的演讲: -[Romana](https://www.youtube.com/watch?v=f-dLKtK6qCs) ([幻灯片](http://www.slideshare.net/RomanaProject/kubecon-london-2016-ronana-cloud-native-sdn)), -[Calico](https://www.youtube.com/watch?v=p1zfh4N4SX0) ([幻灯片](http://www.slideshare.net/kubecon/kubecon-eu-2016-secure-cloudnative-networking-with-project-calico)). - - - -**这是如何工作的** - - - -每套解决方案都有自己不同的具体实现。尽管今天,他们都借助于每种主机上( on-host )的实现机制,但未来的实现可以通过将策略使用在 hypervisor 上,亦或是直接使用到网络本身上来达到同样的目的。 - - - -外部策略控制软件(不同实现各有不同)可以监听 pods 创建以及新加载策略的 API 端点。 -当产生一个需要策略配置的事件之后,监听器会确认这个请求,相应的,控制器会配置接口,使用该策略。 -下面的图例展示了 API 监视器和策略控制器是如何通过主机代理在本地应用网络策略的。 -这些 pods 的网络接口是使用过主机上的 CNI 插件来进行配置的(并未在图中注明)。 - - ![controller.jpg](https://lh5.googleusercontent.com/zMEpLMYmask-B-rYWnbMyGb0M7YusPQFPS6EfpNOSLbkf-cM49V7rTDBpA6k9-Zdh2soMul39rz9rHFJfL-jnEn_mHbpg0E1WlM-wjU-qvQu9KDTQqQ9uBmdaeWynDDNhcT3UjX5) - - - - -如果你一直受网络隔离或安全考虑的困扰,而犹豫要不要使用 Kubernetes 来开发应用程序,这些新的网络策略将会极大地解决你这方面的需求。并不需要等到 Kubernetes 1.3 ,现在就可以通过 `ThirdPartyResource` 的方式来使用这个实现性 API 。 - - - - -如果你对 Kubernetes 和网络感兴趣,可以通过下面的方式参与、加入其中: - -- 我们的[网络 slack channel](https://kubernetes.slack.com/messages/sig-network/) -- 我们的[Kubernetes 特别网络兴趣小组](https://groups.google.com/forum/#!forum/kubernetes-sig-network) 邮件列表 - - - -网络“特别兴趣小组”每两周下午三点(太平洋时间)开会,地址是[SIG-Networking hangout](https://zoom.us/j/5806599998). - -_--Chris Marino, Co-Founder, Pani Networks_ diff --git a/content/zh/blog/_posts/2016-04-Kubernetes-On-Aws_15.md b/content/zh/blog/_posts/2016-04-Kubernetes-On-Aws_15.md deleted file mode 100644 index c5de9e6a12..0000000000 --- a/content/zh/blog/_posts/2016-04-Kubernetes-On-Aws_15.md +++ /dev/null @@ -1,129 +0,0 @@ - - ---- -title: " 如何在AWS上部署安全,可审计,可复现的k8s集群 " -date: 2016-04-15 -slug: kubernetes-on-aws_15 -url: /blog/2016/04/Kubernetes-On-Aws_15 ---- - - - -_今天的客座文章是由Colin Hom撰写,[CoreOS](https://coreos.com/)的基础架构工程师。CoreOS致力于推广谷歌的基础架构模式(Google’s Infrastructure for Everyone Else, #GIFEE),让全世界的容器都能在CoreOS Linux, Tectonic 和 Quay上安全运行。_ - -_加入到我们的[柏林CoreOS盛宴](https://coreos.com/fest/),这是一个开源分布式系统主题的会议,在这里可以了解到更多关于CoreOS和Kubernetes的信息。_ - - - -在CoreOS, 我们一直都是在生产环境中大规模部署Kubernetes。今天我们非常兴奋地想分享一款工具,它能让你的Kubernetes生产环境大规模部署更加的轻松。Kube-aws这个工具可以用来在AWS上部署可审计,可复现的k8s集群,而CoreOS本身就在生产环境中使用它。 - - - -也许今天,你更多的可能是用手工的方式来拼接Kubernetes组件。但有了这个工具之后,Kubernetes可以流水化地打包、交付,节省时间,减少了相互间的依赖,更加快捷地实现生产环境的部署。 - - - -借助于一个简单的模板系统,来生成集群配置,这么做是因为一套声明式的配置模板可以版本控制,审计以及重复部署。而且,由于整个创建过程只用到了[AWS CloudFormation](https://aws.amazon.com/cloudformation/) 和 cloud-init,你也就不需要额外用到其它的配置管理工具。开箱即用! - - - -如果要跳过演讲,直接了解这个项目,可以看看[kube-aws的最新发布](https://github.com/coreos/coreos-kubernetes/releases),支持Kubernetes 1.2.x。如果要部署集群,可以参考[文档]](https://coreos.com/kubernetes/docs/latest/kubernetes-on-aws.html). - - -**为什么是kube-aws?安全,可审计,可复现** - - -Kube-aws设计初衷有三个目标。 - - - -**安全** : TLS 资源在嵌入到CloudFormation JSON之前,通过[AWS 秘钥管理服务](https://aws.amazon.com/kms/)加密。通过单独管理KMS密钥的[IAM 策略](http://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies.html),可以将CloudFormation栈的访问与TLS秘钥的访问分离开。 - - - -**可审计** : kube-aws是围绕集群资产的概念来创建。这些配置和账户资产是对集群的完全描述。由于KMS被用来加密TLS资产,因而可以无所顾忌地将未加密的CloudFormation栈 JSON签入到版本控制服务中。 - - - -**可重复** : _--export_ 选项将参数化的集群定义打包成一整个JSON文件,对应一个CloudFormation栈。这个文件可以版本控制,然后,如果需要的话,通过现有的部署工具直接提交给CloudFormation API。 - - -**如何开始用kube-aws** - - -在此基础之上,kube-aws也实现了一些功能,使得在AWS上部署Kubernetes集群更加容易,灵活。下面是一些例子。 - - -**Route53集成** : Kube-aws 可以管理你的集群DNS记录,作为配置过程的一部分。 - -cluster.yaml -``` -externalDNSName: my-cluster.kubernetes.coreos.com - -createRecordSet: true - -hostedZone: kubernetes.coreos.com - -recordSetTTL: 300 -``` - - -**现有VPC支持** : 将集群部署到现有的VPC上。 - -cluster.yaml -``` -vpcId: vpc-xxxxx - -routeTableId: rtb-xxxxx -``` - - -**验证** : kube-aws 支持验证 cloud-init 和 CloudFormation定义,以及集群栈会集成用到的外部资源。例如,下面就是一个cloud-config,外带一个拼写错误的参数: - -userdata/cloud-config-worker -``` -#cloud-config - -coreos: - - flannel: - interrface: $private\_ipv4 - etcd\_endpoints: {{ .ETCDEndpoints }} -``` - -$ kube-aws validate - - \> Validating UserData... - Error: cloud-config validation errors: - UserDataWorker: line 4: warning: unrecognized key "interrface" - - -考虑如何起步?看看[kube-aws 文档](https://coreos.com/kubernetes/docs/latest/kubernetes-on-aws.html)! - - -**未来的工作** - - -一如既往,kube-aws的目标是让生产环境部署更加的简单。尽管我们现在在AWS下使用kube-aws进行生产环境部署,但是这个项目还是pre-1.0,所以还有很多的地方,kube-aws需要考虑、扩展。 - - -**容错** : CoreOS坚信 Kubernetes on AWS是强健的平台,适于容错、自恢复部署。在接下来的几个星期,kube-aws将会迎接新的考验:混世猴子([Chaos Monkey](https://github.com/Netflix/SimianArmy/wiki/Chaos-Monkey))测试 - 控制平面以及全部! - - -**零停机更新** : 更新CoreOS节点和Kubernetes组件不需要停机,也不需要考虑实例更新策略(instance replacement strategy)的影响。 - - -有一个[github issue](https://github.com/coreos/coreos-kubernetes/issues/340)来追踪这些工作进展。我们期待你的参与,提交issue,或是直接贡献。 - - -_想要更多地了解Kubernetes,来[柏林CoreOS盛宴](https://coreos.com/fest/)看看,- 五月 9-10, 2016_ - - -_– Colin Hom, 基础架构工程师, CoreOS_ diff --git a/content/zh/blog/_posts/2016-07-00-Citrix-Netscaler-And-Kubernetes.md b/content/zh/blog/_posts/2016-07-00-Citrix-Netscaler-And-Kubernetes.md new file mode 100644 index 0000000000..6915b8482a --- /dev/null +++ b/content/zh/blog/_posts/2016-07-00-Citrix-Netscaler-And-Kubernetes.md @@ -0,0 +1,72 @@ +--- +title: " Citrix + Kubernetes = 全垒打 " +date: 2016-07-14 +slug: citrix-netscaler-and-kubernetes +url: /blog/2016/07/Citrix-Netscaler-And-Kubernetes +--- + + + + +编者按:今天的客座文章来自 Citrix Systems 的产品管理总监 Mikko Disini,他分享了他们在 Kubernetes 集成上的合作经验。 _ + + +技术合作就像体育运动。如果你能像一个团队一样合作,你就能在最后关头取得胜利。这就是我们对谷歌云平台团队的经验。 + + +最近,我们与 Google 云平台(GCP)联系,代表 Citrix 客户以及更广泛的企业市场,希望就工作负载的迁移进行协作。此迁移需要将 [NetScaler Docker 负载均衡器]https://www.citrix.com/blogs/2016/06/20/the-best-docker-load-balancer-at-dockercon-in-seattle-this-week/) CPX 包含到 Kubernetes 节点中,并解决将流量引入 CPX 代理的任何问题。 + + + +**为什么是 NetScaler 和 Kubernetes** + + + +1. Citrix 的客户希望他们开始使用 Kubernetes 部署他们的容器和微服务体系结构时,能够像当初迁移到云计算时一样,享有 NetScaler 所提供的第 4 层到第 7 层能力  +2. Kubernetes 提供了一套经过验证的基础设施,可用来运行容器和虚拟机,并自动交付工作负载; +3. NetScaler CPX 提供第 4 层到第 7 层的服务,并为日志和分析平台 [NetScaler 管理和分析系统](https://www.citrix.com/blogs/2016/05/24/introducing-the-next-generation-netscaler-management-and-analytics-system/) 提供高效的度量数据。 + + +我希望我们所有与技术合作伙伴一起工作的经验都能像与 GCP 一起工作一样好。我们有一个列表,包含支持我们的用例所需要解决的问题。我们能够快速协作形成解决方案。为了解决这些问题,GCP 团队提供了深入的技术支持,与 Citrix 合作,从而使得 NetScaler CPX 能够在每台主机上作为客户端代理启动运行。 + + +接下来,需要在 GCP 入口负载均衡器的数据路径中插入 NetScaler CPX,使 NetScaler CPX 能够将流量分散到前端 web 服务器。NetScaler 团队进行了修改,以便 NetScaler CPX 监听 API 服务器事件,并配置自己来创建 VIP、IP 表规则和服务器规则,以便跨前端应用程序接收流量和负载均衡。谷歌云平台团队提供反馈和帮助,验证为克服技术障碍所做的修改。完成了! + + +NetScaler CPX 用例在 [Kubernetes 1.3](https://kubernetes.io/blog/2016/07/kubernets-1.3 - bridge -cloud-native-and-enterprise-workload) 中提供支持。Citrix 的客户和更广泛的企业市场将有机会基于 Kubernetes 享用 NetScaler 服务,从而降低将工作负载转移到云平台的阻力。  + + +您可以在[此处](https://www.citrix.com/networking/microservices.html)了解有关 NetScaler CPX 的更多信息。 + + +_ -- Mikko Disini,Citrix Systems NetScaler 产品管理总监 + diff --git a/content/zh/blog/_posts/2016-07-00-Dashboard-Web-Interface-For-Kubernetes.md b/content/zh/blog/_posts/2016-07-00-Dashboard-Web-Interface-For-Kubernetes.md new file mode 100644 index 0000000000..467d169c0f --- /dev/null +++ b/content/zh/blog/_posts/2016-07-00-Dashboard-Web-Interface-For-Kubernetes.md @@ -0,0 +1,139 @@ +--- +title: " Dashboard - Kubernetes 的全功能 Web 界面 " +date: 2016-07-15 +slug: dashboard-web-interface-for-kubernetes +url: /blog/2016/07/Dashboard-Web-Interface-For-Kubernetes +--- + + + + + +_编者按:这篇文章是[一系列深入的文章](https://kubernetes.io/blog/2016/07/five-days-of-kubernetes-1.3) 中关于Kubernetes 1.3的新内容的一部分_ +[Kubernetes Dashboard](http://github.com/kubernetes/dashboard)是一个旨在为 Kubernetes 世界带来通用监控和操作 Web 界面的项目。三个月前,我们[发布](https://kubernetes.io/blog/2016/04/building-awesome-user-interfaces-for-kubernetes)第一个面向生产的版本,从那时起 dashboard 已经做了大量的改进。在一个 UI 中,您可以在不离开浏览器的情况下,与 Kubernetes 集群执行大多数可能的交互。这篇博客文章分解了最新版本中引入的新功能,并概述了未来的路线图。 + + + +**全功能的 Dashboard** + +由于社区和项目成员的大量贡献,我们能够为[Kubernetes 1.3发行版](https://kubernetes.io/blog/2016/07/kubernetes-1.3-bridging-cloud-native-and-enterprise-workloads)提供许多新功能。我们一直在认真听取用户的反馈(参见[摘要信息图表](http://static.lwy.io/img/kubernetes_dashboard_infographic.png)),并解决了最高优先级的请求和难点。 +--> + + + +Dashboard UI 现在处理所有工作负载资源。这意味着无论您运行什么工作负载类型,它都在 web 界面中可见,并且您可以对其进行操作更改。例如,可以使用[Pet Sets](/docs/user-guide/petset/)修改有状态的 mysql 安装,使用部署对 web 服务器进行滚动更新,或使用守护程序安装群集监视。 + + + + [![](https://lh3.googleusercontent.com/p9bMGxPx4jE6_Z2KB-MktmyuAxyFst-bEk29M_Bn0Bj5ul7uzinH6u5WjHsMmqhGvBwlABZt06dwQ5qkBZiLq_EM1oddCmpwChvXDNXZypaS5l8uzkKuZj3PBUmzTQT4dgDxSXgz) ](https://lh3.googleusercontent.com/p9bMGxPx4jE6_Z2KB-MktmyuAxyFst-bEk29M_Bn0Bj5ul7uzinH6u5WjHsMmqhGvBwlABZt06dwQ5qkBZiLq_EM1oddCmpwChvXDNXZypaS5l8uzkKuZj3PBUmzTQT4dgDxSXgz) + + + +除了查看资源外,还可以创建、编辑、更新和删除资源。这个特性支持许多用例。例如,您可以杀死一个失败的 pod,对部署进行滚动更新,或者只组织资源。您还可以导出和导入云应用程序的 yaml 配置文件,并将它们存储在版本控制系统中。 + + + + ![](https://lh6.googleusercontent.com/zz-qjNcGgvWXrK1LIipUdIdPyeWJ1EyPVJxRnSvI6pMcLBkxDxpQt-ObsIiZsS_X0RjVBWtXYO5TCvhsymb__CGXFzKuPUnUrB4HKnAMsxtYdWLwMmHEb8c9P9Chzlo5ePHRKf5O) + + + +这个版本包括一个用于管理和操作用例的集群节点的 beta 视图。UI 列出集群中的所有节点,以便进行总体分析和快速筛选有问题的节点。details 视图显示有关该节点的所有信息以及指向在其上运行的 pod 的链接。 + + + + ![](https://lh6.googleusercontent.com/3CSTUy-8Tz-yAL9tCqxNUqMcWJYKK0dwk7kidE9zy-L-sXFiD4A4Y2LKEqbJKgI6Fl6xbzYxsziI8dULVXPJbu6eU0ci7hNtqi3tTuhdbVD6CG3EXw151fvt2MQuqumHRbab6g-_) + + + +我们随发行版提供的还有许多小范围的新功能,即:支持命名空间资源、国际化、性能改进和许多错误修复(请参阅[发行说明](https://github.com/kubernetes/dashboard/releases/tag/v1.1.0)中的更多内容)。所有这些改进都会带来更好、更简单的产品用户体验。 + + + +**Future Work** + + + +该团队对跨越多个用例的未来有着雄心勃勃的计划。我们还对所有功能请求开放,您可以在我们的[问题跟踪程序](https://github.com/kubernetes/dashboard/issues)上发布这些请求。 + + + +以下是我们接下来几个月的重点领域: + +- [Handle more Kubernetes resources](https://github.com/kubernetes/dashboard/issues/961) - 显示群集用户可能与之交互的所有资源。一旦完成,dashboard 就可以完全替代cli。 +- [Monitoring and troubleshooting](https://github.com/kubernetes/dashboard/issues/962) - 将资源使用统计信息/图表添加到 Dashboard 中显示的对象。这个重点领域将允许对云应用程序进行可操作的调试和故障排除。 +- [Security, auth and logging in](https://github.com/kubernetes/dashboard/issues/964) - 使仪表板可从群集外部的网络访问,并使用自定义身份验证系统。 + + + +**联系我们** + + + +我们很乐意与您交谈并听取您的反馈! + +- 请在[SIG-UI邮件列表](https://groups.google.com/forum/向我们发送电子邮件!论坛/kubernetes sig ui) +- 在 kubernetes slack 上与我们聊天。[#SIG-UI channel](https://kubernetes.slack.com/messages/sig-ui/) +- 参加我们的会议:东部时间下午4点。请参阅[SIG-UI日历](https://calendar.google.com/calendar/embed?src=google.com_52lm43hc2kur57dgkibltqc6kc%40group.calendar.google.com&ctz=Europe/Warsaw)了解详细信息。 diff --git a/content/zh/blog/_posts/2016-07-00-Oh-The-Places-You-Will-Go.md b/content/zh/blog/_posts/2016-07-00-Oh-The-Places-You-Will-Go.md new file mode 100644 index 0000000000..95adefc352 --- /dev/null +++ b/content/zh/blog/_posts/2016-07-00-Oh-The-Places-You-Will-Go.md @@ -0,0 +1,89 @@ +--- +title: " Kubernetes 生日快乐。哦,这是你要去的地方! " +date: 2016-07-21 +slug: oh-the-places-you-will-go +url: /blog/2016/07/Oh-The-Places-You-Will-Go +--- + + + + + +_编者按,今天的嘉宾帖子来自一位独立的 kubernetes 撰稿人 Justin Santa Barbara,分享了他对项目从一开始到未来发展的思考。_ + +**亲爱的 K8s,** + +_很难相信你是唯一的一个 - 成长这么快的。在你一岁生日的时候,我想我可以写一个小纸条,告诉你为什么我在你出生的时候那么兴奋,为什么我觉得很幸运能成为抚养你长大的一员,为什么我渴望看到你继续成长!_ + + + +_--Justin_ + +你从一个优秀的基础 - 良好的声明性功能开始,它是围绕一个具有良好定义的模式和机制的坚实的 API 构建的,这样我们就可以向前发展了。果然,在你的第一年里,你增长得如此之快:autoscaling、HTTP load-balancing support (Ingress)、support for persistent workloads including clustered databases (PetSets)。你已经和更多的云交了朋友(欢迎 azure 和 openstack 加入家庭),甚至开始跨越区域和集群(Federation)。这些只是一些最明显的变化 - 在你的大脑里发生了太多的变化! + +我觉得你一直保持开放的态度真是太好了 - 你好像把所有的东西都写在 github 上 - 不管是好是坏。我想我们在这方面都学到了很多,比如让工程师做缩放声明的风险,然后在没有完全相同的精确性和严谨性框架的情况下,将这些声明与索赔进行权衡。但我很自豪你选择了不降低你的标准,而是上升到挑战,只是跑得更快 - 这可能不是最现实的办法,但这是唯一的方式能移动山! + + + +然而,不知何故,你已经设法避免了许多其他开源软件陷入的共同死胡同,特别是当那些项目越来越大,开发人员最终要做的比直接使用它更多的时候。你是怎么做到的?有一个很可能是虚构的故事,讲的是 IBM 的一名员工犯了一个巨大的错误,被传唤去见大老板,希望被解雇,却被告知“我们刚刚花了几百万美元培训你。我们为什么要解雇你?“。尽管谷歌对你进行了大量的投资(包括 redhat 和其他公司),但我有时想知道,我们正在避免的错误是否更有价值。有一个非常开放的开发过程,但也有一个“oracle”,它有时会通过告诉我们两年后如果我们做一个特定的设计决策会发生什么来纠正错误。这是你应该听的父母! + + + +所以,尽管你只有一岁,你真的有一个[旧灵魂](http://queue.acm.org/detail.cfm?ID=2898444)。我只是[很多人抚养你]中的一员(https://kubernetes.io/blog/2016/07/happy-k8sbday-1),但对我来说,能够与那些建立了这些令人难以置信的系统并拥有所有这些领域知识的人一起工作是一次极好的学习经历。然而,因为我们是白手起家(而不是采用现有的 Borg 代码),我们处于同一水平,仍然可以就如何培养你进行真正的讨论。好吧,至少和我们的水平一样接近,但值得称赞的是,他们都太好了,从来没提过! + +如果我选择两个聪明人做出的明智决定: + + + +- 标签和选择器给我们声明性的“pointers”,所以我们可以说“为什么”我们想要东西,而不是直接列出东西。这是如何扩展到[伟大高度]的秘密(https://kubernetes.io/blog/2016/07/thousand-instances-of-cassandra-using-kubernetes-pet-set);不是命名每一步,而是说“像第一步一样多走一千步”。 +- 控制器是状态同步器:我们指定目标,您的控制器将不遗余力地工作,使系统达到该状态。它们工作在强类型 API 基础上,并且贯穿整个代码,因此 Kubernetes 比一个大的程序多一百个小程序。仅仅从技术上扩展到数千个节点是不够的;这个项目还必须扩展到数千个开发人员和特性;控制器帮助我们达到目的。 + + + +等等我们就走!我们将取代那些控制器,建立更多,API 基金会让我们构建任何我们可以用这种方式表达的东西 - 大多数东西只是标签或注释远离!但你的思想不会由语言来定义:有了第三方资源,你可以表达任何你选择的东西。现在我们可以不用在 Kubernetes 建造Kubernetes 了,创造出与其他任何东西一样感觉是 Kubernetes 的一部分的东西。最近添加的许多功能,如ingress、DNS integration、autoscaling and network policies ,都已经完成或可以通过这种方式完成。最终,在这些事情发生之前很难想象你会是怎样的一个人,但是明天的标准功能可以从今天开始,没有任何障碍或看门人,甚至对一个听众来说也是这样。 + +所以我期待着看到越来越多的增长发生在离 Kubernetes 核心越来越远的地方。我们必须通过这些阶段来工作;从需要在 kubernetes 内核中发生的事情开始——比如用部署替换复制控制器。现在我们开始构建不需要核心更改的东西。但我们仍然在讨论基础设施和应用程序。接下来真正有趣的是:当我们开始构建依赖于 kubernetes api 的应用程序时。我们一直有使用 kubernetes api 进行自组装的 cassandra 示例,但我们还没有真正开始更广泛地探讨这个问题。正如 S3 APIs 改变了我们构建记忆事物的方式一样,我认为 k8s APIs 也将改变我们构建思考事物的方式。 + + + +所以我很期待你的二岁生日:我可以试着预测你那时的样子,但我知道你会超越我所能想象的最大胆的东西。哦,这是你要去的地方! + + +_-- Justin Santa Barbara, 独立的 Kubernetes 贡献者_ diff --git a/content/zh/blog/_posts/2017-10-00-Five-Days-Of-Kubernetes-18.md b/content/zh/blog/_posts/2017-10-00-Five-Days-Of-Kubernetes-18.md new file mode 100644 index 0000000000..979d5cd931 --- /dev/null +++ b/content/zh/blog/_posts/2017-10-00-Five-Days-Of-Kubernetes-18.md @@ -0,0 +1,72 @@ +--- +title: " Kubernetes 1.8 的五天 " +date: 2017-10-24 +slug: five-days-of-kubernetes-18 +url: /blog/2017/10/Five-Days-Of-Kubernetes-18 +--- + + + + +Kubernetes 1.8 已经推出,数百名贡献者在这个最新版本中推出了成千上万的提交。 + + +社区已经有超过 66,000 个提交在主仓库,并在主仓库之外继续快速增长,这标志着该项目日益成熟和稳定。仅 v1.7.0 到 v1.8.0,社区就记录了所有仓库的超过 120,000 次提交和 17839 次提交。 + + +在拥有 1400 多名贡献者,并且不断发展壮大的社区的帮助下,我们合并了 3000 多个 PR,并发布了 5000 多个提交,最后的 Kubernetes 1.8 在安全和工作负载方面添加了很多的更新。 +这一切都表明稳定性的提高,这是我们整个项目关注成熟[流程](https://github.com/kubernetes/sig-release)、形式化[架构](https://github.com/kubernetes/community/tree/master/sig-architecture)和加强 Kubernetes 的[治理模型](https://github.com/kubernetes/community/tree/master/community/elections/2017)的结果。 + + +虽然有很多改进,但我们在下面列出的这一系列深度文章中突出了一些关键特性。[跟随](https://twitter.com/kubernetesio)并了解存储,安全等方面的新功能和改进功能。 + + + +**第一天:** [Kubernetes 1.8 的五天](https://kubernetes.io/blog/2017/10/five-days-of-kubernetes-18) +**第二天:** [kubeadm v1.8 为 Kubernetes 集群引入了简单的升级](https://kubernetes.io/blog/2017/10/kubeadm-v18-released) +**第三天:** [Kubernetes v1.8 回顾:提升一个 Kubernetes 需要一个 Village](https://kubernetes.io/blog/2017/10/it-takes-village-to-raise-kubernetes) +**第四天:** [使用 RBAC,一般在 Kubernetes v1.8 中提供](https://kubernetes.io/blog/2017/10/using-rbac-generally-available-18) +**第五天:** [在 Kubernetes 执行网络策略](https://kubernetes.io/blog/2017/10/enforcing-network-policies-in-kubernetes) + + + +**链接** + + + +- 在 [Stack Overflow](http://stackoverflow.com/questions/tagged/kubernetes) 上发布问题(或回答问题) +- 加入 [K8sPort](http://k8sport.org/) 布道师的社区门户网站 +- 在 Twitter [@Kubernetesio](https://twitter.com/kubernetesio) 关注我们以获取最新更新 +- 与 [Slack](http://slack.k8s.io/) 上的社区联系 +- 参与 [GitHub](https://github.com/kubernetes/kubernetes) 上的 Kubernetes 项目 + + diff --git a/content/zh/blog/_posts/2017-11-00-Autoscaling-In-Kubernetes.md b/content/zh/blog/_posts/2017-11-00-Autoscaling-In-Kubernetes.md new file mode 100644 index 0000000000..87c9ccd74b --- /dev/null +++ b/content/zh/blog/_posts/2017-11-00-Autoscaling-In-Kubernetes.md @@ -0,0 +1,32 @@ +--- +title: " Kubernetes 中自动缩放 " +date: 2017-11-17 +slug: autoscaling-in-kubernetes +url: /blog/2017/11/Autoscaling-In-Kubernetes +--- + + + + +Kubernetes 允许开发人员根据当前的流量和负载自动调整集群大小和 pod 副本的数量。这些调整减少了未使用节点的数量,节省了资金和资源。 +在这次演讲中,谷歌的 Marcin Wielgus 将带领您了解 Kubernetes 中 pod 和 node 自动调焦的当前状态:它是如何工作的,以及如何使用它,包括在生产应用程序中部署的最佳实践。 + + +喜欢这个演讲吗? 12 月 6 日至 8 日,在 Austin 参加 KubeCon 关于扩展和自动化您的 Kubernetes 集群的更令人兴奋的会议。[现在注册](https://www.eventbrite.com/e/kubecon-cloudnativecon-north-america-registration-37824050754?_ga=2.9666039.317115486.1510003873-1623727562.1496428006)。 + + +一定要查看由 Ron Lipke, Gannet/USA Today Network, 平台即服务高级开发人员,在[公共云中自动化和测试产品就绪的 Kubernetes 集群](http://sched.co/CU64)。 + diff --git a/content/zh/blog/_posts/2018-03-Principles-Of-Container-App-Design.md b/content/zh/blog/_posts/2018-03-Principles-Of-Container-App-Design.md deleted file mode 100644 index 4797bb7986..0000000000 --- a/content/zh/blog/_posts/2018-03-Principles-Of-Container-App-Design.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: "Principles of Container-based Application Design" -date: 2018-03-15 -slug: principles-of-container-app-design -url: /blog/2018/03/Principles-Of-Container-App-Design ---- - - - -现如今,几乎所有的的应用程序都可以在容器中运行。但创建云原生应用,通过诸如 Kubernetes 的云原生平台更有效地自动化运行、管理容器化的应用却需要额外的工作。 -云原生应用需要考虑故障;即使是在底层架构发生故障时也需要可靠地运行。 -为了提供这样的功能,像 Kubernetes 这样的云原生平台需要向运行的应用程序强加一些契约和约束。 -这些契约确保应用可以在符合某些约束的条件下运行,从而使得平台可以自动化应用管理。 - - - -我已经为容器化应用如何之为云原生应用概括出了[七项原则][1]。 - -| ----- | -| ![][2] | -| Container Design Principles | - - - - -这里所述的七项原则涉及到构建时和运行时,两类关注点。 - - -#### 构建时 - - - -* **单一关注点:** 每个容器只解决一个关注点,并且完成的很好。 -* **自包含:** 一个容器只依赖Linux内核。额外的库要求可以在构建容器时加入。 -* **镜像不变性:** 容器化的应用意味着不变性,一旦构建完成,不需要根据环境的不同而重新构建。 - - -#### 运行时 - - - -* **高可观测性:** 每个容器必须实现所有必要的 API 来帮助平台以最好的方式来观测、管理应用。 -* **生命周期一致性:** 一个容器必须要能从平台中获取事件信息,并作出相应的反应。 -* **进程易处理性:** 容器化应用的寿命一定要尽可能的短暂,这样,可以随时被另一个容器所替换。 -* **运行时限制:** 每个容器都必须要声明自己的资源需求,并将资源使用限制在所需要的范围之内。 - - - -编译时原则保证了容器拥有合适的粒度,一致性以及结构。运行时原则明确了容器化必须要实现那些功能才能成为云原生函数。遵循这些原则可以帮助你的应用适应 Kubernetes 上的自动化。 - - - -白皮书可以免费下载: - - - -想要了解更多关于如何面向 Kubernetes 设计云原生应用,可以看看我的 [Kubernetes 模式][3] 一书。 - - - -— [Bilgin Ibryam][4], 首席架构师, Red Hat - -Twitter: 
 -Blog: [http://www.ofbizian.com][5] -Linkedin: - - - -Bilgin Ibryam (@bibryam) 是 Red Hat 的一名首席架构师, ASF 的开源贡献者,博主,作者以及演讲者。 -他是 Camel 设计模式、 Kubernetes 模式的作者。在他的日常生活中,他非常享受指导、培训以及帮助各个团队更加成功地使用分布式系统、微服务、容器,以及云原生应用。 - -[1]: https://www.redhat.com/en/resources/cloud-native-container-design-whitepaper -[2]: https://lh5.googleusercontent.com/1XqojkVC0CET1yKCJqZ3-0VWxJ3W8Q74zPLlqnn6eHSJsjHOiBTB7EGUX5o_BOKumgfkxVdgBeLyoyMfMIXwVm9p2QXkq_RRy2mDJG1qEExJDculYL5PciYcWfPAKxF2-DGIdiLw -[3]: http://leanpub.com/k8spatterns/ -[4]: http://twitter.com/bibryam -[5]: http://www.ofbizian.com/ diff --git a/content/zh/blog/_posts/2018-05-01-developing-on-kubernetes.md b/content/zh/blog/_posts/2018-05-01-developing-on-kubernetes.md new file mode 100644 index 0000000000..5d31031ec7 --- /dev/null +++ b/content/zh/blog/_posts/2018-05-01-developing-on-kubernetes.md @@ -0,0 +1,728 @@ +--- +title: 在 Kubernetes 上开发 +date: 2018-05-01 +slug: developing-on-kubernetes +--- + + + + +**作者**: [Michael Hausenblas](https://twitter.com/mhausenblas) (Red Hat), [Ilya Dmitrichenko](https://twitter.com/errordeveloper) (Weaveworks) + + + +您将如何开发一个 Kubernates 应用?也就是说,您如何编写并测试一个要在 Kubernates 上运行的应用程序?本文将重点介绍在独自开发或者团队协作中,您可能希望了解到的为了成功编写 Kubernetes 应用程序而需面临的挑战,工具和方法。 + + + +我们假定您是一位开发人员,有您钟爱的编程语言,编辑器/IDE(集成开发环境),以及可用的测试框架。在针对 Kubernates 开发应用时,最重要的目标是减少对当前工作流程的影响,改变越少越好,尽量做到最小。举个例子,如果您是 Node.js 开发人员,习惯于那种热重载的环境 - 也就是说您在编辑器里一做保存,正在运行的程序就会自动更新 - 那么跟容器、容器镜像或者镜像仓库打交道,又或是跟 Kubernetes 部署、triggers 以及更多头疼东西打交道,不仅会让人难以招架也真的会让开发过程完全失去乐趣。 + + + +在下文中,我们将首先讨论 Kubernetes 总体开发环境,然后回顾常用工具,最后进行三个示例性工具的实践演练。这些工具允许针对 Kubernetes 进行本地应用程序的开发和迭代。 + + + +## 您的集群运行在哪里? + + + +作为开发人员,您既需要考虑所针对开发的 Kubernetes 集群运行在哪里,也需要思考开发环境如何配置。概念上,有四种开发模式: + +![Dev Modes](/images/blog/2018-05-01-developing-on-kubernetes/dok-devmodes_preview.png) + + + +许多工具支持纯 offline 开发,包括 Minikube、Docker(Mac 版/Windows 版)、Minishift 以及下文中我们将详细讨论的几种。有时,比如说在一个微服务系统中,已经有若干微服务在运行,proxied 模式(通过转发把数据流传进传出集群)就非常合适,Telepresence 就是此类工具的一个实例。live 模式,本质上是您基于一个远程集群进行构建和部署。最后,纯 online 模式意味着您的开发环境和运行集群都是远程的,典型的例子是 [Eclipse Che](https://www.eclipse.org/che/docs/kubernetes-single-user.html) 或者 [Cloud 9](https://github.com/errordeveloper/k9c)。现在让我们仔细看看离线开发的基础:在本地运行 Kubernetes。 + + + +[Minikube](/docs/getting-started-guides/minikube/) 在更加喜欢于本地 VM 上运行 Kubernetes 的开发人员中,非常受欢迎。不久前,Docker 的 [Mac](https://docs.docker.com/docker-for-mac/kubernetes/) 版和 [Windows](https://docs.docker.com/docker-for-windows/kubernetes/) 版,都试验性地开始自带 Kubernetes(需要下载 “edge” 安装包)。在两者之间,以下原因也许会促使您选择 Minikube 而不是 Docker 桌面版: + + + +* 您已经安装了 Minikube 并且它运行良好 +* 您想等到 Docker 出稳定版本 +* 您是 Linux 桌面用户 +* 您是 Windows 用户,但是没有配有 Hyper-V 的 Windows 10 Pro + + + +运行一个本地集群,开发人员可以离线工作,不用支付云服务。云服务收费一般不会太高,并且免费的等级也有,但是一些开发人员不喜欢为了使用云服务而必须得到经理的批准,也不愿意支付意想不到的费用,比如说忘了下线而集群在周末也在运转。 + + + +有些开发人员却更喜欢远程的 Kubernetes 集群,这样他们通常可以获得更大的计算能力和存储容量,也简化了协同工作流程。您可以更容易的拉上一个同事来帮您调试,或者在团队内共享一个应用的使用。再者,对某些开发人员来说,尽可能的让开发环境类似生产环境至关重要,尤其是您依赖外部厂商的云服务时,如:专有数据库、云对象存储、消息队列、外商的负载均衡器或者邮件投递系统。 + + + +总之,无论您选择本地或者远程集群,理由都足够多。这很大程度上取决于您所处的阶段:从早期的原型设计/单人开发到后期面对一批稳定微服务的集成。 + + + +既然您已经了解到运行环境的基本选项,那么我们就接着讨论如何迭代式的开发并部署您的应用。 + + + +## 常用工具 + + + +我们现在回顾既可以允许您可以在 Kubernetes 上开发应用程序又尽可能最小地改变您现有的工作流程的一些工具。我们致力于提供一份不偏不倚的描述,也会提及使用某个工具将会意味着什么。 + + + +请注意这很棘手,因为即使在成熟定型的技术中做选择,比如说在 JSON、YAML、XML、REST、gRPC 或者 SOAP 之间做选择,很大程度也取决于您的背景、喜好以及公司环境。在 Kubernetes 生态系统内比较各种工具就更加困难,因为技术发展太快,几乎每周都有新工具面市;举个例子,仅在准备这篇博客的期间,[Gitkube](https://gitkube.sh/) 和 [Watchpod](https://github.com/MinikubeAddon/watchpod) 相继出品。为了进一步覆盖到这些新的,以及一些相关的已推出的工具,例如 [Weave Flux](https://github.com/weaveworks/flux) 和 OpenShift 的 [S2I](https://docs.openshift.com/container-platform/3.9/creating_images/s2i.html),我们计划再写一篇跟进的博客。 + +### Draft + + + + +[Draft](https://github.com/Azure/draft) 旨在帮助您将任何应用程序部署到 Kubernetes。它能够检测到您的应用所使用的编程语言,并且生成一份 Dockerfile 和 Helm 图表。然后它替您启动构建并且依照 Helm 图表把所生产的镜像部署到目标集群。它也可以让您很容易地设置到 localhost 的端口映射。 + + + +这意味着: + + +* 用户可以任意地自定义 Helm 图表和 Dockerfile 模版,或者甚至创建一个 [custom pack](https://github.com/Azure/draft/blob/master/docs/reference/dep-003.md)(使用 Dockerfile、Helm 图表以及其他)以备后用 + + +* 要想理解一个应用应该怎么构建并不容易,在某些情况下,用户也许需要修改 Draft 生成的 Dockerfile 和 Heml 图表 + + +* 如果使用 [Draft version 0.12.0](https://github.com/Azure/draft/releases/tag/v0.12.0)1 或者更老版本,每一次用户想要测试一个改动,他们需要等 Draft 把代码拷贝到集群,运行构建,推送镜像并且发布更新后的图表;这些步骤可能进行得很快,但是每一次用户的改动都会产生一个镜像(无论是否提交到 git ) + + +* 在 Draft 0.12.0版本,构建是本地进行的 +* 用户不能选择 Helm 以外的工具进行部署 +* 它可以监控本地的改动并且触发部署,但是这个功能默认是关闭的 + + +* 它允许开发人员使用本地或者远程的 Kubernates 集群 +* 如何部署到生产环境取决于用户, Draft 的作者推荐了他们的另一个项目 - Brigade +* 可以代替 Skaffold, 并且可以和 Squash 一起使用 + + + +更多信息: + +* [Draft: Kubernetes container development made easy](https://kubernetes.io/blog/2017/05/draft-kubernetes-container-development) +* [Getting Started Guide](https://github.com/Azure/draft/blob/master/docs/getting-started.md) + +【1】:此处疑为 0.11.0,因为 0.12.0 已经支持本地构建,见下一条 + +### Skaffold + + + +[Skaffold](https://github.com/GoogleCloudPlatform/skaffold) 让 CI 集成具有可移植性的,它允许用户采用不同的构建系统,镜像仓库和部署工具。它不同于 Draft,同时也具有一定的可比性。它具有生成系统清单的基本能力,但那不是一个重要功能。Skaffold 易于扩展,允许用户在构建和部署应用的每一步选取相应的工具。 + + + +这意味着: + + +* 模块化设计 +* 不依赖于 CI,用户不需要 Docker 或者 Kubernetes 插件 +* 没有 CI 也可以工作,也就是说,可以在开发人员的电脑上工作 +* 它可以监控本地的改动并且触发部署 + + +* 它允许开发人员使用本地或者远程的 Kubernetes 集群 +* 它可以用于部署生产环境,用户可以精确配置,也可以为每一套目标环境提供不同的生产线 +* 可以代替 Draft,并且和其他工具一起使用 + + + +更多信息: + +* [Introducing Skaffold: Easy and repeatable Kubernetes development](https://cloudplatform.googleblog.com/2018/03/introducing-Skaffold-Easy-and-repeatable-Kubernetes-development.html) +* [Getting Started Guide](https://github.com/GoogleCloudPlatform/skaffold#getting-started-with-local-tooling) + +### Squash + + +[Squash](https://github.com/solo-io/squash) 包含一个与 Kubernetes 全面集成的调试服务器,以及一个 IDE 插件。它允许您插入断点和所有的调试操作,就像您所习惯的使用 IDE 调试一个程序一般。它允许您将调试器应用到 Kubernetes 集群中运行的 pod 上,从而让您可以使用 IDE 调试 Kubernetes 集群。 + + + +这意味着: + + +* 不依赖您选择的其它工具 +* 需要一组特权 DaemonSet +* 可以和流行 IDE 集成 +* 支持 Go、Python、Node.js、Java 和 gdb + + +* 用户必须确保容器中的应用程序使编译时使用了调试符号 +* 可与此处描述的任何其他工具结合使用 +* 它可以与本地或远程 Kubernetes 集群一起使用 + + + +更多信息: + +* [Squash: A Debugger for Kubernetes Apps](https://www.youtube.com/watch?v=5TrV3qzXlgI) +* [Getting Started Guide](https://github.com/solo-io/squash/blob/master/docs/getting-started.md) + +### Telepresence + + +[Telepresence](https://www.telepresence.io/) 使用双向代理将开发人员工作站上运行的容器与远程 Kubernetes 集群连接起来,并模拟集群内环境以及提供对配置映射和机密的访问。它消除了将应用部署到集群的需要,并利用本地容器抽象出网络和文件系统接口,以使其看起来应用好像就在集群中运行,从而改进容器应用程序开发的迭代时间。 + + + +这意味着: + + +* 它不依赖于其它您选取的工具 +* 可以同 Squash 一起使用,但是 Squash 必须用于调试集群中的 pods,而传统/本地调试器需要用于调试通过 Telepresence 连接到集群的本地容器 +* Telepresence 会产生一些网络延迟 + + +* 它通过辅助进程提供连接 - sshuttle,基于SSH的一个工具 +* 还提供了使用 LD_PRELOAD/DYLD_INSERT_LIBRARIES 的更具侵入性的依赖注入模式 +* 它最常用于远程 Kubernetes 集群,但也可以与本地集群一起使用 + + + +更多信息: + +* [Telepresence: fast, realistic local development for Kubernetes microservices](https://www.telepresence.io/) +* [Getting Started Guide](https://www.telepresence.io/tutorials/docker) +* [How It Works](https://www.telepresence.io/discussion/how-it-works) + +### Ksync + + + + +[Ksync](https://github.com/vapor-ware/ksync) 在本地计算机和运行在 Kubernetes 中的容器之间同步应用程序代码(和配置),类似于 [oc rsync](https://docs.openshift.com/container-platform/3.9/dev_guide/copy_files_to_container.html) 在 OpenShift 中的角色。它旨在通过消除构建和部署步骤来缩短应用程序开发的迭代时间。 + + + + +这意味着: + + +* 它绕过容器图像构建和修订控制 +* 使用编译语言的用户必须在 pod(TBC)内运行构建 +* 双向同步 - 远程文件会复制到本地目录 +* 每次更新远程文件系统时都会重启容器 +* 无安全功能 - 仅限开发 + + +* 使用 [Syncthing](https://github.com/syncthing/syncthing),一个用于点对点同步的 Go 语言库 +* 需要一个在集群中运行的特权 DaemonSet +* Node 必须使用带有 overlayfs2 的 Docker - 在写作本文时,尚不支持其他 CRI 实现 + + + +更多信息: + +* [Getting Started Guide](https://github.com/vapor-ware/ksync#getting-started) +* [How It Works](https://github.com/vapor-ware/ksync/blob/master/docs/architecture.md) +* [Katacoda scenario to try out ksync in your browser](https://www.katacoda.com/vaporio/scenarios/ksync) +* [Syncthing Specification](https://docs.syncthing.net/specs/) + + + +## 实践演练 + + + + +我们接下来用于练习使用工具的应用是一个简单的[股市模拟器](https://github.com/kubernauts/dok-example-us),包含两个微服务: + + + +* `stock-gen`(股市数据生成器)微服务是用 Go 编写的,随机生成股票数据并通过 HTTP 端点 `/ stockdata` 公开 +* 第二个微服务,`stock-con`(股市数据消费者)是一个 Node.js 应用程序,它使用来自 `stock-gen` 的股票数据流,并通过 HTTP 端点 `/average/$SYMBOL` 提供股价移动平均线,也提供一个健康检查端点 `/healthz`。 + + + +总体上,此应用的默认配置如下图所示: + +![Default Setup](/images/blog/2018-05-01-developing-on-kubernetes/dok-architecture_preview.png) + + + +在下文中,我们将选取以上讨论的代表性工具进行实践演练:ksync,具有本地构建的 Minikube 以及 Skaffold。对于每个工具,我们执行以下操作: + + + +* 设置相应的工具,包括部署准备和 `stock-con` 微服务数据的本地读取 +* 执行代码更新,即更改 `stock-con` 微服务的 `/healthz` 端点的源代码并观察网页刷新 + + + +请注意,我们一直使用 Minikube 的本地 Kubernetes 集群,但是您也可以使用 ksync 和 Skaffold 的远程集群跟随练习。 + + + +### 实践演练:ksync + + + +作为准备,安装 [ksync](https://vapor-ware.github.io/ksync/#installation),然后执行以下步骤配置开发环境: + +``` +$ mkdir -p $(pwd)/ksync +$ kubectl create namespace dok +$ ksync init -n dok +``` + + + +完成基本设置后,我们可以告诉 ksync 的本地客户端监控 Kubernetes 的某个命名空间,然后我们创建一个规范来定义我们想要同步的文件夹(本地的 `$(pwd)/ksync` 和容器中的 `/ app` )。请注意,目标 pod 是用 selector 参数指定: + +``` +$ ksync watch -n dok +$ ksync create -n dok --selector=app=stock-con $(pwd)/ksync /app +$ ksync get -n dok +``` + + + +现在我们部署股价数据生成器和股价数据消费者微服务: + +``` +$ kubectl -n=dok apply \ + -f https://raw.githubusercontent.com/kubernauts/dok-example-us/master/stock-gen/app.yaml +$ kubectl -n=dok apply \ + -f https://raw.githubusercontent.com/kubernauts/dok-example-us/master/stock-con/app.yaml +``` + + + +一旦两个部署建好并且 pod 开始运行,我们转发 `stock-con` 服务以供本地读取(另开一个终端窗口): + +``` +$ kubectl get -n dok po --selector=app=stock-con \ + -o=custom-columns=:metadata.name --no-headers | \ + xargs -IPOD kubectl -n dok port-forward POD 9898:9898 +``` + + + +这样,通过定期查询 `healthz` 端点,我们就应该能够从本地机器上读取 `stock-con` 服务,查询命令如下(在一个单独的终端窗口): + +``` +$ watch curl localhost:9898/healthz +``` + + + +现在,改动 `ksync/stock-con` 目录中的代码,例如改动 [`service.js` 中定义的 `/healthz` 端点代码](https://github.com/kubernauts/dok-example-us/blob/2334ee8fb11f8813370122bd46285cf45bdd4c48/stock-con/service.js#L52),在其 JSON 形式的响应中新添一个字段并观察 pod 如何更新以及 `curl localhost:9898/healthz` 命令的输出发生何种变化。总的来说,您最后应该看到类似的内容: + + +![Preview](/images/blog/2018-05-01-developing-on-kubernetes/dok-ksync_preview.png) + + + + +### 实践演练:带本地构建的 Minikube + + + + +对于以下内容,您需要启动并运行 Minikube,我们将利用 Minikube 自带的 Docker daemon 在本地构建镜像。作为准备,请执行以下操作 + +``` +$ git clone https://github.com/kubernauts/dok-example-us.git && cd dok-example-us +$ eval $(minikube docker-env) +$ kubectl create namespace dok +``` + + + +现在我们部署股价数据生成器和股价数据消费者微服务: + + +``` +$ kubectl -n=dok apply -f stock-gen/app.yaml +$ kubectl -n=dok apply -f stock-con/app.yaml +``` + + + +一旦两个部署建好并且 pod 开始运行,我们转发 `stock-con` 服务以供本地读取(另开一个终端窗口): + +``` +$ kubectl get -n dok po --selector=app=stock-con \ + -o=custom-columns=:metadata.name --no-headers | \ + xargs -IPOD kubectl -n dok port-forward POD 9898:9898 & +$ watch curl localhost:9898/healthz +``` + + +现在,改一下 `ksync/stock-con` 目录中的代码,例如修改 [`service.js` 中定义的 `/healthz` 端点代码](https://github.com/kubernauts/dok-example-us/blob/2334ee8fb11f8813370122bd46285cf45bdd4c48/stock-con/service.js#L52),在其 JSON 形式的响应中添加一个字段。在您更新完代码后,最后一步是构建新的容器镜像并启动新部署,如下所示: + + +``` +$ docker build -t stock-con:dev -f Dockerfile . +$ kubectl -n dok set image deployment/stock-con *=stock-con:dev +``` + + +总的来说,您最后应该看到类似的内容: + +![Local Preview](/images/blog/2018-05-01-developing-on-kubernetes/dok-minikube-localdev_preview.png) + + + +### 实践演练:Skaffold + + + +要进行此演练,首先需要安装 [Skaffold](https://github.com/GoogleContainerTools/skaffold#installation)。完成后,您可以执行以下步骤来配置开发环境: + +``` +$ git clone https://github.com/kubernauts/dok-example-us.git && cd dok-example-us +$ kubectl create namespace dok +``` + + +现在我们部署股价数据生成器(但是暂不部署股价数据消费者,此服务将使用 Skaffold 完成): + +``` +$ kubectl -n=dok apply -f stock-gen/app.yaml +``` + + + + +请注意,最初我们在执行 `skaffold dev` 时发生身份验证错误,为避免此错误需要安装[问题322](https://github.com/GoogleContainerTools/skaffold/issues/322) 中所述的修复。本质上,需要将 `〜/.docker/config.json` 的内容改为: + + +``` +{ + "auths": {} +} +``` + + + +接下来,我们需要略微改动 `stock-con/app.yaml`,这样 Skaffold 才能正常使用此文件: + + + +在 `stock-con` 部署和服务中添加一个 `namespace` 字段,其值为 `dok` + +将容器规范的 `image` 字段更改为 `quay.io/mhausenblas/stock-con`,因为 Skaffold 可以即时管理容器镜像标签。 + + +最终的 stock-con 的 `app.yaml` 文件看起来如下: + + +``` +apiVersion: apps/v1beta1 +kind: Deployment +metadata: + labels: + app: stock-con + name: stock-con + namespace: dok +spec: + replicas: 1 + template: + metadata: + labels: + app: stock-con + spec: + containers: + - name: stock-con + image: quay.io/mhausenblas/stock-con + env: + - name: DOK_STOCKGEN_HOSTNAME + value: stock-gen + - name: DOK_STOCKGEN_PORT + value: "9999" + ports: + - containerPort: 9898 + protocol: TCP + livenessProbe: + initialDelaySeconds: 2 + periodSeconds: 5 + httpGet: + path: /healthz + port: 9898 + readinessProbe: + initialDelaySeconds: 2 + periodSeconds: 5 + httpGet: + path: /healthz + port: 9898 +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: stock-con + name: stock-con + namespace: dok +spec: + type: ClusterIP + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 9898 + selector: + app: stock-con +``` + + +我们能够开始开发之前的最后一步是配置 Skaffold。因此,在 `stock-con/` 目录中创建文件 `skaffold.yaml`,其中包含以下内容: + +``` +apiVersion: skaffold/v1alpha2 +kind: Config +build: + artifacts: + - imageName: quay.io/mhausenblas/stock-con + workspace: . + docker: {} + local: {} +deploy: + kubectl: + manifests: + - app.yaml +``` + + +现在我们准备好开始开发了。为此,在 `stock-con/` 目录中执行以下命令: + +``` +$ skaffold dev +``` + + + +上面的命令将触发 `stock-con` 图像的构建和部署。一旦 `stock-con` 部署的 pod 开始运行,我们再次转发 `stock-con` 服务以供本地读取(在单独的终端窗口中)并检查 `healthz` 端点的响应: + +```bash +$ kubectl get -n dok po --selector=app=stock-con \ + -o=custom-columns=:metadata.name --no-headers | \ + xargs -IPOD kubectl -n dok port-forward POD 9898:9898 & +$ watch curl localhost:9898/healthz +``` + + +现在,如果您修改一下 `stock-con` 目录中的代码,例如 [`service.js` 中定义的 `/healthz` 端点代码](https://github.com/kubernauts/dok-example-us/blob/2334ee8fb11f8813370122bd46285cf45bdd4c48/stock-con/service.js#L52),在其 JSON 形式的响应中添加一个字段,您应该看到 Skaffold 可以检测到代码改动并创建新图像以及部署它。您的屏幕看起来应该类似这样: + + +![Skaffold Preview](/images/blog/2018-05-01-developing-on-kubernetes/dok-skaffold_preview.png) + + +至此,您应该对不同的工具如何帮您在 Kubernetes 上开发应用程序有了一定的概念,如果您有兴趣了解有关工具和/或方法的更多信息,请查看以下资源: + +* Blog post by Shahidh K Muhammed on [Draft vs Gitkube vs Helm vs Ksonnet vs Metaparticle vs Skaffold](https://blog.hasura.io/draft-vs-gitkube-vs-helm-vs-ksonnet-vs-metaparticle-vs-skaffold-f5aa9561f948) (03/2018) +* Blog post by Gergely Nemeth on [Using Kubernetes for Local Development](https://nemethgergely.com/using-kubernetes-for-local-development/index.html), with a focus on Skaffold (03/2018) +* Blog post by Richard Li on [Locally developing Kubernetes services (without waiting for a deploy)](https://hackernoon.com/locally-developing-kubernetes-services-without-waiting-for-a-deploy-f63995de7b99), with a focus on Telepresence +* Blog post by Abhishek Tiwari on [Local Development Environment for Kubernetes using Minikube](https://abhishek-tiwari.com/local-development-environment-for-kubernetes-using-minikube/) (09/2017) +* Blog post by Aymen El Amri on [Using Kubernetes for Local Development — Minikube](https://medium.com/devopslinks/using-kubernetes-minikube-for-local-development-c37c6e56e3db) (08/2017) +* Blog post by Alexis Richardson on [​GitOps - Operations by Pull Request](https://www.weave.works/blog/gitops-operations-by-pull-request) (08/2017) +* Slide deck [GitOps: Drive operations through git](https://docs.google.com/presentation/d/1d3PigRVt_m5rO89Ob2XZ16bW8lRSkHHH5k816-oMzZo/), with a focus on Gitkube by Tirumarai Selvan (03/2018) +* Slide deck [Developing apps on Kubernetes](https://speakerdeck.com/mhausenblas/developing-apps-on-kubernetes), a talk Michael Hausenblas gave at a CNCF Paris meetup (04/2018) +* YouTube videos: + * [TGI Kubernetes 029: Developing Apps with Ksync](https://www.youtube.com/watch?v=QW85Y0Ug3KY ) + * [TGI Kubernetes 030: Exploring Skaffold](https://www.youtube.com/watch?v=McwwWhCXMxc) + * [TGI Kubernetes 031: Connecting with Telepresence](https://www.youtube.com/watch?v=zezeBAJ_3w8) + * [TGI Kubernetes 033: Developing with Draft](https://www.youtube.com/watch?v=8B1D7cTMPgA) +* Raw responses to the [Kubernetes Application Survey](https://docs.google.com/spreadsheets/d/12ilRCly2eHKPuicv1P_BD6z__PXAqpiaR-tDYe2eudE/edit) 2018 by SIG Apps + + + +有了这些,我们这篇关于如何在 Kubernetes 上开发应用程序的博客就可以收尾了,希望您有所收获,如果您有反馈和/或想要指出您认为有用的工具,请通过 Twitter 告诉我们:[Ilya](https://twitter.com/errordeveloper) 和 [Michael](https://twitter.com/mhausenblas) diff --git a/content/zh/blog/_posts/2018-05-30-say-hello-to-discuss-kubernetes.md b/content/zh/blog/_posts/2018-05-30-say-hello-to-discuss-kubernetes.md new file mode 100644 index 0000000000..eb1aba85d2 --- /dev/null +++ b/content/zh/blog/_posts/2018-05-30-say-hello-to-discuss-kubernetes.md @@ -0,0 +1,67 @@ +--- +title: 'Kubernetes 1 11:向 discuss kubernetes 问好' +layout: blog +date: 2018-05-30 +--- + + + + + +作者: Jorge Castro (Heptio) + + + +就一个超过 35,000 人的全球性社区而言,参与其中时沟通是非常关键的。 跟踪 Kubernetes 社区中的所有内容可能是一项艰巨的任务。 一方面,我们有官方资源,如 Stack Overflow,GitHub 和邮件列表,另一方面,我们有更多瞬时性的资源,如 Slack,你可以加入进去、与某人聊天然后各走各路。 + + + + +Slack 非常适合随意和及时的对话,并与其他社区成员保持联系,但未来很难轻易引用通信。此外,在35,000名参与者中提问并得到回答很难。邮件列表在有问题尝试联系特定人群并且想要跟踪大家的回应时非常有用,但是对于大量人员来说可能是麻烦的。 Stack Overflow 和 GitHub 非常适合在涉及代码的项目或问题上进行协作,并且如果在将来要进行搜索也很有用,但某些主题如“你最喜欢的 CI/CD 工具是什么”或“[Kubectl提示和技巧](http://discuss.kubernetes.io/t/kubectl-tips-and-tricks/192)“在那里是没有意义的。 + +虽然我们目前的各种沟通渠道对他们自己来说都很有价值,但我们发现电子邮件和实时聊天之间仍然存在差距。在网络的其他部分,许多其他开源项目,如 Docker、Mozilla、Swift、Ghost 和 Chef,已经成功地在[Discourse](http://www.discourse.org/features)之上构建社区,一个开放的讨论平台。那么,如果我们可以使用这个工具将我们的讨论结合在一个平台下,使用开放的API,或许也不会让我们的大部分信息消失在网络中呢?只有一种方法可以找到:欢迎来到[discuss.kubernetes.io](http://discuss.kubernetes.io) + + + +马上,我们有用户可以浏览的类别。检查和发布这些类别允许用户参与他们可能感兴趣的事情,而无需订阅列表。精细的通知控件允许用户只订阅他们想要的类别或标签,并允许通过电子邮件回复主题。 + +生态系统合作伙伴和开发人员现在有一个地方可以[宣布项目](http://discuss.kubernetes.io/c/announcements),他们正在为用户工作,而不会想知道它是否会在官方列表中脱离主题。我们可以让这个地方不仅仅是关于核心 Kubernetes,而是关于我们社区正在建设的数百个精彩工具。 + +这个新的社区论坛为人们提供了一个可以讨论 Kubernetes 的地方,也是开发人员在 Kubernetes 周围发布事件的声音板,同时可以搜索并且更容易被更广泛的用户访问。 + +进来看看。我们刚刚开始,所以,您可能希望从[自我介绍](http://discuss.kubernetes.io/t/introduce-yourself-here/56)开始,到处浏览。也有 [Android](http://play.google.com/store/apps/details?id=com.discourse&hl=en_US&rdid=com.discourse&pli=1) 和 [iOS](http://itunes.apple.com/us/app/discourse-app/id1173672076?mt=8) 应用下载。 + diff --git a/content/zh/blog/_posts/2018-06-06-4-years-of-k8s.md b/content/zh/blog/_posts/2018-06-06-4-years-of-k8s.md new file mode 100644 index 0000000000..b4e118b584 --- /dev/null +++ b/content/zh/blog/_posts/2018-06-06-4-years-of-k8s.md @@ -0,0 +1,42 @@ +--- +title: Kubernetes 这四年 +approvers: +cn-approvers: +- congfairy +layout: blog +date: 2018-06-06 +--- + + + **作者**:Joe Beda( Heptio 首席技术官兼创始人) + 2014 年 6 月 6 日,我检查了 Kubernetes 公共代码库的[第一次 commit](https://github.com/kubernetes/kubernetes/commit/2c4b3a562ce34cddc3f8218a2c4d11c7310e6d56) 。许多人会认为这是故事开始的地方。这难道不是一切开始的地方吗?但这的确不能把整个过程说清楚。 + + ![k8s_first_commit](/images/blog/2018-06-06-4-years-of-k8s/k8s-first-commit.png) + + + + 第一次 commit 涉及的人员众多,自那以后 Kubernetes 的成功归功于更大的开发者阵容。 + Kubernetes 建立在过去十年曾经在 Google 的 Borg 集群管理系统中验证过的思路之上。而 Borg 本身也是 Google 和其他公司早期努力的结果。 + 具体而言,Kubernetes 最初是从 Brendan Burns 的一些原型开始,结合我和 Craig McLuckie 正在进行的工作,以更好地将 Google 内部实践与 Google Cloud 的经验相结合。 Brendan,Craig 和我真的希望人们使用它,所以我们建议将这个原型构建为一个开源项目,将 Borg 的最佳创意带给大家。 +在我们所有人同意后,就开始着手构建这个系统了。我们采用了 Brendan 的原型(Java 语言),用 Go 语言重写了它,并且以上述核心思想去构建该系统。到这个时候,团队已经成长为包括 Ville Aikas,Tim Hockin,Brian Grant,Dawn Chen 和 Daniel Smith。一旦我们有了一些工作需求,有人必须承担一些脱敏的工作,以便为公开发布做好准备。这个角色最终由我承担。当时,我不知道这件事情的重要性,我创建了一个新的仓库,把代码搬过来,然后进行了检查。所以在我第一次提交 public commit 之前,就有工作已经启动了。 +那时 Kubernetes 的版本只是现在版本的简单雏形。核心概念已经有了,但非常原始。例如,Pods 被称为 Tasks,这在我们推广前一天就被替换。2014年6月10日 Eric Brewe 在第一届 DockerCon 上的演讲中正式发布了 Kubernetes 。您可以在此处观看该视频: + + +
+ + + + 但是,无论多么原始,这小小的一步足以激起一个开始强大而且变得更强大的社区的兴趣。在过去的四年里,Kubernetes 已经超出了我们所有人的期望。我们对 Kubernetes 社区的所有人员表示感谢。该项目所取得的成功不仅基于代码和技术,还基于一群出色的人聚集在一起所做的有意义的事情。Sarah Novotny 策划的一套 [Kubernetes 价值观](https://github.com/kubernetes/steering/blob/master/values.md)是以上最好的表现形式。 + 让我们一起期待下一个4年!🎉🎉🎉 diff --git a/content/zh/blog/_posts/2018-06-07-dynamic-ingress-kubernetes.md b/content/zh/blog/_posts/2018-06-07-dynamic-ingress-kubernetes.md new file mode 100644 index 0000000000..bb8d7d848c --- /dev/null +++ b/content/zh/blog/_posts/2018-06-07-dynamic-ingress-kubernetes.md @@ -0,0 +1,129 @@ +--- +title: 'Kubernetes 内的动态 Ingress' +layout: blog +--- + + + +作者: Richard Li (Datawire) + + + +Kubernetes 可以轻松部署由许多微服务组成的应用程序,但这种架构的关键挑战之一是动态地将流量路由到这些服务中的每一个。 +一种方法是使用 [Ambassador](https://www.getambassador.io), +一个基于 [Envoy Proxy](https://www.envoyproxy.io) 构建的 Kubernetes 原生开源 API 网关。 +Ambassador 专为动态环境而设计,这类环境中的服务可能被频繁添加或删除。 + +Ambassador 使用 Kubernetes 注解进行配置。 +注解用于配置从给定 Kubernetes 服务到特定 URL 的具体映射关系。 +每个映射中可以包括多个注解,用于配置路由。 +注解的例子有速率限制、协议、跨源请求共享(CORS)、流量影射和路由规则等。 + + + +## 一个简单的 Ambassador 示例 + +Ambassador 通常作为 Kubernetes Deployment 来安装,也可以作为 Helm Chart 使用。 +配置 Ambassador 时,请使用 Ambassador 注解创建 Kubernetes 服务。 +下面是一个例子,用来配置 Ambassador,将针对 /httpbin/ 的请求路由到公共的 httpbin.org 服务: + +``` +apiVersion: v1 +kind: Service +metadata: + name: httpbin + annotations: + getambassador.io/config: | + --- + apiVersion: ambassador/v0 + kind: Mapping + name: httpbin_mapping + prefix: /httpbin/ + service: httpbin.org:80 + host_rewrite: httpbin.org +spec: + type: ClusterIP + ports: + - port: 80 +``` + + + +例子中创建了一个 Mapping 对象,其 prefix 设置为 /httpbin/,service 名称为 httpbin.org。 +其中的 host_rewrite 注解指定 HTTP 的 host 头部字段应设置为 httpbin.org。 + + + +## Kubeflow + +[Kubeflow](https://github.com/kubeflow/kubeflow) 提供了一种简单的方法,用于在 Kubernetes 上轻松部署机器学习基础设施。 +Kubeflow 团队需要一个代理,为 Kubeflow 中所使用的各种服务提供集中化的认证和路由能力;Kubeflow 中许多服务本质上都是生命期很短的。 + +
Kubeflow architecture, pre-Ambassador
+ + + +## 服务配置 + +有了 Ambassador,Kubeflow 可以使用分布式模型进行配置。 +Ambassador 不使用集中的配置文件,而是允许每个服务通过 Kubernetes 注解在 Ambassador 中配置其路由。 +下面是一个简化的配置示例: + +``` +--- +apiVersion: ambassador/v0 +kind: Mapping +name: tfserving-mapping-test-post +prefix: /models/test/ +rewrite: /model/test/:predict +method: POST +service: test.kubeflow:8000 +``` + + + +示例中,“test” 服务使用 Ambassador 注解来为服务动态配置路由。 +所配置的路由仅在 HTTP 方法是 POST 时触发;注解中同时还给出了一条重写规则。 + + + +## Kubeflow 和 Ambassador + +通过 Ambassador,Kubeflow 可以使用 Kubernetes 注解轻松管理路由。 +Kubeflow 配置同一个 Ingress 对象,将流量定向到 Ambassador,然后根据需要创建具有 Ambassador 注解的服务,以将流量定向到特定后端。 +例如,在部署 TensorFlow 服务时,Kubeflow 会创建 Kubernetes 服务并为其添加注解, +以便用户能够在 `https:///models/<模型名称>/` 处访问到模型本身。 +Kubeflow 还可以使用 Envoy Proxy 来进行实际的 L7 路由。 +通过 Ambassador,Kubeflow 能够更充分地利用 URL 重写和基于方法的路由等额外的路由配置能力。 + +如果您对在 Kubeflow 中使用 Ambassador 感兴趣,标准的 Kubeflow 安装会自动安装和配置 Ambassador。 + +如果您有兴趣将 Ambassador 用作 API 网关或 Kubernetes 的 Ingress 解决方案, +请参阅 [Ambassador 入门指南](https://www.getambassador.io/user-guide/getting-started)。 + diff --git a/content/zh/blog/_posts/2018-08-29-kubernetes-testing-ci-automating-contributor-experience.md b/content/zh/blog/_posts/2018-08-29-kubernetes-testing-ci-automating-contributor-experience.md new file mode 100644 index 0000000000..8720e483ea --- /dev/null +++ b/content/zh/blog/_posts/2018-08-29-kubernetes-testing-ci-automating-contributor-experience.md @@ -0,0 +1,241 @@ + + +--- +layout: blog +title: '机器可以完成这项工作,一个关于 kubernetes 测试、CI 和自动化贡献者体验的故事' +date: 2019-08-29 +--- + + + +**作者**:Aaron Crickenberger(谷歌)和 Benjamin Elder(谷歌) + + + +_”大型项目有很多不那么令人兴奋,但却很辛苦的工作。比起辛苦工作,我们更重视把时间花在自动化重复性工作上,如果这项工作无法实现自动化,我们的文化就是承认并奖励所有类型的贡献。然而,英雄主义是不可持续的。“_ - [Kubernetes Community Values](https://git.k8s.io/community/values.md#automation-over-process) + + + +像许多开源项目一样,Kubernetes 托管在 GitHub 上。 如果项目位于在开发人员已经工作的地方,使用的开发人员已经知道的工具和流程,那么参与的障碍将是最低的。 因此,该项目完全接受了这项服务:它是我们工作流程,问题跟踪,文档,博客平台,团队结构等的基础。 + + + +这个策略奏效了。 它运作良好,以至于该项目迅速超越了其贡献者的人类能力。 接下来是一次令人难以置信的自动化和创新之旅。 我们不仅需要在飞行途中重建我们的飞机而不会崩溃,我们需要将其转换为火箭飞船并发射到轨道。 我们需要机器来完成这项工作。 + + + +## 工作 + + + +最初,我们关注的事实是,我们需要支持复杂的分布式系统(如 Kubernetes)所要求的大量测试。 真实世界中的故障场景必须通过端到端(e2e)测试来执行,确保正确的功能。 不幸的是,e2e 测试容易受到薄片(随机故障)的影响,并且需要花费一个小时到一天才能完成。 + + + +进一步的经验揭示了机器可以为我们工作的其他领域: + + + +* Pull Request 工作流程 + * 贡献者是否签署了我们的 CLA? + * Pull Request 通过测试吗? + * Pull Request 可以合并吗? + * 合并提交是否通过了测试? +* 鉴别分类 + * 谁应该审查 Pull Request? + * 是否有足够的信息将问题发送给合适的人? + * 问题是否依旧存在? +* 项目健康 + * 项目中发生了什么? + * 我们应该注意什么? + + + +当我们开发自动化来改善我们的情况时,我们遵循了以下几个指导原则: + + + +* 遵循适用于 Kubernetes 的推送/拉取控制循环模式 +* 首选无状态松散耦合服务 +* 更倾向于授权整个社区权利,而不是赋予少数核心贡献者权力 +* 做好自己的事,而不要重新造轮子 + + + +## 了解 Prow + + + +这促使我们创建 [Prow](https://git.k8s.io/test-infra/prow) 作为我们自动化的核心组件。 Prow有点像 [If This, Then That](https://ifttt.com/) 用于 GitHub 事件, 内置 [commands](https://prow.k8s.io/command-help), [plugins](https://prow.k8s.io/plugins), 和实用程序。 我们在 Kubernetes 之上建立了 Prow,让我们不必担心资源管理和日程安排,并确保更愉快的运营体验。 + + + +Prow 让我们做以下事情: + + + +* 允许我们的社区通过评论诸如“/priority critical-urgent”,“/assign mary”或“/close”之类的命令对 issues/Pull Requests 进行分类 +* 根据用户更改的代码数量或创建的文件自动标记 Pull Requests +* 标出长时间保持不活动状态 issues/Pull Requests +* 自动合并符合我们PR工作流程要求的 Pull Requests +* 运行定义为[Knative Builds](https://github.com/knative/build)的 Kubernetes Pods或 Jenkins jobs的 CI 作业 +* 实施组织范围和重构 GitHub 仓库策略,如[Knative Builds](https://github.com/kubernetes/test-infra/tree/master/prow/cmd/branchprotector)和[GitHub labels](https://github.com/kubernetes/test-infra/tree/master/label_sync) + + + +Prow最初由构建 Google Kubernetes Engine 的工程效率团队开发,并由 Kubernetes SIG Testing 的多个成员积极贡献。 Prow 已被其他几个开源项目采用,包括 Istio,JetStack,Knative 和 OpenShift。 [Getting started with Prow](https://github.com/kubernetes/test-infra/blob/master/prow/getting_started.md)需要一个 Kubernetes 集群和 `kubectl apply starter.yaml`(在 Kubernetes 集群上运行 pod)。 + + + +一旦我们安装了 Prow,我们就开始遇到其他的问题,因此需要额外的工具以支持 Kubernetes 所需的规模测试,包括: + + + +- [Boskos](https://github.com/kubernetes/test-infra/tree/master/boskos): 管理池中的作业资源(例如 GCP 项目),检查它们是否有工作并自动清理它们 ([with monitoring](http://velodrome.k8s.io/dashboard/db/boskos-dashboard?orgId=1)) +- [ghProxy](https://github.com/kubernetes/test-infra/tree/master/ghproxy): 优化用于 GitHub API 的反向代理 HTTP 缓存,以确保我们的令牌使用不会达到 API 限制 ([with monitoring](http://velodrome.k8s.io/dashboard/db/github-cache?refresh=1m&orgId=1)) +- [Greenhouse](https://github.com/kubernetes/test-infra/tree/master/greenhouse): 允许我们使用远程 bazel 缓存为 Pull requests 提供更快的构建和测试结果 ([with monitoring](http://velodrome.k8s.io/dashboard/db/bazel-cache?orgId=1)) +- [Splice](https://github.com/kubernetes/test-infra/tree/master/prow/cmd/splice): 允许我们批量测试和合并 Pull requests,确保我们的合并速度不仅限于我们的测试速度 +- [Tide](https://github.com/kubernetes/test-infra/tree/master/prow/cmd/tide): 允许我们合并通过 GitHub 查询选择的 Pull requests,而不是在队列中排序,允许显着更高合并速度与拼接一起 + + + +## 关注项目健康状况 + + + +随着工作流自动化的实施,我们将注意力转向了项目健康。我们选择使用 Google Cloud Storage (GCS)作为所有测试数据的真实来源,允许我们依赖已建立的基础设施,并允许社区贡献结果。然后,我们构建了各种工具来帮助个人和整个项目理解这些数据,包括: + + + +* [Gubernator](https://github.com/kubernetes/test-infra/tree/master/gubernator): 显示给定 Pull Request 的结果和测试历史 +* [Kettle](https://github.com/kubernetes/test-infra/tree/master/kettle): 将数据从 GCS 传输到可公开访问的 bigquery 数据集 +* [PR dashboard](https://k8s-gubernator.appspot.com/pr): 一个工作流程识别仪表板,允许参与者了解哪些 Pull Request 需要注意以及为什么 +* [Triage](https://storage.googleapis.com/k8s-gubernator/triage/index.html): 识别所有作业和测试中发生的常见故障 +* [Testgrid](https://k8s-testgrid.appspot.com/): 显示所有运行中给定作业的测试结果,汇总各组作业的测试结果 + + + +我们与云计算本地计算基金会(CNCF)联系,开发 DevStats,以便从我们的 GitHub 活动中收集见解,例如: + + + +* [Which prow commands are people most actively using](https://k8s.devstats.cncf.io/d/5/bot-commands-repository-groups?orgId=1) +* [PR reviews by contributor over time](https://k8s.devstats.cncf.io/d/46/pr-reviews-by-contributor?orgId=1&var-period=d7&var-repo_name=All&var-reviewers=All) +* [Time spent in each phase of our PR workflow](https://k8s.devstats.cncf.io/d/44/pr-time-to-approve-and-merge?orgId=1) + + + +## Into the Beyond + + + +今天,Kubernetes 项目跨越了5个组织125个仓库。有31个特殊利益集团和10个工作组在项目内协调发展。在过去的一年里,该项目有 [来自13800多名独立开发人员的参与](https://k8s.devstats.cncf.io/d/13/developer-activity-counts-by-repository-group?orgId=1&var-period_name=Last%20year&var-metric=contributions&var-repogroup_name=All)。 + + + +在任何给定的工作日,我们的 Prow 实例[运行超过10,000个 CI 工作](http://velodrome.k8s.io/dashboard/db/bigquery-metrics?panelId=10&fullscreen&orgId=1&from=now-6M&to=now); 从2017年3月到2018年3月,它有430万个工作岗位。 这些工作中的大多数涉及建立整个 Kubernetes 集群,并使用真实场景来实施它。 它们使我们能够确保所有受支持的 Kubernetes 版本跨云提供商,容器引擎和网络插件工作。 他们确保最新版本的 Kubernetes 能够启用各种可选功能,安全升级,满足性能要求,并跨架构工作。 + + + +今天[来自CNCF的公告](https://www.cncf.io/announcement/2018/08/29/cncf-receives-9-million-cloud-credit-grant-from-google) - 注意到 Google Cloud 有开始将 Kubernetes 项目的云资源的所有权和管理权转让给 CNCF 社区贡献者,我们很高兴能够开始另一个旅程。 允许项目基础设施由贡献者社区拥有和运营,遵循对项目其余部分有效的相同开放治理模型。 听起来令人兴奋。 请来 kubernetes.slack.com 上的 #sig-testing on kubernetes.slack.com 与我们联系。 + + + +想了解更多? 快来看看这些资源: + + + +* [Prow: Testing the way to Kubernetes Next](https://bentheelder.io/posts/prow) +* [Automation and the Kubernetes Contributor Experience](https://www.youtube.com/watch?v=BsIC7gPkH5M) diff --git a/content/zh/blog/_posts/2018-10-03-kubedirector.md b/content/zh/blog/_posts/2018-10-03-kubedirector.md new file mode 100644 index 0000000000..e07f1bb35f --- /dev/null +++ b/content/zh/blog/_posts/2018-10-03-kubedirector.md @@ -0,0 +1,306 @@ +--- +layout: blog +title: 'KubeDirector:在 Kubernetes 上运行复杂状态应用程序的简单方法' +date: 2018-10-03 +--- + + + + + +**作者**:Thomas Phelan(BlueData) + + +KubeDirector 是一个开源项目,旨在简化在 Kubernetes 上运行复杂的有状态扩展应用程序集群。KubeDirector 使用自定义资源定义(CRD) +框架构建,并利用了本地 Kubernetes API 扩展和设计哲学。这支持与 Kubernetes 用户/资源 管理以及现有客户端和工具的透明集成。 + + +我们最近[介绍了 KubeDirector 项目](https://medium.com/@thomas_phelan/operation-stateful-introducing-bluek8s-and-kubernetes-director-aa204952f619/),作为我们称为 BlueK8s 的更广泛的 Kubernetes 开源项目的一部分。我很高兴地宣布 [KubeDirector](https://github.com/bluek8s/kubedirector/) 的 +pre-alpha 代码现在已经可用。在这篇博客文章中,我将展示它是如何工作的。 + + +KubeDirector 提供以下功能: + + + +* 无需修改代码即可在 Kubernetes 上运行非云原生有状态应用程序。换句话说,不需要分解这些现有的应用程序来适应微服务设计模式。 +* 本机支持保存特定于应用程序的配置和状态。 +* 与应用程序无关的部署模式,最大限度地减少将新的有状态应用程序装载到 Kubernetes 的时间。 + + +KubeDirector 使熟悉数据密集型分布式应用程序(如 Hadoop、Spark、Cassandra、TensorFlow、Caffe2 等)的数据科学家能够在 Kubernetes 上运行这些应用程序 -- 只需极少的学习曲线,无需编写 GO 代码。由 KubeDirector 控制的应用程序由一些基本元数据和相关的配置工件包定义。应用程序元数据称为 KubeDirectorApp 资源。 + + +要了解 KubeDirector 的组件,请使用类似于以下的命令在 [GitHub](https://github.com/bluek8s/kubedirector/) 上克隆存储库: + +``` +git clone http://@github.com/bluek8s/kubedirector. +``` + + +Spark 2.2.1 应用程序的 KubeDirectorApp 定义位于文件 `kubedirector/deploy/example_catalog/cr-app-spark221e2.json` 中。 + + ``` + ~> cat kubedirector/deploy/example_catalog/cr-app-spark221e2.json + { + "apiVersion": "kubedirector.bluedata.io/v1alpha1", + "kind": "KubeDirectorApp", + "metadata": { + "name" : "spark221e2" + }, + "spec" : { + "systemctlMounts": true, + "config": { + "node_services": [ + { + "service_ids": [ + "ssh", + "spark", + "spark_master", + "spark_worker" + ], +… +``` + + +应用程序集群的配置称为 KubeDirectorCluster 资源。示例 Spark 2.2.1 集群的 KubeDirectorCluster 定义位于文件 +`kubedirector/deploy/example_clusters/cr-cluster-spark221.e1.yaml` 中。 + +``` +~> cat kubedirector/deploy/example_clusters/cr-cluster-spark221.e1.yaml +apiVersion: "kubedirector.bluedata.io/v1alpha1" +kind: "KubeDirectorCluster" +metadata: + name: "spark221e2" +spec: + app: spark221e2 + roles: + - name: controller + replicas: 1 + resources: + requests: + memory: "4Gi" + cpu: "2" + limits: + memory: "4Gi" + cpu: "2" + - name: worker + replicas: 2 + resources: + requests: + memory: "4Gi" + cpu: "2" + limits: + memory: "4Gi" + cpu: "2" + - name: jupyter +… +``` + + + +## 使用 KubeDirector 在 Kubernetes 上运行 Spark + + +使用 KubeDirector,可以轻松在 Kubernetes 上运行 Spark 集群。 + + +首先,使用命令 `kubectl version` 验证 Kubernetes(版本 1.9 或更高)是否正在运行 + +``` +~> kubectl version +Client Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.3", GitCommit:"a4529464e4629c21224b3d52edfe0ea91b072862", GitTreeState:"clean", BuildDate:"2018-09-09T18:02:47Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"} +Server Version: version.Info{Major:"1", Minor:"11", GitVersion:"v1.11.3", GitCommit:"a4529464e4629c21224b3d52edfe0ea91b072862", GitTreeState:"clean", BuildDate:"2018-09-09T17:53:03Z", GoVersion:"go1.10.3", Compiler:"gc", Platform:"linux/amd64"} +``` + + +使用以下命令部署 KubeDirector 服务和示例 KubeDirectorApp 资源定义: + +``` +cd kubedirector +make deploy +``` + + +这些将启动 KubeDirector pod: + +``` +~> kubectl get pods +NAME READY STATUS RESTARTS AGE +kubedirector-58cf59869-qd9hb 1/1 Running 0 1m +``` + + +`kubectl get KubeDirectorApp` 列出中已安装的 KubeDirector 应用程序 + +``` +~> kubectl get KubeDirectorApp +NAME AGE +cassandra311 30m +spark211up 30m +spark221e2 30m +``` + + +现在,您可以使用示例 KubeDirectorCluster 文件和 `kubectl create -f deploy/example_clusters/cr-cluster-spark211up.yaml` 命令 +启动 Spark 2.2.1 集群。验证 Spark 集群已经启动: + +``` +~> kubectl get pods +NAME READY STATUS RESTARTS AGE +kubedirector-58cf59869-djdwl 1/1 Running 0 19m +spark221e2-controller-zbg4d-0 1/1 Running 0 23m +spark221e2-jupyter-2km7q-0 1/1 Running 0 23m +spark221e2-worker-4gzbz-0 1/1 Running 0 23m +spark221e2-worker-4gzbz-1 1/1 Running 0 23m +``` + + +现在运行的服务包括 Spark 服务: + +``` +~> kubectl get service +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubedirector ClusterIP 10.98.234.194 60000/TCP 1d +kubernetes ClusterIP 10.96.0.1 443/TCP 1d +svc-spark221e2-5tg48 ClusterIP None 8888/TCP 21s +svc-spark221e2-controller-tq8d6-0 NodePort 10.104.181.123 22:30534/TCP,8080:31533/TCP,7077:32506/TCP,8081:32099/TCP 20s +svc-spark221e2-jupyter-6989v-0 NodePort 10.105.227.249 22:30632/TCP,8888:30355/TCP 20s +svc-spark221e2-worker-d9892-0 NodePort 10.107.131.165 22:30358/TCP,8081:32144/TCP 20s +svc-spark221e2-worker-d9892-1 NodePort 10.110.88.221 22:30294/TCP,8081:31436/TCP 20s +``` + + +将浏览器指向端口 31533 连接到 Spark 主节点 UI: + +![kubedirector](/images/blog/2018-10-03-kubedirector/kubedirector.png) + + +就是这样! +事实上,在上面的例子中,我们还部署了一个 Jupyter notebook 和 Spark 集群。 + + +要启动另一个应用程序(例如 Cassandra),只需指定另一个 KubeDirectorApp 文件: + +``` +kubectl create -f deploy/example_clusters/cr-cluster-cassandra311.yaml +``` + + +查看正在运行的 Cassandra 集群: + +``` +~> kubectl get pods +NAME READY STATUS RESTARTS AGE +cassandra311-seed-v24r6-0 1/1 Running 0 1m +cassandra311-seed-v24r6-1 1/1 Running 0 1m +cassandra311-worker-rqrhl-0 1/1 Running 0 1m +cassandra311-worker-rqrhl-1 1/1 Running 0 1m +kubedirector-58cf59869-djdwl 1/1 Running 0 1d +spark221e2-controller-tq8d6-0 1/1 Running 0 22m +spark221e2-jupyter-6989v-0 1/1 Running 0 22m +spark221e2-worker-d9892-0 1/1 Running 0 22m +spark221e2-worker-d9892-1 1/1 Running 0 22m +``` + + +现在,您有一个 Spark 集群(带有 Jupyter notebook )和一个运行在 Kubernetes 上的 Cassandra 集群。 +使用 `kubectl get service` 查看服务集。 + +``` +~> kubectl get service +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +kubedirector ClusterIP 10.98.234.194 60000/TCP 1d +kubernetes ClusterIP 10.96.0.1 443/TCP 1d +svc-cassandra311-seed-v24r6-0 NodePort 10.96.94.204 22:31131/TCP,9042:30739/TCP 3m +svc-cassandra311-seed-v24r6-1 NodePort 10.106.144.52 22:30373/TCP,9042:32662/TCP 3m +svc-cassandra311-vhh29 ClusterIP None 8888/TCP 3m +svc-cassandra311-worker-rqrhl-0 NodePort 10.109.61.194 22:31832/TCP,9042:31962/TCP 3m +svc-cassandra311-worker-rqrhl-1 NodePort 10.97.147.131 22:31454/TCP,9042:31170/TCP 3m +svc-spark221e2-5tg48 ClusterIP None 8888/TCP 24m +svc-spark221e2-controller-tq8d6-0 NodePort 10.104.181.123 22:30534/TCP,8080:31533/TCP,7077:32506/TCP,8081:32099/TCP 24m +svc-spark221e2-jupyter-6989v-0 NodePort 10.105.227.249 22:30632/TCP,8888:30355/TCP 24m +svc-spark221e2-worker-d9892-0 NodePort 10.107.131.165 22:30358/TCP,8081:32144/TCP 24m +svc-spark221e2-worker-d9892-1 NodePort 10.110.88.221 22:30294/TCP,8081:31436/TCP 24m +``` + + + +## 参与其中 + + +KubeDirector 是一个完全开放源码的 Apache v2 授权项目 – 在我们称为 BlueK8s 的更广泛的计划中,它是多个开放源码项目中的第一个。 +KubeDirector 的 pre-alpha 代码刚刚发布,我们希望您加入到不断增长的开发人员、贡献者和使用者社区。 +在 Twitter 上关注 [@BlueK8s](https://twitter.com/BlueK8s/),并通过以下渠道参与: + + + +* KubeDirector [Slack 聊天室](https://join.slack.com/t/bluek8s/shared_invite/enQtNDUwMzkwODY5OTM4LTRhYmRmZmE4YzY3OGUzMjA1NDg0MDVhNDQ2MGNkYjRhM2RlMDNjMTI1NDQyMjAzZGVlMDFkNThkNGFjZGZjMGY/) +* KubeDirector [GitHub 仓库](https://github.com/bluek8s/kubedirector/) diff --git a/content/zh/blog/_posts/2018-10-11-topology-aware-volume-provisioning.md b/content/zh/blog/_posts/2018-10-11-topology-aware-volume-provisioning.md new file mode 100644 index 0000000000..3aefd018ab --- /dev/null +++ b/content/zh/blog/_posts/2018-10-11-topology-aware-volume-provisioning.md @@ -0,0 +1,268 @@ +--- +layout: blog +title: 'Kubernetes 中的拓扑感知数据卷供应' +date: 2018-10-11 +--- + + + +**作者**: Michelle Au(谷歌) + + +通过提供拓扑感知动态卷供应功能,具有持久卷的多区域集群体验在 Kubernetes 1.12 中得到了改进。此功能使得 Kubernetes 在动态供应卷时能做出明智的决策,方法是从调度器获得为 Pod 提供数据卷的最佳位置。在多区域集群环境,这意味着数据卷能够在满足你的 Pod 运行需要的合适的区域被供应,从而允许您跨故障域轻松部署和扩展有状态工作负载,从而提供高可用性和容错能力。 + + +## 以前的挑战 + + +在此功能被提供之前,在多区域集群中使用区域化的持久磁盘(例如 AWS ElasticBlockStore,Azure Disk,GCE PersistentDisk)运行有状态工作负载存在许多挑战。动态供应独立于 Pod 调度处理,这意味着只要您创建了一个 PersistentVolumeClaim(PVC),一个卷就会被供应。这也意味着供应者不知道哪些 Pod 正在使用该卷,也不清楚任何可能影响调度的 Pod 约束。 + + +这导致了不可调度的 Pod,因为在以下区域中配置了卷: + + +* 没有足够的 CPU 或内存资源来运行 Pod +* 与节点选择器、Pod 亲和或反亲和策略冲突 +* 由于污点(taint)不能运行 Pod + + +另一个常见问题是,使用多个持久卷的非有状态 Pod 可能会在不同的区域中配置每个卷,从而导致一个不可调度的 Pod。 + + +次优的解决方法包括节点超配,或在正确的区域中手动创建卷,但这会造成难以动态部署和扩展有状态工作负载的问题。 + + +拓扑感知动态供应功能解决了上述所有问题。 + + +## 支持的卷类型 + + +在 1.12 中,以下驱动程序支持拓扑感知动态供应: + + +* AWS EBS +* Azure Disk +* GCE PD (包括 Regional PD) +* CSI(alpha) - 目前只有 GCE PD CSI 驱动实现了拓扑支持 + + +## 设计原则 + + +虽然最初支持的插件集都是基于区域的,但我们设计此功能时遵循 Kubernetes 跨环境可移植性的原则。 +拓扑规范是通用的,并使用类似于基于标签的规范,如 Pod nodeSelectors 和 nodeAffinity。 +该机制允许您定义自己的拓扑边界,例如内部部署集群中的机架,而无需修改调度程序以了解这些自定义拓扑。 + + +此外,拓扑信息是从 Pod 规范中抽象出来的,因此 Pod 不需要了解底层存储系统的拓扑特征。 +这意味着您可以在多个集群、环境和存储系统中使用相同的 Pod 规范。 + + +## 入门 + + +要启用此功能,您需要做的就是创建一个将 `volumeBindingMode` 设置为 `WaitForFirstConsumer` 的 StorageClass: + +``` +kind: StorageClass +apiVersion: storage.k8s.io/v1 +metadata: + name: topology-aware-standard +provisioner: kubernetes.io/gce-pd +volumeBindingMode: WaitForFirstConsumer +parameters: + type: pd-standard +``` + + +这个新设置表明卷配置器不立即创建卷,而是等待使用关联的 PVC 的 Pod 通过调度运行。 +请注意,不再需要指定以前的 StorageClass `zone` 和 `zones` 参数,因为现在在哪个区域中配置卷由 Pod 策略决定。 + + +接下来,使用此 StorageClass 创建一个 Pod 和 PVC。 +此过程与之前相同,但在 PVC 中指定了不同的 StorageClass。 +以下是一个假设示例,通过指定许多 Pod 约束和调度策略来演示新功能特性: + + +* 一个 Pod 多个 PVC +* 跨子区域的节点亲和 +* 同一区域 Pod 反亲和 + +``` +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: web +spec: + serviceName: "nginx" + replicas: 2 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: failure-domain.beta.kubernetes.io/zone + operator: In + values: + - us-central1-a + - us-central1-f + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - nginx + topologyKey: failure-domain.beta.kubernetes.io/zone + containers: + - name: nginx + image: gcr.io/google_containers/nginx-slim:0.8 + ports: + - containerPort: 80 + name: web + volumeMounts: + - name: www + mountPath: /usr/share/nginx/html + - name: logs + mountPath: /logs + volumeClaimTemplates: + - metadata: + name: www + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: topology-aware-standard + resources: + requests: + storage: 10Gi + - metadata: + name: logs + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: topology-aware-standard + resources: + requests: + storage: 1Gi +``` + + +之后,您可以看到根据 Pod 设置的策略在区域中配置卷: + +``` +$ kubectl get pv -o=jsonpath='{range .items[*]}{.spec.claimRef.name}{"\t"}{.metadata.labels.failure\-domain\.beta\.kubernetes\.io/zone}{"\n"}{end}' +www-web-0 us-central1-f +logs-web-0 us-central1-f +www-web-1 us-central1-a +logs-web-1 us-central1-a +``` + + +## 我怎样才能了解更多? + + +有关拓扑感知动态供应功能的官方文档可在此处获取:https://kubernetes.io/docs/concepts/storage/storage-classes/#volume-binding-mode + + +有关 CSI 驱动程序的文档,请访问:https://kubernetes-csi.github.io/docs/ + + +## 下一步是什么? + + +我们正积极致力于改进此功能以支持: + + +* 更多卷类型,包括本地卷的动态供应 +* 动态容量可附加计数和每个节点的容量限制 + + +## 我如何参与? + + +如果您对此功能有反馈意见或有兴趣参与设计和开发,请加入 [Kubernetes 存储特别兴趣小组](https://github.com/kubernetes/community/tree/master/sig-storage)(SIG)。我们正在快速成长,并始终欢迎新的贡献者。 + + +特别感谢帮助推出此功能的所有贡献者,包括 Cheng Xing ([verult](https://github.com/verult))、Chuqiang Li ([lichuqiang](https://github.com/lichuqiang))、David Zhu ([davidz627](https://github.com/davidz627))、Deep Debroy ([ddebroy](https://github.com/ddebroy))、Jan Šafránek ([jsafrane](https://github.com/jsafrane))、Jordan Liggitt ([liggitt](https://github.com/liggitt))、Michelle Au ([msau42](https://github.com/msau42))、Pengfei Ni ([feiskyer](https://github.com/feiskyer))、Saad Ali ([saad-ali](https://github.com/saad-ali))、Tim Hockin ([thockin](https://github.com/thockin)),以及 Yecheng Fu ([cofyc](https://github.com/cofyc))。 diff --git a/content/zh/blog/_posts/2018-10-15-steering-election-results.md b/content/zh/blog/_posts/2018-10-15-steering-election-results.md new file mode 100644 index 0000000000..8e7d5edf7e --- /dev/null +++ b/content/zh/blog/_posts/2018-10-15-steering-election-results.md @@ -0,0 +1,73 @@ +--- +layout: blog +title: '2018 年督导委员会选举结果' +date: 2018-10-15 +--- + + + +**作者**: Jorge Castro (Heptio), Ihor Dvoretskyi (CNCF), Paris Pittman (Google) + + +## 结果 + +[Kubernetes 督导委员会选举](https://kubernetes.io/blog/2018/09/06/2018-steering-committee-election-cycle-kicks-off/)现已完成,以下候选人获得了立即开始的两年任期: + +* Aaron Crickenberger, Google, [@spiffxp](https://github.com/spiffxp) +* Davanum Srinivas, Huawei, [@dims](https://github.com/dims) +* Tim St. Clair, Heptio, [@timothysc](https://github.com/timothysc) + + +## 十分感谢! + + +* 督导委员会荣誉退休成员 [Quinton Hoole](https://github.com/quinton-hoole),表扬他在过去一年为社区所作的贡献。我们期待着 +* 参加竞选的候选人。愿我们永远拥有一群强大的人,他们希望在每一次选举中都能像你们一样推动社区向前发展。 +* 共计 307 名选民参与投票。 +* 本次选举由康奈尔大学主办 [CIVS](https://civs.cs.cornell.edu/)! + + +## 加入督导委员会 + +你可以关注督导委员会的[任务清单](https://git.k8s.io/steering/backlog.md),并通过向他们的[代码仓库](https://github.com/kubernetes/steering)提交 issue 或 PR 的方式来参与。他们也会在[UTC 时间每周三晚 8 点](https://github.com/kubernetes/steering)举行会议,并定期与我们的贡献者见面。 + + +督导委员会会议: + +* [YouTube 播放列表](https://www.youtube.com/playlist?list=PL69nYSiGNLP1yP1B_nd9-drjoxp0Q14qM) + + +与我们的贡献者会面: + + + +* [2018 年 10 月 3 日](https://youtu.be/x6Jm8p0K-IQ) +* [2018 年 7 月 5 日](https://youtu.be/UbxWV12Or58) diff --git a/content/zh/blog/_posts/2018-10-16-kubernetes-2018-north-american-contributor-summit.md b/content/zh/blog/_posts/2018-10-16-kubernetes-2018-north-american-contributor-summit.md new file mode 100644 index 0000000000..b504a5c6b6 --- /dev/null +++ b/content/zh/blog/_posts/2018-10-16-kubernetes-2018-north-american-contributor-summit.md @@ -0,0 +1,118 @@ +--- +layout: "Blog" +title: "Kubernetes 2018 年北美贡献者峰会" +date: 2018-10-16 +--- + + +**作者:** + +[Bob Killen][bob](密歇根大学) +[Sahdev Zala][sahdev](IBM), +[Ihor Dvoretskyi][ihor](CNCF) + + +2018 年北美 Kubernetes 贡献者峰会将在西雅图 [KubeCon + CloudNativeCon][kubecon] 会议之前举办,这将是迄今为止规模最大的一次盛会。 + +这是一个将新老贡献者聚集在一起,面对面交流和分享的活动;并为现有的贡献者提供一个机会,帮助塑造社区发展的未来。它为新的社区成员提供了一个学习、探索和实践贡献工作流程的良好空间。 + + +与之前的贡献者峰会不同,本次活动为期两天,有一个更为轻松的行程安排,一般贡献者将于 12 月 9 日(周日)下午 5 点至 8 点在距离会议中心仅几步远的 [Garage Lounge and Gaming Hall][garage] 举办峰会。在那里,贡献者也可以进行台球、保龄球等娱乐活动,而且还有各种食品和饮料。 + + +接下来的一天,也就是 10 号星期一,有三个独立的会议你可以选择参与: + + +### 新贡献者研讨会: + +为期半天的研讨会旨在让新贡献者加入社区,并营造一个良好的 Kubernetes 社区工作环境。 +请在开会期间保持在场,该讨论会不允许随意进出。 + + +### 当前贡献者追踪: + +保留给那些积极参与项目开发的贡献者;目前的贡献者追踪包括讲座、研讨会、聚会、Unconferences 会议、指导委员会会议等等! +请留意 [GitHub 中的时间表][时间表],因为内容经常更新。 + + +### Docs 冲刺: + +SIG-Docs 将在活动日期临近的时候列出一个需要处理的问题和挑战列表。 + + +## 注册: + +要注册贡献者峰会,请参阅 Git Hub 上的[活动详情注册部分][注册]。请注意报名正在审核中。 +如果您选择了 “当前贡献者追踪”,而您却不是一个活跃的贡献者,您将被要求参加新贡献者研讨会,或者被要求进入候补名单。 +成千上万的贡献者只有 300 个位置,我们需要确保正确的人被安排席位。 + + +如果您有任何问题或疑虑,请随时通过 community@kubernetes.io 联系贡献者峰会组织团队。 + + +期待在那里看到每个人! + +[bob]: https://twitter.com/mrbobbytables +[sahdev]: https://twitter.com/sp_zala +[ihor]: https://twitter.com/idvoretskyi +[kubecon]: https://events.linuxfoundation.org/events/kubecon-cloudnativecon-north-america-2018/ +[garage]: https://www.garagebilliards.com/ +[时间表]: https://git.k8s.io/community/events/2018/12-contributor-summit#agenda +[注册]: https://git.k8s.io/community/events/2018/12-contributor-summit#registration diff --git a/content/zh/blog/_posts/2018-11-08-kubernetes-docs-update-i18n.md b/content/zh/blog/_posts/2018-11-08-kubernetes-docs-update-i18n.md new file mode 100644 index 0000000000..cf6d5e58cb --- /dev/null +++ b/content/zh/blog/_posts/2018-11-08-kubernetes-docs-update-i18n.md @@ -0,0 +1,89 @@ +--- +layout: blog +title: 'Kubernetes 文档更新,国际版' +date: 2018-11-08 +--- + + + +**作者**:Zach Corleissen (Linux 基金会) + + +作为文档特别兴趣小组(SIG Docs)的联合主席,我很高兴能与大家分享 Kubernetes 文档在本地化(l10n)方面所拥有的一个完全成熟的工作流。 + + +## 丰富的缩写 + + +L10n 是 _localization_ 的缩写。 + + +I18n 是 _internationalization_ 的缩写。 + + +I18n 定义了[做什么](https://www.w3.org/International/questions/qa-i18n) 能让 l10n 更容易。而 L10n 更全面,相比翻译( _t9n_ )具备更完善的流程。 + + +## 为什么本地化很重要 + + +SIG Docs 的目标是让 Kubernetes 更容易为尽可能多的人使用。 + + +一年前,我们研究了是否有可能由一个独立翻译 Kubernetes 文档的中国团队来主持文档输出。经过多次交谈(包括 OpenStack l10n 的专家),[多次转变](https://kubernetes.io/blog/2018/05/05/hugo-migration/),以及[重新致力于更轻松的本地化](https://github.com/kubernetes/website/pull/10485),我们意识到,开源文档就像开源软件一样,是在可能的边缘不断进行实践。 + + +整合工作流程、语言标签和团队级所有权可能看起来像是十分简单的改进,但是这些功能使 l10n 可以扩展到规模越来越大的 l10n 团队。随着 SIG Docs 不断改进,我们已经在单一工作流程中偿还了大量技术债务并简化了 l10n。这对未来和现在都很有益。 + + +## 整合的工作流程 + + +现在,本地化已整合到 [kubernetes/website](https://github.com/kubernetes/website) 存储库。我们已经配置了 Kubernetes CI/CD 系统,[Prow](https://github.com/kubernetes/test-infra/tree/master/prow) 来处理自动语言标签分配以及团队级 PR 审查和批准。 + + +### 语言标签 + + +Prow 根据文件路径自动添加语言标签。感谢 SIG Docs 贡献者 [June Yi](https://github.com/kubernetes/test-infra/pull/9835),他让人们还可以在 pull request(PR)注释中手动分配语言标签。例如,当为 issue 或 PR 留下下述注释时,将为之分配标签 `language/ko`(Korean)。 + +``` +/language ko +``` + + + +这些存储库标签允许审阅者按语言过滤 PR 和 issue。例如,您现在可以过滤 kubernetes/website 面板中[具有中文内容的 PR](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+label%3Alanguage%2Fzh)。 + + +### 团队审核 + + +L10n 团队现在可以审查和批准他们自己的 PR。例如,英语的审核和批准权限在位于用于显示英语内容的顶级子文件夹中的 [OWNERS 文件中指定](https://github.com/kubernetes/website/blob/master/content/en/OWNERS)。 + + +将 `OWNERS` 文件添加到子目录可以让本地化团队审查和批准更改,而无需由可能并不擅长该门语言的审阅者进行批准。 + + +## 下一步是什么 + + +我们期待着[上海的 doc sprint](https://kccncchina2018english.sched.com/event/HVb2/contributor-summit-doc-sprint-additional-registration-required) 能作为中国 l10n 团队的资源。 + + +我们很高兴继续支持正在取得良好进展的日本和韩国 l10n 队伍。 + + +如果您有兴趣将 Kubernetes 本地化为您自己的语言或地区,请查看我们的[本地化 Kubernetes 文档指南](https://kubernetes.io/docs/contribute/localization/),并联系 [SIG Docs 主席团](https://github.com/kubernetes/community/tree/master/sig-docs#leadership)获取支持。 + + +### 加入SIG Docs + + +如果您对 Kubernetes 文档感兴趣,请参加 SIG Docs [每周会议](https://github.com/kubernetes/community/tree/master/sig-docs#meetings),或在 [Kubernetes Slack 加入 #sig-docs](https://kubernetes.slack.com/messages/C1J0BPD2M/details/)。 diff --git a/content/zh/blog/_posts/2018-12-05-new-contributor-shanghai.md b/content/zh/blog/_posts/2018-12-05-new-contributor-shanghai.md index 88add3bf23..c3c74e4298 100644 --- a/content/zh/blog/_posts/2018-12-05-new-contributor-shanghai.md +++ b/content/zh/blog/_posts/2018-12-05-new-contributor-shanghai.md @@ -3,8 +3,8 @@ layout: blog title: '新贡献者工作坊上海站' date: 2018-12-05 --- - - +--- +title: 案例分析 +linkTitle: 案例分析 +bigheader: Kubernetes 用户案例分析 +abstract: 在生产环境下使用 Kubernetes 的案例集 +layout: basic +class: gridPage +cid: caseStudies +--- + + diff --git a/content/zh/case-studies/adform/adform_featured_logo.png b/content/zh/case-studies/adform/adform_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cd0fa7b6c9c4e1e2bcb4702de2e2ccd3fd5693c2 GIT binary patch literal 7110 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 WLghSRo#cPMtjS3$1Ir~%0{;toIy|2M literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/adform/index.html b/content/zh/case-studies/adform/index.html new file mode 100644 index 0000000000..e9a8acc7a2 --- /dev/null +++ b/content/zh/case-studies/adform/index.html @@ -0,0 +1,118 @@ +--- +title: Adform Case Study +linkTitle: Adform +case_study_styles: true +cid: caseStudies +css: /css/style_case_studies.css +logo: adform_featured_logo.png +draft: false +featured: true +weight: 47 +quote: > + Kubernetes enabled the self-healing and immutable infrastructure. We can do faster releases, so our developers are really happy. They can ship our features faster than before, and that makes our clients happier. +--- + +
+

CASE STUDY:
Improving Performance and Morale with Cloud Native + +

+ +
+ +
+ Company  AdForm     Location  Copenhagen, Denmark     Industry  Adtech +
+ +
+
+
+
+

Challenge

+ Adform’s mission is to provide a secure and transparent full stack of advertising technology to enable digital ads across devices. The company has a large infrastructure: OpenStack-based private clouds running on 1,100 physical servers in 7 data centers around the world, 3 of which were opened in the past year. With the company’s growth, the infrastructure team felt that "our private cloud was not really flexible enough," says IT System Engineer Edgaras Apšega. "The biggest pain point is that our developers need to maintain their virtual machines, so rolling out technology and new software takes time. We were really struggling with our releases, and we didn’t have self-healing infrastructure." + + +
+ +

Solution

+ The team, which had already been using Prometheus for monitoring, embraced Kubernetes and cloud native practices in 2017. "To start our Kubernetes journey, we had to adapt all our software, so we had to choose newer frameworks," says Apšega. "We also adopted the microservices way, so observability is much better because you can inspect the bug or the services separately." + + +
+ +
+ +

Impact

+ "Kubernetes helps our business a lot because our features are coming to market faster," says Apšega. The release process went from several hours to several minutes. Autoscaling has been at least 6 times faster than the semi-manual VM bootstrapping and application deployment required before. The team estimates that the company has experienced cost savings of 4-5x due to less hardware and fewer man hours needed to set up the hardware and virtual machines, metrics, and logging. Utilization of the hardware resources has been reduced as well, with containers notching 2-3 times more efficiency over virtual machines. "The deployments are very easy because developers just push the code and it automatically appears on Kubernetes," says Apšega. Prometheus has also had a positive impact: "It provides high availability for metrics and alerting. We monitor everything starting from hardware to applications. Having all the metrics in Grafana dashboards provides great insight on your systems." + + +
+ +
+
+
+
+"Kubernetes enabled the self-healing and immutable infrastructure. We can do faster releases, so our developers are really happy. They can ship our features faster than before, and that makes our clients happier."

— Edgaras Apšega, IT Systems Engineer, Adform
+ +
+
+ + +
+
+

Adform made headlines last year when it detected the HyphBot ad fraud network that was costing some businesses hundreds of thousands of dollars a day.

With its mission to provide a secure and transparent full stack of advertising technology to enable an open internet, Adform published a white paper revealing what it did—and others could too—to limit customers’ exposure to the scam.

+In that same spirit, Adform is sharing its cloud native journey. "When you see that everyone shares their best practices, it inspires you to contribute back to the project," says IT Systems Engineer Edgaras Apšega.

+The company has a large infrastructure: OpenStack-based private clouds running on 1,100 physical servers in their own seven data centers around the world, three of which were opened in the past year. With the company’s growth, the infrastructure team felt that "our private cloud was not really flexible enough," says Apšega. "The biggest pain point is that our developers need to maintain their virtual machines, so rolling out technology and new software really takes time. We were really struggling with our releases, and we didn’t have self-healing infrastructure." + + +
+
+
+
+ "The fact that Cloud Native Computing Foundation incubated Kubernetes was a really big point for us because it was vendor neutral. And we can see that a community really gathers around it. Everyone shares their experiences, their knowledge, and the fact that it’s open source, you can contribute."

— Edgaras Apšega, IT Systems Engineer, Adform
+
+
+
+
+ +The team, which had already been using Prometheus for monitoring, embraced Kubernetes, microservices, and cloud native practices. "The fact that Cloud Native Computing Foundation incubated Kubernetes was a really big point for us because it was vendor neutral," says Apšega. "And we can see that a community really gathers around it."

+A proof of concept project was started, with a Kubernetes cluster running on bare metal in the data center. When developers saw how quickly containers could be spun up compared to the virtual machine process, "they wanted to ship their containers in production right away, and we were still doing proof of concept," says IT Systems Engineer Andrius Cibulskis. +Of course, a lot of work still had to be done. "First of all, we had to learn Kubernetes, see all of the moving parts, how they glue together," says Apšega. "Second of all, the whole CI/CD part had to be redone, and our DevOps team had to invest more man hours to implement it. And third is that developers had to rewrite the code, and they’re still doing it." +

+The first production cluster was launched in the spring of 2018, and is now up to 20 physical machines dedicated for pods throughout three data centers, with plans for separate clusters in the other four data centers. The user-facing Adform application platform, data distribution platform, and back ends are now all running on Kubernetes. "Many APIs for critical applications are being developed for Kubernetes," says Apšega. "Teams are rewriting their applications to .NET core, because it supports containers, and preparing to move to Kubernetes. And new applications, by default, go in containers." + + +
+
+
+
+"Releases are really nice for them, because they just push their code to Git and that’s it. They don’t have to worry about their virtual machines anymore."

— Andrius Cibulskis, IT Systems Engineer, Adform
+
+
+ +
+
+This big push has been driven by the real impact that these new practices have had. "Kubernetes helps our business a lot because our features are coming to market faster," says Apšega. "The deployments are very easy because developers just push the code and it automatically appears on Kubernetes." The release process went from several hours to several minutes. Autoscaling is at least six times faster than the semi-manual VM bootstrapping and application deployment required before.

+The team estimates that the company has experienced cost savings of 4-5x due to less hardware and fewer man hours needed to set up the hardware and virtual machines, metrics, and logging. Utilization of the hardware resources has been reduced as well, with containers notching two to three times more efficiency over virtual machines.

+Prometheus has also had a positive impact: "It provides high availability for metrics and alerting," says Apšega. "We monitor everything starting from hardware to applications. Having all the metrics in Grafana dashboards provides great insight on our systems." + + + +
+ +
+
+ "I think that our company just started our cloud native journey. It seems like a huge road ahead, but we’re really happy that we joined it."

— Edgaras Apšega, IT Systems Engineer, Adform
+
+
+ +
+All of these benefits have trickled down to individual team members, whose working lives have been changed for the better. "They used to have to get up at night to re-start some services, and now Kubernetes handles all of that," says Apšega. Adds Cibulskis: "Releases are really nice for them, because they just push their code to Git and that’s it. They don’t have to worry about their virtual machines anymore." Even the security teams have been impacted. "Security teams are always not happy," says Apšega, "and now they’re happy because they can easily inspect the containers." +The company plans to remain in the data centers for now, "mostly because we want to keep all the data, to not share it in any way," says Cibulskis, "and it’s cheaper at our scale." But, Apšega says, the possibility of using a hybrid cloud for computing is intriguing: "One of the projects we’re interested in is the Virtual Kubelet that lets you spin up the working nodes on different clouds to do some computing." +

+Apšega, Cibulskis and their colleagues are keeping tabs on how the cloud native ecosystem develops, and are excited to contribute where they can. "I think that our company just started our cloud native journey," says Apšega. "It seems like a huge road ahead, but we’re really happy that we joined it." + + + +
+ +
diff --git a/content/zh/case-studies/amadeus/amadeus_featured.png b/content/zh/case-studies/amadeus/amadeus_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..d23d7b0163854a5da1da707c3c4aee2f43a594a5 GIT binary patch literal 6970 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 E2e!!Rvj6}9 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/amadeus/amadeus_logo.png b/content/zh/case-studies/amadeus/amadeus_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6191c7f6819f2c325bf843e85d63a35a2f4ff6ac GIT binary patch literal 19562 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 +

CASE STUDY:
Another Technical Evolution for a 30-Year-Old Company +

+
+
+ Company  Amadeus IT Group     Location  Madrid, Spain     Industry  Travel Technology +
+
+
+
+
+

Challenge

+ In the past few years, Amadeus, which provides IT solutions to the travel industry around the world, found itself in need of a new platform for the 5,000 services supported by its service-oriented architecture. The 30-year-old company operates its own data center in Germany, and there were growing demands internally and externally for solutions that needed to be geographically dispersed. And more generally, "we had objectives of being even more highly available," says Eric Mountain, Senior Expert, Distributed Systems at Amadeus. Among the company’s goals: to increase automation in managing its infrastructure, optimize the distribution of workloads, use data center resources more efficiently, and adopt new technologies more easily. +
+
+

Solution

+ Mountain has been overseeing the company’s migration to Kubernetes, using OpenShift Container Platform, Red Hat’s enterprise container platform. +

+

Impact

+ One of the first projects the team deployed in Kubernetes was the Amadeus Airline Cloud Availability solution, which helps manage ever-increasing flight-search volume. "It’s now handling in production several thousand transactions per second, and it’s deployed in multiple data centers throughout the world," says Mountain. "It’s not a migration of an existing workload; it’s a whole new workload that we couldn’t have done otherwise. [This platform] gives us access to market opportunities that we didn’t have before." +
+
+
+ +
+
+ "We want multi-data center capabilities, and we want them for our mainstream system as well. We didn’t think that we could achieve them with our existing system. We need new automation, things that Kubernetes and OpenShift bring."

- Eric Mountain, Senior Expert, Distributed Systems at Amadeus IT Group
+
+
+
+ +
+

In his two decades at Amadeus, Eric Mountain has been the migrations guy.

+ Back in the day, he worked on the company’s move from Unix to Linux, and now he’s overseeing the journey to cloud native. "Technology just keeps changing, and we embrace it," he says. "We are celebrating our 30 years this year, and we continue evolving and innovating to stay cost-efficient and enhance everyone’s travel experience, without interrupting workflows for the customers who depend on our technology."

+ That was the challenge that Amadeus—which provides IT solutions to the travel industry around the world, from flight searches to hotel bookings to customer feedback—faced in 2014. The technology team realized it was in need of a new platform for the 5,000 services supported by its service-oriented architecture.

+ The tipping point occurred when they began receiving many requests, internally and externally, for solutions that needed to be geographically outside the company’s main data center in Germany. "Some requests were for running our applications on customer premises," Mountain says. "There were also new services we were looking to offer that required response time to the order of a few hundred milliseconds, which we couldn’t achieve with transatlantic traffic. Or at least, not without eating into a considerable portion of the time available to our applications for them to process individual queries."

+ More generally, the company was interested in leveling up on high availability, increasing automation in managing infrastructure, optimizing the distribution of workloads and using data center resources more efficiently. "We have thousands and thousands of servers," says Mountain. "These servers are assigned roles, so even if the setup is highly automated, the machine still has a given role. It’s wasteful on many levels. For instance, an application doesn’t necessarily use the machine very optimally. Virtualization can help a bit, but it’s not a silver bullet. If that machine breaks, you still want to repair it because it has that role and you can’t simply say, ‘Well, I’ll bring in another machine and give it that role.’ It’s not fast. It’s not efficient. So we wanted the next level of automation."

+
+
+ +
+
+ "We hope that if we build on what others have built, what we do might actually be upstream-able. As Kubernetes and OpenShift progress, we see that we are indeed able to remove some of the additional layers we implemented to compensate for gaps we perceived earlier." +
+
+ +
+
+ While mainly a C++ and Java shop, Amadeus also wanted to be able to adopt new technologies more easily. Some of its developers had started using languages like Python and databases like Couchbase, but Mountain wanted still more options, he says, "in order to better adapt our technical solutions to the products we offer, and open up entirely new possibilities to our developers." Working with recent technologies and cool new things would also make it easier to attract new talent. +

+ All of those needs led Mountain and his team on a search for a new platform. "We did a set of studies and proofs of concept over a fairly short period, and we considered many technologies," he says. "In the end, we were left with three choices: build everything on premise, build on top of Kubernetes whatever happens to be missing from our point of view, or go with OpenShift and build whatever remains there." +

+ The team decided against building everything themselves—though they’d done that sort of thing in the past—because "people were already inventing things that looked good," says Mountain. +

+ Ultimately, they went with OpenShift Container Platform, Red Hat’s Kubernetes-based enterprise offering, instead of building on top of Kubernetes because "there was a lot of synergy between what we wanted and the way Red Hat was anticipating going with OpenShift," says Mountain. "They were clearly developing Kubernetes, and developing certain things ahead of time in OpenShift, which were important to us, such as more security." +

+ The hope was that those particular features would eventually be built into Kubernetes, and, in the case of security, Mountain feels that has happened. "We realize that there’s always a certain amount of automation that we will probably have to develop ourselves to compensate for certain gaps," says Mountain. "The less we do that, the better for us. We hope that if we build on what others have built, what we do might actually be upstream-able. As Kubernetes and OpenShift progress, we see that we are indeed able to remove some of the additional layers we implemented to compensate for gaps we perceived earlier." +
+
+ +
+
+ "It’s not a migration of an existing workload; it’s a whole new workload that we couldn’t have done otherwise. [This platform] gives us access to market opportunities that we didn’t have before." +
+
+ +
+
+ The first project the team tackled was one that they knew had to run outside the data center in Germany. Because of the project’s needs, "We couldn’t rely only on the built-in Kubernetes service discovery; we had to layer on top of that an extra service discovery level that allows us to load balance at the operation level within our system," says Mountain. They also built a stream dedicated to monitoring, which at the time wasn’t offered in the Kubernetes or OpenShift ecosystem. Now that Prometheus and other products are available, Mountain says the company will likely re-evaluate their monitoring system: "We obviously always like to leverage what Kubernetes and OpenShift can offer." +

+ The second project ended up going into production first: the Amadeus Airline Cloud Availability solution, which helps manage ever-increasing flight-search volume and was deployed in public cloud. Launched in early 2016, it is "now handling in production several thousand transactions per second, and it’s deployed in multiple data centers throughout the world," says Mountain. "It’s not a migration of an existing workload; it’s a whole new workload that we couldn’t have done otherwise. [This platform] gives us access to market opportunities that we didn’t have before." +

+ Having been through this kind of technical evolution more than once, Mountain has advice on how to handle the cultural changes. "That’s one aspect that we can tackle progressively," he says. "We have to go on supplying our customers with new features on our pre-existing products, and we have to keep existing products working. So we can’t simply do absolutely everything from one day to the next. And we mustn’t sell it that way." +

+ The first order of business, then, is to pick one or two applications to demonstrate that the technology works. Rather than choosing a high-impact, high-risk project, Mountain’s team selected a smaller application that was representative of all the company’s other applications in its complexity: "We just made sure we picked something that’s complex enough, and we showed that it can be done." +
+
+ +
+
+ "The bottom line is we want these multi-data center capabilities, and we want them as well for our mainstream system," he says. "And we don’t think that we can implement them with our previous system. We need the new automation, homogeneity, and scale that Kubernetes and OpenShift bring." +
+
+ +
+
+ Next comes convincing people. "On the operations side and on the R&D side, there will be people who say quite rightly, ‘There is a system, and it works, so why change?’" Mountain says. "The only thing that really convinces people is showing them the value." For Amadeus, people realized that the Airline Cloud Availability product could not have been made available on the public cloud with the company’s existing system. The question then became, he says, "Do we go into a full-blown migration? Is that something that is justified?" +

+ "The bottom line is we want these multi-data center capabilities, and we want them as well for our mainstream system," he says. "And we don’t think that we can implement them with our previous system. We need the new automation, homogeneity, and scale that Kubernetes and OpenShift bring." +

+ So how do you get everyone on board? "Make sure you have good links between your R&D and your operations," he says. "Also make sure you’re going to talk early on to the investors and stakeholders. Figure out what it is that they will be expecting from you, that will convince them or not, that this is the right way for your company." +

+ His other advice is simply to make the technology available for people to try it. "Kubernetes and OpenShift Origin are open source software, so there’s no complicated license key for the evaluation period and you’re not limited to 30 days," he points out. "Just go and get it running." Along with that, he adds, "You’ve got to be prepared to rethink how you do things. Of course making your applications as cloud native as possible is how you’ll reap the most benefits: 12 factors, CI/CD, which is continuous integration, continuous delivery, but also continuous deployment." +

+ And while they explore that aspect of the technology, Mountain and his team will likely be practicing what he preaches to others taking the cloud native journey. "See what happens when you break it, because it’s important to understand the limits of the system," he says. Or rather, he notes, the advantages of it. "Breaking things on Kube is actually one of the nice things about it—it recovers. It’s the only real way that you’ll see that you might be able to do things." +
+
diff --git a/content/zh/case-studies/ancestry/ancestry_featured.png b/content/zh/case-studies/ancestry/ancestry_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..6d63daae32139867e33f6fe0d3eb68a36f0c4ded GIT binary patch literal 21016 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/ancestry/ancestry_logo.png b/content/zh/case-studies/ancestry/ancestry_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5fbade8decbc19b9e913fb9a7f0cd70d9f152ab3 GIT binary patch literal 21141 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/ancestry/index.html b/content/zh/case-studies/ancestry/index.html new file mode 100644 index 0000000000..a992a284ac --- /dev/null +++ b/content/zh/case-studies/ancestry/index.html @@ -0,0 +1,117 @@ +--- +title: Ancestry Case Study + +case_study_styles: true +cid: caseStudies +css: /css/style_ancestry.css +--- + +

+

CASE STUDY:
Digging Into the Past With New Technology

+ +
+ +
+ Company  Ancestry     Location  Lehi, Utah     Industry  Internet Company, Online Services +
+ +
+ +
+
+
+ +

Challenge

+Ancestry, the global leader in family history and consumer genomics, uses sophisticated engineering and technology to help everyone, everywhere discover the story of what led to them. The company has spent more than 30 years innovating and building products and technologies that at their core, result in real and emotional human responses. Ancestry currently serves more than 2.6 million paying subscribers, holds 20 billion historical records, 90 million family trees and more than four million people are in its AncestryDNA network, making it the largest consumer genomics DNA network in the world. The company's popular website, ancestry.com, has been working with big data long before the term was popularized. The site was built on hundreds of services, technologies and a traditional deployment methodology. "It's worked well for us in the past," says Paul MacKay, software engineer and architect at Ancestry, "but had become quite cumbersome in its processing and is time-consuming. As a primarily online service, we are constantly looking for ways to accelerate to be more agile in delivering our solutions and our products." + +
+ +
+ +
+

Solution

+ + The company is transitioning to cloud native infrastructure, using Docker containerization, Kubernetes orchestration and Prometheus for cluster monitoring.
+
+

Impact

+ "Every single product, every decision we make at Ancestry, focuses on delighting our customers with intimate, sometimes life-changing discoveries about themselves and their families," says MacKay. "As the company continues to grow, the increased productivity gains from using Kubernetes has helped Ancestry make customer discoveries faster. With the move to Dockerization for example, instead of taking between 20 to 50 minutes to deploy a new piece of code, we can now deploy in under a minute for much of our code. We’ve truly experienced significant time savings in addition to the various features and benefits from cloud native and Kubernetes-type technologies." +
+
+
+ +
+
+ "At a certain point, you have to step back if you're going to push a new technology and get key thought leaders with engineers within the organization to become your champions for new technology adoption. At training sessions, the development teams were always the ones that were saying, 'Kubernetes saved our time tremendously; it's an enabler. It really is incredible.'"

- PAUL MACKAY, SOFTWARE ENGINEER AND ARCHITECT AT ANCESTRY +
+
+ +
+
+

It started with a Shaky Leaf.

+ + Since its introduction a decade ago, the Shaky Leaf icon has become one of Ancestry's signature features, which signals to users that there's a helpful hint you can use to find out more about your family tree.

+ So when the company decided to begin moving its infrastructure to cloud native technology, the first service that was launched on Kubernetes, the open source platform for managing application containers across clusters of hosts, was this hint system. Think of it as Amazon's recommended products, but instead of recommending products the company recommends records, stories, or familial connections. "It was a very important part of the site," says Ancestry software engineer and architect Paul MacKay, "but also small enough for a pilot project that we knew we could handle in a very appropriate, secure way."

+ And when it went live smoothly in early 2016, "our deployment time for this service literally was cut down from 50 minutes to 2 or 5 minutes," MacKay adds. "The development team was just thrilled because we're focused on supplying a great experience for our customers. And that means features, it means stability, it means all those things that we need for a first-in-class type operation."

+ The stability of that Shaky Leaf was a signal for MacKay and his team that their decision to embrace cloud native technologies was the right one for the company. With a private data center, Ancestry built its website (which launched in 1996) on hundreds of services and technologies and a traditional deployment methodology. "It worked well for us in the past, but the sum of the legacy systems became quite cumbersome in its processing and was time-consuming," says MacKay. "We were looking for other ways to accelerate, to be more agile in delivering our solutions and our products." +
+
+ +
+
+"And when it [Kubernetes] went live smoothly in early 2016, 'our deployment time for this service literally was cut down from 50 minutes to 2 or 5 minutes,' MacKay adds. 'The development team was just thrilled because we're focused on supplying a great experience for our customers. And that means features, it means stability, it means all those things that we need for a first-in-class type operation.'" +
+
+ +
+
+ That need led them in 2015 to explore containerization. Ancestry engineers had already been using technology like Java and Python on Linux, so part of the decision was about making the infrastructure more Linux-friendly. They quickly decided that they wanted to go with Docker for containerization, "but it always comes down to the orchestration part of it to make it really work," says MacKay.

+ His team looked at orchestration platforms offered by Docker Compose, Mesos and OpenStack, and even started to prototype some homegrown solutions. And then they started hearing rumblings of the imminent release of Kubernetes v1.0. "At the forefront, we were looking at the secret store, so we didn't have to manage that all ourselves, the config maps, the methodology of seamless deployment strategy," he says. "We found that how Kubernetes had done their resources, their types, their labels and just their interface was so much further advanced than the other things we had seen. It was a feature fit."

+
+ Plus, MacKay says, "I just believed in the confidence that comes with the history that Google has with containerization. So we started out right on the leading edge of it. And we haven't looked back since."

+ Which is not to say that adopting a new technology hasn't come with some challenges. "Change is hard," says MacKay. "Not because the technology is hard or that the technology is not good. It's just that people like to do things like they had done [before]. You have the early adopters and you have those who are coming in later. It was a learning experience on both sides."

+ Figuring out the best deployment operations for Ancestry was a big part of the work it took to adopt cloud native infrastructure. "We want to make sure the process is easy and also controlled in the manner that allows us the highest degree of security that we demand and our customers demand," says MacKay. "With Kubernetes and other products, there are some good solutions, but a little bit of glue is needed to bring it into corporate processes and governances. It's like having a set of gloves that are generic, but when you really do want to grab something you have to make it so it's customized to you. That's what we had to do."

+ Their best practices include allowing their developers to deploy into development stage and production, but then controlling the aspects that need governance and auditing, such as secrets. They found that having one namespace per service is useful for achieving that containment of secrets and config maps. And for their needs, having one container per pod makes it easier to manage and to have a smaller unit of deployment. +

+
+
+ +
+
+ +"The success of Ancestry's first deployment of the hint system on Kubernetes helped create momentum for greater adoption of the technology." + +
+
+ +
+
+ With that process established, the time spent on deployment was cut down to under a minute for some services. "As programmers, we have what's called REPL: read, evaluate, print, and loop, but with Kubernetes, we have CDEL: compile, deploy, execute, and loop," says MacKay. "It's a very quick loop back and a great benefit to understand that when our services are deployed in production, they're the same as what we tested in the pre-production environments. The approach of cloud native for Ancestry provides us a better ability to scale and to accommodate the business needs as work loads occur."

+ The success of Ancestry's first deployment of the hint system on Kubernetes helped create momentum for greater adoption of the technology. "Engineers like to code, they like to do features, they don't like to sit around waiting for things to be deployed and worrying about scaling up and out and down," says MacKay. "After a while the engineers became our champions. At training sessions, the development teams were always the ones saying, 'Kubernetes saved our time tremendously; it's an enabler; it really is incredible.' Over time, we were able to convince our management that this was a transition that the industry is making and that we needed to be a part of it."

+ A year later, Ancestry has transitioned a good number of applications to Kubernetes. "We have many different services that make up the rich environment that [the website] has from both the DNA side and the family history side," says MacKay. "We have front-end stacks, back-end stacks and back-end processing type stacks that are in the cluster."

+ The company continues to weigh which services it will move forward to Kubernetes, which ones will be kept as is, and which will be replaced in the future and thus don't have to be moved over. MacKay estimates that the company is "approaching halfway on those features that are going forward. We don't have to do a lot of convincing anymore. It's more of an issue of timing with getting product management and engineering staff the knowledge and information that they need." +
+
+ +
+
+ "... 'I believe in Kubernetes. I believe in containerization. I think + if we can get there and establish ourselves in that world, we will be further along and far better off being agile and all the things we talk about, + and it'll go forward.'" +
+
+ +
+
+ + +Looking ahead, MacKay sees Ancestry maximizing the benefits of Kubernetes in 2017. "We're very close to having everything that should be or could be in a Linux-friendly world in Kubernetes by the end of the year," he says, adding that he's looking forward to features such as federation and horizontal pod autoscaling that are currently in the works. "Kubernetes has been very wonderful for us and we continue to ride the wave."

+That wave, he points out, has everything to do with the vibrant Kubernetes community, which has grown by leaps and bounds since Ancestry joined it as an early adopter. "This is just a very rough way of judging it, but on Slack in June 2015, there were maybe 500 on there," MacKay says. "The last time I looked there were maybe 8,500 just on the Slack channel. There are so many major companies and different kinds of companies involved now. It's the variety of contributors, the number of contributors, the incredibly competent and friendly community."

+As much as he and his team at Ancestry have benefited from what he calls "the goodness and the technical abilities of many" in the community, they've also contributed information about best practices, logged bug issues and participated in the open source conversation. And they've been active in attending meetups to help educate and give back to the local tech community in Utah. Says MacKay: "We're trying to give back as far as our experience goes, rather than just code." +

When he meets with companies considering adopting cloud native infrastructure, the best advice he has to give from Ancestry's Kubernetes journey is this: "Start small, but with hard problems," he says. And "you need a patron who understands the vision of containerization, to help you tackle the political as well as other technical roadblocks that can occur when change is needed."

+With the changes that MacKay's team has led over the past year and a half, cloud native will be part of Ancestry's technological genealogy for years to come. MacKay has been such a champion of the technology that he says people have jokingly accused him of having a Kubernetes tattoo.

+"I really don't," he says with a laugh. "But I'm passionate. I'm not exclusive to any technology; I use whatever I need that's out there that makes us great. If it's something else, I'll use it. But right now I believe in Kubernetes. I believe in containerization. I think if we can get there and establish ourselves in that world, we will be further along and far better off being agile and all the things we talk about, and it'll go forward."

+He pauses. "So, yeah, I guess you can say I'm an evangelist for Kubernetes," he says. "But I'm not getting a tattoo!" + + +
+
diff --git a/content/zh/case-studies/ant-financial/ant-financial_featured_logo.png b/content/zh/case-studies/ant-financial/ant-financial_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cb4034502734d828b5f11f0385d663c549fbce73 GIT binary patch literal 10263 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 ZV8VHekLa9RM*m*blb2SJs+BMa{V&C6E&Tuh literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/ant-financial/index.html b/content/zh/case-studies/ant-financial/index.html new file mode 100644 index 0000000000..92b46526de --- /dev/null +++ b/content/zh/case-studies/ant-financial/index.html @@ -0,0 +1,96 @@ +--- +title: Ant Financial Case Study +linkTitle: ant-financial +case_study_styles: true +cid: caseStudies +css: /css/style_case_studies.css +featured: false +--- + +
+

CASE STUDY:
Ant Financial’s Hypergrowth Strategy Using Kubernetes + +

+ +
+ +
+ Company  Ant Financial     Location  Hangzhou, China     Industry  Financial Services +
+ +
+
+
+
+

Challenge

+ Officially founded in October 2014, Ant Financial originated from Alipay, the world’s largest online payment platform that launched in 2004. The company also offers numerous other services leveraging technology innovation. With the volume of transactions Alipay handles for its 900+ million users worldwide (through its local and global partners)—256,000 transactions per second at the peak of Double 11 Singles Day 2017, and total gross merchandise value of $31 billion for Singles Day 2018—not to mention that of its other services, Ant Financial faces “data processing challenge in a whole new way,” says Haojie Hang, who is responsible for Product Management for the Storage and Compute Group. “We see three major problems of operating at that scale: how to provide real-time compute, storage, and processing capability, for instance to make real-time recommendations for fraud detection; how to provide intelligence on top of this data, because there’s too much data and then we’re not getting enough insight; and how to apply security in the application level, in the middleware level, the system level, even the chip level.” In order to provide reliable and consistent services to its customers, Ant Financial embraced containers in early 2014, and soon needed an orchestration solution for the tens-of-thousands-of-node clusters in its data centers. + +

Solution

+ After investigating several technologies, the team chose Kubernetes for orchestration, as well as a number of other CNCF projects, including Prometheus, OpenTracing, etcd and CoreDNS. “In late 2016, we decided that Kubernetes will be the de facto standard,” says Hang. “Looking back, we made the right bet on the right technology. But then we needed to move the production workload from the legacy infrastructure to the latest Kubernetes-enabled platform, and that took some time, because we are very careful in terms of reliability and consistency.” All core financial systems were containerized by November 2017, and the migration to Kubernetes is ongoing. +
+

Impact

+ “We’ve seen at least tenfold in improvement in terms of the operations with cloud native technology, which means you can have tenfold increase in terms of output,” says Hang. Ant also provides its fully integrated financial cloud platform to business partners around the world, and hopes to power the next generation of digital banking with deep experience in service innovation and technology expertise. Hang says the team hasn’t begun to focus on optimizing the Kubernetes platform, either: “Because we’re still in the hyper growth stage, we’re not in a mode where we do cost saving yet.” +
+ +
+
+
+
+ "In late 2016, we decided that Kubernetes will be the de facto standard. Looking back, we made the right bet on the right technology." +

- HAOJIE HANG, PRODUCT MANAGEMENT, ANT FINANCIAL
+
+
+
+
+

A spinoff of the multinational conglomerate Alibaba, Ant Financial boasts a $150+ billion valuation and the scale to match. The fintech startup, launched in 2014, is comprised of Alipay, the world’s largest online payment platform, and numerous other services leveraging technology innovation.

+ And the volume of transactions that Alipay handles for over 900 million users worldwide (through its local and global partners) is staggering: 256,000 per second at the peak of Double 11 Singles Day 2017, and total gross merchandise value of $31 billion for Singles Day 2018. With the mission of “bringing the world equal opportunities,” Ant Financial is dedicated to creating an open, shared credit system and financial services platform through technology innovations. +

+ Combine that with the operations of its other properties—such as the Huabei online credit system, Jiebei lending service, and the 350-million-user Ant Forest green energy mobile app—and Ant Financial faces “data processing challenge in a whole new way,” says Haojie Hang, who is responsible for Product Management for the Storage and Compute Group. “We see three major problems of operating at that scale: how to provide real-time compute, storage, and processing capability, for instance to make real-time recommendations for fraud detection; how to provide intelligence on top of this data, because there’s too much data and we’re not getting enough insight; and how to apply security in the application level, in the middleware level, the system level, even the chip level.” +

+ To address those challenges and provide reliable and consistent services to its customers, Ant Financial embraced Docker containerization in 2014. But they soon realized that they needed an orchestration solution for some tens-of-thousands-of-node clusters in the company’s data centers. +
+
+
+
+ "On Double 11 this year, we had plenty of nodes on Kubernetes, but compared to the whole scale of our infrastructure, this is still in progress."

- RANGER YU, GLOBAL TECHNOLOGY PARTNERSHIP & DEVELOPMENT, ANT FINANCIAL
+ +
+
+
+
+ The team investigated several technologies, including Docker Swarm and Mesos. “We did a lot of POCs, but we’re very careful in terms of production systems, because we want to make sure we don’t lose any data,” says Hang. “You cannot afford to have a service downtime for one minute; even one second has a very, very big impact. We operate every day under pressure to provide reliable and consistent services to consumers and businesses in China and globally.” +

+ Ultimately, Hang says Ant chose Kubernetes because it checked all the boxes: a strong community, technology that “will be relevant in the next three to five years,” and a good match for the company’s engineering talent. “In late 2016, we decided that Kubernetes will be the de facto standard,” says Hang. “Looking back, we made the right bet on the right technology. But then we needed to move the production workload from the legacy infrastructure to the latest Kubernetes-enabled platform. We spent a lot of time learning and then training our people to build applications on Kubernetes well.” +

+ All core financial systems were containerized by November 2017, and the migration to Kubernetes is ongoing. Ant’s platform also leverages a number of other CNCF projects, including Prometheus, OpenTracing, etcd and CoreDNS. “On Double 11 this year, we had plenty of nodes on Kubernetes, but compared to the whole scale of our infrastructure, this is still in progress,” says Ranger Yu, Global Technology Partnership & Development. +
+
+
+
+ "We’re very grateful for CNCF and this amazing technology, which we need as we continue to scale globally. We’re definitely embracing the community and open source more in the future."

- HAOJIE HANG, PRODUCT MANAGEMENT, ANT FINANCIAL
+
+
+ +
+
+ Still, there has already been an impact. “Cloud native technology has benefited us greatly in terms of efficiency,” says Hang. “In general, we want to make sure our infrastructure is nimble and flexible enough for the work that could happen tomorrow. That’s the goal. And with cloud native technology, we’ve seen at least tenfold improvement in operations, which means you can have tenfold increase in terms of output. Let’s say you are operating 10 nodes with one person. With cloud native, tomorrow you can have 100 nodes.” +

+ Ant also provides its financial cloud platform to partners around the world, and hopes to power the next generation of digital banking with deep experience in service innovation and technology expertise. Hang says the team hasn’t begun to focus on optimizing the Kubernetes platform, either: “Because we’re still in the hyper growth stage, we’re not in a mode where we do cost-saving yet.” +

+ The CNCF community has also been a valuable asset during Ant Financial’s move to cloud native. “If you are applying a new technology, it’s very good to have a community to discuss technical problems with other users,” says Hang. “We’re very grateful for CNCF and this amazing technology, which we need as we continue to scale globally. We’re definitely embracing the community and open sourcing more in the future.” +
+ +
+
+"In China, we are the North Star in terms of innovation in financial and other related services,” says Hang. “We definitely want to make sure we’re still leading in the next 5 to 10 years with our investment in technology."

- RANGER YU, GLOBAL TECHNOLOGY PARTNERSHIP & DEVELOPMENT, ANT FINANCIAL
+
+ +
+ In fact, the company has already started to open source some of its cloud native middleware. “We are going to be very proactive about that,” says Yu. “CNCF provided a platform so everyone can plug in or contribute components. This is very good open source governance.” +

+ Looking ahead, the Ant team will continue to evaluate many other CNCF projects. Building a service mesh community in China, the team has brought together many China-based companies and developers to discuss the potential of that technology. “Service mesh is very attractive for Chinese developers and end users because we have a lot of legacy systems running now, and it’s an ideal mid-layer to glue everything together, both new and legacy,” says Hang. “For new technologies, we look very closely at whether they will last.” +

+ At Ant, Kubernetes passed that test with flying colors, and the team hopes other companies will follow suit. “In China, we are the North Star in terms of innovation in financial and other related services,” says Hang. “We definitely want to make sure we’re still leading in the next 5 to 10 years with our investment in technology.” + +
+
diff --git a/content/zh/case-studies/appdirect/appdirect_featured_logo.png b/content/zh/case-studies/appdirect/appdirect_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..724a8a75684f03e1c3b02ac0c85d924c6c7805ee GIT binary patch literal 5645 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 KRSJ}!JpTtL)KVA# literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/appdirect/index.html b/content/zh/case-studies/appdirect/index.html new file mode 100644 index 0000000000..16d93cce5c --- /dev/null +++ b/content/zh/case-studies/appdirect/index.html @@ -0,0 +1,99 @@ +--- +title: AppDirect Case Study + +linkTitle: AppDirect +case_study_styles: true +cid: caseStudies +css: /css/style_case_studies.css +logo: appdirect_featured_logo.png +featured: true +weight: 4 +quote: > + We made the right decisions at the right time. Kubernetes and the cloud native technologies are now seen as the de facto ecosystem. +--- + +
+

CASE STUDY:
AppDirect: How AppDirect Supported the 10x Growth of Its Engineering Staff with Kubernetess +

+ +
+ +
+ Company  AppDirect     Location  San Francisco, California +     Industry  Software +
+ +
+
+
+
+

Challenge

+ AppDirect provides an end-to-end commerce platform for cloud-based products and services. When Director of Software Development Pierre-Alexandre Lacerte began working there in 2014, the company had a monolith application deployed on a "tomcat infrastructure, and the whole release process was complex for what it should be," he says. "There were a lot of manual steps involved, with one engineer building a feature, then another team picking up the change. So you had bottlenecks in the pipeline to ship a feature to production." At the same time, the engineering team was growing, and the company realized it needed a better infrastructure to both support that growth and increase velocity. +

+

Solution

+ "My idea was: Let’s create an environment where teams can deploy their services faster, and they will say, ‘Okay, I don’t want to build in the monolith anymore. I want to build a service,’" says Lacerte. They considered and prototyped several different technologies before deciding to adopt Kubernetes in early 2016. Lacerte’s team has also integrated Prometheus monitoring into the platform; tracing is next. Today, AppDirect has more than 50 microservices in production and 15 Kubernetes clusters deployed on AWS and on premise around the world. +

+

Impact

+ The Kubernetes platform has helped support the engineering team’s 10x growth over the past few years. Coupled with the fact that they were continually adding new features, Lacerte says, "I think our velocity would have slowed down a lot if we didn’t have this new infrastructure." Moving to Kubernetes and services has meant that deployments have become much faster due to less dependency on custom-made, brittle shell scripts with SCP commands. Time to deploy a new version has shrunk from 4 hours to a few minutes. Additionally, the company invested a lot of effort to make things self-service for developers. "Onboarding a new service doesn’t require Jira tickets or meeting with three different teams," says Lacerte. Today, the company sees 1,600 deployments per week, compared to 1-30 before. The company also achieved cost savings by moving its marketplace and billing monoliths to Kubernetes from legacy EC2 hosts as well as by leveraging autoscaling, as traffic is higher during business hours. +
+
+
+
+
+ "It was an immense engineering culture shift, but the benefits are undeniable in terms of scale and speed." +

- Alexandre Gervais, Staff Software Developer, AppDirect
+
+
+
+
+

With its end-to-end commerce platform for cloud-based products and services, AppDirect has been helping organizations such as Comcast and GoDaddy simplify the digital supply chain since 2009.

+
+ When Director of Software Development Pierre-Alexandre Lacerte started working there in 2014, the company had a monolith application deployed on a "tomcat infrastructure, and the whole release process was complex for what it should be," he says. "There were a lot of manual steps involved, with one engineer building a feature then creating a pull request, and a QA or another engineer validating the feature. Then it gets merged and someone else will take care of the deployment. So we had bottlenecks in the pipeline to ship a feature to production."

+ At the same time, the engineering team of 40 was growing, and the company wanted to add an increasing number of features to its products. As a member of the platform team, Lacerte began hearing from multiple teams that wanted to deploy applications using different frameworks and languages, from Node.js to Spring Boot Java. He soon realized that in order to both support growth and increase velocity, the company needed a better infrastructure, and a system in which teams are autonomous, can do their own deploys, and be responsible for their services in production. + +
+
+
+
+ "We made the right decisions at the right time. Kubernetes and the cloud native technologies are now seen as the de facto ecosystem. We know where to focus our efforts in order to tackle the new wave of challenges we face as we scale out. The community is so active and vibrant, which is a great complement to our awesome internal team."

- Alexandre Gervais, Staff Software Developer, AppDirect +
+ +
+
+
+
+ From the beginning, Lacerte says, "My idea was: Let’s create an environment where teams can deploy their services faster, and they will say, ‘Okay, I don’t want to build in the monolith anymore. I want to build a service.’" (Lacerte left the company in 2019.)

+ Working with the operations team, Lacerte’s group got more control and access to the company’s AWS infrastructure, and started prototyping several orchestration technologies. "Back then, Kubernetes was a little underground, unknown," he says. "But we looked at the community, the number of pull requests, the velocity on GitHub, and we saw it was getting traction. And we found that it was much easier for us to manage than the other technologies." + They spun up the first few services on Kubernetes using Chef and Terraform provisioning, and as more services were added, more automation was, too. "We have clusters around the world—in Korea, in Australia, in Germany, and in the U.S.," says Lacerte. "Automation is critical for us." They’re now largely using Kops, and are looking at managed Kubernetes offerings from several cloud providers.

+ Today, though the monolith still exists, there are fewer and fewer commits and features. All teams are deploying on the new infrastructure, and services are the norm. AppDirect now has more than 50 microservices in production and 15 Kubernetes clusters deployed on AWS and on premise around the world.

+ Lacerte’s strategy ultimately worked because of the very real impact the Kubernetes platform has had to deployment time. Due to less dependency on custom-made, brittle shell scripts with SCP commands, time to deploy a new version has shrunk from 4 hours to a few minutes. Additionally, the company invested a lot of effort to make things self-service for developers. "Onboarding a new service doesn’t require Jira tickets or meeting with three different teams," says Lacerte. Today, the company sees 1,600 deployments per week, compared to 1-30 before. +
+
+
+
+ "I think our velocity would have slowed down a lot if we didn’t have this new infrastructure."

- Pierre-Alexandre Lacerte, Director of Software Development, AppDirect
+
+
+ +
+ +
+ Additionally, the Kubernetes platform has helped support the engineering team’s 10x growth over the past few years. "Ownership, a core value of AppDirect, reflects in our ability to ship services independently of our monolith code base," says Staff Software Developer Alexandre Gervais, who worked with Lacerte on the initiative. "Small teams now own critical parts of our business domain model, and they operate in their decoupled domain of expertise, with limited knowledge of the entire codebase. This reduces and isolates some of the complexity." Coupled with the fact that they were continually adding new features, Lacerte says, "I think our velocity would have slowed down a lot if we didn’t have this new infrastructure." + The company also achieved cost savings by moving its marketplace and billing monoliths to Kubernetes from legacy EC2 hosts as well as by leveraging autoscaling, as traffic is higher during business hours.

+ AppDirect’s cloud native stack also includes gRPC and Fluentd, and the team is currently working on setting up OpenCensus. The platform already has Prometheus integrated, so "when teams deploy their service, they have their notifications, alerts and configurations," says Lacerte. "For example, in the test environment, I want to get a message on Slack, and in production, I want a Slack message and I also want to get paged. We have integration with pager duty. Teams have more ownership on their services." + +
+ +
+
+"We moved from a culture limited to ‘pushing code in a branch’ to exciting new responsibilities outside of the code base: deployment of features and configurations; monitoring of application and business metrics; and on-call support in case of outages. It was an immense engineering culture shift, but the benefits are undeniable in terms of scale and speed."

- Pierre-Alexandre Lacerte, Director of Software Development, AppDirect
+
+ +
+ That of course also means more responsibility. "We asked engineers to expand their horizons," says Gervais. "We moved from a culture limited to ‘pushing code in a branch’ to exciting new responsibilities outside of the code base: deployment of features and configurations; monitoring of application and business metrics; and on-call support in case of outages. It was an immense engineering culture shift, but the benefits are undeniable in terms of scale and speed."

+ As the engineering ranks continue to grow, the platform team has a new challenge, of making sure that the Kubernetes platform is accessible and easily utilized by everyone. "How can we make sure that when we add more people to our team that they are efficient, productive, and know how to ramp up on the platform?" Lacerte says. So we have the evangelists, the documentation, some project examples. We do demos, we have AMA sessions. We’re trying different strategies to get everyone’s attention."

+ Three and a half years into their Kubernetes journey, Gervais feels AppDirect "made the right decisions at the right time," he says. "Kubernetes and the cloud native technologies are now seen as the de facto ecosystem. We know where to focus our efforts in order to tackle the new wave of challenges we face as we scale out. The community is so active and vibrant, which is a great complement to our awesome internal team. Going forward, our focus will really be geared towards benefiting from the ecosystem by providing added business value in our day-to-day operations." + + +
+
diff --git a/content/zh/case-studies/blablacar/blablacar_featured.png b/content/zh/case-studies/blablacar/blablacar_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..cfe37257b99e73fefe25b5f6fd582feafd6dff07 GIT binary patch literal 7867 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/blablacar/blablacar_logo.png b/content/zh/case-studies/blablacar/blablacar_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..14606e036002ed9ad34469a06a8ed39f86e41d71 GIT binary patch literal 7841 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/blablacar/index.html b/content/zh/case-studies/blablacar/index.html new file mode 100644 index 0000000000..2d55ffb8d0 --- /dev/null +++ b/content/zh/case-studies/blablacar/index.html @@ -0,0 +1,98 @@ +--- +title: BlaBlaCar Case Study + +case_study_styles: true +cid: caseStudies +css: /css/style_blablacar.css +--- + +
+

CASE STUDY:
Turning to Containerization to Support Millions of Rideshares

+ +
+ +
+ Company  BlaBlaCar     Location  Paris, France     Industry  Ridesharing Company +
+ +
+
+
+
+

Challenge

+ The world’s largest long-distance carpooling community, BlaBlaCar, connects 40 million members across 22 countries. The company has been experiencing exponential growth since 2012 and needed its infrastructure to keep up. "When you’re thinking about doubling the number of servers, you start thinking, ‘What should I do to be more efficient?’" says Simon Lallemand, Infrastructure Engineer at BlaBlaCar. "The answer is not to hire more and more people just to deal with the servers and installation." The team knew they had to scale the platform, but wanted to stay on their own bare metal servers. +
+
+

Solution

+ Opting not to shift to cloud virtualization or use a private cloud on their own servers, the BlaBlaCar team became early adopters of containerization, using the CoreOs runtime rkt, initially deployed using fleet cluster manager. Last year, the company switched to Kubernetes orchestration, and now also uses Prometheus for monitoring. +
+ +
+

Impact

+ "Before using containers, it would take sometimes a day, sometimes two, just to create a new service," says Lallemand. "With all the tooling that we made around the containers, copying a new service now is a matter of minutes. It’s really a huge gain. We are better at capacity planning in our data center because we have fewer constraints due to this abstraction between the services and the hardware we run on. For the developers, it also means they can focus only on the features that they’re developing, and not on the infrastructure." +
+
+
+
+
+ "When you’re switching to this cloud-native model and running everything in containers, you have to make sure that at any moment you can reboot without any downtime and without losing traffic. [With Kubernetes] our infrastructure is much more resilient and we have better availability than before."

- Simon Lallemand, Infrastructure Engineer at BlaBlaCar
+
+
+ +
+
+

For the 40 million users of BlaBlaCar, it’s easy to find strangers headed in the same direction to share rides and costs. You can even choose how much "bla bla" chatter you want from a long-distance ride mate.

+ Behind the scenes, though, the infrastructure was falling woefully behind the rider community’s exponential growth. Founded in 2006, the company hit its current stride around 2012. "Our infrastructure was very traditional," says Infrastructure Engineer Simon Lallemand, who began working at the company in 2014. "In the beginning, it was a bit chaotic because we had to [grow] fast. But then comes the time when you have to design things to make it manageable."

+ By 2015, the company had about 50 bare metal servers. The team was using a MySQL database and PHP, but, Lallemand says, "it was a very static way." They also utilized the configuration management system, Chef, but had little automation in its process. "When you’re thinking about doubling the number of servers, you start thinking, ‘What should I do to be more efficient?’" says Lallemand. "The answer is not to hire more and more people just to deal with the servers and installation."

+ Instead, BlaBlaCar began its cloud-native journey but wasn’t sure which route to take. "We could either decide to go into cloud virtualization or even use a private cloud on our own servers," says Lallemand. "But going into the cloud meant we had to make a lot of changes in our application work, and we were just not ready to make the switch from on premise to the cloud." They wanted to keep the great performance they got on bare metal, so they didn’t want to go to virtualization on premise.

+ The solution: containerization. This was early 2015 and containers were still relatively new. "It was a bold move at the time," says Lallemand. "We decided that the next servers that we would buy in the new data center would all be the same model, so we could outsource the maintenance of the servers. And we decided to go with containers and with CoreOS Container Linux as an abstraction for this hardware. It seemed future-proof to go with containers because we could see what companies were already doing with containers." +
+
+ +
+
+ "With all the tooling that we made around the containers, copying a new service is a matter of minutes. It’s a huge gain. For the developers, it means they can focus only on the features that they’re developing and not on the infrastructure or the hour they would test their code, or the hour that it would get deployed." +
+
+ +
+
+ Next, they needed to choose a runtime for the containers, but "there were very few deployments in production at that time," says Lallemand. They experimented with Docker but decided to go with rkt. Lallemand explains that for BlaBlaCar, it was "much simpler to integrate things that are on rkt." At the time, the project was still pre-v1.0, so "we could speak with the developers of rkt and give them feedback. It was an advantage." Plus, he notes, rkt was very stable, even at this early stage.

+ Once those decisions were made that summer, the company came up with a plan for implementation. First, they formed a task force to create a workflow that would be tested by three of the 10 members on Lallemand’s team. But they took care to run regular workshops with all 10 members to make sure everyone was on board. "When you’re focused on your product sometimes you forget if it’s really user friendly, whether other people can manage to create containers too," Lallemand says. "So we did a lot of iterations to find a good workflow."

+ After establishing the workflow, Lallemand says with a smile that "we had this strange idea that we should try the most difficult thing first. Because if it works, it will work for everything." So the first project the team decided to containerize was the database. "Nobody did that at the time, and there were really no existing tools for what we wanted to do, including building container images," he says. So the team created their own tools, such as dgr, which builds container images so that the whole team has a common framework to build on the same images with the same standards. They also revamped the service-discovery tools Nerve and Synapse; their versions, Go-Nerve and Go-Synapse, were written in Go and built to be more efficient and include new features. All of these tools were open-sourced.

+ At the same time, the company was working to migrate its entire platform to containers with a deadline set for Christmas 2015. With all the work being done in parallel, BlaBlaCar was able to get about 80 percent of its production into containers by its deadline with live traffic running on containers during December. (It’s now at 100 percent.) "It’s a really busy time for traffic," says Lallemand. "We knew that by using those new servers with containers, it would help us handle the traffic."

+ In the middle of that peak season for carpooling, everything worked well. "The biggest impact that we had was for the deployment of new services," says Lallemand. "Before using containers, we had to first deploy a new server and create configurations with Chef. It would take sometimes a day, sometimes two, just to create a new service. And with all the tooling that we made around the containers, copying a new service is a matter of minutes. So it’s really a huge gain. For the developers, it means they can focus only on the features that they’re developing and not on the infrastructure or the hour they would test their code, or the hour that it would get deployed." +
+
+ +
+
+ "We realized that there was a really strong community around it [Kubernetes], which meant we would not have to maintain a lot of tools of our own," says Lallemand. "It was better if we could contribute to some bigger project like Kubernetes." +
+
+ +
+
+ In order to meet their self-imposed deadline, one of the decisions they made was to not do any "orchestration magic" for containers in the first production alignment. Instead, they used the basic fleet tool from CoreOS to deploy their containers. (They did build a tool called GGN, which they’ve open-sourced, to make it more manageable for their system engineers to use.)

+ Still, the team knew that they’d want more orchestration. "Our tool was doing a pretty good job, but at some point you want to give more autonomy to the developer team," Lallemand says. "We also realized that we don’t want to be the single point of contact for developers when they want to launch new services." By the summer of 2016, they found their answer in Kubernetes, which had just begun supporting rkt implementation.

+ After discussing their needs with their contacts at CoreOS and Google, they were convinced that Kubernetes would work for BlaBlaCar. "We realized that there was a really strong community around it, which meant we would not have to maintain a lot of tools of our own," says Lallemand. "It was better if we could contribute to some bigger project like Kubernetes." They also started using Prometheus, as they were looking for "service-oriented monitoring that could be updated nightly." Production on Kubernetes began in December 2016. "We like to do crazy stuff around Christmas," he adds with a laugh.

+ BlaBlaCar now has about 3,000 pods, with 1200 of them running on Kubernetes. Lallemand leads a "foundations team" of 25 members who take care of the networks, databases and systems for about 100 developers. There have been some challenges getting to this point. "The rkt implementation is still not 100 percent finished," Lallemand points out. "It’s really good, but there are some features still missing. We have questions about how we do things with stateful services, like databases. We know how we will be migrating some of the services; some of the others are a bit more complicated to deal with. But the Kubernetes community is making a lot of progress on that part."

+ The team is particularly happy that they’re now able to plan capacity better in the company’s data center. "We have fewer constraints since we have this abstraction between the services and the hardware we run on," says Lallemand. "If we lose a server because there’s a hardware problem on it, we just move the containers onto another server. It’s much more efficient. We do that by just changing a line in the configuration file. And with Kubernetes, it should be automatic, so we would have nothing to do." +
+
+ +
+
+ "If we lose a server because there’s a hardware problem on it, we just move the containers onto another server. It’s much more efficient. We do that by just changing a line in the configuration file. With Kubernetes, it should be automatic, so we would have nothing to do." +
+
+ +
+
+ And these advances ultimately trickle down to BlaBlaCar’s users. "We have improved availability overall on our website," says Lallemand. "When you’re switching to this cloud-native model with running everything in containers, you have to make sure that you can at any moment reboot a server or a data container without any downtime, without losing traffic. So now our infrastructure is much more resilient and we have better availability than before."

+ Within BlaBlaCar’s technology department, the cloud-native journey has created some profound changes. Lallemand thinks that the regular meetings during the conception stage and the training sessions during implementation helped. "After that everybody took part in the migration process," he says. "Then we split the organization into different ‘tribes’—teams that gather developers, product managers, data analysts, all the different jobs, to work on a specific part of the product. Before, they were organized by function. The idea is to give all these tribes access to the infrastructure directly in a self-service way without having to ask. These people are really autonomous. They have responsibility of that part of the product, and they can make decisions faster."

+ This DevOps transformation turned out to be a positive one for the company’s staffers. "The team was very excited about the DevOps transformation because it was new, and we were working to make things more reliable, more future-proof," says Lallemand. "We like doing things that very few people are doing, other than the internet giants."

+ With these changes already making an impact, BlaBlaCar is looking to split up more and more of its application into services. "I don’t say microservices because they’re not so micro," Lallemand says. "If we can split the responsibilities between the development teams, it would be easier to manage and more reliable, because we can easily add and remove services if one fails. You can handle it easily, instead of adding a big monolith that we still have."

+ When Lallemand speaks to other European companies curious about what BlaBlaCar has done with its infrastructure, he tells them to come along for the ride. "I tell them that it’s such a pleasure to deal with the infrastructure that we have today compared to what we had before," he says. "They just need to keep in mind their real motive, whether it’s flexibility in development or reliability or so on, and then go step by step towards reaching those objectives. That’s what we’ve done. It’s important not to do technology for the sake of technology. Do it for a purpose. Our focus was on helping the developers." +
+
diff --git a/content/zh/case-studies/blackrock/blackrock_featured.png b/content/zh/case-studies/blackrock/blackrock_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..3898b88c9fa43c09caea23dd985c1bab1802d986 GIT binary patch literal 6391 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/blackrock/blackrock_logo.png b/content/zh/case-studies/blackrock/blackrock_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..51e914a63b259a76b0239d93c2ce872f7722e941 GIT binary patch literal 6430 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 ImCSJe1$hptGynhq literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/blackrock/index.html b/content/zh/case-studies/blackrock/index.html new file mode 100644 index 0000000000..6bef0ec708 --- /dev/null +++ b/content/zh/case-studies/blackrock/index.html @@ -0,0 +1,112 @@ +--- +title: BlackRock Case Study + +case_study_styles: true +cid: caseStudies +css: /css/style_blackrock.css +--- + +
+

CASE STUDY:
+
Rolling Out Kubernetes in Production in 100 Days
+

+ +
+ +
+ Company  BlackRock     Location  New York, NY     Industry  Financial Services +
+ +
+ +
+ +
+
+

Challenge

+ The world’s largest asset manager, BlackRock operates a very controlled static deployment scheme, which has allowed for scalability over the years. But in their data science division, there was a need for more dynamic access to resources. "We want to be able to give every investor access to data science, meaning Python notebooks, or even something much more advanced, like a MapReduce engine based on Spark," says Michael Francis, a Managing Director in BlackRock’s Product Group, which runs the company’s investment management platform. "Managing complex Python installations on users’ desktops is really hard because everyone ends up with slightly different environments. We have existing environments that do these things, but we needed to make it real, expansive and scalable. Being able to spin that up on demand, tear it down, make that much more dynamic, became a critical thought process for us. It’s not so much that we had to solve our main core production problem, it’s how do we extend that? How do we evolve?" +
+ +
+

Solution

+ Drawing from what they learned during a pilot done last year using Docker environments, Francis put together a cross-sectional team of 20 to build an investor research web app using Kubernetes with the goal of getting it into production within one quarter. +

+

Impact

+ "Our goal was: How do you give people tools rapidly without having to install them on their desktop?" says Francis. And the team hit the goal within 100 days. Francis is pleased with the results and says, "We’re going to use this infrastructure for lots of other application workloads as time goes on. It’s not just data science; it’s this style of application that needs the dynamism. But I think we’re 6-12 months away from making a [large scale] decision. We need to gain experience of running the system in production, we need to understand failure modes and how best to manage operational issues. What’s interesting is that just having this technology there is changing the way our developers are starting to think about their future development." + +
+
+ +
+ +
+
+ "My message to other enterprises like us is you can actually integrate Kubernetes into an existing, well-orchestrated machinery. You don’t have to throw out everything you do. And using Kubernetes made a complex problem significantly easier."

- Michael Francis, Managing Director, BlackRock
+
+
+ +
+ +
+ One of the management objectives for BlackRock’s Product Group employees in 2017 was to "build cool stuff." Led by Managing Director Michael Francis, a cross-sectional group of 20 did just that: They rolled out a full production Kubernetes environment and released a new investor research web app on it. In 100 days.

+ For a company that’s the world’s largest asset manager, "just equipment procurement can take 100 days sometimes, let alone from inception to delivery," says Karl Wieman, a Senior System Administrator. "It was an aggressive schedule. But it moved the dial." + In fact, the project achieved two goals: It solved a business problem (creating the needed web app) as well as provided real-world, in-production experience with Kubernetes, a cloud-native technology that the company was eager to explore. "It’s not so much that we had to solve our main core production problem, it’s how do we extend that? How do we evolve?" says Francis. The ultimate success of this project, beyond delivering the app, lies in the fact that "we’ve managed to integrate a radically new thought process into a controlled infrastructure that we didn’t want to change."

+ After all, in its three decades of existence, BlackRock has "a very well-established environment for managing our compute resources," says Francis. "We manage large cluster processes on machines, so we do a lot of orchestration and management for our main production processes in a way that’s very cloudish in concept. We’re able to manage them in a very controlled, static deployment scheme, and that has given us a huge amount of scalability."

+ Though that works well for the core production, the company has found that some data science workloads require more dynamic access to resources. "It’s a very bursty process," says Francis, who is head of data for the company’s Aladdin investment management platform division.

+ Aladdin, which connects the people, information and technology needed for money management in real time, is used internally and is also sold as a platform to other asset managers and insurance companies. "We want to be able to give every investor access to data science, meaning Python notebooks, or even something much more advanced, like a MapReduce engine based on Spark," says Francis. But "managing complex Python installations on users’ desktops is really hard because everyone ends up with slightly different environments. Docker allows us to flatten that environment." +
+
+ +
+
+ "We manage large cluster processes on machines, so we do a lot of orchestration and management for our main production processes in a way that’s very cloudish in concept. We’re able to manage them in a very controlled, static deployment scheme, and that has given us a huge amount of scalability." +
+
+ +
+
+ Still, challenges remain. "If you have a shared cluster, you get this storming herd problem where everyone wants to do the same thing at the same time," says Francis. "You could put limits on it, but you’d have to build an infrastructure to define limits for our processes, and the Python notebooks weren’t really designed for that. We have existing environments that do these things, but we needed to make it real, expansive, and scalable. Being able to spin that up on demand, tear it down, and make that much more dynamic, became a critical thought process for us."

+ Made up of managers from technology, infrastructure, production operations, development and information security, Francis’s team was able to look at the problem holistically and come up with a solution that made sense for BlackRock. "Our initial straw man was that we were going to build everything using Ansible and run it all using some completely different distributed environment," says Francis. "That would have been absolutely the wrong thing to do. Had we gone off on our own as the dev team and developed this solution, it would have been a very different product. And it would have been very expensive. We would not have gone down the route of running under our existing orchestration system. Because we don’t understand it. These guys [in operations and infrastructure] understand it. Having the multidisciplinary team allowed us to get to the right solutions and that actually meant we didn’t build anywhere near the amount we thought we were going to end up building."

+ In search of a solution in which they could manage usage on a user-by-user level, Francis’s team gravitated to Red Hat’s OpenShift Kubernetes offering. The company had already experimented with other cloud-native environments, but the team liked that Kubernetes was open source, and "we felt the winds were blowing in the direction of Kubernetes long term," says Francis. "Typically we make technology choices that we believe are going to be here in 5-10 years’ time, in some form. And right now, in this space, Kubernetes feels like the one that’s going to be there." Adds Uri Morris, Vice President of Production Operations: "When you see that the non-Google committers to Kubernetes overtook the Google committers, that’s an indicator of the momentum."

+ Once that decision was made, the major challenge was figuring out how to make Kubernetes work within BlackRock’s existing framework. "It’s about understanding how we can operate, manage and support a platform like this, in addition to tacking it onto our existing technology platform," says Project Manager Michael Maskallis. "All the controls we have in place, the change management process, the software development lifecycle, onboarding processes we go through—how can we do all these things?"

+ The first (anticipated) speed bump was working around issues behind BlackRock’s corporate firewalls. "One of our challenges is there are no firewalls in most open source software," says Francis. "So almost all install scripts fail in some bizarre way, and pulling down packages doesn’t necessarily work." The team ran into these types of problems using Minikube and did a few small pushes back to the open source project. + + +
+
+ +
+
+ "Typically we make technology choices that we believe are going to be here in 5-10 years’ time, in some form. And right now, in this space, Kubernetes feels like the one that’s going to be there." +
+
+ +
+
+ There were also questions about service discovery. "You can think of Aladdin as a cloud of services with APIs between them that allows us to build applications rapidly," says Francis. "It’s all on a proprietary message bus, which gives us all sorts of advantages but at the same time, how does that play in a third party [platform]?"

+ Another issue they had to navigate was that in BlackRock’s existing system, the messaging protocol has different instances in the different development, test and production environments. While Kubernetes enables a more DevOps-style model, it didn’t make sense for BlackRock. "I think what we are very proud of is that the ability for us to push into production is still incredibly rapid in this [new] infrastructure, but we have the control points in place, and we didn’t have to disrupt everything," says Francis. "A lot of the cost of this development was thinking how best to leverage our internal tools. So it was less costly than we actually thought it was going to be."

+ The project leveraged tools associated with the messaging bus, for example. "The way that the Kubernetes cluster will talk to our internal messaging platform is through a gateway program, and this gateway program already has built-in checks and throttles," says Morris. "We can use them to control and potentially throttle the requests coming in from Kubernetes’s very elastic infrastructure to the production infrastructure. We’ll continue to go in that direction. It enables us to scale as we need to from the operational perspective."

+ The solution also had to be complementary with BlackRock’s centralized operational support team structure. "The core infrastructure components of Kubernetes are hooked into our existing orchestration framework, which means that anyone in our support team has both control and visibility to the cluster using the existing operational tools," Morris explains. "That means that I don’t need to hire more people."

+ With those points established, the team created a procedure for the project: "We rolled this out first to a development environment, then moved on to a testing environment and then eventually to two production environments, in that sequential order," says Maskallis. "That drove a lot of our learning curve. We have all these moving parts, the software components on the infrastructure side, the software components with Kubernetes directly, the interconnectivity with the rest of the environment that we operate here at BlackRock, and how we connect all these pieces. If we came across issues, we fixed them, and then moved on to the different environments to replicate that until we eventually ended up in our production environment where this particular cluster is supposed to live."

+ The team had weekly one-hour working sessions with all the members (who are located around the world) participating, and smaller breakout or deep-dive meetings focusing on specific technical details. Possible solutions would be reported back to the group and debated the following week. "I think what made it a successful experiment was people had to work to learn, and they shared their experiences with others," says Vice President and Software Developer Fouad Semaan. Then, Francis says, "We gave our engineers the space to do what they’re good at. This hasn’t been top-down." + + +
+
+ +
+
+ "The core infrastructure components of Kubernetes are hooked into our existing orchestration framework, which means that anyone in our support team has both control and visibility to the cluster using the existing operational tools. That means that I don’t need to hire more people." + +
+
+ +
+
+ They were led by one key axiom: To stay focused and avoid scope creep. This meant that they wouldn’t use features that weren’t in the core of Kubernetes and Docker. But if there was a real need, they’d build the features themselves. Luckily, Francis says, "Because of the rapidity of the development, a lot of things we thought we would have to build ourselves have been rolled into the core product. [The package manager Helm is one example]. People have similar problems."

+ By the end of the 100 days, the app was up and running for internal BlackRock users. The initial capacity of 30 users was hit within hours, and quickly increased to 150. "People were immediately all over it," says Francis. In the next phase of this project, they are planning to scale up the cluster to have more capacity.

+ Even more importantly, they now have in-production experience with Kubernetes that they can continue to build on—and a complete framework for rolling out new applications. "We’re going to use this infrastructure for lots of other application workloads as time goes on. It’s not just data science; it’s this style of application that needs the dynamism," says Francis. "Is it the right place to move our core production processes onto? It might be. We’re not at a point where we can say yes or no, but we felt that having real production experience with something like Kubernetes at some form and scale would allow us to understand that. I think we’re 6-12 months away from making a [large scale] decision. We need to gain experience of running the system in production, we need to understand failure modes and how best to manage operational issues."

+ For other big companies considering a project like this, Francis says commitment and dedication are key: "We got the signoff from [senior management] from day one, with the commitment that we were able to get the right people. If I had to isolate what makes something complex like this succeed, I would say senior hands-on people who can actually drive it make a huge difference." With that in place, he adds, "My message to other enterprises like us is you can actually integrate Kubernetes into an existing, well-orchestrated machinery. You don’t have to throw out everything you do. And using Kubernetes made a complex problem significantly easier." + +
+
diff --git a/content/zh/case-studies/bose/bose_featured_logo.png b/content/zh/case-studies/bose/bose_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d4af69ed7275bed5ed2ee6657e8d563a0ad0befc GIT binary patch literal 3564 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/bose/index.html b/content/zh/case-studies/bose/index.html new file mode 100644 index 0000000000..d22de2187a --- /dev/null +++ b/content/zh/case-studies/bose/index.html @@ -0,0 +1,103 @@ +--- +title: Bose Case Study +linkTitle: Bose +case_study_styles: true +cid: caseStudies +css: /css/style_case_studies.css +logo: bose_featured_logo.png +featured: false +weight: 2 +quote: > + The CNCF Landscape quickly explains what’s going on in all the different areas from storage to cloud providers to automation and so forth. This is our shopping cart to build a cloud infrastructure. We can go choose from the different aisles. +--- + +
+

CASE STUDY:
Bose: Supporting Rapid Development for Millions of IoT Products With Kubernetes + +

+ +
+ +
+ Company  Bose Corporation     Location  Framingham, Massachusetts +     Industry  Consumer Electronics +
+ +
+
+
+
+

Challenge

+ A household name in high-quality audio equipment, Bose has offered connected products for more than five years, and as that demand grew, the infrastructure had to change to support it. "We needed to provide a mechanism for developers to rapidly prototype and deploy services all the way to production pretty fast,” says Lead Cloud Engineer Josh West. In 2016, the company decided to start building a platform from scratch. The primary goal: "To be one to two steps ahead of the different product groups so that we are never scrambling to catch up with their scale,” says Cloud Architecture Manager Dylan O’Mahony. +

+

Solution

+ From the beginning, the team knew it wanted a microservices architecture. After evaluating and prototyping a couple of orchestration solutions, the team decided to adopt Kubernetes for its scaled IoT Platform-as-a-Service running on AWS. The platform, which also incorporated Prometheus monitoring, launched in production in 2017, serving over 3 million connected products from the get-go. Bose has since adopted a number of other CNCF technologies, including Fluentd, CoreDNS, Jaeger, and OpenTracing. +

+

Impact

+ With about 100 engineers onboarded, the platform is now enabling 30,000 non-production deployments across dozens of microservices per year. In 2018, there were 1250+ production deployments. Just one production cluster holds 1,800 namespaces and 340 worker nodes. "We had a brand new service taken from concept through coding and deployment all the way to production, including hardening, security testing and so forth, in less than two and a half weeks,” says O’Mahony. +
+ +
+
+
+
+ "At Bose we’re building an IoT platform that has enabled our physical products. If it weren’t for Kubernetes and the rest of the CNCF projects being free open source software with such a strong community, we would never have achieved scale, or even gotten to launch on schedule." +

- Josh West, Lead Cloud Engineer, Bose
+
+
+
+
+

A household name in high-quality audio equipment, Bose has offered connected products for more than five years, and as that demand grew, the infrastructure had to change to support it.

+ "We needed to provide a mechanism for developers to rapidly prototype and deploy services all the way to production pretty fast,” says Lead Cloud Engineer Josh West. "There were a lot of cloud capabilities we wanted to provide to support our audio equipment and experiences.”

+In 2016, the company decided to start building an IoT platform from scratch. The primary goal: "To be one to two steps ahead of the different product groups so that we are never scrambling to catch up with their scale,” says Cloud Architecture Manager Dylan O’Mahony. "If they release a new connected product, we want to be already well ahead of being able to handle whatever scale that they’re going to throw at us.”

+From the beginning, the team knew it wanted a microservices architecture and platform as a service. After evaluating and prototyping orchestration solutions, including Mesos and Docker Swarm, the team decided to adopt Kubernetes for its platform running on AWS. Kubernetes was still in 1.5, but already the technology could do much of what the team wanted and needed for the present and the future. For West, that meant having storage and network handled. O’Mahony points to Kubernetes’ portability in case Bose decides to go multi-cloud.

+"Bose is a company that looks out for the long term,” says West. "Going with a quick commercial off-the-shelf solution might’ve worked for that point in time, but it would not have carried us forward, which is what we needed from Kubernetes and the CNCF.” + + +
+
+
+
+ "Everybody on the team thinks in terms of automation, leaning out the processes, getting things done as quickly as possible. When you step back and look at what it means for a 50-plus-year-old speaker company to have that sort of culture, it really is quite incredible, and I think the tools that we use and the foundation that we’ve built with them is a huge piece of that."

- Dylan O’Mahony, Cloud Architecture Manager, Bose
+ +
+
+
+
+ The team spent time working on choosing tooling to make the experience easier for developers. "Our developers interact with tools provided by our Ops team, and the Ops team run all of their tooling on top of Kubernetes,” says O’Mahony. "We try not to make direct Kubernetes access the only way. In fact, ideally, our developers wouldn’t even need to know that they’re running on Kubernetes.”

+ The platform, which also incorporated Prometheus monitoring from the beginning, backdoored its way into production in 2017, serving over 3 million connected products from the get-go. "Even though the speakers and the products that we were designing this platform for were still quite a ways away from being launched, we did have some connected speakers on the market,” says O’Mahony. "We basically started to point certain features of those speakers and the apps that go with those speakers to this platform.”

+ Today, just one of Bose’s production clusters holds 1,800 namespaces/discrete services and 340 nodes. With about 100 engineers now onboarded, the platform infrastructure is now enabling 30,000 non-production deployments across dozens of microservices per year. In 2018, there were 1250+ production deployments.. It’s a staggering improvement over some of Bose’s previous deployment processes, which supported far fewer deployments and services. + +
+
+
+
+ "The CNCF Landscape quickly explains what’s going on in all the different areas from storage to cloud providers to automation and so forth. This is our shopping cart to build a cloud infrastructure. We can go choose from the different aisles."

- Josh West, Lead Cloud Engineer, Bose
+
+
+ +
+
+ "We had a brand new service deployed from concept through coding and deployment all the way to production, including hardening, security testing and so forth, in less than two and a half weeks,” says O’Mahony. "Everybody thinks in terms of automation, leaning out the processes, getting things done as quickly as possible. When you step back and look at what it means for a 50-plus-year-old speaker company to have that sort of culture, it really is quite incredible, and I think the tools that we use and the foundation that we’ve built is a huge piece of that.”

+ Many of those technologies—such as Fluentd, CoreDNS, Jaeger, and OpenTracing—come from the CNCF Landscape, which West and O’Mahony have relied upon throughout Bose’s cloud native journey. "The CNCF Landscape quickly explains what’s going on in all the different areas from storage to cloud providers to automation and so forth,” says West. "This is our shopping cart to build a cloud infrastructure. We can go choose from the different aisles.”

+ And, he adds, "If it weren’t for Kubernetes and the rest of the CNCF projects being free open source software with such a strong community, we would never have achieved scale, or even gotten to launch on schedule.”

+ Another benefit of going cloud native: "We are even attracting much more talent into Bose because we’re so involved with the CNCF Landscape,” says West. (Yes, they’re hiring.) "It’s just enabled so many people to do so many great things and really brought Bose into the future of cloud.” + + +
+ +
+
+"We have a lot going on to support many more of our business units at Bose in addition to the consumer electronics division, which we currently do. It’s only because of the cloud native landscape and the tools and the features that are available that we can provide such a fantastic cloud platform for all the developers and divisions that are trying to enable some pretty amazing experiences."

- Dylan O’Mahony, Cloud Architecture Manager, Bose
+
+ +
+ In the coming year, the team wants to work on service mesh and serverless, as well as expansion around the world. "Getting our latency down by going multi-region is going to be a big focus for us,” says O’Mahony. "In order to make sure that our customers in Japan, Australia, and everywhere else are having a good experience, we want to have points of presence closer to them. It’s never been done at Bose before.”

+ That won’t stop them, because the team is all about lofty goals. "We want to get to billions of connected products!” says West. "We have a lot going on to support many more of our business units at Bose in addition to the consumer electronics division, which we currently do. It’s only because of the cloud native landscape and the tools and the features that are available that we can provide such a fantastic cloud platform for all the developers and divisions that are trying to enable some pretty amazing experiences.”

+ In fact, given the scale the platform is already supporting, says O’Mahony, "doing anything other than Kubernetes, I think, would be folly at this point.” + + +
+
+ + diff --git a/content/zh/case-studies/box/box_featured.png b/content/zh/case-studies/box/box_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..fc6dec602af171e0cc744837848cafec610ce686 GIT binary patch literal 6348 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 R_xwwNrX;5>i;y-C`hRemAC>?B literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/box/box_logo.png b/content/zh/case-studies/box/box_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b401dec6248c6b4c83e131158e57c7965fcda99f GIT binary patch literal 5988 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 ZgcBus$zz-|_rJe3D9ETvS4*0P{2$eNyT1Sc literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/box/index.html b/content/zh/case-studies/box/index.html new file mode 100644 index 0000000000..bead8eb01a --- /dev/null +++ b/content/zh/case-studies/box/index.html @@ -0,0 +1,114 @@ +--- +title: Box Case Study +case_study_styles: true +cid: caseStudies +css: /css/style_box.css +video: https://www.youtube.com/embed/of45hYbkIZs?autoplay=1 +quote: > + Kubernetes has the opportunity to be the new cloud platform. The amount of innovation that's going to come from being able to standardize on Kubernetes as a platform is incredibly exciting - more exciting than anything I've seen in the last 10 years of working on the cloud. + +--- + +
+

CASE STUDY:
+
An Early Adopter Envisions + a New Cloud Platform
+

+
+ + +
+ Company  Box     Location  Redwood City, California     Industry  Technology +
+ +
+ +
+ +
+
+ +

Challenge

+ Founded in 2005, the enterprise content management company allows its more than 50 million users to manage content in the cloud. Box was built primarily with bare metal inside the company’s own data centers, with a monolithic PHP code base. As the company was expanding globally, it needed to focus on "how we run our workload across many different cloud infrastructures from bare metal to public cloud," says Sam Ghods, Cofounder and Services Architect of Box. "It’s been a huge challenge because of different clouds, especially bare metal, have very different interfaces." +
+
+ +
+

Solution

+ Over the past couple of years, Box has been decomposing its infrastructure into microservices, and became an early adopter of, as well as contributor to, Kubernetes container orchestration. Kubernetes, Ghods says, has allowed Box’s developers to "target a universal set of concepts that are portable across all clouds."

+ +

Impact

+ "Before Kubernetes," Ghods says, "our infrastructure was so antiquated it was taking us more than six months to deploy a new microservice. Today, a new microservice takes less than five days to deploy. And we’re working on getting it to an hour." +
+
+ +
+ +
+
+ "We looked at a lot of different options, but Kubernetes really stood out....the fact that on day one it was designed to run on bare metal just as well as Google Cloud meant that we could actually migrate to it inside of our data centers, and then use those same tools and concepts to run across public cloud providers as well."

- SAM GHOUDS, CO-FOUNDER AND SERVICES ARCHITECT OF BOX +
+
+ +
+ +
+

In the summer of 2014, Box was feeling the pain of a decade’s worth of hardware and software infrastructure that wasn’t keeping up with the company’s needs.

+ + A platform that allows its more than 50 million users (including governments and big businesses like General Electric) to manage and share content in the cloud, Box was originally a PHP monolith of millions of lines of code built exclusively with bare metal inside of its own data centers. It had already begun to slowly chip away at the monolith, decomposing it into microservices. And "as we’ve been expanding into regions around the globe, and as the public cloud wars have been heating up, we’ve been focusing a lot more on figuring out how we run our workload across many different environments and many different cloud infrastructure providers," says Box Cofounder and Services Architect Sam Ghods. "It’s been a huge challenge thus far because of all these different providers, especially bare metal, have very different interfaces and ways in which you work with them."

+ Box’s cloud native journey accelerated that June, when Ghods attended DockerCon. The company had come to the realization that it could no longer run its applications only off bare metal, and was researching containerizing with Docker, virtualizing with OpenStack, and supporting public cloud.

+ At that conference, Google announced the release of its Kubernetes container management system, and Ghods was won over. "We looked at a lot of different options, but Kubernetes really stood out, especially because of the incredibly strong team of Borg veterans and the vision of having a completely infrastructure-agnostic way of being able to run cloud software," he says, referencing Google’s internal container orchestrator Borg. "The fact that on day one it was designed to run on bare metal just as well as Google Cloud meant that we could actually migrate to it inside of our data centers, and then use those same tools and concepts to run across public cloud providers as well."

+ Another plus: Ghods liked that Kubernetes has a universal set of API objects like pod, service, replica set and deployment object, which created a consistent surface to build tooling against. "Even PaaS layers like OpenShift or Deis that build on top of Kubernetes still treat those objects as first-class principles," he says. "We were excited about having these abstractions shared across the entire ecosystem, which would result in a lot more momentum than we saw in other potential solutions."

+ Box deployed Kubernetes in a cluster in a production data center just six months later. Kubernetes was then still pre-beta, on version 0.11. They started small: The very first thing Ghods’s team ran on Kubernetes was a Box API checker that confirms Box is up. "That was just to write and deploy some software to get the whole pipeline functioning," he says. Next came some daemons that process jobs, which was "nice and safe because if they experienced any interruptions, we wouldn’t fail synchronous incoming requests from customers." + +
+
+ +
+
+ "As we’ve been expanding into regions around the globe, and as the public cloud wars have been heating up, we’ve been focusing a lot more on figuring out how we [can have Kubernetes help] run our workload across many different environments and many different cloud infrastructure providers." +
+
+ +
+
+ The first live service, which the team could route to and ask for information, was launched a few months later. At that point, Ghods says, "We were comfortable with the stability of the Kubernetes cluster. We started to port some services over, then we would increase the cluster size and port a few more, and that’s ended up to about 100 servers in each data center that are dedicated purely to Kubernetes. And that’s going to be expanding a lot over the next 12 months, probably too many hundreds if not thousands."

+ While observing teams who began to use Kubernetes for their microservices, "we immediately saw an uptick in the number of microservices being released," Ghods notes. "There was clearly a pent-up demand for a better way of building software through microservices, and the increase in agility helped our developers be more productive and make better architectural choices." +

"There was clearly a pent-up demand for a better way of building software through microservices, and the increase in agility helped our developers be more productive and make better architectural choices."

+ Ghods reflects that as early adopters, Box had a different journey from what companies experience now. "We were definitely lock step with waiting for certain things to stabilize or features to get released," he says. "In the early days we were doing a lot of contributions [to components such as kubectl apply] and waiting for Kubernetes to release each of them, and then we’d upgrade, contribute more, and go back and forth several times. The entire project took about 18 months from our first real deployment on Kubernetes to having general availability. If we did that exact same thing today, it would probably be no more than six."

+ In any case, Box didn’t have to make too many modifications to Kubernetes for it to work for the company. "The vast majority of the work our team has done to implement Kubernetes at Box has been making it work inside of our existing (and often legacy) infrastructure," says Ghods, "such as upgrading our base operating system from RHEL6 to RHEL7 or integrating it into Nagios, our monitoring infrastructure. But overall Kubernetes has been remarkably flexible with fitting into many of our constraints, and we’ve been running it very successfully on our bare metal infrastructure."

+ Perhaps the bigger challenge for Box was a cultural one. "Kubernetes, and cloud native in general, represents a pretty big paradigm shift, and it’s not very incremental," Ghods says. "We’re essentially making this pitch that Kubernetes is going to solve everything because it does things the right way and everything is just suddenly better. But it’s important to keep in mind that it’s not nearly as proven as many other solutions out there. You can’t say how long this or that company took to do it because there just aren’t that many yet. Our team had to really fight for resources because our project was a bit of a moonshot." +
+
+ +
+
+ "The vast majority of the work our team has done to implement Kubernetes at Box has been making it work inside of our existing [and often legacy] infrastructure....overall Kubernetes has been remarkably flexible with fitting into many of our constraints, and we’ve been running it very successfully on our bare metal infrastructure." +
+
+ +
+
+ Having learned from experience, Ghods offers these two pieces of advice for companies going through similar challenges: +

1. Deliver early and often.

Service discovery was a huge problem for Box, and the team had to decide whether to build an interim solution or wait for Kubernetes to natively satisfy Box’s unique requirements. After much debate, "we just started focusing on delivering something that works, and then dealing with potentially migrating to a more native solution later," Ghods says. "The above-all-else target for the team should always be to serve real production use cases on the infrastructure, no matter how trivial. This helps keep the momentum going both for the team itself and for the organizational perception of the project."

+

2. Keep an open mind about what your company has to abstract away from developers and what it doesn’t.

Early on, the team built an abstraction on top of Docker files to help ensure that images had the right security updates. + This turned out to be superfluous work, since container images are considered immutable and you can easily scan them post-build to ensure they do not contain vulnerabilities. Because managing infrastructure through containerization is such a discontinuous leap, it’s better to start by interacting directly with the native tools and learning their unique advantages and caveats. An abstraction should be built only after a practical need for it arises.

+ In the end, the impact has been powerful. "Before Kubernetes," Ghods says, "our infrastructure was so antiquated it was taking us more than six months to deploy a new microservice. Now a new microservice takes less than five days to deploy. And we’re working on getting it to an hour. Granted, much of that six months was due to how broken our systems were, but bare metal is intrinsically a difficult platform to support unless you have a system like Kubernetes to help manage it."

+ By Ghods’s estimate, Box is still several years away from his goal of being a 90-plus percent Kubernetes shop. "We’re very far along on having a mission-critical, stable Kubernetes deployment that provides a lot of value," he says. "Right now about five percent of all of our compute runs on Kubernetes, and I think in the next six months we’ll likely be between 20 to 50 percent. We’re working hard on enabling all stateless service use cases, and shift our focus to stateful services after that." +
+
+ +
+
+ "Ghods predicts that Kubernetes has the opportunity to be the new cloud platform. '...because it’s a never-before-seen level of automation and intelligence surrounding infrastructure that is portable and agnostic to every way you can run your infrastructure.'" +
+
+ +
+
+ In fact, that’s what he envisions across the industry: Ghods predicts that Kubernetes has the opportunity to be the new cloud platform. Kubernetes provides an API consistent across different cloud platforms including bare metal, and "I don’t think people have seen the full potential of what’s possible when you can program against one single interface," he says. "The same way AWS changed infrastructure so that you don’t have to think about servers or cabinets or networking equipment anymore, Kubernetes enables you to focus exclusively on the containers that you’re running, which is pretty exciting. That’s the vision."

+ Ghods points to projects that are already in development or recently released for Kubernetes as a cloud platform: cluster federation, the Dashboard UI, and CoreOS’s etcd operator. "I honestly believe it’s the most exciting thing I’ve seen in cloud infrastructure," he says, "because it’s a never-before-seen level of automation and intelligence surrounding infrastructure that is portable and agnostic to every way you can run your infrastructure."

+ Box, with its early decision to use bare metal, embarked on its Kubernetes journey out of necessity. But Ghods says that even if companies don’t have to be agnostic about cloud providers today, Kubernetes may soon become the industry standard, as more and more tooling and extensions are built around the API.

+ "The same way it doesn’t make sense to deviate from Linux because it’s such a standard," Ghods says, "I think Kubernetes is going down the same path. It is still early days—the documentation still needs work and the user experience for writing and publishing specs to the Kubernetes clusters is still rough. When you’re on the cutting edge you can expect to bleed a little. But the bottom line is, this is where the industry is going. Three to five years from now it’s really going to be shocking if you run your infrastructure any other way." +
+
diff --git a/content/zh/case-studies/box/video.png b/content/zh/case-studies/box/video.png new file mode 100644 index 0000000000000000000000000000000000000000..4c61e7440fc48cdc122d5a014d67f106be58f28c GIT binary patch literal 134595 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%0AHg6S8HC9LvfQPI0Q{_^I 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/buffer/buffer_featured.png b/content/zh/case-studies/buffer/buffer_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..cd6aaba4ca6a0327e3fdc9f43385b4199ff3fccb GIT binary patch literal 5263 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/buffer/buffer_logo.png b/content/zh/case-studies/buffer/buffer_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1b4b3b7e525d0a796046cdacfaec27aab25cc3e0 GIT binary patch literal 4791 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 +

CASE STUDY:
+
Making Deployments Easy for a Small, Distributed Team
+

+ --> +
+

案例研究:
+
使小型分布式团队轻松部署
+

+
+ + +
+ 公司 Buffer     位置  全球     行业  社交媒体技术公司 +
+ +
+ +
+
+
+ + +

挑战

+ Buffer 拥有一支80人的分布式团队,他们遍布全球近十几个时区。这样一个为代理商和营销人员提供社交媒体管理的公司,希望解决其“典型的单一庞大编码基数问题”,架构师 Dan Farrelly 这样说。“我们希望拥有一种流动性的基础架构,开发人员可以创建一个应用程序,可以根据需要部署并横向扩展它”。 +
+ +
+ +

解决方案

+拥抱容器化,Buffer 将其基础设施从 AWS 上的 Elastic Beanstalk 迁移到由 Kubernetes 负责编排的 Docker 上。 +
+
+ +

影响

+Farrelly 说,新系统“提高了我们将新变化进行部署和上线的能力”。“在自己的计算机上构建一些东西,并且知道它是可用的,这已经让事情简单了很多;而且我们的反馈周期现在也快了很多。” +
+
+
+ +
+
+ +“我们的团队能够直接使用既有的 Kubernetes 解决方案,这太棒了,而且它还在不断改进中。在意识到我们需要某些功能之前,它就出现在下一个版本中,或者在未来几个月内出现。

- DAN FARRELLY, BUFFER ARCHITECT +
+
+ +
+
+ +

Dan Farrelly 用木工类比来解释他的公司 Buffer ,随着过去几年的发展,公司开始有这个问题。

+ + +“如果你自己做一张桌子,这很好!”公司的架构师说。“如果你请另一个人一起来做这个桌子,也许这个人可以在你抛光桌面时开始对腿进行抛光。但是,当你把第三个或第四个人带进来时,有人也许应该在另外一张桌子上工作。”需要处理越来越多不同的桌子,使 Buffer 走上了 Kubernetes 实现微服务和容器化的道路。 +

+ +自2012年左右以来,Buffer 开始使用 Elastic Beanstalk ,这是亚马逊网络服务提供的网络基础设施编排服务。“我们部署了一个单一的PHP应用程序,它是在五六个环境中相同的应用程序,”Farrelly 说。“我们在很大程度上是一家产品驱动型的公司。” + +这一切都是为了尽快给应用推出新功能并进行交付,如果能够正常运行,我们就不会花太多时间在上面。如果产品变得有点慢,我们可能会使用更快的服务器或只是增加一个实例,这些就已经足够了。然后继续前进。 +

+ +但事情在2016年就到了头。随着应用提交修改的数量不断增加,Farrelly 和 Buffer 当时的首席技术官 Sunil Sadasivan 决定,是重新思考和构建其基础架构的时候了。“这是一个典型的单一庞大编码基数问题,”Farrelly说。公司的一些团队已经在开发环境中成功使用Docker,但在生产环境中,运行在 Docker 上的唯一应用程序是一个看不到真实用户流量的营销网站。他们希望在使用 Docker 上更进一步,下一步是寻找业务流程的选项。 +
+
+ +
+
+ +Kubernetes 所做的所有事情都很好地适应了 Buffer 的需求。Farrelly 说:“我们希望拥有一种流动基础架构,开发人员可以创建一个应用程序,并在必要时部署并进行水平扩展。”“我们很快就使用一些脚本来设置几个测试集群,在容器中构建了一些小的概念性验证应用程序,并在一小时内部署了这些内容。我们在生产中运行容器方面经验很少。令人惊奇的是,我们能很快地用 Kubernetes 来处理。” +
+
+ +
+
+ +首先,他们考虑了MesosphereDC/OSAmazon Elastic Container Service(他们的数据系统团队已经将其用于某些数据管道作业)。虽然他们对这些产品印象深刻,但他们最终还是与 Kubernetes 合作。 + +Farrelly 说:“我们的应用仍在 AWS 上运行,但是我们的团队通过 Kubernetes 无需手动配置即可创建服务并按需创建负载均衡器,这是使用 Kubernetes 的最佳入门体验。”“我们不需要考虑如何配置这个或那个,特别是相较于以前的 Elastic Beanstalk 环境,它为我们提供了一个自动配置的负载均衡器。我真的很喜欢 Kubernetes 对命令行的控制,只需要对端口进行配置,这样更加灵活。Kubernetes 是为做它所做的事情而设计的,所以它做得非常好。” +

+ +Kubernetes 所做的所有事情都很好地适应了 Buffer 的需求。Farrelly 说:“我们希望拥有一种流动基础架构,开发人员可以创建一个应用程序,并在必要时部署并进行水平扩展。”“我们很快就使用一些脚本来设置几个测试集群,在容器中构建了一些小的概念性验证应用程序,并在一小时内部署了这些内容。我们在生产中运行容器方面经验很少。令人惊奇的是,我们能很快地用 Kubernetes 来处理。” +

+ +最重要的是,它为公司最显著的特征之一提供了强大的解决方案:他们的远程团队分布在十几个不同的时区。Farrelly 说:“对我们的基础设施有深入了解的人生活在不同于我们相对集中的时区,而我们的大部分产品工程师都住在其他地方。”“因此,我们确实希望有人能够尽早掌握这套系统并利用好它,而不必担心部署工程师正在睡觉。否则,人们会为了一些东西必须得等待12到24小时左右。看到人们前进得更快,这真的很酷。” +

+ +Farrelly 说,Buffer 拥有相对较小的工程团队,只有 25 人,只有少数人从事基础设施工作,大多数前端开发人员都需要“一些强大的配置能力,以便部署任何他们想要的内容。”以前,“只有几个人知道如何用旧的方式设置一切。有了这个系统,审查文档变得很容易,并且能很快地看到效果。它降低了我们获取在开发环境中所需要一切的门槛。因为我们团队的人数不足以来构建所有这些工具或像其他大公司那样管理基础架构。” +
+
+ +
+
+ +Farrelly 说:“在我们以往的工作方式中,反馈循环流程要长得多,而且很微妙,因为如果你部署了某些东西,就存在破坏其他东西的风险。”“我们通过围绕 Kubernetes 构建的部署类型,能够及时检测 Bug 并修复它们,并使其部署得超快。这一秒正在修复漏洞,不一会就上线运行了。” +
+
+ +
+
+ +为了帮助解决这一问题,Buffer 开发人员编写了一个部署机器人,该机器人包装了 Kubernetes 部署过程,并且每个团队都可以使用。”“以前,我们的数据分析师会更新 Python 分析脚本,并且必须等待该团队的主管单击该按钮并部署它,”Farrelly 解释道。“现在,我们的数据分析师可以进行更改,输入 Slack 命令,‘/deploy’,它会立即进行部署。他们不需要等待这些缓慢的周转时间,他们甚至不知道它在哪里运行。这些都不重要了。 +

+ +团队使用 Kubernetes 从头开始构建的第一个应用程序是一种新的图像大小调整服务。作为一种社交媒体管理工具,它允许营销团队通过发帖进行协作,并通过多个社交媒体配置文件和网络发送更新,Buffer 必须能够根据需要调整照片的大小,以满足不同的社交网络。Farrelly 说:“我们一直有这些拼凑在一起的解决方案。” +

+ +为了创建这项新服务,一位高级产品工程师被指派学习 Docker 和 Kubernetes,然后构建服务、测试、部署和监视服务,他能够相对快速地完成该服务。Farrelly说:“在我们以往的工作方式中,反馈循环流程要长得多,而且很微妙,因为如果你部署了某些东西,就存在破坏其他东西的风险。”“我们通过围绕 Kubernetes 构建的部署类型,能够及时检测 Bug 并修复它们,并使其部署得超快。这一秒正在修复漏洞,不一会就上线运行了。” +

+ +此外,与旧系统不同,他们只需一个命令就可以水平缩放内容。“当我们推出它,”Farrelly说,“我们可以预测,只需点击一个按钮。这使我们能够处理用户对系统的需求,并轻松扩展以处理它。” +

+ +他们以前不能做的另外一件事是金丝雀部署。Farrelly说,这种新功能“使我们在部署重大变革方面更加自信。”“以前,虽然进行很多测试但仍表现不错,但它也存在很多‘手指交叉’。这是每天运行 800000 次的东西,这是我们业务的核心。如果它不工作,我们的业务也无法运行。在 Kubernetes 世界中,我可以执行金丝雀部署以测试 1%,如果它不工作,我可以很快将其关闭。这使我们在快速部署和推出新更改的同时降低风险的能力得到了提高。” + +
+
+ +
+
+ +Farrelly 说:“如果你想在生产中运行容器,拥有像谷歌内部使用的那种效果,那么 Kubernetes 就是一个很好的方法。”“我们是一个相对较小的团,实际上运行 Kubernetes,我们之前从来没来做过这样的事情。因此,它比你想象的更容易上手,这正是我想要告诉正在尝试使用它的人们的一件很重要的事。挑几个应用,把它们准备好,在机器上运行几个月,看看它能处理的怎么样。通过这种方式你可以学到很多东西。” +
+
+ +
+
+ +到 2016 年 10 月,Buffer 54% 的流量都通过其 Kubernetes 集群。Farrelly 说:“我们很多传统功能仍然运行正常,这些部分可能会转移到 Kubernetes 或永远留在我们的旧设置中。”但该公司当时承诺,“所有新的开发,所有新功能,将在Kubernetes上运行。” +

+ +2017年计划是将所有旧应用程序迁移到新的 Kubernetes 集群,并运行他们从旧基础架构中撤出的所有内容,以及他们正在另一个 Kubernetes 集群上开发的新服务。Farrelly 说:“我想为团队中的每个人带来我们早期服务的所有好处。” +

+

+ +对于 Buffer 的工程师来说,这是一个令人兴奋的过程。“每次部署新服务时,我们都需要弄清楚:好的,体系结构是什么?这些服务如何沟通?构建此服务的最佳方式是什么?”Farrelly说。“然后,我们使用 Kubernetes 的特性将所有部分聚合到一起。在学习如何设计面向服务的体系结构时,它使我们能够进行试验。以前,我们只是不能做到这一点。这实际上给了我们一个空白的白板,所以我们可以做任何我们想要的。” +

+ +部分空白是 Kubernetes 提供的灵活性,如果某一天 Buffer 可能想要或需要改变他的云服务。“这是与云无关的,所以也许有一天我们可以切换到谷歌或其他地方,”Farrelly 说。“我们非常依赖亚马逊的基础服务,但很高兴知道,如果我们需要的话,我们可以搬走。” +

+ +此时,Buffer 团队无法想象以任何其他方式运行其基础结构,他们很乐意传播这一信息。Farrelly 说:“如果你想在生产中运行容器,拥有像谷歌内部使用的那种效果,那么 Kubernetes 就是一个很好的方法。”“我们是一个相对较小的团队,实际上运行 Kubernetes,我们之前从来没来做过这样的事情。因此,它比你想象的更容易上手,这正是我想要告诉正在尝试使用它的人们的一件很重要的事。挑几个应用,把它们准备好,在机器上运行几个月,看看它能处理的怎么样。通过这种方式你可以学到很多东西。” +

+
+
diff --git a/content/zh/case-studies/capital-one/capitalone_featured_logo.png b/content/zh/case-studies/capital-one/capitalone_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f57c7697e36fd06fbd418787ea15eea218bc7692 GIT binary patch literal 11306 zcmcI~WmH`;*Cy_6rMQ<;>;e~emm(K;cXuuh7bxx&T3m~}yL<7XE$;4aLtmTu@y_>a z=B#y2lAZl*%g)M4R>GAOq|i}_P@tfo&}F2>mEX#Rx7QyD=IslklXmo0ymyt*bX9RM zcl9uGHiHr|buc!gkg+qeFjF=&GWB#CHsgnaf_1i1)pXUA|IBORV8?9qmxmc_=lF(( zg5nnfI~tkTn7L9In^{=d3s9Z5c2ZGTnF>&80OeWb9mUKnt)#u2%~ZS;R872WOn6MG zgaj%0!Mtw*?95z^D8P2M_Ab0&0jht<<$bIFC9_ab{DZ~SMu6&{Mrq0`QHVJ>n^6Fn zIhjlV9IO;vJj?)2Rt_M5k%EmCz{SD}WMSoGVg>NBa`UnQDE{?Oy=ikcHRn|pm;9Hm zx0V2vrK_tWFAIx@hX=C5YTQ#nax^2+U;fLj7+E;$|); z&Q^}DRu1+Qemh)*xuz|fqDxW3)sk!1;EV8VrTc)uYYj6 zxGJ0dZ!`WYw~MN$qZx~`nTvy)v&q|dm{b27{1&_aSMy%XyZvkXwGh;J01{j<1{9Dd{ z#RC9hJR(3K7biPA03gB5!zIEc&Lzq!$}Yym#SWDGH&({p#ns5(#O&X?t^Vr%Czj)X z#PW(cn;E$}IIB81*#0{Ulq?-w9b7CO94W-a{*F438Aw4dZ)9R+|Cjvn?@;~Ib8$0g zD|a(fNoNN;ihsnK*XqC6!Op`i4rCJ*XJ?ZH{`G-df{Rm3lwAbKF2>C+A@b(KKe49& zC4T?HO8j53EN{lJ{7sbqBXRysddtSY)&ER`x5j@al9~P6>~VgZCgxCp4^U9_3Nqp% zs^Fy~Jw!u1wFiF{cMI=?iJ9;?TMOFm0<1wVb1y zmSIf^XH5kHBuB&HY$aTS`#9HK%a}7Wm8^N>w1Ld_k#N`foRhfNh#u!95A>O1dS5&O zWi02TuxdVOuo1_(F)RJu)6k}fJ=f_u663B1x6jwFFAoR}#UCweQ53kGo8eN@&K{7^ zgMujx6Y-ECG;oz4EM1JFu&EHrq?NpwYWgVjDb^iQvF`(fXY%_+`v;2?647~@e<(D6 zcIB|8G#;x{_joy%p~p9w5c*14`3{O&Np*7F^!O&bH-@3~{=j;C|4OI)C6!1+4PL{c zz{hW70tZHlA|6c(6o8e@ffCP=D;-aTEi#e?FPz=yKneGznevHgBj`-34VszR&=3WN z@=QDqkrN*x0$PLWhY^JlsRjJ_w&H7i>0R=8HGO?p7#T^;K?EO`BG_16rm2R%1tSuy z9T6e0y)CK+57HZ(`&ENJ*7m!%)(^4^WsV0GB}F4L9hIsyr5UIUCEP_qYq$lC0r&=G znJ^x$L@+>@@Y;h#ozIke6&v*@jy<5W&miuu@haNKRod5NW2=}#5pE%1g8a;d1cgG@ zPFij@=6%LhD4&}iFRmjo3Koks^d?$Pz-T}4cUTK=M^3kj#_1oOy*~!@>T|3RdaxGd z-auanJ*Zq1E$AM#N#*F&4kqKcqrJ+9JUZ)&l|D=PVi-gv-Og&UJj9vMGu7;g>ah*gNRq?pOWFNlSFr zsM|ZhX?&jX{<@)B$m1En!LxbK9pnS0N-~*}I;lj|l^Ic}rWyF9Sq{sS#;}2=SAaPW z<5XByD;o}-wSSEQz;6}>iKRRieql(bS(8)JFj#WJ!_!bnQb3Ns%ZfJ%?R zThlN22|I1?;hk~NX5Vb!Upz4k3IKP6TzUn`kKu8n)B|r|ANBZd!X7b8G?Pm!QFEcL zsP}Y5oF8a9V-tSlBjwC~qn6Iba-1YS>b285pdR2>EHAFk;_tu{V*(`l)rg zW|5Fe%afWC8o;l=)eEZa! zm$ZB)Av;n;q*WJA0;>)sis`3&%`iUa=^1`kJd&}$78(LlyM8|X$}VEc`*gxNYjn*t zB|Ro1JL7Uriz(>ab)24Ub;@|jV09audR~3`@T7>Y7TsKKng&W;h-FYeE1XzZVzh#? z*TCcet4eNM2nB${eN<-4(Nm{PV07eL9S3}vg;cO`fROq)4@tv@@#92V7(_4dfJkw& zS4Qtg4q-wLvP*h{H>Ox4zppz6?z=)xBDlQFFhFT;F4EVCX-nw`nBXq)%w1ik?j^6B zmH{p0r7GhPB~@`wK4}`I0ea;^Ts769CVmhwbaJtzQKvZ(i4rFS#K5zRO-n|nlu2_x z;@n%_xW%kh0(H(cAP*snJspbgs>o;%2yshmY#oj0KKnvmE?Fw4koS1?0zJVMpV0@0;*c7GB0vp`)q7haHQ9H0RXR@cC6o)Kxjj88>2*sk1`I$HR%) z`tsF_jg9yGG?bw(%(2jUzQ^agBb)KEo}=rDh)bACU&pA)vT;Q%dKf$QS5slQ5Y(g!#)gu zPtU2MsXfPHI)TIana^VJgVI$szGZ8b>v-bXE&T2SQBn7o_{7y}K94tia&o|S@At~e zmS046*&h6h8Ej%cwcDk8JoD1E!w!JB-{<pi>rg|mm4#hX*OtWG$-8! zXsfXTbdVu&qZZ0R9G-?2b`;z7N_!Bu1;9T9n}vE^FEd~@l3rH13EZK8CS|`hLFEJ~ zjp9-^%`O=!H1i_kmEL#Vb&R85cDYCL-io7lhNJ6OiuzGrK>uZ5=^@HV1|nHewDWo3 zQw+IUe_y&zgL=#E1@@ta0U+rIPzJmH+0mFIjYbAy`f2nIW7szaZ)OU#`>>M4y|GOt z5}L;fOa$~(FwNMfigC-Rqc~sYRyOFmU00C_`AD(tnw%%~gr!9OYQN{iJ~PIP$eC3a z4@T>ca|-*)u9TB?J(rwzl9Bqld2ksd`sU3$WX*DKW%jycIMLBMnJBwM3OQ6HY2~`# z?G-z}?k`o$e{yGe6a_mlqw+XE!r{xrdyyvKIx6TZhirbqlR+pcZKs;|?EO+yTERQv z0agguGlK0ljN63|9YoCX1OKsHv_8mj)rQKB|_Vfbvru z+a|C~`a*f?R;qQb?5~gRsmo=9ySv;NM0}J3U98qYKdwK!JGhIyQs(`ek zR+G_XVBld^9%Pf!=559p=y1{}yGp(W+yS4 zdM+tbig}vpb)_H`x(vyyntQ$J{d8xdaY#%jsJp&_yzcc)$I;0jRa{;=&PbSa z1j&VineVry#~=m7o%)@)^^Rf6l(0d+82HD-9DB?xPn3nbp`5|-qdIl=`tAwa#=`45 zqm5&!?MMj7Y}RK2k1$0Y_mwUu-}%lT63N)Hw(OWsJ5UajdwTgWG?=sazJf9`t_Dw0 zWa&Pq#o{p0>(amh8_}A6><(z0IC%Jrh}*cQtlaDg#mzik%y=laRCo60Cqf@yRT;eM zazBTAhycD{uxoU3mOCh*tWH*yiZ!U07XCEH_M+s-fRrY|SqqaQ@;;xHoArgEE}(X5 z0N;^U`k$T3dD!!W{UXA%qxh`aW=mp+-}YhfSVn9Nt2xge2KlmO?!O(PDZtLNM(IHJNa21@0w6PZ9C5-^) zS#AoMAM69L8g@Ey^4w!JUsN6c?U&o`HQw#uN#BI!(^{4&?-WFXqust`>?C z6fLMTh`#3)j%zlZE8))+yFC19UKy}9^krSVrz3kRxRe`E*s5msm9Nu zO}c{qI3lRi9?ewJ=CZR8OWyuW6=8oSDxbK#y&0g8FgEq!eI@m-&(+LBySS}t5fM6f z=Ik7#GV?ei!za07T!)T-u;DIF|5N2x+#r#y8+E@&7%-XL?H}*Dn-RXOP*|Lc=@=%z zh!=xVCw=`Er}0CB?kW+%Ebkc|2GD|4%zSZudTl(g-}TYzYqiE{?Lw3wb5&y*??4fv zG9GwkX@e{|%R9C0j@ZhoM=q;UzZ%s|8g2JdR?euq%ei)FzhgJ1)IzbXL+ogH#N$u4 z{Uuq`cKd0g+X%POdt)UmAKS_O^WS=8j)X=ui_7{fqX}&+uUiX*&EklNH*FL> zo(D(v0b!$?tGcS;XcsX0!*fs@YzL7H#LAnwB>J5ZH0-#>qLMT$;KhL6;~+$*N6nNJ zH?QZlu^vyuB+31{;pC#aCPMBw>rDtp>r>eb>=sGMZGeMZw#jF@XJp&?HCF?ka~|7K zwr)t{t8~^tZq=Y9X6EAx3P^&Q_;zRHICj<9>>+ADRNo(XpR+Gu;1|#TTLw){UB_OQ zaWHRC@b2YV%AQM#n23a_IC;;dKkT$}SzzgNy($IWhdOxPbF`cJ4&?WHp5O z+cMKA?uD(2r|IRFKP1*rf*7_jCl;-b!c4NjrbjLw8TR|%5m#PL5+~-N=aqQ}E|*b@ zs&hPbM2_qlGf?|COki7MRJVWhq2^})*x!hF_{3*Xv_DgmKd~U``q=z_!WWY8Q#q$y zNto<1FiVWgpVT?ktKWw#T`je{ysl$XhewnrK%6v{E= zbAUE#xd#SGk*S`aZjwxaC=miV5*-nL2r@qv z8RnabvvYXMH9s?CY97b)h|ub4WT_bjU{lZ$-e@HS4G^s);^wN_f4@Ej^G%!Un!Fix{}OdF(xclvv>wo%dymm3vQn z%5qS4GC!rBmSpc7QOS-yqS5EBFF0qJ{UhYbNNWG*d?!vlTK8mAG<>j)J5PHhBEzM>%VKyG|9B2glEow5 z8_qTWRP2d>Wg7EWO{TRn7p4WoJ=@rh?)wJ@vJUbLpzfD$d09$tG`~Oh_qnEkPsNS6M3&Qsq2GU%ufWA?=QO} z@cAM!o|+EF;A89HjpY+-H7r@OlE zrL0rGtXytzB%BXD6fAx-d-1P?y z`&7+kR;}NxW%dw#I~@zP)8kywP=4ecFq@u_ZbMx!aZ_lhZvSn*h*;f0h00BNH z6?t2=fpXOPjn-*cGQDWS$$A|9^9K4ORG3d3qJkJftu7JPE5=#1%n!?UP8^cEiH=^R z(A%N7j1NZiLYKj2wwL5B(GU3Zfe8Z>Rb-3wSi)^6IxWsT71@(qh}2!=YjP!JU17nt zAB|F^;8GRQ2DR47cKjMJ@OUq(n)Ued`!lVcfVMfQd0iCDg8H8MCFg5_);`3@I{?^L zi5s08mvwUUb^(`zF?;k)hXn}jlVCQmB^M)20S zw|?{edPvMGuXLLV1+70ARe?Ls73q|nfgT)4+i@Jfis#oP!AFMBSbdisT*1WOEQ6*oE2~HKvL}nfU;k(CjKTcn`~9ZfQAs7JbN4Tz*_; z{+egT>vgS~TL0pyEN0k5s>A&hz3TjH0dbb^x{JwfUD%HA#xp*ukb%q7hbqk|s18hx zQz#)@!_)Kz`lqAap2rifk1dMs_X*8*4!I_f_x*%M(rO$F7t|E71-E1J&*<3ZN1cgaoMJ`u zAxJ23P$b4l>PO5RD+eZ>4y#U!=hf}FIC9C>u-nc8fBh}~(p!>_(?BjIFWvoj6X_gy z?kQ>}c~bJkb)5p9=RX5112D3s@roZw={NzhufvUL25CMfbuX^$HbkT+{yv@e*AAS> zlgclKmQ!$O29_a)P~I68Z%e|(B51-G3+ts9%TWtY}=YHRK9*% z7A`;(Y7D-A`!eOF&Dr~-v$rEFxr#QH(A(L%Sum({On#X)@Mzv1gSbxKLH7 zT*yRhkiY;Cby5M3Nyh!cmef>=f{vX4_l!&3z2qk$s$t{ybVvSl{-p{MdqPFmI@`d{@G^FL4pV$Q;+%u@|W9xr<^p4{+^zPR76 zoqS(&!?8=E9z<1>XA;b+^ftd(F{w{1WD(z&Sxc4W)xh(8;ZF2BevEZf5a{mF?0nTE zZVHkc6-#l2*#*s6vQEk{T+tElNd?)9iGZxsOmx_{A0fGl9e0=!kydJ>{Nqp$y|e9b zB1M(v?(+GMCXWmpVf;FaEF1<-U4Qo-q{xZAi#fon}!unP?r#jul?YOnu7fsesdYHu0 zRP`B)9Sj&frr&Mkh$`*2#@fcRj4{he>c5Osw+jWH#yvP_$-uW0A4spqOGt&MVJ~XU z6c)90oowf^33JH>+`V=3&mpYa*R%%AnxgK-GI(e*=b@*CK)-p@9Bl}_1JiCy}YjHa(x~`xtIL`dsc>7GHz1SF^At2$+B0994R;kjrm}wN zvSWag>|=LuUczIZgVq>U=xKvt9twmgC&dS3IDx3-Cj0%|Pui)Ma$aEqyu zqWUOSKYWtNBt7HgtJY8m4&~T$&0`+6jYt<6n>51J;-0x}4jMbIur$w%p~2(Ax0xpm)i-64gLR!*GpB!Ufy!O^aH`vomk!9Gx%wjfoxiMkqFGFOtX z>S2UOCI5F(Tw|Ve1<@e-ex^hnfVmq+805wC`J*hu*YI$*eJ94^x)Nx14tbL?icU-v z=KT5b`=dcElhA{DqGZ&gkELE`<);Uj^Vk7;096_l=Id2<#0ep_?&m6!xg*L;tWbEu z$l+`&U_EYE3%si`$AuTapTc0eNQ!@z`G=Uw^M$RZ+m;TtsAPP+UWw4vU;g)hh6~AR z9v$(W-~OTUXchZ+Ztzc7#0U~2Q5jdNes5o&&{tU1HQvE)cq=NB3KbphPh_M&=ZB`# z$n}=Yznnb{9{MjaS-XL6q7p3B`s2u9#~JfzwMRqcTGEWzHXPAxALO5R#&j4CR0^OO z)=*Tn5qx%u$+QV`hY=7rp6L0a*$#q*S&u3s43n1s@M)NLmlxnKT!sIX!o{HsO*P6(K|sMeHn5mUFye z>DnEDgi}8Mc0ij$daKTVyQp~BfKSO8b}t!iU>3B8^g^RY_dXE(=Mi?8pv);Vi(^CD zZ25N89v{eCc30$B3{Alria1mzR*7-?bYF32>AT9O-vz5pTUdZpw5Yb(b%GQp&vXUI z#HKtqMIsD;F`Q`oCDZH0f3w5(>!`~yzi22;E-ppP)bT=Zz71efS0-+FX>oX)O~8WY z3$VS&Ch%8Cv)tqQjX~9lIN^(%lZ{zYf8Ask@B{`R9PePh@`9)3ihAHvaIM&MuhV<< z{qxY%g8-O+E-rqhWj;DTZ+K|rNK+7<4DMUxQ?VI9pe;P8d17&G%%NwOE|nEnK@~^o zfge`yDLDEsNc(+j6+J|TiC69VhtHsNzj)a!l~bDOIRteF8M|6J9jn?K26fXq%E7dl zXeySwYH%u{vJxR*+=$#G10-F?w>-=WZze`H?>C<7-8Do&{SCP_kc5&=c_!wpESJYw zuX5RtUK|b?>-Y6BG`t0a#6Zo`p1I1*?`=29B0{!I{HilYXLp_=Z|C!*IP$Q39wg~m zGqg;ZROi2wD>{FaMyLWKk`p6=jarv`VJwx}8m@t1WDajTuuv&6`N)l%L(i^{sP22?JqXsX8>@4HL5>$ zE&eK=34qo^^%I2p!|8Cow73}xCdqY zc2{!C{~=SwYlODyr{>`)=hgOJ6VKMG_4lofaBy;Qb$$LzN77?$GZ@9Iw12Rg1abM) zEC?osSj8G2-W<+HDgKzie&AC8R)U;l=A0{jpzr#|d2Cy_i*vXmQdPr!f9L0KKzC^{ zmD1Jv+V`Tj3nZNnJL#yppg4kxUM${gk);lfSfqC;l*lm8BUFqH4L6hDe(QOA3@-C> zdJON*VkpkdvV&w{YL;I4U4Ei|VE$osYwk?fuIi1~X7b8jd+KA|Qy*Vh;p;V(y#4zz zdawPy-l~wSX|0vX-`5YY*LvWvJ0LToF+cudI6C0lH5mDBoRBN~xd1hB*Pka>v5-$8 z{3ty>eay{u5_*c)O|*_uwo-fhFj{kbFWHbtrri;E3y#Yu*-m%`Dd@J9WU71vUBfpYry3TcfMt3+~o7D~$ zvS-vxtAqJe_1wkcAhhy{?|lcK{)%Jok;K?qU z@^y=E2f>#6l4UD@ljJD-xX{x}(sw_%%4xsmVpwG_fZQ^4_&D|ag%6~m?>Q}aTCu=+ zdCdZ12itC-Z-%ymC*0nj1G;*^)zY40N3s4(x4i_WzXW(qj*eO@*fZEDUw#z|jio(9 zv+ZL#_`qWD@9VSxk*aDkMP>*TVKwzKng$>E^bZNGW@IPzuih+G+gIOW{Ew% zW>bH?{Y-qhQg&{!ea<34F~`BvD(|Z{#!AEV0f}mE`!FG`&2z;SLcuIUWoymLZ&xlGXm041#SL z*!!(0sM&fuInhZH6B+AwmmFBg?1^1ne>?jwavq{_)m8qsTOq{#UQ_DSMDBlhxZRlq zPn^LmL9NZ@V>o|5Gw}2!sq|Gy7%r=8=O*YKj)-2syDMw$ybid-yRclh;c1gZxVmSsDpb0Tk&#~956$j)!YKn2nHdj-LQ^16ik%JpY!@>eCW`1->nZu` z%;&pwZYSlXOPB9kTcd6Acodlq=Xm&}B&?Hz4+#|=f^O^lzPtPde>*hRwQlb6VpCYW zR&AqBE@rGvUO!D0?CX6LZVN8h9|Y1i#y~LJQyAG}+xFS~Ju6}QP$_JEpI36kd@lR zU4yz=H9dMR)VUAp{G<}U729du?TUW(@EC|l9QutFK*;~HBb2I9HspEUUj+U972)k( z52X?z5=kc4MBHNa=|jD&?#^e4?;CvH!hMnbeJ;0DS|Ql@JnaB^kSz6+IjDy#f?ilv m92-9D|9h#ce&G*;2E~F9fcpCe`TXzgT^R`l@d{Bx$o~Sc%O{xt literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/capital-one/index.html b/content/zh/case-studies/capital-one/index.html new file mode 100644 index 0000000000..773db4869e --- /dev/null +++ b/content/zh/case-studies/capital-one/index.html @@ -0,0 +1,96 @@ +--- +title: Capital One Case Study +case_study_styles: true +cid: caseStudies +css: /css/style_case_studies.css +--- + +
+

CASE STUDY:
Supporting Fast Decisioning Applications with Kubernetes + +

+ +
+ +
+ Company  Capital One     Location  McLean, Virginia     Industry  Retail banking +
+ +
+
+
+
+

Challenge

+ The team set out to build a provisioning platform for Capital One applications deployed on AWS that use streaming, big-data decisioning, and machine learning. One of these applications handles millions of transactions a day; some deal with critical functions like fraud detection and credit decisioning. The key considerations: resilience and speed—as well as full rehydration of the cluster from base AMIs. + +
+

Solution

+ The decision to run Kubernetes "is very strategic for us," says John Swift, Senior Director Software Engineering. "We use Kubernetes as a substrate or an operating system, if you will. There’s a degree of affinity in our product development." +
+ +
+ +

Impact

+ "Kubernetes is a significant productivity multiplier," says Lead Software Engineer Keith Gasser, adding that to run the platform without Kubernetes would "easily see our costs triple, quadruple what they are now for the amount of pure AWS expense." Time to market has been improved as well: "Now, a team can come to us and we can have them up and running with a basic decisioning app in a fortnight, which before would have taken a whole quarter, if not longer." Deployments increased by several orders of magnitude. Plus, the rehydration/cluster-rebuild process, which took a significant part of a day to do manually, now takes a couple hours with Kubernetes automation and declarative configuration. + + +
+ +
+
+
+
+

+"With the scalability, the management, the coordination, Kubernetes really empowers us and gives us more time back than we had before." — Jamil Jadallah, Scrum Master +
+
+ +
+
+

+ As a top 10 U.S. retail bank, Capital One has applications that handle millions of transactions a day. Big-data decisioning—for fraud detection, credit approvals and beyond—is core to the business. To support the teams that build applications with those functions for the bank, the cloud team led by Senior Director Software Engineering John Swift embraced Kubernetes for its provisioning platform. "Kubernetes and its entire ecosystem are very strategic for us," says Swift. "We use Kubernetes as a substrate or an operating system, if you will. There’s a degree of affinity in our product development."

+ Almost two years ago, the team embarked on this journey by first working with Docker. Then came Kubernetes. "We wanted to put streaming services into Kubernetes as one feature of the workloads for fast decisioning, and to be able to do batch alongside it," says Lead Software Engineer Keith Gasser. "Once the data is streamed and batched, there are so many tool sets in Flink that we use for decisioning. We want to provide the tools in the same ecosystem, in a consistent way, rather than have a large custom snowflake ecosystem where every tool needs its own custom deployment. Kubernetes gives us the ability to bring all of these together, so the richness of the open source and even the license community dealing with big data can be corralled." + + + +
+
+
+
+ "We want to provide the tools in the same ecosystem, in a consistent way, rather than have a large custom snowflake ecosystem where every tool needs its own custom deployment. Kubernetes gives us the ability to bring all of these together, so the richness of the open source and even the license community dealing with big data can be corralled." + + +
+
+
+
+ In this first year, the impact has already been great. "Time to market is really huge for us," says Gasser. "Especially with fraud, you have to be very nimble in the way you respond to threats in the marketplace—being able to add and push new rules, detect new patterns of behavior, detect anomalies in account and transaction flows." With Kubernetes, "a team can come to us and we can have them up and running with a basic decisioning app in a fortnight, which before would have taken a whole quarter, if not longer. Kubernetes is a manifold productivity multiplier."

+ Teams now have the tools to be autonomous in their deployments, and as a result, deployments have increased by two orders of magnitude. "And that was with just seven dedicated resources, without needing a whole group sitting there watching everything," says Scrum Master Jamil Jadallah. "That’s a huge cost savings. With the scalability, the management, the coordination, Kubernetes really empowers us and gives us more time back than we had before." + +
+
+
+
+ With Kubernetes, "a team can come to us and we can have them up and running with a basic decisioning app in a fortnight, which before would have taken a whole quarter, if not longer. Kubernetes is a manifold productivity multiplier." +
+
+ +
+
+ Kubernetes has also been a great time-saver for Capital One’s required period "rehydration" of clusters from base AMIs. To minimize the attack vulnerability profile for applications in the cloud, "Our entire clusters get rebuilt from scratch periodically, with new fresh instances and virtual server images that are patched with the latest and greatest security patches," says Gasser. This process used to take the better part of a day, and personnel, to do manually. It’s now a quick Kubernetes job.

+ Savings extend to both capital and operating expenses. "It takes very little to get into Kubernetes because it’s all open source," Gasser points out. "We went the DIY route for building our cluster, and we definitely like the flexibility of being able to embrace the latest from the community immediately without waiting for a downstream company to do it. There’s capex related to those licenses that we don’t have to pay for. Moreover, there’s capex savings for us from some of the proprietary software that we get to sunset in our particular domain. So that goes onto our ledger in a positive way as well." (Some of those open source technologies include Prometheus, Fluentd, gRPC, Istio, CNI, and Envoy.) + +
+ +
+
+ "If we had to do all of this without Kubernetes, on underlying cloud services, I could easily see our costs triple, quadruple what they are now for the amount of pure AWS expense. That doesn’t account for personnel to deploy and maintain all the additional infrastructure." +
+
+ +
+ And on the opex side, Gasser says, the savings are high. "We run dozens of services, we have scores of pods, many daemon sets, and since we’re data-driven, we take advantage of EBS-backed volume claims for all of our stateful services. If we had to do all of this without Kubernetes, on underlying cloud services, I could easily see our costs triple, quadruple what they are now for the amount of pure AWS expense. That doesn’t account for personnel to deploy and maintain all the additional infrastructure."

+ The team is confident that the benefits will continue to multiply—without a steep learning curve for the engineers being exposed to the new technology. "As we onboard additional tenants in this ecosystem, I think the need for folks to understand Kubernetes may not necessarily go up. In fact, I think it goes down, and that’s good," says Gasser. "Because that really demonstrates the scalability of the technology. You start to reap the benefits, and they can concentrate on all the features they need to build for great decisioning in the business— fraud decisions, credit decisions—and not have to worry about, ‘Is my AWS server broken? Is my pod not running?’" +
+ +
diff --git a/content/zh/case-studies/ccp-games/ccp_logo.png b/content/zh/case-studies/ccp-games/ccp_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cbf3d267ba8ddce67119711911d799ef87dc4c3d GIT binary patch literal 20368 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 y1pnU6*%t)})QeQ@uKW+Ou>ooT literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/ccp-games/index.html b/content/zh/case-studies/ccp-games/index.html new file mode 100644 index 0000000000..8867cbb323 --- /dev/null +++ b/content/zh/case-studies/ccp-games/index.html @@ -0,0 +1,4 @@ +--- +title: CCP Games +content_url: https://cloud.google.com/customers/ccp-games/ +--- \ No newline at end of file diff --git a/content/zh/case-studies/cern/cern_featured_logo.png b/content/zh/case-studies/cern/cern_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b873b828b1d4124a302dc1bb3985a4734f92699d GIT binary patch literal 2849 zcmcImdpwls9-mSwp*y=>$FzG~GB-1W8HUUyBe{fXBCEN)7@CWjVa9bjNs}De)-72H zg+*d>7Tc`*_O z{h%TaCBpt7MR)UrlKDaaibGh#S!gT{YJ*3htua_U-V$nsLfaxywn#JvjVu zHiu0h+hT06R1D6>mSl}aQ}IqDES5?pEtWtQ z0t_)<=)>n9`cys7V7{0y3g!!-Wb%BqY@lXt3>JqsFEpP|@JGIYkP`v0cL@1h=!Xmu zIA364O~F{>Fn9`%Ox`gc0Uou(W{0gc$q9!>Tj4QO*heh;3(Xny*+dBMf!_6K-i&kMok&aOSu3V|$1aiKW*NHxPbPPDb$jdC|a)^FdQSV}s| zPJDK6r{|HS{uGUCJ@YJywW3eswMs9Pwk*=TqnP|A9DB;pX(h?n-19h&um~P~d^}D4 zYw@`UuV*9PP%2_2lBtK?-C2Xx-7TtNmBYmQ_q~$9BBJcwTMneyJbB~7nd3pI_2NOJ^_j*{tt!wTN zswJb}6~kjD29oto8y@v9m&@h%AJu)|iQ{e9u%XnG!ae^Ax*5Ct!sEt9TDrErr{@6e zShDb0Q>y7Y9y=tY1flY~V^qS~>*8dpOgVY-SkOCCdYMqJg+VnNx0c5LDF1!CuPkzIF`_HoXadgX=sp0)? zeFFQ(%NX2yG*~BIjnpjWHqlMMZ;CFCJ{((wT3!Cw69L@;O*1 z?3mSSpwd{fCB}Js$Eg)@&Ka@+of78MSYMrw1z=m~=H@2cz4%~*iEB~2zrVkeh0sE4 zA&ifYpO~1?>L0^7#=WIakE~sp-WAW!i?khh)xJ7A=|EapYHF$~cc!Gre_8QzvAe~M zp*L%NO;Vfa-ECl-#Ms>j8c4DB6CLN$EULQ0|x$egc+|!Q=5XXBel? zo}C)}UAbv_fHICtFNxERtp2fn(m{RyXnT>z2Ctm*nqcqdk$+Z>J-w5eVAQ09y!K8) zw`FfKSInZIzE?c^SJweQBpD-NS(nEc+ba(C4YuYQxGEHi=_g6d)AWc{fols5`gvP) zDa(xpg!sC?;#TU_BG($<}I3M^{(S>7>Np!)h|6_PkmY#=&7ke)zhv zNz6K(2*LFDQ@yHlhow)O(@E*1pd+^qSF<~v;YTg<4*Ev&L<{p72?+^{w<*zMmlGoR zRfg;IF#9flSNYS$`~_i5X8ykyTy1MM_X}=o&2@a)lyfA4U+A+P8{>vsaoouA5Qk%4 z(bzc$%_H?Ec6WE{jhgq|y_;=g5KlFQcD{UezNY5kO7&!4s9l(Us^Wlu=1mH0_k}wn zGe-X~HC>{stH0pt$xw!$Up8Y%tzP}KyuNVy$*)Nzz0<1_De9q$6^_vb>8*iglc4X0 zD_-}8w7;~bv8(Z*>96ocNnbB?{&vlR@EMwJZ2KKq-B^E0a&mG*%9iM{-WJd>e0X>m z>#^v1G_6si@s-JxxiZvl#EDp4owWtT(>Fv5nGm>-w{=&fai-U)ejuI9&R&TpFER?+yH@kZjZ@vBvH_cC*;`cj?8yJJoihMZ;|FyHqg!ah6C zL{=Ap$ZWT5i;=5ZT6X0P^=OIIc2qw-xQJ?MzAnwcTf&Tst9@2q`Miej(Hk2Zd!cN< zjYpf9l+veahVLCuQ^XdPx2jaSkMSlJq>DZwlBP$@s3=W*LljNCm}0O+M}4Y_+LxDo^1Q4<6A0PC`IwZnI(J)hKdYMV&Tl;m&94p^!^ckCt}^l;VOit(-uitS!@ z-09ktzW0OC#mA~IO_dZ9uzEwCe9`#2u1o$CxU|FpVL-6@wy2ao&* Dp~2S} literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/cern/index.html b/content/zh/case-studies/cern/index.html new file mode 100644 index 0000000000..9bd7970245 --- /dev/null +++ b/content/zh/case-studies/cern/index.html @@ -0,0 +1,93 @@ +--- +title: CERN Case Study +linkTitle: cern +case_study_styles: true +cid: caseStudies +css: /css/style_case_studies.css +logo: cern_featured_logo.png +--- + +
+

CASE STUDY: CERN
CERN: Processing Petabytes of Data More Efficiently with Kubernetes + +

+ +
+ +
+ Company  CERN     Location  Geneva, Switzerland +     Industry  Particle physics research +
+ +
+
+
+
+

Challenge

+ At CERN, the European Organization for Nuclear Research, physicists conduct experiments to learn about fundamental science. In its particle accelerators, "we accelerate protons to very high energy, close to the speed of light, and we make the two beams of protons collide," says CERN Software Engineer Ricardo Rocha. "The end result is a lot of data that we have to process." CERN currently stores 330 petabytes of data in its data centers, and an upgrade of its accelerators expected in the next few years will drive that number up by 10x. Additionally, the organization experiences extreme peaks in its workloads during periods prior to big conferences, and needs its infrastructure to scale to those peaks. "We want to have a more hybrid infrastructure, where we have our on premise infrastructure but can make use of public clouds temporarily when these peaks come up," says Rocha. "We’ve been looking to new technologies that can help improve our efficiency in our infrastructure so that we can dedicate more of our resources to the actual processing of the data." +

+

Solution

+ CERN’s technology team embraced containerization and cloud native practices, choosing Kubernetes for orchestration, Helm for deployment, Prometheus for monitoring, and CoreDNS for DNS resolution inside the clusters. Kubernetes federation has allowed the organization to run some production workloads both on premise and in public clouds. +

+

Impact

+ "Kubernetes gives us the full automation of the application," says Rocha. "It comes with built-in monitoring and logging for all the applications and the workloads that deploy in Kubernetes. This is a massive simplification of our current deployments." The time to deploy a new cluster for a complex distributed storage system has gone from more than 3 hours to less than 15 minutes. Adding new nodes to a cluster used to take more than an hour; now it takes less than 2 minutes. The time it takes to autoscale replicas for system components has decreased from more than an hour to less than 2 minutes. Initially, virtualization gave 20% overhead, but with tuning this was reduced to ~5%. Moving to Kubernetes on bare metal would get this to 0%. Not having to host virtual machines is expected to also get 10% of memory capacity back. + +
+ +
+
+
+
+ "Kubernetes is something we can relate to very much because it’s naturally distributed. What it gives us is a uniform API across heterogeneous resources to define our workloads. This is something we struggled with a lot in the past when we want to expand our resources outside our infrastructure." +

- Ricardo Rocha, Software Engineer, CERN
+
+
+
+
+

With a mission of researching fundamental science, and a stable of extremely large machines, the European Organization for Nuclear Research (CERN) operates at what can only be described as hyperscale.

+ Experiments are conducted in particle accelerators, the biggest of which is 27 kilometers in circumference. "We accelerate protons to very high energy, to close to the speed of light, and we make the two beams of protons collide in well-defined places," says CERN Software Engineer Ricardo Rocha. "We build experiments around these places where we do the collisions. The end result is a lot of data that we have to process."

+ And he does mean a lot: CERN currently stores and processes 330 petabytes of data—gathered from 4,300 projects and 3,300 users—using 10,000 hypervisors and 320,000 cores in its data centers.

+ Over the years, the CERN technology department has built a large computing infrastructure, based on OpenStack private clouds, to help the organization’s physicists analyze and treat all this data. The organization experiences extreme peaks in its workloads. "Very often, just before conferences, physicists want to do an enormous amount of extra analysis to publish their papers, and we have to scale to these peaks, which means overcommitting resources in some cases," says Rocha. "We want to have a more hybrid infrastructure, where we have our on premise infrastructure but can make use of public clouds temporarily when these peaks come up."

+ Additionally, few years ago, CERN announced that it would be doing a big upgrade of its accelerators, which will mean a ten-fold increase in the amount of data that can be collected. "So we’ve been looking to new technologies that can help improve our efficiency in our infrastructure, so that we can dedicate more of our resources to the actual processing of the data," says Rocha. + +
+
+
+
+ "Before, the tendency was always: ‘I need this, I get a couple of developers, and I implement it.’ Right now it’s ‘I need this, I’m sure other people also need this, so I’ll go and ask around.’ The CNCF is a good source because there’s a very large catalog of applications available. It’s very hard right now to justify developing a new product in-house. There is really no real reason to keep doing that. It’s much easier for us to try it out, and if we see it’s a good solution, we try to reach out to the community and start working with that community."

- Ricardo Rocha, Software Engineer, CERN
+ +
+
+
+
+ Rocha’s team started looking at Kubernetes and containerization in the second half of 2015. "We’ve been using distributed infrastructures for decades now," says Rocha. "Kubernetes is something we can relate to very much because it’s naturally distributed. What it gives us is a uniform API across heterogeneous resources to define our workloads. This is something we struggled with a lot in the past when we want to expand our resources outside our infrastructure."

+ The team created a prototype system for users to deploy their own Kubernetes cluster in CERN’s infrastructure, and spent six months validating the use cases and making sure that Kubernetes integrated with CERN’s internal systems. The main use case is batch workloads, which represent more than 80% of resource usage at CERN. (One single project that does most of the physics data processing and analysis alone consumes 250,000 cores.) "This is something where the investment in simplification of the deployment, logging, and monitoring pays off very quickly," says Rocha. Other use cases include Spark-based data analysis and machine learning to improve physics analysis. "The fact that most of these technologies integrate very well with Kubernetes makes our lives easier," he adds.

+ The system went into production in October 2016, also using Helm for deployment, Prometheus for monitoring, and CoreDNS for DNS resolution within the cluster. "One thing that Kubernetes gives us is the full automation of the application," says Rocha. "So it comes with built-in monitoring and logging for all the applications and the workloads that deploy in Kubernetes. This is a massive simplification of our current deployments." The time to deploy a new cluster for a complex distributed storage system has gone from more than 3 hours to less than 15 minutes.

Adding new nodes to a cluster used to take more than an hour; now it takes less than 2 minutes. The time it takes to autoscale replicas for system components has decreased from more than an hour to less than 2 minutes. + +
+
+
+
+ "With Kubernetes, there’s a well-established technology and a big community that we can contribute to. It allows us to do our physics analysis without having to focus so much on the lower level software. This is just exciting. We are looking forward to keep contributing to the community and collaborating with everyone."

- Ricardo Rocha, Software Engineer, CERN
+
+
+ +
+
+ Rocha points out that the metric used in the particle accelerators may be events per second, but in reality "it’s how fast and how much of the data we can process that actually counts." And efficiency has certainly been improved with Kubernetes. Initially, virtualization gave 20% overhead, but with tuning this was reduced to ~5%. Moving to Kubernetes on bare metal would get this to 0%. Not having to host virtual machines is expected to also get 10% of memory capacity back.

+ Kubernetes federation, which CERN has been using for a portion of its production workloads since February 2018, has allowed the organization to adopt a hybrid cloud strategy. And it was remarkably simple to do. "We had a summer intern working on federation," says Rocha. "For many years, I’ve been developing distributed computing software, which took like a decade and a lot of effort from a lot of people to stabilize and make sure it works. And for our intern, in a couple of days he was able to demo to me and my team that we had a cluster at CERN and a few clusters outside in public clouds that were federated together and that we could submit workloads to. This was shocking for us. It really shows the power of using this kind of well-established technologies."

+ With such results, adoption of Kubernetes has made rapid gains at CERN, and the team is eager to give back to the community. "If we look back into the ’90s and early 2000s, there were not a lot of companies focusing on systems that have to scale to this kind of size, storing petabytes of data, analyzing petabytes of data," says Rocha. "The fact that Kubernetes is supported by such a wide community and different backgrounds, it motivates us to contribute back." + +
+ +
+
+This means that the physicist can build his or her analysis and publish it in a repository, share it with colleagues, and in 10 years redo the same analysis with new data. If we looked back even 10 years, this was just a dream."

- Ricardo Rocha, Software Engineer, CERN
+
+ +
+ These new technologies aren’t just enabling infrastructure improvements. CERN also uses the Kubernetes-based Reana/Recast platform for reusable analysis, which is "the ability to define physics analysis as a set of workflows that are fully containerized in one single entry point," says Rocha. "This means that the physicist can build his or her analysis and publish it in a repository, share it with colleagues, and in 10 years redo the same analysis with new data. If we looked back even 10 years, this was just a dream."

+ All of these things have changed the culture at CERN considerably. A decade ago, "The tendency was always: ‘I need this, I get a couple of developers, and I implement it,’" says Rocha. "Right now it’s ‘I need this, I’m sure other people also need this, so I’ll go and ask around.’ The CNCF is a good source because there’s a very large catalog of applications available. It’s very hard right now to justify developing a new product in-house. There is really no real reason to keep doing that. It’s much easier for us to try it out, and if we see it’s a good solution, we try to reach out to the community and start working with that community." + +
+
diff --git a/content/zh/case-studies/chinaunicom/chinaunicom_featured_logo.png b/content/zh/case-studies/chinaunicom/chinaunicom_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f90ff1e509c85399714cdc171e247dd166ce7f7b GIT binary patch literal 11459 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 bC=>_?ld3|vFTCY{uNBKlDM{9dn}q%!-XMLi literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/chinaunicom/index.html b/content/zh/case-studies/chinaunicom/index.html new file mode 100644 index 0000000000..675273c47f --- /dev/null +++ b/content/zh/case-studies/chinaunicom/index.html @@ -0,0 +1,99 @@ +--- +title: China Unicom Case Study + +linkTitle: chinaunicom +case_study_styles: true +cid: caseStudies +css: /css/style_case_studies.css +logo: chinaunicom_featured_logo.png +featured: true +weight: 1 +quote: > + Kubernetes has improved our experience using cloud infrastructure. There is currently no alternative technology that can replace it. +--- + +
+

CASE STUDY:
China Unicom: How China Unicom Leveraged Kubernetes to Boost Efficiency
and Lower IT Costs + +

+ +
+ +
+ Company  China Unicom     Location  Beijing, China     Industry  Telecom +
+ +
+
+
+
+

Challenge

+ China Unicom is one of the top three telecom operators in China, and to serve its 300 million users, the company runs several data centers with thousands of servers in each, using Docker containerization and VMWare and OpenStack infrastructure since 2016. Unfortunately, "the resource utilization rate was relatively low," says Chengyu Zhang, Group Leader of Platform Technology R&D, "and we didn’t have a cloud platform to accommodate our hundreds of applications." Formerly an entirely state-owned company, China Unicom has in recent years taken private investment from BAT (Baidu, Alibaba, Tencent) and JD.com, and is now focusing on internal development using open source technology, rather than commercial products. As such, Zhang’s China Unicom Lab team began looking for open source orchestration for its cloud infrastructure. +

+

Solution

+ Because of its rapid growth and mature open source community, Kubernetes was a natural choice for China Unicom. The company’s Kubernetes-enabled cloud platform now hosts 50 microservices and all new development going forward. "Kubernetes has improved our experience using cloud infrastructure," says Zhang. "There is currently no alternative technology that can replace it." China Unicom also uses Istio for its microservice framework, Envoy, CoreDNS, and Fluentd. +

+

Impact

+ At China Unicom, Kubernetes has improved both operational and development efficiency. Resource utilization has increased by 20-50%, lowering IT infrastructure costs, and deployment time has gone from a couple of hours to 5-10 minutes. "This is mainly because of the self-healing and scalability, so we can increase our efficiency in operation and maintenance," Zhang says. "For example, we currently have only five people maintaining our multiple systems. We could never imagine we can achieve this scalability in such a short time." + +
+ +
+
+
+
+ "Kubernetes has improved our experience using cloud infrastructure. There is currently no alternative technology that can replace it." +

- Chengyu Zhang, Group Leader of Platform Technology R&D, China Unicom
+
+
+
+
+

With more than 300 million users, China Unicom is one of the country’s top three telecom operators.

+ + Behind the scenes, the company runs multiple data centers with thousands of servers in each, using Docker containerization and VMWare and OpenStack infrastructure since 2016. Unfortunately, "the resource utilization rate was relatively low," says Chengyu Zhang, Group Leader of Platform Technology R&D, "and we didn’t have a cloud platform to accommodate our hundreds of applications."

+ Zhang’s team, which is responsible for new technology, R&D and platforms, set out to find an IT management solution. Formerly an entirely state-owned company, China Unicom has in recent years taken private investment from BAT (Baidu, Alibaba, Tencent) and JD.com, and is now focusing on homegrown development using open source technology, rather than commercial products. For that reason, the team began looking for open source orchestration for its cloud infrastructure. + +
+
+
+
+ "We could never imagine we can achieve this scalability in such a short time."

- Chengyu Zhang, Group Leader of Platform Technology R&D, China Unicom
+ +
+
+
+
+ Though China Unicom was already using Mesos for a core telecom operator system, the team felt that Kubernetes was a natural choice for the new cloud platform. "The main reason was that it has a mature community," says Zhang. "It grows very rapidly, and so we can learn a lot from others’ best practices." China Unicom also uses Istio for its microservice framework, Envoy, CoreDNS, and Fluentd.

+ The company’s Kubernetes-enabled cloud platform now hosts 50 microservices and all new development going forward. China Unicom developers can easily leverage the technology through APIs, without doing the development work themselves. The cloud platform provides 20-30 services connected to the company’s data center PaaS platform, as well as supports things such as big data analysis for internal users in the branch offices across the 31 provinces in China.

+ "Kubernetes has improved our experience using cloud infrastructure," says Zhang. "There is currently no alternative technology that can replace it." + +
+
+
+
+ "This technology is relatively complicated, but as long as developers get used to it, they can enjoy all the benefits."

- Jie Jia, Member of Platform Technology R&D, China Unicom
+
+
+ +
+
+ In fact, Kubernetes has boosted both operational and development efficiency at China Unicom. Resource utilization has increased by 20-50%, lowering IT infrastructure costs, and deployment time has gone from a couple of hours to 5-10 minutes. "This is mainly because of the self-healing and scalability of Kubernetes, so we can increase our efficiency in operation and maintenance," Zhang says. "For example, we currently have only five people maintaining our multiple systems."

+ With the wins China Unicom has experienced with Kubernetes, Zhang and his team are eager to give back to the community. That starts with participating in meetups and conferences, and offering advice to other companies that are considering a similar path. "Especially for those companies who have had traditional cloud computing system, I really recommend them to join the cloud native computing community," says Zhang. + +
+ +
+
+"Companies can use the managed services offered by companies like Rancher, because they have already customized this technology, you can easily leverage this technology."

- Jie Jia, Member of Platform Technology R&D, China Unicom
+
+ +
+ Platform Technology R&D team member Jie Jia adds that though "this technology is relatively complicated, as long as developers get used to it, they can enjoy all the benefits." And Zhang points out that in his own experience with virtual machine cloud, "Kubernetes and these cloud native technologies are relatively simpler."

+ Plus, "companies can use the managed services offered by companies like Rancher, because they have already customized this technology," says Jia. "You can easily leverage this technology."

+ Looking ahead, China Unicom plans to develop more applications on Kubernetes, focusing on big data and machine learning. The team is continuing to optimize the cloud platform that it built, and hopes to pass the conformance test to join CNCF’s Certified Kubernetes Conformance Program. They’re also hoping to someday contribute code back to the community.

+ If that sounds ambitious, it’s because the results they’ve gotten from adopting Kubernetes have been beyond even their greatest expectations. Says Zhang: "We could never imagine we can achieve this scalability in such a short time." + +
+
+ + diff --git a/content/zh/case-studies/city-of-montreal/city-of-montreal_featured_logo.png b/content/zh/case-studies/city-of-montreal/city-of-montreal_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..be2af029f0bdc7045c598d84b99c07272ca5c3f1 GIT binary patch literal 9647 zcmch7WmFv7vM|A20|X5W?(WXu9zxK-V1vU9F2Nbks#Sh%>GIDz4$%ps;=Dn)w}ORy%`#N5+y5G)D@hrnp9rR$=rsv>L#v1d2=3y0mq z9txv|gAV#HmC*gkcQq!7e6L9`<$)&cYsIfWP?)!=C?|<^WLrjpAY}2KaBGbX7H|fDk7z z6(2i4n;91`AC-U*I~P9>uaFQc6*niBAP1))2Nw?;7r!tsr!Y4+)jt;iwwjZ+t)4|2WgU!L2=3g9S zz|Lk))=(E~hy&GM98F9it}bE#n56%`1$(Hf>c1H~IRB$4n94XjOrRWG?3^6-_J8f` zZ)|55P4NGS@gK3BwLGC<4o$E##MQ|RW)BORe-XoU_rEXn7a~j=VHt>-t3BAkMNvi! z0GnYqw>B3R;NunKmgAOzK_C~GtdNv6FRv^R$R{N$D9Z`t52prRrI z{5}3J!DDV6^iLSxxlYv-g%}Yzw`B^7_d=^<{`}*etgP%1Fnf6^Sep7Oopvz$chi83 z{Cul;iyQK2ju4A+A9^zZ<hK0*bY+rw7dvEzg}E6r8E4DI24=RKI3fbOPNF6>0G+J_r-x z;}d^cKUo&xGx?%H6%`TTb+^&?f`y^?aoJbvs^k**1O?W3oV8qDi5wY(|hMqSz$jx?k?5z#Q){s_y9ivbo-qvGmm~d+{6% zEh9Fn{_HfMEhs3wWN@-4ln>{Q1GLfvlE4l{$Q>OWttc;tJ{pLYCnio;ulL*>tyFk2 zQd57?tFxe3{usjdV2I>_YinyuLqpTs?T5HvcOCXFztL{7{MyIbdOu%2*6ZrTkYH!f zyf!O~oUv3%hlGp_hmw11Tt1eU<4?w^(DA@qv~PDfz)le&`g&$JU=k1qCuU3F_n$;?yEJa*y24iS> zJf_u%HM@xU9tnB}>E0esoV1+!hs3^>(0<}(+9#^6R-C4vk#Mf9|l&`%XF%ORMGhFMxkd(Fq%s#R=Q(-2h`L#7ap6gR{kK!S?pHX8CT<_YH@wM69}7 zEw|q0GP=EUEw%^jLz}@tijgjAK(h`9pB8Pom!pm8np2l;; zTkLmZ79t%#;T(bX_DS4M$W7OqfaRDuRtjN3>|6@q) zy2P`*c*h=%>AHYyW}|(8@Xg7Jv#WE6-^p?vG5oAeXq?9DT+l_`uD1p~a}nb_C4Xk^ zX*vl>D!Y;9_N&A}a&DI}y$bzYK9)#6`}_KB<15@8Y6USD2N^I3e3klo%gydOX4G2NGihA78l+j+NlRJU%@oMd)tJihHjZD(`1k&u;z zsWR)e*ec{q)7>+kjpOd*wgVN!Rk}HzRb~rAj?X`r*yiNn35hGN&Rbg@?tV#}#av6s zoUf#yAS5Iv`<*8hbdN=<)xucqVE?;ux!v9Xs|-=D^;0aR0KNmcxW~lgWX;^Jsh)$% zW%qct!PPJa?*8Haen4QLTgsWT6-g1+s_Pz{@9yR}0Wd7Y4?z<7$j<)eXc0@zpowz1 zgtO2Kj{m!QF7hj-rI7C#BiHaLte{5QftX{1rUr-Ka-hr{DM3v3ypoa4Z?&q0EWcH-OH(xe0?mE|H-NjxOK+EW_2 zk7422!k!mDC-dcFNYUoeL%J!&KG}d1m%Il5+Y*;=6J=oDAW zu#)hapLG;Iq_OO!Qa`mApRO5OSj_o#`m1HnW=qH9Qf!U-KQU3Lb}@5x$cC#IEAR8?2y8Cly2} zM6=W#xY^(@R4oxi8VVf?5j>weHkU)@j7?J5T5&-jYaGDb$qR@o9bcv)0u;lM`}==L z;IZr?=p^IsB@-|;7EI4zMrbs7Q>LTdc6Inh<>SSJup<bW*!xC&M7x5P zLCtiBXz9Z%k5o0Vwk{)WWj{u%PcMV|Mhx~yd`~NmEY9vu z3ijJRMy7x?Y#POkTO9%);&vB~o0U=SD8e0{epWka$eR#M7)J#a}jlQ*6}cdCT}2%wWS zo$Gb1r(C%KDw0qO5o;G3*xq1FORS9^Hj|DVsxsExIO^r!(|q~D{d-XQoM|d zu@UV)T@fc^CMXrU9?m`lKHw@Ocqb=FgO9-6dI)4>F&17S;_Lx}#GB_-?BB9WxcKPM zNPx^HR+%Wwi9iDb!GNDnXGppWMV1^5kOF+```;tX_IS)}Y{v^HBD3KEQwa$YIpQVn zi^lv?LJoajp4OfbCZZlqpD*A#eq8SObaf-aOUUM@oxrb6ekdlxrxBICN5CxdFG!NcbDbeE7;Ym@PihG}pf4qOErR%Xb(FM|} z8XOsefBO`fio>?QG-U)xmNpX>7Rna&Ify((Lv(7gTa3!EKqUGsFUJd+46Njz$}`;X zK~eBU>o?`WyiyF1Tp954lB5dy36;y2(|-!bPraUqM6NQjO6`dnnLUEGcjK*c>6?0+|W z@_2cc_(hE9D-#_0QtNdUdhtt=^>7jkJQA@v1zs1Pq7PWtU zPc=8<<~TZlJqbN*KwTyv02dzPn~IsbD?=oDx>%{r_@)F-B_OC+D;Hs%!19%eF6ptID6NqhEPw0o& zv%&IVkB?GYdDC3RipyS0aXnEN#&7~WJ=xi5J`YJTBn*q>VNDLvEOR|NZ0~z^Q&qD0 zKl}*g{;&wE1taYAo0dWO^=QWW_ctbj2cP6KX3QBU?SotOG-{s5^9fp z!+dV_YZIa4=CltJtM5=iivh&=8olCh&VKnDR>Su_X%$v*HcNlOT}lSJaKOz$Np|7e$eDheAoZ5mOjagpEq71gYpFU%GH17L zGClx0I?NE{J^p^fPmjeqSW>pg#|!WF6Yn`dueK0mk5)TCe676SaUJw~2)}`^rRmGG zTA3_?o)1;8``(WuC71L&zr)XK9IEz;qg(DTzA_fgxqiiCL#sD}k}@`q${z z)($wRIBt`5orQ3tnxo@+o#pr#EOZ?jQ&Lym+}qdF)8n&Sm}p2ekk`>^j@#2*l4Z^z z4418}tVG^ku|(^jr56@Hm+Ssr&U%J&M7pT@ay~%BW>Cs~^g&5U%`L_|-sfB%?3Oyb zX&4d7!_BYl;JCSe+4;Kj3<2J-!!0_ThmbwAAUZOVn^0d%%VlR~pCy(3so9}oboaf1 z>_sZCXuJ3R#^u(o(63)|a&rCj{i+%Khl>@5?#I6~C)69!k-Fzes?5HAOO8AX! zp0BZwW(q*2>aA~JA&e?BNS0Mq1@r4TM(P6|qz=l!&}MJIyn|vnt2E_T$jTJ{>nqoQ zP}PDIj&&R0Lo2BJki?L?WPp5sGkrD>)N@jb=yNm0Lx*fxf;Hv`72awIwy zC8#>`;AY^PiJC(Pdm#+V?M~b1f>-nw7AqKS1L|4DdW*r1o5i$j9+f&(AZMsc@VH|Q zvG)A~LJu@A%Cuh8`)q9~y{>L|?8>NK!}Ivr=OHMT{EPm;LT_*aqepY@x0m7rnm`a4 zA(@$-9cGZt5Kdw-P-C2+NLs`-r6U=mcz?6)tS1x)8hFrRE%})P)ZRK{$t9YqLFLZ{ zXO=)4_PYrJitQkB`coVd(suxw*D#Qsjmyaqx13|8ssvoIIJ&sh!%>^WO~%Ko5ZMki z+N-Il4XB4`H(whlZ~SVY(fb&+e`p54Q%sGsnTsOxmN~%=G_o0rCQVg|y5ffzqat1) zx*~aMTdgkPtoiGNhG->dwqJYvG>!<#LpQM;ciUf-W$Ed($r5*s7$VlJswIBOz@+(8e?f8{V03<~~V2N|yaFJRrb|2HKx3P(XR0*~Q z=}DnE_0=s$jzli631A7HHa!ln)E`Lf(ax}_C7ZAXc$nIWo$m6m%f#(%A zG`y;&gpZ1-k78;e*S{$r`v(gX8HdEK6pzK)R7YcCJt$Oi+`rw;%`FdW2za)g^~3q? z%iS*QR5t$EJ(lI_0(HsdPmUQS=ifcf6mYiiSgOktdh=*sXGX+JEL4C5q{{}y4-ye zDSP3u)f1XF)B<4E$rw;atg`?z_84p!7!ontpe=HKI>~}18d9-4TU!O~UPzVUJ3qu% zR=gsJ$i>|33U}UgAA__j;cKPE`T J)yjiHk;9m#<7Y#5h;Zf4n1z)4a5opvd-`X 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/city-of-montreal/index.html b/content/zh/case-studies/city-of-montreal/index.html new file mode 100644 index 0000000000..151ce44b21 --- /dev/null +++ b/content/zh/case-studies/city-of-montreal/index.html @@ -0,0 +1,99 @@ +--- +title: City of Montreal Case Study +linkTitle: city-of-montreal +case_study_styles: true +cid: caseStudies +css: /css/style_case_studies.css +featured: false +--- + +
+

CASE STUDY:
City of Montréal - How the City of Montréal Is Modernizing Its 30-Year-Old, Siloed Architecture with Kubernetes + +

+ +
+ +
+ Company  City of Montréal     Location  Montréal, Québec, Canada     Industry  Government +
+ +
+
+
+
+

Challenge

+ Like many governments, Montréal has a number of legacy systems, and “we have systems that are older than some developers working here,” says the city’s CTO, Jean-Martin Thibault. “We have mainframes, all flavors of Windows, various flavors of Linux, old and new Oracle systems, Sun servers, all kinds of databases. Like all big corporations, some of the most important systems, like Budget and Human Resources, were developed on mainframes in-house over the past 30 years.” There are over 1,000 applications in all, and most of them were running on different ecosystems. In 2015, a new management team decided to break down those silos, and invest in IT in order to move toward a more integrated governance for the city. They needed to figure out how to modernize the architecture. + +

Solution

+ The first step was containerization. The team started with a small Docker farm with four or five servers, with Rancher for providing access to the Docker containers and their logs and Jenkins to deploy. “We based our effort on the new trends; we understood the benefits of immutability and deployments without downtime and such things,” says Solutions Architect Marc Khouzam. They soon realized they needed orchestration as well, and opted for Kubernetes. Says Enterprise Architect Morgan Martinet: “Kubernetes offered concepts on how you would describe an architecture for any kind of application, and based on those concepts, deploy what’s required to run the infrastructure. It was becoming a de facto standard.” +
+

Impact

+ The time to market has improved drastically, from many months to a few weeks. Deployments went from months to hours. “In the past, you would have to ask for virtual machines, and that alone could take weeks, easily,” says Thibault. “Now you don’t even have to ask for anything. You just create your project and it gets deployed.” Kubernetes has also improved the efficiency of how the city uses its compute resources: “Before, the 200 application components we currently run on Kubernetes would have required hundreds of virtual machines, and now, if we’re talking about a single environment of production, we are able to run them on 8 machines, counting the masters of Kubernetes,” says Martinet. And it’s all done with a small team of just 5 people operating the Kubernetes clusters. +
+ +
+
+
+
+ "We realized the limitations of having a non-orchestrated Docker environment. Kubernetes came to the rescue, bringing in all these features that make it a lot easier to manage and give a lot more benefits to the users." +

- JEAN-MARTIN THIBAULT, CTO, CITY OF MONTRÉAL
+
+
+
+
+

The second biggest municipality in Canada, Montréal has a large number of legacy systems keeping the government running. And while they don’t quite date back to the city’s founding in 1642, “we have systems that are older than some developers working here,” jokes the city’s CTO, Jean-Martin Thibault.

+ “We have mainframes, all flavors of Windows, various flavors of Linux, old and new Oracle systems, Sun servers, all kinds of databases. Some of the most important systems, like Budget and Human Resources, were developed on mainframes in-house over the past 30 years.” +

+ In recent years, that fact became a big pain point. There are over 1,000 applications in all, running on almost as many different ecosystems. In 2015, a new city management team decided to break down those silos, and invest in IT in order to move toward a more integrated governance. “The organization was siloed, so as a result the architecture was siloed,” says Thibault. “Once we got integrated into one IT team, we decided to redo an overall enterprise architecture.” +

+ The first step to modernize the architecture was containerization. “We based our effort on the new trends; we understood the benefits of immutability and deployments without downtime and such things,” says Solutions Architect Marc Khouzam. The team started with a small Docker farm with four or five servers, with Rancher for providing access to the Docker containers and their logs and Jenkins for deployment. +
+
+
+
+ "Getting a project running in Kubernetes is entirely dependent on how long you need to program the actual software. It’s no longer dependent on deployment. Deployment is so fast that it’s negligible."

- MARC KHOUZAM, SOLUTIONS ARCHITECT, CITY OF MONTRÉAL
+ +
+
+
+
+ But this Docker farm setup had some limitations, including the lack of self-healing and dynamic scaling based on traffic, and the effort required to optimize server resources and scale to multiple instances of the same container. The team soon realized they needed orchestration as well. “Kubernetes came to the rescue,” says Thibault, “bringing in all these features that make it a lot easier to manage and give a lot more benefits to the users.” +

+ The team had evaluated several orchestration solutions, but Kubernetes stood out because it addressed all of the pain points. (They were also inspired by Yahoo! Japan’s use case, which the team members felt came close to their vision.) “Kubernetes offered concepts on how you would describe an architecture for any kind of application, and based on those concepts, deploy what’s required to run the infrastructure,” says Enterprise Architect Morgan Martinet. “It was becoming a de facto standard. It also promised portability across cloud providers. The choice of Kubernetes now gives us many options such as running clusters in-house or in any IaaS provider, or even using Kubernetes-as-a-service in any of the major cloud providers.” +

+ Another important factor in the decision was vendor neutrality. “As a government entity, it is essential for us to be neutral in our selection of products and providers,” says Thibault. “The independence of the Cloud Native Computing Foundation from any company provides this.” +
+
+
+
+ "Kubernetes has been great. It’s been stable, and it provides us with elasticity, resilience, and robustness. While re-architecting for Kubernetes, we also benefited from the monitoring and logging aspects, with centralized logging, Prometheus logging, and Grafana dashboards. We have enhanced visibility of what’s being deployed."

- MORGAN MARTINET, ENTERPRISE ARCHITECT, CITY OF MONTRÉAL
+
+
+ +
+
+ The Kubernetes implementation began with the deployment of a small cluster using an internal Ansible playbook, which was soon replaced by the Kismatic distribution. Given the complexity they saw in operating a Kubernetes platform, they decided to provide development groups with an automated CI/CD solution based on Helm. “An integrated CI/CD solution on Kubernetes standardized how the various development teams designed and deployed their solutions, but allowed them to remain independent,” says Khouzam. +

+ During the re-architecting process, the team also added Prometheus for monitoring and alerting, Fluentd for logging, and Grafana for visualization. “We have enhanced visibility of what’s being deployed,” says Martinet. Adds Khouzam: “The big benefit is we can track anything, even things that don’t run inside the Kubernetes cluster. It’s our way to unify our monitoring effort.” +

+ All together, the cloud native solution has had a positive impact on velocity as well as administrative overhead. With standardization, code generation, automatic deployments into Kubernetes, and standardized monitoring through Prometheus, the time to market has improved drastically, from many months to a few weeks. Deployments went from months and weeks of planning down to hours. “In the past, you would have to ask for virtual machines, and that alone could take weeks to properly provision,” says Thibault. Plus, for dedicated systems, experts often had to be brought in to install them with their own recipes, which could take weeks and months. +

+ Now, says Khouzam, “we can deploy pretty much any application that’s been Dockerized without any help from anybody. Getting a project running in Kubernetes is entirely dependent on how long you need to program the actual software. It’s no longer dependent on deployment. Deployment is so fast that it’s negligible.” + +
+ +
+
+"We’re working with the market when possible, to put pressure on our vendors to support Kubernetes, because it’s a much easier solution to manage"

- MORGAN MARTINET, ENTERPRISE ARCHITECT, CITY OF MONTRÉAL
+
+ +
+ Kubernetes has also improved the efficiency of how the city uses its compute resources: “Before, the 200 application components we currently run in Kubernetes would have required hundreds of virtual machines, and now, if we’re talking about a single environment of production, we are able to run them on 8 machines, counting the masters of Kubernetes,” says Martinet. And it’s all done with a small team of just five people operating the Kubernetes clusters. Adds Martinet: “It’s a dramatic improvement no matter what you measure.” +

+ So it should come as no surprise that the team’s strategy going forward is to target Kubernetes as much as they can. “If something can’t run inside Kubernetes, we’ll wait for it,” says Thibault. That means they haven’t moved any of the city’s Windows systems onto Kubernetes, though it’s something they would like to do. “We’re working with the market when possible, to put pressure on our vendors to support Kubernetes, because it’s a much easier solution to manage,” says Martinet. +

+ Thibault sees a near future where 60% of the city’s workloads are running on a Kubernetes platform—basically any and all of the use cases that they can get to work there. “It’s so much more efficient than the way we used to do things,” he says. “There’s no looking back.” + +
+
diff --git a/content/zh/case-studies/crowdfire/crowdfire_featured_logo.png b/content/zh/case-studies/crowdfire/crowdfire_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ef84b16ea06c7de72fa288068f309fa91eaa36a5 GIT binary patch literal 7827 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 M91QwN=6Udc0K2Me2><{9 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/crowdfire/index.html b/content/zh/case-studies/crowdfire/index.html new file mode 100644 index 0000000000..227a5c0839 --- /dev/null +++ b/content/zh/case-studies/crowdfire/index.html @@ -0,0 +1,101 @@ +--- +title: Crowdfire Case Study + +case_study_styles: true +cid: caseStudies +css: /css/style_crowdfire.css +--- + +
+

CASE STUDY:
How to Keep Iterating a Fast-Growing App With a Cloud-Native Approach

+ +
+ +
+ Company  Crowdfire     Location  Mumbai, India     Industry  Social Media Software +
+ +
+
+
+
+

Challenge

+ Crowdfire helps content creators create their content anywhere on the Internet and publish it everywhere else in the right format. Since its launch in 2010, it has grown to 16 million users. The product began as a monolith app running on Google App Engine, and in 2015, the company began a transformation to microservices running on Amazon Web Services Elastic Beanstalk. "It was okay for our use cases initially, but as the number of services, development teams and scale increased, the deploy times, self-healing capabilities and resource utilization started to become problems for us," says Software Engineer Amanpreet Singh, who leads the infrastructure team for Crowdfire.
+

Solution

+ "We realized that we needed a more cloud-native approach to deal with these issues," says Singh. The team decided to implement a custom setup of Kubernetes based on Terraform and Ansible. +
+
+ +
+ +

Impact

+ "Kubernetes has helped us reduce the deployment time from 15 minutes to less than a minute," says Singh. "Due to Kubernetes’s self-healing nature, the operations team doesn’t need to do any manual intervention in case of a node or pod failure." Plus, he says, "Dev-Prod parity has improved since developers can experiment with options in dev/staging clusters, and when it’s finalized, they just commit the config changes in the respective code repositories. These changes automatically get replicated on the production cluster via CI/CD pipelines." +
+ +
+
+
+
+ "In the 15 months that we’ve been using Kubernetes, it has been amazing for us. It enabled us to iterate quickly, increase development speed, and continuously deliver new features and bug fixes to our users, while keeping our operational costs and infrastructure management overhead under control."

- Amanpreet Singh, Software Engineer at Crowdfire
+
+
+
+
+

"If you build it, they will come."

+ For most content creators, only half of that movie quote may ring true. Sure, platforms like Wordpress, YouTube and Shopify have made it simple for almost anyone to start publishing new content online, but attracting an audience isn’t as easy. Crowdfire "helps users publish their content to all possible places where their audience exists," says Amanpreet Singh, a Software Engineer at the company based in Mumbai, India. Crowdfire has gained more than 16 million users—from bloggers and artists to makers and small businesses—since its launch in 2010.

+ With that kind of growth—and a high demand from users for new features and continuous improvements—the Crowdfire team struggled to keep up behind the scenes. In 2015, they moved their monolith Java application to Amazon Web Services Elastic Beanstalk and started breaking it down into microservices.

+ It was a good first step, but the team soon realized they needed to go further down the cloud-native path, which would lead them to Kubernetes. "It was okay for our use cases initially, but as the number of services and development teams increased and we scaled further, deploy times, self-healing capabilities and resource utilization started to become problematic," says Singh, who leads the infrastructure team at Crowdfire. "We realized that we needed a more cloud-native approach to deal with these issues."

+ As he looked around for solutions, Singh had a checklist of what Crowdfire needed. "We wanted to keep some things separate so they could be shipped independent of other things; this would help remove blockers and let different teams work at their own pace," he says. "We also make a lot of data-driven decisions, so shipping a feature and its iterations quickly was a must."

+ Kubernetes checked all the boxes and then some. "One of the best things was the built-in service discovery," he says. "When you have a bunch of microservices that need to call each other, having internal DNS readily available and service IPs and ports automatically set as environment variables help a lot." Plus, he adds, "Kubernetes’s opinionated approach made it easier to get started." + +
+
+
+
+ "We realized that we needed a more cloud-native approach to deal with these issues," says Singh. The team decided to implement a custom setup of Kubernetes based on Terraform and Ansible." +
+
+
+
+ There was another compelling business reason for the cloud-native approach. "In today’s world of ever-changing business requirements, using cloud native technology provides a variety of options to choose from—even the ability to run services in a hybrid cloud environment," says Singh. "Businesses can keep services in a region closest to the users, and thus benefit from high-availability and resiliency."

+ So in February 2016, Singh set up a test Kubernetes cluster using the kube-up scripts provided. "I explored the features and was able to deploy an application pretty easily," he says. "However, it seemed like a black box since I didn’t understand the components completely, and had no idea what the kube-up script did under the hood. So when it broke, it was hard to find the issue and fix it."

+ To get a better understanding, Singh dove into the internals of Kubernetes, reading the docs and even some of the code. And he looked to the Kubernetes community for more insight. "I used to stay up a little late every night (a lot of users were active only when it’s night here in India) and would try to answer questions on the Kubernetes community Slack from users who were getting started," he says. "I would also follow other conversations closely. I must admit I was able to avoid a lot of issues in our setup because I knew others had faced the same issues."

+ Based on the knowledge he gained, Singh decided to implement a custom setup of Kubernetes based on Terraform and Ansible. "I wrote Terraform to launch Kubernetes master and nodes (Auto Scaling Groups) and an Ansible playbook to install the required components," he says. (The company recently switched to using prebaked AMIs to make the node bringup faster, and is planning to change its networking layer.)

+ +
+
+
+
+ "Kubernetes helped us reduce the deployment time from 15 minutes to less than a minute. Due to Kubernetes’s self-healing nature, the operations team doesn’t need to do any manual intervention in case of a node or pod failure." +
+
+ +
+
+ First, the team migrated a few staging services from Elastic Beanstalk to the new Kubernetes staging cluster, and then set up a production cluster a month later to deploy some services. The results were convincing. "By the end of March 2016, we established that all the new services must be deployed on Kubernetes," says Singh. "Kubernetes helped us reduce the deployment time from 15 minutes to less than a minute. Due to Kubernetes’s self-healing nature, the operations team doesn’t need to do any manual intervention in case of a node or pod failure." On top of that, he says, "Dev-Prod parity has improved since developers can experiment with options in dev/staging clusters, and when it’s finalized, they just commit the config changes in the respective code repositories. These changes automatically get replicated on the production cluster via CI/CD pipelines. This brings more visibility into the changes being made, and keeping an audit trail."

+ Over the next six months, the team worked on migrating all the services from Elastic Beanstalk to Kubernetes, except for the few that were deprecated and would soon be terminated anyway. The services were moved one at a time, and their performance was monitored for two to three days each. Today, "We’re completely migrated and we run all new services on Kubernetes," says Singh.

+ The impact has been considerable: With Kubernetes, the company has experienced a 90% cost savings on Elastic Load Balancer, which is now only used for their public, user-facing services. Their EC2 operating expenses have been decreased by as much as 50%.

+ All 30 engineers at Crowdfire were onboarded at once. "I gave an internal talk where I shared the basic components and demoed the usage of kubectl," says Singh. "Everyone was excited and happy about using Kubernetes. Developers have more control and visibility into their applications running in production now. Most of all, they’re happy with the low deploy times and self-healing services."

+ And they’re much more productive, too. "Where we used to do about 5 deployments per day," says Singh, "now we’re doing 30+ production and 50+ staging deployments almost every day." + + +
+
+
+
+ The impact has been considerable: With Kubernetes, the company has experienced a 90% cost savings on Elastic Load Balancer, which is now only used for their public, user-facing services. Their EC2 operating expenses have been decreased by as much as 50%. + +
+
+
+
+ + Singh notes that almost all of the engineers interact with the staging cluster on a daily basis, and that has created a cultural change at Crowdfire. "Developers are more aware of the cloud infrastructure now," he says. "They’ve started following cloud best practices like better health checks, structured logs to stdout [standard output], and config via files or environment variables."

+ With Crowdfire’s commitment to Kubernetes, Singh is looking to expand the company’s cloud-native stack. The team already uses Prometheus for monitoring, and he says he is evaluating Linkerd and Envoy Proxy as a way to "get more metrics about request latencies and failures, and handle them better." Other CNCF projects, including OpenTracing and gRPC are also on his radar.

+ Singh has found that the cloud-native community is growing in India, too, particularly in Bangalore. "A lot of startups and new companies are starting to run their infrastructure on Kubernetes," he says.

+ And when people ask him about Crowdfire’s experience, he has this advice to offer: "Kubernetes is a great piece of technology, but it might not be right for you, especially if you have just one or two services or your app isn’t easy to run in a containerized environment," he says. "Assess your situation and the value that Kubernetes provides before going all in. If you do decide to use Kubernetes, make sure you understand the components that run under the hood and what role they play in smoothly running the cluster. Another thing to consider is if your apps are ‘Kubernetes-ready,’ meaning if they have proper health checks and handle termination signals to shut down gracefully."

+ And if your company fits that profile, go for it. Crowdfire clearly did—and is now reaping the benefits. "In the 15 months that we’ve been using Kubernetes, it has been amazing for us," says Singh. "It enabled us to iterate quickly, increase development speed and continuously deliver new features and bug fixes to our users, while keeping our operational costs and infrastructure management overhead under control." + + +
+
diff --git a/content/zh/case-studies/goldman-sachs/gs_logo.png b/content/zh/case-studies/goldman-sachs/gs_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc8c14566ae5bc2fdfd9323c09feab1b8b25da8 GIT binary patch literal 23083 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 RV}Gszs48lq%H_>N{vQp8*bV>y literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/goldman-sachs/index.html b/content/zh/case-studies/goldman-sachs/index.html new file mode 100644 index 0000000000..93d3022d12 --- /dev/null +++ b/content/zh/case-studies/goldman-sachs/index.html @@ -0,0 +1,4 @@ +--- +title: Goldman Sachs +content_url: http://blogs.wsj.com/cio/2016/02/24/big-changes-in-goldmans-software-emerge-from-small-containers/ +--- \ No newline at end of file diff --git a/content/zh/case-studies/golfnow/golfnow_featured.png b/content/zh/case-studies/golfnow/golfnow_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..0b99ac3b8f8f81dd990436b54c08f335dbf40996 GIT binary patch literal 22915 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/golfnow/golfnow_logo.png b/content/zh/case-studies/golfnow/golfnow_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..dbeb127b02a270963c61bb29f21dd9f2d9b576c9 GIT binary patch literal 8858 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

Co!VWdh$tGc8PQuMiXrEdE;5v=4p?3 zeU_fOtxdmk=upu%6TT9Mnx+&;ZB+PX<5X&0E?m2^tpENr7kGv~VQ$SJbvE5mxd>K7 z{5JJNnx03|+%vC?qMh$qZznnI&YCe`HEJUTbOz2EY%d%g7*hy|=AO0ppO+(l< z&?AQxhKh`>+BthU6W~>RgX78ZcppS`lY&ves*}$V6Eg#Lu$_RM42~(7qF4^G+0YJa zr8MPN&pKbIoaxms(NkT{&j~Y=tr3Lvtj9?{I)JS|oHHytx$x4V%E7?xV50*vkk+4FYfdndT;L+j{7)Xm()yqi4l%n;ak1$xVx zy+5txfLbhdD-29vkj4DU`P(dPGG?@&E?6zDUJ8U^RLA2Ic>YA$8Mm1NMW**C9%&k- zteHOG3;ud@=^4HtEo&d_8YP@_PQ*MK=SYU)$b*7ckYhkjw5H>h^%~A=;weWbhG5QYklHdGHQho~8CT}kcTb0dJg(nq8rC{fUm>(QY{&4QXc2bbC? zKNOoEi=)5M(rE1m=56IoC1XVKp2tDiUh!U4<3bxujT-JuD4TvU*lPK(c#y9=lz^_O zLQq-m+0%IS@v3XD0b6ic^5Ak3bE8JCykAY5xX>n5eW2Y<2|Xgt(W~ixc;!lP#&gcw zTw4uEQi&`y?%*CVr8DSD5lPY<`pi=z)Jkn6Ja3HtG562gBdohSqE9DjNJfe7o`&W# zFHKH(vI&-2<|(&ZGkmcO#~-w2oT9H+jaQ>3@<bA|N50A{82n^kg>w{aZv)R_%R-v>D|8 E0r1&*@&Et; literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/golfnow/index.html b/content/zh/case-studies/golfnow/index.html new file mode 100644 index 0000000000..f4bf4d4f27 --- /dev/null +++ b/content/zh/case-studies/golfnow/index.html @@ -0,0 +1,125 @@ +--- +title: GolfNow Case Study + +case_study_styles: true +cid: caseStudies +css: /css/style_golfnow.css +--- + +

+

CASE STUDY:
+
Saving Time and Money with Cloud Native Infrastructure
+

+
+ +
+ Company GolfNow     Location Orlando, Florida     Industry Golf Industry Technology and Services Provider +
+ +
+ +
+
+
+ +

Challenge

+ A member of the NBC Sports Group, GolfNow is the golf industry’s technology and services leader, managing 10 different products, as well as the largest e-commerce tee time marketplace in the world. As its business began expanding rapidly and globally, GolfNow’s monolithic application became problematic. "We kept growing our infrastructure vertically rather than horizontally, and the cost of doing business became problematic," says Sheriff Mohamed, GolfNow’s Director, Architecture. "We wanted the ability to more easily expand globally." +
+
+ +
+

Solution

+ Turning to microservices and containerization, GolfNow began moving its applications and databases from third-party services to its own clusters running on Docker and Kubernetes.

+ +

Impact

+ The results were immediate. While maintaining the same capacity—and beyond, during peak periods—GolfNow saw its infrastructure costs for the first application virtually cut in half. +
+
+
+ + +
+
+ "With our growth we obviously needed to expand our infrastructure, and we kept growing vertically rather than horizontally. We were basically wasting money and doubling the cost of our infrastructure."

- SHERIFF MOHAMED, DIRECTOR, ARCHITECTURE AT GOLFNOW +
+
+ +
+
+

It’s not every day that you can say you’ve slashed an operating expense by half.

+ + But Sheriff Mohamed and Josh Chandler did just that when they helped lead their company, GolfNow, on a journey from a monolithic to a containerized, cloud native infrastructure managed by Kubernetes. +

+ A top-performing business within the NBC Sports Group, GolfNow is a technology and services company with the largest tee time marketplace in the world. GolfNow serves 5 million active golfers across 10 different products. In recent years, the business had grown so fast that the infrastructure supporting their giant monolithic application (written in C#.NET and backed by SQL Server database management system) could not keep up. "With our growth we obviously needed to expand our infrastructure, and we kept growing vertically rather than horizontally," says Sheriff, GolfNow’s Director, Architecture. "Our costs were growing exponentially. And on top of that, we had to build a Disaster Recovery (DR) environment, which then meant we’d have to copy exactly what we had in our original data center to another data center that was just the standby. We were basically wasting money and doubling the cost of our infrastructure." +

+ In moving just the first of GolfNow’s important applications—a booking engine for golf courses and B2B marketing platform—from third-party services to their own Kubernetes environment, "our bill went down drastically," says Sheriff. +

+ The path to those stellar results began in late 2014. In order to support GolfNow’s global growth, the team decided that the company needed to have multiple data centers and the ability to quickly and easily re-route traffic as needed. "From there we knew that we needed to go in a direction of breaking things apart, microservices, and containerization," says Sheriff. "At the time we were trying to get away from C#.NET and SQL Server since it didn’t run very well on Linux, where everything container was running smoothly." +

+ To that end, the team shifted to working with Node.js, the open-source, cross-platform JavaScript runtime environment for developing tools and applications, and MongoDB, the open-source database program. At the time, Docker, the platform for deploying applications in containers, was still new. But once the team began experimenting with it, Sheriff says, "we realized that was the way we wanted to go, especially since that’s the way the industry is heading." +
+
+ +
+
+ "The team migrated the rest of the application into their Kubernetes cluster. And the impact was immediate: On top of cutting monthly costs by a large percentage, says Sheriff, 'Running at the same capacity and during our peak time, we were able to horizontally grow. Since we were using our VMs more efficiently with containers, we didn’t have to pay extra money at all.'" +
+
+ +
+
+ GolfNow’s dev team ran an "internal, low-key" proof of concept and were won over. "We really liked how easy it was to be able to pass containers around to each other and have them up and running in no time, exactly the way it was running on my machine," says Sheriff. "Because that is always the biggest gripe that Ops has with developers, right? ‘It worked on my machine!’ But then we started getting to the point of, ‘How do we make sure that these things stay up and running?’"

+ That led the team on a quest to find the right orchestration system for the company’s needs. Sheriff says the first few options they tried were either too heavy or "didn’t feel quite right." In late summer 2015, they discovered the just-released Kubernetes, which Sheriff immediately liked for its ease of use. "We did another proof of concept," he says, "and Kubernetes won because of the fact that the community backing was there, built on top of what Google had already done." +

+ But before they could go with Kubernetes, NBC, GolfNow’s parent company, also asked them to comparison shop with another company. Sheriff and his team liked the competing company’s platform user interface, but didn’t like that its platform would not allow containers to run natively on Docker. With no clear decision in sight, Sheriff’s VP at GolfNow, Steve McElwee, set up a three-month trial during which a GolfNow team (consisting of Sheriff and Josh, who’s now Lead Architect, Open Platforms) would build out a Kubernetes environment, and a large NBC team would build out one with the other company’s platform. +

+ "We spun up the cluster and we tried to get everything to run the way we wanted it to run," Sheriff says. "The biggest thing that we took away from it is that not only did we want our applications to run within Kubernetes and Docker, we also wanted our databases to run there. We literally wanted our entire infrastructure to run within Kubernetes." +

+ At the time there was nothing in the community to help them get Kafka and MongoDB clusters running within a Kubernetes and Docker environment, so Sheriff and Josh figured it out on their own, taking a full month to get it right. "Everything started rolling from there," Sheriff says. "We were able to get all our applications connected, and we finished our side of the proof of concept a month in advance. My VP was like, ‘Alright, it’s over. Kubernetes wins.’" +

+ The next step, beginning in January 2016, was getting everything working in production. The team focused first on one application that was already written in Node.js and MongoDB. A booking engine for golf courses and B2B marketing platform, the application was already going in the microservice direction but wasn’t quite finished yet. At the time, it was running in Heroku Compose and other third-party services—resulting in a large monthly bill. + +
+
+ +
+
+ "'The time I spent actually moving the applications was under 30 seconds! We can move data centers in just incredible amounts of time. If you haven’t come from the Kubernetes world you wouldn’t believe me.' Sheriff puts it in these terms: 'Before Kubernetes I wasn’t sleeping at night, literally. I was woken up all the time, because things were down. After Kubernetes, I’ve been sleeping at night.'" +
+
+ +
+
+ "The goal was to take all of that out and put it within this new platform we’ve created with Kubernetes on Google Compute Engine (GCE)," says Sheriff. "So we ended up building piece by piece, in parallel, what was out in Heroku and Compose, in our Kubernetes cluster. Then, literally, just switched configs in the background. So in Heroku we had the app running hitting a Compose database. We’d take the config, change it and make it hit the database that was running in our cluster." +

+ Using this procedure, they were able to migrate piecemeal, without any downtime. The first migration was done during off hours, but to test the limits, the team migrated the second database in the middle of the day, when lots of users were running the application. "We did it," Sheriff says, "and again it was successful. Nobody noticed." +

+ After three weeks of monitoring to make sure everything was running stable, the team migrated the rest of the application into their Kubernetes cluster. And the impact was immediate: On top of cutting monthly costs by a large percentage, says Sheriff, "Running at the same capacity and during our peak time, we were able to horizontally grow. Since we were using our VMs more efficiently with containers, we didn’t have to pay extra money at all." +

+ Not only were they saving money, but they were also saving time. "I had a meeting this morning about migrating some applications from one cluster to another," says Josh. "I spent about 2 hours explaining the process. The time I spent actually moving the applications was under 30 seconds! We can move data centers in just incredible amounts of time. If you haven’t come from the Kubernetes world you wouldn’t believe me." Sheriff puts it in these terms: "Before Kubernetes I wasn’t sleeping at night, literally. I was woken up all the time, because things were down. After Kubernetes, I’ve been sleeping at night." +

+ A small percentage of the applications on GolfNow have been migrated over to the Kubernetes environment. "Our Core Team is rewriting a lot of the .NET applications into .NET Core [which is compatible with Linux and Docker] so that we can run them within containers," says Sheriff. +

+ Looking ahead, Sheriff and his team want to spend 2017 continuing to build a whole platform around Kubernetes with Drone, an open-source continuous delivery platform, to make it more developer-centric. "Now they’re able to manage configuration, they’re able to manage their deployments and things like that, making all these subteams that are now creating all these microservices, be self sufficient," he says. "So it can pull us away from applications and allow us to just make sure the cluster is running and healthy, and then actually migrate that over to our Ops team." + +
+
+ +
+
+ "Having gone from complete newbies to production-ready in three months, the GolfNow team is eager to encourage other companies to follow their lead. 'This is The Six Million Dollar Man of the cloud right now,' adds Josh. 'Just try it out, watch it happen. I feel like the proof is in the pudding when you look at these kinds of application stacks. They’re faster, they’re more resilient.'" +
+
+ +
+
+ And long-term, Sheriff has an even bigger goal for getting more people into the Kubernetes fold. "We’re actually trying to make this platform generic enough so that any of our sister companies can use it if they wish," he says. "Most definitely I think it can be used as a model. I think the way we migrated into it, the way we built it out, are all ways that I think other companies can learn from, and should not be afraid of." +

+ The GolfNow team is also giving back to the Kubernetes community by open-sourcing a bot framework that Josh built. "We noticed that the dashboard user interface is actually moving a lot faster than when we started," says Sheriff. "However we realized what we needed was something that’s more of a bot that really helps us administer Kubernetes as a whole through Slack." Josh explains: "With the Kubernetes-Slack integration, you can essentially hook into a cluster and the issue commands and edit configurations. We’ve tried to simplify the security configuration as much as possible. We hope this will be our major thank you to Kubernetes, for everything you’ve given us." +

+ Having gone from complete newbies to production-ready in three months, the GolfNow team is eager to encourage other companies to follow their lead. The lessons they’ve learned: "You’ve got to have buy-in from your boss," says Sheriff. "Another big deal is having two to three people dedicated to this type of endeavor. You can’t have people who are half in, half out." And if you don’t have buy-in from the get go, proving it out will get you there. +

+ "This is The Six Million Dollar Man of the cloud right now," adds Josh. "Just try it out, watch it happen. I feel like the proof is in the pudding when you look at these kinds of application stacks. They’re faster, they’re more resilient." + +
+
diff --git a/content/zh/case-studies/haufegroup/haufegroup_featured.png b/content/zh/case-studies/haufegroup/haufegroup_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..08b09ec9db8b7792d07a9a4d385cbd546d2446ed GIT binary patch literal 5841 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/haufegroup/haufegroup_logo.png b/content/zh/case-studies/haufegroup/haufegroup_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5d8245b0f6d18fcf18d871f7c657716b37f2ef96 GIT binary patch literal 5794 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/haufegroup/index.html b/content/zh/case-studies/haufegroup/index.html new file mode 100644 index 0000000000..f4256ff569 --- /dev/null +++ b/content/zh/case-studies/haufegroup/index.html @@ -0,0 +1,112 @@ +--- +title: Haufe Group Case Study + +case_study_styles: true +cid: caseStudies +css: /css/style_haufegroup.css +--- + + +
+

CASE STUDY:
Paving the Way for Cloud Native for Midsize Companies

+ +
+ +
+ Company  Haufe Group     Location  Freiburg, Germany     Industry  Media and Software +
+ +
+ +
+ +
+
+

Challenge

+ Founded in 1930 as a traditional publisher, Haufe Group has grown into a media and software company with 95 percent of its sales from digital products. Over the years, the company has gone from having "hardware in the basement" to outsourcing its infrastructure operations and IT. More recently, the development of new products, from Internet portals for tax experts to personnel training software, has created demands for increased speed, reliability and scalability. "We need to be able to move faster," says Solution Architect Martin Danielsson. "Adapting workloads is something that we really want to be able to do." +
+
+

Solution

+ Haufe Group began its cloud-native journey when Microsoft Azure became available in Europe; the company needed cloud deployments for its desktop apps with bandwidth-heavy download services. "After that, it has been different projects trying out different things," says Danielsson. Two years ago, Holger Reinhardt joined Haufe Group as CTO and rapidly re-oriented the traditional host provider-based approach toward a cloud and API-first strategy. +
+
+ A core part of this strategy was a strong mandate to embrace infrastructure-as-code across the entire software deployment lifecycle via Docker. The company is now getting ready to go live with two services in production using Kubernetes orchestration on Microsoft Azure and Amazon Web Services. The team is also working on breaking up one of their core Java Enterprise desktop products into microservices to allow for better evolvability and dynamic scaling in the cloud. +
+
+

Impact

+ With the ability to adapt workloads, Danielsson says, teams "will be able to scale down to around half the capacity at night, saving 30 percent of the hardware cost." Plus, shorter release times have had a major impact. "Before, we had to announce at least a week in advance when we wanted to do a release because there was a huge checklist of things that you had to do," he says. "By going cloud native, we have the infrastructure in place to be able to automate all of these things. Now we can get a new release done in half an hour instead of days." + +
+
+ +
+ +
+
+ "Over the next couple of years, people won’t even think that much about it when they want to run containers. Kubernetes is going to be the go-to solution."

- Martin Danielsson, Solution Architect, Haufe Group
+
+
+ +
+ +
+

More than 80 years ago, Haufe Group was founded as a traditional publishing company, printing books and commentary on paper.

By the 1990s, though, the company’s leaders recognized that the future was digital, and to their credit, were able to transform Haufe Group into a media and software business that now gets 95 percent of its sales from digital products. "Among the German companies doing this, we were one of the early adopters," says Martin Danielsson, Solution Architect for Haufe Group.

+ And now they’re leading the way for midsize companies embracing cloud-native technology like Kubernetes. "The really big companies like Ticketmaster and Google get it right, and the startups get it right because they’re faster," says Danielsson. "We’re in this big lump of companies in the middle with a lot of legacy, a lot of structure, a lot of culture that does not easily fit the cloud technologies. We’re just 1,500 people, but we have hundreds of customer-facing applications. So we’re doing things that will be relevant for many companies of our size or even smaller."

+ Many of those legacy challenges stemmed from simply following the technology trends of the times. "We used to do full DevOps," he says. In the 1990s and 2000s, "that meant that you had your hardware in the basement. And then 10 years ago, the hype of the moment was to outsource application operations, outsource everything, and strip down your IT department to take away the distraction of all these hardware things. That’s not our area of expertise. We didn’t want to be an infrastructure provider. And now comes the backlash of that."

+ Haufe Group began feeling the pain as they were developing more new products, from Internet portals for tax experts to personnel training software, that have created demands for increased speed, reliability and scalability. "Right now, we have this break in workflows, where we go from writing concepts to developing, handing it over to production and then handing that over to your host provider," he says. "And then when things go bad we have no clue what went wrong. We definitely want to take back control, and we want to move a lot faster. Adapting workloads is something that we really want to be able to do."

+ Those needs led them to explore cloud-native technology. Their first foray into the cloud was doing deployments in Microsoft Azure, once it became available in Europe, for desktop products that had built-in download services. Hosting expenses for such bandwidth-heavy services were too high, so the company turned to the cloud. "After that, it has been different projects trying out different things," says Danielsson. +
+
+ +
+
+ "We have been doing containers for the last two years, and we really got the hang of how they work," says Danielsson. "But it was always for development and test, never in production, because we didn’t fully understand how that would work. And to me, Kubernetes was definitely the technology that solved that." +
+
+ +
+
+ + Two years ago, Holger Reinhardt joined Haufe Group as CTO and rapidly re-oriented the traditional host provider-based approach toward a cloud and API-first strategy. A core part of this strategy was a strong mandate to embrace infrastructure-as-code across the entire software deployment lifecycle via Docker. + Some experiments went further than others; German regulations about sensitive data proved to be a road block in moving some workloads to Azure and Amazon Web Services. "Due to our history, Germany is really strict with things like personally identifiable data," Danielsson says.

+ These experiments took on new life with the arrival of the Azure Sovereign Cloud for Germany (an Azure clone run by the German T-Systems provider). With the availability of Azure.de—which conforms to Germany’s privacy regulations—teams started to seriously consider deploying production loads in Docker into the cloud. "We have been doing containers for the last two years, and we really got the hang of how they work," says Danielsson. "But it was always for development and test, never in production, because we didn’t fully understand how that would work. And to me, Kubernetes was definitely the technology that solved that."

+ In parallel, Danielsson had built an API management system with the aim of supporting CI/CD scenarios, aspects of which were missing in off-the-shelf API management products. With a foundation based on Mashape’s Kong gateway, it is open-sourced as wicked.haufe.io. He put wicked.haufe.io to use with his product team.

Otherwise, Danielsson says his philosophy was "don’t try to reinvent the wheel all the time. Go for what’s there and 99 percent of the time it will be enough. And if you think you really need something custom or additional, think perhaps once or twice again. One of the things that I find so amazing with this cloud-native framework is that everything ties in."

+ Currently, Haufe Group is working on two projects using Kubernetes in production. One is a new mobile application for researching legislation and tax laws. "We needed a way to take out functionality from a legacy core and put an application on top of that with an API gateway—a lot of moving parts that screams containers," says Danielsson. So the team moved the build pipeline away from "deploying to some old, huge machine that you could deploy anything to" and onto a Kubernetes cluster where there would be automatic CI/CD "with feature branches and all these things that were a bit tedious in the past." +
+
+ +
+
+ "Before, we had to announce at least a week in advance when we wanted to do a release because there was a huge checklist of things that you had to do," says Danielsson. "By going cloud native, we have the infrastructure in place to be able to automate all of these things. Now we can get a new release done in half an hour instead of days." +
+
+ +
+
+ It was a proof of concept effort, and the proof was in the pudding. "Everyone was really impressed at what we accomplished in a week," says Danielsson. "We did these kinds of integrations just to make sure that we got a handle on how Kubernetes works. If you can create optimism and buzz around something, it’s half won. And if the developers and project managers know this is working, you’re more or less done." Adds Reinhardt: "You need to create some very visible, quick wins in order to overcome the status quo."

+ The impact on the speed of deployment was clear: "Before, we had to announce at least a week in advance when we wanted to do a release because there was a huge checklist of things that you had to do," says Danielsson. "By going cloud native, we have the infrastructure in place to be able to automate all of these things. Now we can get a new release done in half an hour instead of days."

+ The potential impact on cost was another bonus. "Hosting applications is quite expensive, so moving to the cloud is something that we really want to be able to do," says Danielsson. With the ability to adapt workloads, teams "will be able to scale down to around half the capacity at night, saving 30 percent of the hardware cost."

+ Just as importantly, Danielsson says, there’s added flexibility: "When we try to move or rework applications that are really crucial, it’s often tricky to validate whether the path we want to take is going to work out well. In order to validate that, we would need to reproduce the environment and really do testing, and that’s prohibitively expensive and simply not doable with traditional host providers. Cloud native gives us the ability to do risky changes and validate them in a cost-effective way."

+ As word of the two successful test projects spread throughout the company, interest in Kubernetes has grown. "We want to be able to support our developers in running Kubernetes clusters but we’re not there yet, so we allow them to do it as long as they’re aware that they are on their own," says Danielsson. "So that’s why we are also looking at things like [the managed Kubernetes platform] CoreOS Tectonic, Azure Container Service, ECS, etc. These kinds of services will be a lot more relevant to midsize companies that want to leverage cloud native but don’t have the IT departments or the structure around that."

+ In the next year and a half, Danielsson says the company will be working on moving one of their legacy desktop products, a web app for researching legislation and tax laws originally built in Java Enterprise, onto cloud-native technology. "We’re doing a microservice split out right now so that we can independently deploy the different parts," he says. The main website, which provides free content for customers, is also moving to cloud native. + +
+
+ +
+
+ "the execution of a strategy requires alignment of culture, structure and technology. Only if those three dimensions are aligned can you successfully execute a transformation into microservices and cloud-native architectures. And it is only then that the Cloud will pay the dividends in much faster speeds in product innovation and much lower operational costs." + +
+
+ +
+
+ But with these goals, Danielsson believes there are bigger cultural challenges that need to be constantly addressed. The move to new technology, not to mention a shift toward DevOps, means a lot of change for employees. "The roles were rather fixed in the past," he says. "You had developers, you had project leads, you had testers. And now you get into these really, really important things like test automation. Testers aren’t actually doing click testing anymore, and they have to write automated testing. And if you really want to go full-blown CI/CD, all these little pieces have to work together so that you get the confidence to do a check in, and know this check in is going to land in production, because if I messed up, some test is going to break. This is a really powerful thing because whatever you do, whenever you merge something into the trunk or to the master, this is going live. And that’s where you either get the people or they run away screaming." + Danielsson understands that it may take some people much longer to get used to the new ways.

+ "Culture is nothing that you can force on people," he says. "You have to live it for yourself. You have to evangelize. You have to show the advantages time and time again: This is how you can do it, this is what you get from it." To that end, his team has scheduled daylong workshops for the staff, bringing in outside experts to talk about everything from API to Devops to cloud.

+ For every person who runs away screaming, many others get drawn in. "Get that foot in the door and make them really interested in this stuff," says Danielsson. "Usually it catches on. We have people you never would have expected chanting, ‘Docker Docker Docker’ now. It’s cool to see them realize that there is a world outside of their Python libraries. It’s awesome to see them really work with Kubernetes."

+ Ultimately, Reinhardt says, "the execution of a strategy requires alignment of culture, structure and technology. Only if those three dimensions are aligned can you successfully execute a transformation into microservices and cloud-native architectures. And it is only then that the Cloud will pay the dividends in much faster speeds in product innovation and much lower operational costs." + +
+
diff --git a/content/zh/case-studies/huawei/huawei_featured.png b/content/zh/case-studies/huawei/huawei_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..22071b4691e3830c0ee3636f04e6aabf02d5fe83 GIT binary patch literal 14310 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 Wkvu)p=jJ~*@1(`$#cD(h0{=gHoFJJ1 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/huawei/huawei_logo.png b/content/zh/case-studies/huawei/huawei_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..94361a27eb5af3a06992dda4aa1b411ab702ee2e GIT binary patch literal 14274 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 W@eBhBOaJ+*PEu4>q*h2j@P7e3cUl|( literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/huawei/index.html b/content/zh/case-studies/huawei/index.html new file mode 100644 index 0000000000..cfd2f562b6 --- /dev/null +++ b/content/zh/case-studies/huawei/index.html @@ -0,0 +1,433 @@ +--- +title: 华为案例分析 + +case_study_styles: true +cid: caseStudies +css: /css/style_huawei.css +--- + + + +
+

案例分析:
以用户和供应商身份拥抱云原生

+ +
+ +
+ 公司  华为     地点  中国深圳     产业  通信设备 + +
+ +
+ +
+ +
+
+

挑战

+ + 华为是世界上最大的电信设备制造商,拥有超过 18 万名员工。 + + + 为了支持华为在全球的快速业务发展,华为内部 IT 部门有 8 个数据中心, + 这些数据中心在 100K+ VMs 上运行了 800 多个应用程序,服务于这 18 万用户。 + + + 随着新应用程序的快速增长,基于 VM 的应用程序的管理和部署的成本和效率都成为业务敏捷性的关键挑战。 + + + 该公司首席软件架构师、开源社区总监侯培新表示: + “这是一个超大的分布式系统,因此我们发现,以更一致的方式管理所有任务始终是一个挑战。 + 我们希望进入一种更敏捷、更得体的实践”。 + + +
+ +
+

解决方案

+ + 在决定使用容器技术后,华为开始将内部 IT 部门的应用程序迁移到 Kubernetes 上运行。 + 到目前为止,大约 30% 的应用程序已经转移为云原生程序。 + +
+
+

影响

+ + “到 2016 年底,华为的内部 IT 部门使用基于 Kubernetes 的平台即服务(PaaS)解决方案管理了 4000 多个节点和数万个容器。 + 全局部署周期从一周缩短到几分钟,应用程序交付效率提高了 10 倍”。 + + + 对于底线,侯培新表示,“我们还看到运营开支大幅削减,在某些情况下可削减 20% 到 30%,我们认为这对我们的业务非常有帮助”。 + + + 这里给出一些华为内部结果资料、外部需求,也是公司的技术包装产品 FusionStage™ , + 它被作为一套 PaaS 解决方案提供给其客户。 + +
+ +
+ +
+ +
+
+ “如果你是一个供应商,为了说服你的客户,你应该自己使用它。 + 幸运的是,因为华为有很多员工,我们可以利用这种技术来展示我们所能构建的云的规模。” + + +
+ +
- 侯培新,首席软件架构师、开源社区总监 + +
+
+
+ +
+ +
+ 华为的 Kubernetes 之旅始于一位开发者。 + + + 两年前,这家网络和电信巨头雇佣的一名工程师对 Kubernetes + 这一跨主机集群的管理应用程序容器的技术产生了兴趣,并开始为其开源社区作出贡献。 + + + 随着技术和社区的发展,他不断地将这门技术告诉他的经理们。

+ + + 与此同时,华为也在为其内部的企业 IT 部门寻找更好的编排系统,该系统应该支持每一个业务的流程处理。 + + + 华为首席软件架构师、开源社区总监侯培新表示, + “我们在全球拥有逾 18 万名员工,内部流程复杂,所以这个部门可能每周都需要开发一些新的应用程序。 + + + 我们的 IT 部门经常需要启动数万个容器,任务要跨越全球数千个节点。 + 这是一个超大的分布式的系统,所以我们发现以更一致的方式管理所有的任务总是一个挑战”。

+ + + 过去,华为曾使用虚拟机来封装应用程序,但是,“每次我们启动虚拟机时”,侯培新说, + “无论是因为它是一项新服务,还是因为它是一项由于节点功能异常而被关闭的服务,都需要花费大量时间”。 + + + 华为转向了容器化,所以是时候尝试 Kubernetes 了。 + 采纳了这位工程师的建议花费了一年的时间,这个过程“不是一蹴而就的”,侯说, + + + 但一旦投入使用,“Kubernetes 基本上解决了我们的大部分问题。 + 以前,部署时间大约需要一周,现在只需几分钟。 + + + 开发人员非常高兴。使用 Kubernetes 的那个部门也十分高兴”。

+ + + 侯培新看到了使用这项技术给公司带来的巨大好处, + “Kubernetes 为基于云的应用程序带来了敏捷性、扩展能力和 DevOps 实践”,他说, + + + “它为我们提供了自定义调度体系结构的能力,这使得容器任务之间的关联性成为可能,从而提高了效率。 + 它支持多种容器格式,同时广泛支持各种容器网络解决方案和容器存储方案”。 + +
+
+ +
+
+ “Kubernetes 基本上解决了我们的大部分问题。 + 以前,部署时间大约需要一周,现在只需几分钟。 + 开发人员很高兴。使用 Kubernetes 的部门也很高兴。” + +
+
+ +
+
+ 最重要的是,这对底线有影响。侯培新说, + “我们还看到,在某些情况下,运营开支会大幅削减 20% 到 30%,这对我们的业务非常有帮助”。

+ + + 华为对这些初步结果感到满意,并看到客户对云原生技术的需求,因此加大了 Kubernetes 的投入。 + 2016 年春,公司不仅成为用户,而且成为了供应商。

+ + + “我们构建了 Kubernetes 技术解决方案”,侯培新说, + 指的是华为的 FusionStage™ PaaS 输出。 + + + “我们的客户,从非常大的电信运营商到银行,都喜欢云原生的想法。他们喜欢 Kubernetes 的技术。 + 但是他们需要花费大量的时间来分解他们的应用程序,将它们转换为微服务体系结构。 + 作为解决方案提供者,我们帮助他们。 + + + 我们已经开始与一些中国银行合作,我们看到中国移动(China Mobile)和德国电信(Deutsche Telekom)等客户对我们很感兴趣”。

+ + + “如果你是一个用户,你就仅仅是个用户”,侯培新补充道,“但如果你是一个供应商,为了说服你的客户,你应该自己使用它。 + + + 幸运的是,因为华为有很多员工,我们可以利用这种技术来展示我们所能构建的云的规模,向客户提供智慧服务”。 + + + 尽管华为拥有自己的私有云,但其许多客户使用华为的解决方案运行跨云应用程序。 + 这是一个很大的卖点,大多数公共云提供商现在都支持 Kubernetes。 + 侯培新说,“这使得跨云转换比其他解决方案更容易”。

+ +
+
+ +
+
+ “我们的客户,从非常大的电信运营商到银行,都喜欢云原生的想法。他们喜欢 Kubernetes 的技术。 + 但是他们需要花很多时间来分解他们的应用程序,把它们变成微服务体系结构,作为一个解决方案提供商,我们帮助他们。” + +
+
+ +
+
+ + 在华为内部,一旦他的团队完成内部业务流程部门向 Kubernetes 的转型,侯培新希望说服更多部门转向云原生开发和实践。 + + + “我们有很多软件开发人员,所以我们将为他们提供我们的平台作为服务解决方案,我们自己的产品”, + 他说,“我们希望在他们的迭代周期中看到显著的成本削减”。

+ + + 在见证了华为最开始的向 Kubernetes 的转型之后,侯培新为其他考虑该技术的公司提供了建议, + “当你开始设计应用程序的架构时,首先考虑云原生,然后再考虑微服务架构”,他说,“我想你会从中受益”。

+ + + 但是如果您已经有了遗留应用程序,“首先从这些应用程序中一些对微服务友好的部分开始, + 这些部分相对容易分解成更简单的部分,并且相对轻量级”,侯培新说, + + + “不要从一开始就认为我想在几天内将整个架构或所有东西都迁移到微服务中。 + 不要把它当作目标。你应该循序渐进地做这件事。 + 我想说的是,对于遗留应用程序,并不是每个部分都适合微服务架构”。

+ + + 毕竟,尽管侯培新对华为的 Kubernetes 充满热情,但他估计, + “未来 10 年,或许 80% 的工作负载可以分布式地在云原生环境中运行,但仍然有 20% 不是,但是没关系。 + 如果我们能够让 80% 的工作负载真正是云原生的、敏捷的,那么最终会有一个更好的世界”。 + +
+
+ +
+
+ “未来 10 年,可能 80% 的工作负载可以分布式地在云原生环境中运行,但仍然有 20% 不是,不过没关系。 + 如果我们能够让 80% 的工作负载真正是云原生的、敏捷的,那么最终会有一个更好的世界。” + +
+
+
+
+ 在不久的将来,侯培新期待着围绕着 Kubernetes 开发的新功能,尤其是华为正在开发的那些功能。 + + + 华为的工程师已经在为联邦功能(将多个 Kubernetes 集群放在一个框架中进行无缝管理)、调度、容器网络和存储,以及刚刚发布的一项名为 + Container Ops 的技术工作,这是一个 DevOps 管道引擎。 + + + “这将把每个 DevOps 作业放到一个容器中”,他解释说,“这种容器机制使用 Kubernetes 运行,也用于测试 Kubernetes。 + 有了这种机制,我们可以比以前更容易地创建、共享和管理容器化 DevOps 作业”。

+ + + 尽管如此,侯培新认为这项技术只是实现其全部潜力的一半。 + 首先,也是最重要的,他想要扩大它可以协调的规模, + 这对于华为这样的超大规模公司以及它的一些客户来说非常重要。

+ + + 侯培新自豪地指出,在华为第一位工程师成为 Kubernetes 的贡献者和传道者两年后,华为现在是这个社区的最大贡献者。 + 他说,“我们发现,你对社区的贡献越大,你得到的回报也就越多”。 + +
+
diff --git a/content/zh/case-studies/ibm/ibm_featured_logo.png b/content/zh/case-studies/ibm/ibm_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..adb07a8cdf58888b9884161d64112179b2987112 GIT binary patch literal 11298 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 \ No newline at end of file diff --git a/content/zh/case-studies/ibm/index.html b/content/zh/case-studies/ibm/index.html new file mode 100644 index 0000000000..bb9a4a8943 --- /dev/null +++ b/content/zh/case-studies/ibm/index.html @@ -0,0 +1,93 @@ +--- +title: 案例研究:IBM + +case_study_styles: true +cid: caseStudies +css: /css/style_ibm.css +--- + + + +
+

案例研究:
在 Kubernetes 上使用 Notary 和 TUF 建立镜像信任服务

+ +
+ +
+ 公司  IBM     位置  阿蒙克, 纽约     行业  云计算 +
+ +
+
+
+
+

挑战

+ +IBM Cloud 提供公共、私有和混合云功能,包括基于 OpenWhisk 的服务 (FaaS)、托管于 Kubernetes 和容器,以及 Cloud Foundry 服务 (PaaS) 的各种运行时。这些运行时与公司企业技术(如 MQ 和 DB2、其现代人工智能 (AI) Watson 和数据分析服务)的强大功能相结合。IBM Cloud 用户可以使用其目录中 170 多个不同云原生服务的功能,包括 IBM 的气象公司 API 和数据服务等功能。在 2017 年后期,IBM 云容器托管团队希望构建镜像信任服务。

+

解决方案

+ +2018 年 2 月,这项新服务在 IBM 云中公开发布。IBM 云容器托管团队的软件开发者 Michael Hough 说,名为 Portieris 的镜像信任服务完全基于 Cloud Native Computing Foundation (CNCF) 的开源项目 Notary。Portieris 是 Kubernetes 的准入控制器,用于强制执行适当的信任等级。用户可以为每个 Kubernetes 命名空间或在集群级别创建镜像安全策略,并为不同的镜像强制实施不同级别的信任。Portieris 是 IBM 信任内容的关键部分,因为它使用户能够从 IKS 集群中使用公司的 Notary。产品是 Notary 服务器在 IBM 的云中运行,然后 Portieris 在 IKS 集群内运行。这使用户能够让 IKS 集群验证他们加载容器的镜像是否包含他们期望的内容,而 Portieris 是允许 IKS 集群应用该验证的原因。 + +
+
+

影响

+ +IBM 打算提供基于 Kubernetes 的容器服务和镜像托管服务,目的是为其企业客户提供完全安全的端到端平台。Hough 说:“镜像签名是该产品的关键部分之一,我们的容器托管团队将 Notary 视为在当前 Docker 和容器生态系统中实现该功能的实际方式。”该公司以前没有提供镜像签名,Notary 是它用来实现该功能的工具。“我们有一个多租户 Docker 托管服务,具有私有镜像托管功能,” Hough 说。“ Docker 托管使用哈希值来确保镜像内容正确,并且数据在传输和静态时都进行了加密。但它没有提供任何保证谁推镜像。我们使用 Notary 来允许用户在其专用注册表命名空间中签名镜像(如果他们愿意的话)。” +
+ +
+
+
+
+ + “我们将 CNCF 视为云原生开源的安全避难所,为成员项目(无论是原始供应商还是项目)提供稳定性、使用寿命和预期维护。”

- Michael Hough, IBM 容器托管团队软件开发人员 +
+
+
+
+ +

Docker 已经创建了 Notary 项目作为 The Update Framework (TUF) 的实现,TUF 的此实现为 Docker 内容信任提供了功能。

IBM 云容器托管团队的软件开发者 Michael Hough 说:“在 TUF 和 Notary 对 CNCF 做出了贡献后,我们发现它正在成为容器生态系统中镜像签名的实际标准。”

+ +选择 Notary 的关键原因是它已经与 IBM 的容器托管正在使用的现有身份验证技术兼容。TUF 的设计也是如此,它不要求托管团队必须涉足密钥管理业务。他说,这两项都是“有吸引力的设计决定,证实了我们对 Notary 的选择是正确的。”

+ +在 IBM Cloud 中引入 Notary 功能以实现镜像签名,可提高 IBM 云平台的安全性,“我们预计这将包括签署 IBM 官方镜像以及预期的有安全需求的企业客户,” Hough 说。与安全策略实现结合使用时,我们预计 CI/CD 管道中会更多地使用部署策略,以便根据镜像签名者对服务部署进行精细控制。 + +Hough 说,镜像签名的可用性“对于需要这种级别镜像来源和安全性的客户来说,是一个巨大的好处。”“借助我们的 IBM 云上的 Kubernetes 以及我们提供的许可控制器,它允许 IBM 服务以及 IBM 公共云的客户使用安全策略来控制服务部署。” +
+
+
+
+ + 镜像签名是我们 Kubernetes 容器服务的关键部分之一,我们的容器托管团队将 Notary 视为在当前 Docker 和容器生态系统中实现该功能的实际方式。

- Michael Hough, IBM 容器托管团队软件开发人员 + +
+
+
+
+ +现在,Notary 通常作为现有 IBM 云容器托管的一个组件在 IBM 的公共云中提供服务,因此它被部署为五个 IBM 云区域中的高可用服务。此高可用性部署在五个区域中的每个区域中各有三个实例,实现负载均衡与故障转移。Hough 说:“我们还将其部署到后端 IBM Cloudant 持久性存储服务,并随端到端 TLS 支持一起部署。”

+ +IBM 团队创建并开源了名为 Portieris 的 Kubernetes 准入控制器,该控制器使用 Notary 签名信息与客户定义的安全策略相结合,以控制将镜像部署到集群中。“我们希望通过使用我们的 Notary 服务来推动 Portieris 的使用,” Hough 说。

+ +IBM 在创建和支持开源基础(包括 CNCF)方面一直占据主导地位。IBM 开放技术副总裁 Todd Moore 是现任 CNCF 董事会主席,许多 IBM 员工活跃于 CNCF 成员项目中。 +
+
+
+
+ + “有新项目应对这些挑战,包括在 CNCF 内。我们一定会饶有兴趣地关注这些进步。我们发现 Notary 社区是一个积极友好的社区,对变化持开放态度,例如我们为持久存储添加的 CouchDB 后端。”

- Michael Hough, IBM 容器托管团队软件开发人员 +
+
+
+
+ +该公司已经使用的 CNCF 项目有 containerdEnvoyPrometheusgRPCCNI,而且正在探索 SPIFFESPIRE 在未来的潜在可用性。

+ +对于希望部署 Notary 或云原生基础架构的其他公司,Hough 有何建议?

+ +“虽然对于云原生基础结构软件的许多领域也是如此,但我们发现,高可用性、多区域的 Notary 部署需要扎实的实现来处理证书管理和轮换,”他说。“有新项目应对这些挑战,包括在 CNCF 内。我们一定会饶有兴趣地关注这些进步。我们发现 Notary 社区是一个积极友好的社区,对变化持开放态度,例如我们为持久存储添加的 CouchDB 后端。” +
+
diff --git a/content/zh/case-studies/ing/ing_featured_logo.png b/content/zh/case-studies/ing/ing_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f6d4489715aa4bc1ecbed9ec6b21531e07a02ffe GIT binary patch literal 10305 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 E0oEjKyZ`_I literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/jd-com/jd-com_featured_logo.png b/content/zh/case-studies/jd-com/jd-com_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e89799842938622272852d418ac0ce065b2736f1 GIT binary patch literal 6581 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/netease/index.html b/content/zh/case-studies/netease/index.html new file mode 100644 index 0000000000..0ce8d133e2 --- /dev/null +++ b/content/zh/case-studies/netease/index.html @@ -0,0 +1,105 @@ +--- +title: 案例研究:NetEase +case_study_styles: true +cid: caseStudies +css: /css/style_case_studies.css +--- + + + +
+

案例研究:
网易如何利用 Kubernetes 支持在全球的互联网业务

+ +
+ + +
+ 公司  网易     位置  杭州,中国     行业  互联网科技 +
+ +
+
+
+
+

挑战

+ +其游戏业务是世界上最大的游戏业务之一,但这不是网易为中国消费者提供的所有。公司还经营电子商务、广告、音乐流媒体、在线教育和电子邮件平台;其中最后一个服务有近10亿用户通过网站使用免费的电子邮件服务,如163.com。2015 年,为所有这些系统提供基础设施的网易云团队意识到,他们的研发流程正在减缓开发人员的速度。网易云和容器服务架构师冯长健表示:“我们的用户需要自己准备所有基础设施。”“我们希望通过无服务器容器服务自动为用户提供基础设施和工具。” +

+

解决方案

+ +在考虑构建自己的业务流程解决方案后,网易决定将其私有云平台建立在 Kubernetes 的基础上。这项技术来自 Google,这一事实让团队有信心,它能够跟上网易的规模。“经过2到3个月的评估,我们相信它能满足我们的需求,”冯长健说。该团队于 2015 年开始与 Kubernetes 合作,那会它甚至还不是1.0版本。如今,网易内部云平台还使用了 CNCF 项目 PrometheusEnvoyHarborgRPCHelm, 在生产集群中运行 10000 个节点,并可支持集群多达 30000 个节点。基于对内部平台的学习,公司向外部客户推出了基于 Kubernetes 的云和微服务型 PaaS 产品,网易轻舟微服务。 + + +

+

影响

+ +网易团队报告说,Kubernetes 已经提高了研发效率一倍多,部署效率提高了 2.8倍。“过去,如果我们想要进行升级,我们需要与其他团队合作,甚至加入其他部门,”冯长健说。“我们需要专人来准备一切,需要花费约半个小时。现在我们只需 5 分钟即可完成。”新平台还允许使用 GPU 和 CPU 资源进行混合部署。“以前,如果我们将所有资源都用于 GPU,则 CPU 的备用资源将没有。但是现在,由于混合部署,我们有了很大的改进,”他说。这些改进也提高了资源的利用率。 +
+
+ +
+
+
+ + “系统可以在单个群集中支持 30000 个节点。在生产中,我们在单个群集中获取到了 10000 个节点的数据。整个内部系统都在使用该系统进行开发、测试和生产。”

— 曾宇兴,网易架构师
+
+
+
+
+ +

其游戏业务是世界第五大游戏业务,但这不是网易为消费者提供的所有业务。

公司还在中国经营电子商务、广告、音乐流媒体、在线教育和电子邮件平台;其中最后一个服务是有近10亿用户使用的网站,如163.com126.com免费电子邮件服务。有了这样的规模,为所有这些系统提供基础设施的网易云团队在 2015 年就意识到,他们的研发流程使得开发人员难以跟上需求。网易云和容器服务架构师冯长健表示:“我们的用户需要自己准备所有基础设施。”“我们渴望通过无服务器容器服务自动为用户提供基础设施和工具。”

+ +在考虑构建自己的业务流程解决方案后,网易决定将其私有云平台建立在 Kubernetes 的基础上。这项技术来自谷歌,这一事实让团队有信心,它能够跟上网易的规模。“经过2到3个月的评估,我们相信它能满足我们的需求,”冯长健说。 +
+
+
+
+ +“我们利用 Kubernetes 的可编程性,构建一个平台,以满足内部客户对升级和部署的需求。”

- 冯长健,网易云和容器托管平台架构师
+
+
+
+
+ +该团队于 2015 年开始采用 Kubernetes,那会它甚至还不是1.0版本,因为它相对易于使用,并且使 DevOps 在公司中得以实现。“我们放弃了 Kubernetes 的一些概念;我们只想使用标准化框架,”冯长健说。“我们利用 Kubernetes 的可编程性,构建一个平台,以满足内部客户对升级和部署的需求。”

+ +团队首先专注于构建容器平台以更好地管理资源,然后通过添加内部系统(如监视)来改进对微服务的支持。这意味着整合了 CNCF 项目 PrometheusEnvoyHarborgRPCHelm。“我们正在努力提供简化和标准化的流程,以便我们的用户和客户能够利用我们的最佳实践,”冯长健说。

+ +团队正在继续改进。例如,企业的电子商务部分需要利用混合部署,过去需要使用两个单独的平台:基础架构即服务平台和 Kubernetes 平台。最近,网易创建了一个跨平台应用程序,支持将两者同时使用单命令部署。 +
+
+
+
+ +“只要公司拥有成熟的团队和足够的开发人员,我认为 Kubernetes 是一个很好的有所助力的技术。”

- 李兰青, 网易 Kubernetes 开发人员
+
+
+ + +
+
+ +“系统可以在单个群集中支持 30000 个节点。在生产中,我们在单个群集中获取到了 10000 个节点的数据。整个内部系统都在使用该系统进行开发、测试和生产。”

+ +网易团队报告说,Kubernetes 已经提高了研发效率一倍多。部署效率提高了 2.8倍。“过去,如果我们想要进行升级,我们需要与其他团队合作,甚至加入其他部门,”冯长健说。“我们需要专人来准备一切,需要花费约半个小时。现在我们只需 5 分钟即可完成。”新平台还允许使用 GPU 和 CPU 资源进行混合部署。“以前,如果我们将所有资源都用于 GPU,则 CPU 的备用资源将没有。但是现在,由于混合部署,我们有了很大的改进,”他说。这些改进也提高了资源的利用率。 + +
+ +
+
+ +“通过与这个社区接触,我们可以从中获得一些经验,我们也可以从中获益。我们可以看到社区所关心的问题和挑战,以便我们参与其中。”

- 李兰青, 网易 Kubernetes 开发人员
+
+
+
+ +基于使用内部平台的成果和学习,公司向外部客户推出了基于 Kubernetes 的云和微服务型 PaaS 产品,网易轻舟微服务。“我们的想法是,我们可以找到我们的游戏和电子商务以及云音乐提供商遇到的问题,所以我们可以整合他们的体验,并提供一个平台,以满足所有用户的需求,”曾宇兴说。

+ +无论是否使用网易产品,该团队鼓励其他公司尝试 Kubernetes。Kubernetes 开发者李兰青表示:“只要公司拥有成熟的团队和足够的开发人员,我认为 Kubernetes 是一个很好的技术,可以帮助他们。”

+ +作为最终用户和供应商,网易已经更多地参与社区,向其他公司学习,分享他们所做的工作。该团队一直在为 Harbor 和 Envoy 项目做出贡献,在网易进行规模测试技术时提供反馈。“我们是一个团队,专注于应对微服务架构的挑战,”冯长健说。“通过与这个社区接触,我们可以从中获得一些经验,我们也可以从中获益。我们可以看到社区所关心的问题和挑战,以便我们参与其中。” +
+
diff --git a/content/zh/case-studies/netease/netease_featured_logo.png b/content/zh/case-studies/netease/netease_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5700b940f34af36f4685436c03b54ddb77935086 GIT binary patch literal 5601 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 Kqf(Br4*4%k>=jP{ literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/newyorktimes/newyorktimes_featured.png b/content/zh/case-studies/newyorktimes/newyorktimes_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..fad0927883a9310b252dc3ea75172b7bba5a9e0f GIT binary patch literal 20189 zcmeI4cT`hZ*YM+vXauDwB8ngcML?2}(EHGf^xh$a009yp3B8R7BT{4p0ckq)Cej2% z1XKnP5mBm$fT(l<5ow`)7j-n_I8UDUUGMi_vQjqZ?sCrW?0xRJcdg4seO>hf^vCEy zAkYC#4HZM+w;%X~f`0m@RuCKg+%g{hQob*ePO;LFb{$=U@j#E7e>O7NGPBICHmt@C_gBk$otvJ zUw%|DL^J{GNy2*Ixp(}c96Y>9auCQ)ps%kl-GiH^?K*gxzq4)?>* zM3SlxfZz+#A6gQP{XH>oLk!Wwn}Eis`T#@W{n6-2Sf_83^EXdBNB*_%7(eX4nC%?- zZ1yP?KF^RWFji@00tQ9$AQ*dixXXXeGX1|0aw{wEWR)09jGJEvg~sA{$O_29zc>3f z=ifYHR8S<0{7z0ng{6SEF+yA#DJd?`KFjtdsu_e25~Xk)o77 zC^WzK0o0HqiiG;Fyin>=_;Ex_J9!XrD3UxDhjPZiJ@L-6@NbP2nqMj zqLNPHjz|dv%JCCK9UV&Zf4ElhKzr|0%oo>=|3lXl=KpZ5N5BHB9m<_TXQ%i7(-1#! z^N&y(SR#<4{uH?jWbmi;%n0N4_tw7-xMM%9OP(kK5wlZua*)5u?(0JKb)DL=`Bc5q zDD=*XCXe1J3Jd`FZ>`_D_0{r=8TNlWfuH?TnE!hWUl$DiKNZwxSD&>0-3igdiR6nS zU=*E!ocM3+{j=x4n|>cc7QS;9aL4|AGCsHdeUARh+JDZe?9SpQ4desRH`J$jK*+-X z(e^F!XMOXXd3E>xq%VOK23~N)&i5Bn%ERBATKs2I%ERBAezP>eV@dMJFVVhhrm)&s zfj=(|M!;qPBQGu{CL$&a|GxQq3w^8~#@$>63)C=iCo_?Vzl^>=@sX)U;NrS3P!$lPlr2-8XB@L=F4Hs2JlnOLl zlr*TyG+a~>Q7X`IQPQ9)({NEmM5#c-MM;CIOv6PL5v2kR7bOj4XQE?7ga=*3N&1lG^olnTvQQJ zD$sCI(x58Sa8X4>sX)U;NrS5VA92xtdk7GN2cG=%1s?I+E36|3JRZo6)-coofdWo} zK);>`f!4Nx-zgBtTNnhIwg-WvuYy2FJmT$|)j%LN0ZkP}W4{;g(w+TSd&&1YQ&MIJ zhJM!(*#|v*P>Ej&4AoHQriXwHcjuVv@4^b|JX%@^V417phD0XYswfp??mKz%BrDH> zQ*CNS;%CJ%>+h~CZVRJgACB4j$JowoZw9wJEkBkbhAduNxht~I$%1Xyz3cRJ$-sk- zyFfy_?zvjSZJnHLw>~X9tG_Z+13GI%7q{fK^~x zVuUG-`}Pn%R&DWDxp$$Vh=>XQ)Vvcf^%R*OwYO*J=9iY1YUO@dT1u3!8F0s_p^c4i zDHZzVKy#8|Hsm@9EpY9^knf>Zz2{{iP5pZr-;R&>SqjnTc1?LcJRB7qxH30fj#km4 zZ+Y%inIRi;*JP#-net8|;{m?LV{2nkPR6&Jm6PS@Xof1Ws&*s)`dfN`Ma6TLxdvOh z-A3l-=7!epH*baromA-x%PJt>xfAtBOF^OWLZg9Bo?M;JUb?*!^{3|*S)1YFxBzU+ z;}Sb}sWOkykP!J!FY&Zklp}j~RdIiT*!26zNcB5@7cG)Dhd9L2I)0A7UQoc_@9G^M z8J{f5>ox-86A}`VkT5IMw|;!b*vxF@NqmjR%hkD_+Dg|dvV=tgX7Nb$5g~g=LatKC zhsRR|lP=-E_quY5xRNxzG#w1HO74@JtKmQY^ixRk=-sX9bdmfg>>CH_mS;6JG+s&G zeC%RPUY3cVqni-)s5x%t%T&UE?%2R6+v*whm+&tLHnYSS~> zbzdP`z?a#emVf$0W;1(}jmd$b!J*S1r^2{5KE8=lR8%Y)A)MMyUVLDsstUFG4Kp^L zF7N9zL|*!N&wiKg>R9U*RyMYr+}xCo@gvS1IY-AQFY^Za%+v3u-zZsht{ezhnaT)R z)^=36-P+U2|o4t1B0TwYR_5=E;-g#l=8Ral*7C`AQ+&(aD)pHvW!F z+v~ZDL+8(jrRz?t5l61c`1ZA`51y7f%5#O>k-62j$(Yae+ugFuH{%oQ-2Ok~A#}!JJg$&$E$*xXrNUERo!rfWGC%Ljo#goLyU z4g320&$d}#mk$;XURcZ7*U1pZ9r;?>I``?*r@!9&#ekJ7==l|_k^d!z0}S0$OA8AN zr48cwd3k*6UAgh`@ljDx&aIcCV`5H*_gD(~)Y)u;_dFP{&@VAnS65GFO}>(NG$CMF z2nO3)epidqV+_PRIj+c@gQIs1VvJT*^qV|%fL&C0Y%1T^eWW~KtS&eqp~|x4{>blF zdz4H2M^;vWvE7yQeld2&EM$>OiP_KK9=pi?H$yAC>F6}qi!QXcX(R-`*>!=Aj?U}& z%F@;*V)jMrt>{{xrD@K^3`OPN_*v<%P2_Ib$K-3Lk$VdA4{U99OlU36E~ge78kw4k zFQ*{9IHj)^73Jxs+;JUyghUT)PJ~6$*FJDWZW0I09+bx1vcO>r3w_dN<&%ex-P-WK^d?pOHgWw@Omqrj)}c!;{kX_=k-K08ylN$Cb=8V z^VjMJtMToCTa2Y?rAuh?uSTopB;SP+&05$q}s=JraO!l5ht)BO(W6IB~ zj=Lo9_sXqiu-<++$S$_p#?d(C*~1EVEVhtDUpKV1Su!ti!)hX1zd_bbyuBiVE}}%a zDJb|>w&AsEb0D`itITYBi+awlGZmDU!l45Gca5CSKUpbhKI`h{W&=wmNhi0PY<24$ zYE?KfIiWDNc2TIkufJC&<4N=p7(0plz7H3Zn=8~Vef$zo8|sYt9oJ>_ijDL4pD=I| z)j|)H2iGa)Uza2L;PH5e{?=pH+r;E>dqv>NJCiQtdEG|m75tRd zL5$iP^wzGUN8lAg>&aqnACFznSBtr2E+n2-Qc++6WqN1WT;zUE8LvxHp{UQ`iJ^QgcQP%${uncuum=!T+P z3ENxB7Zlcdt3z!Y1E8{yp!GQ$sO7DP^+9Xnu^eIClE)d3@-i^)GvH@6Ev{-Y zFXSJnIo=%Og}x?cV!{*t;ubc$cgBz@BqMO`!{dR<U(l^zNTYniQ}9hNir*Wd3i1D zlgcbc6~SNNdjjC3f24PhUghSmjgGxvdWZ?27s>*V^mN>C&BcpdsUe5mMAL`h+ zpjFQzt&(_xPYerBWZu!5=wP9fj=ia3addkFj|j#fW}F0~rh96Q9O6_`vpSqAMYGqJ z-(lpe*PkylutAX~CgWpc{)7E9Buz~@-?_o=&{w~N>jVAcSe!s02U_&R*+yWdg}tn* z!M>Yh=j$P^zR#_yT$ftz`iDn4>t0s`d%t^*;Nw%{OP0!jx1GXGD$xXC5GTihErN5)n=83|ZXZpIQtF(acI~YySA;=tz}J{l{13 zWTg4X%d>-d)2`wA?$*}rWv07FpO%$fOgP;Ux~Nlc>rrWOm_EX^xa8)|YY1F`qU|s+ zX{~x!pWY(5R$6vu$Q@yR1&`Xzb27IljNc(D0RJF-;%ws!h^oP{ zSf}Y*g_oZpysNzN$!?k}04o1FeK&bzWB*-Jb+qUE*WwL{ZFYyv|li<;Iq3!d)A z#y#N|JJ*lyk3CFGRRr^fsT!ONx7ThTBM6)}D(=G&CZc@Y|k4(gKy2+YTQqF@5EqgsCG2OReFf`)n{e9$R7o1uYjo2TJ@r-BKCA{nKfU6Qvc9scbCtEp;}8~`pX(N=uLijN zqD4vHbdhUn9GJl9yOT%Rww_==ViGtWr`Vqx{-A-&jRs@=CtXU+=`*9K28jck_@);`#3 zYNjb{Zx~dR;T(6fG^5qy=)-;iPYug0w3k+&B2BA+FRO*Lx+gt2sRl+tI?g~KJb!Y8 z3%7)EgTwyN=MPw#gW~qoHzL{h>$JNICb|N}AlsRLUDE5r^MyLZRejb|IP^LbJGa~_ zB%JxOeN1zUer)|=l|mVnN33_f`ukUE_r39!=4^@GR0X4=9N1f0Th&iOwp1eI-nsQZH-l zkUHJr%)g<8#Kih<+Ny&0g=sJ!WVz4I8@F z^6zED7x4D%d8X;<=@z+_mr3v%pXrxJ(b~YK#2~-B+s(}lo2s^(MTwQZR@6K- zZ=cfDJ2E~o!Y#*JdBd;JN03Y~`-v+&^2=rJ-SLNb{E46_}LEvC8Pl@iJ{)oPv zU0TXzfkM7S1xI8`_tXbJS;4A2MtU8r9(y|KZrx;Z< zSXJW&byOY@(@9OyVcbgzZ~U3s`}!<%wnRjMoux_QlotMGjXPur-O|+stjlI;+OAc1 zG8=|R%M`TOij0fmf?QhFb!WV~MIJbkKvZKB)I zNY&u3|Kj-U3H;fW8|`EC3=GQPX79DE80e1Q#aUiK~{H{N-HQ)YR(*D6Z8Wbl?he#5V>W8uRM3#%G;@4BH?SjZlQB+Nu3 zqTk##CMK%OrN^o!$V+rKvVH6r(s8o<<00r=!>tdCm@NJa-J>Xr3q!CrMT09>PJ(4S zA3B0FpJd2Xx%WARBU!r+W+;ReNZd4 z+#K!e$l2chag7>v6~~-X+wI|Lv6Q1n!I@DX2-(jj%LYY6MBGh_2drm3CGo?z1;9!v zz zAWgnUg>Fw~J5`if3>RJ&+^P>)*&1E9Iy{!B8bP;r<%DEd6H5(aUQxjwD40$NOqRnfHbMvdy@#u)j$o z#lazt3%C?N)qE>b(O**^cGYUV+6bQAA`6S=;wcYAtzSP!!S`>bcIhuK+K zSy-Np&RGhfkSRa?{IfumARHd*`sYK?`O&A(c!yQl59CbL|Vsi5+~!{&V>NG;O@N!iHV8jzI7doK_Rxbj>fDy-KS2SDqrDv z!iyg5tSj5w&?*@9`VyziuvHZq82#nTm$$2{y5hUK;$Mest}FamSI%^Qcqs6StBICY zRF6r`AnvBPnW?Gg@%fqJ`RC=ld0V&5`cw_v?~J(i<+tdZWs4gg+`po!a6y$ zSF0W(A{*P47Zz|$gM0SSZJ`cbPfJMfS$#it!(B-OtEq`mRRvb-4yOc%7UH3n(%|{} zyoely1+A@X3sX#9n@q70aiaaDHXO3{+^Wx5BTnrDR(#!jvqBR9cCTwaX^k-WzS=YM z-h*+Q-Eo{!A37v12=mBGXys*E1yX$n)ev8tPS#4^XdC}Yl9BN5GrxwzyS!) z{w5dEWAlb42DWpATHb8PDEZfjd)Wsz%lI`^^`Ot5>u@jTD_OEEOKO-#r@2!TL|wYAiZ!RtKujlstPf3d8Kx4{d2 zpoV3j3Boln#KGSMqT-BjbYau>cDV0i?Bd`Y=J(n~0RqAHcQ>^RwA9y=b3%9vIs9!S z6zc5@dP5)z%AvjvPM$7-Y>qDX-F*~cyDtV{Z0^pAFbhe25q)1Z7dLmUaDNw*a064P za8D;$XPB}Qn?k4@7{J>l(19(~+sh|FE>scruW{wT`@dfc!`S}SB+ye4_U}bm>Kn4D zA^cs~B!#2|okS%>*ra8JM5RO|Bt-?-#6(1;g+(NVMWh5pMCC+ex`uI`|5U3W*4N zd;i_nzghQAqhHi*JM1UK@mrYIW@2yJ;NwV?iJ2<)f{Qa8u z?^XSK=jty0?!hk3n*IoHwttFJLw+q9*`eIGONS5Z@4qWk4BRwyc6N4k zt&NXYYcg+9I$gnLWGr?ZP1TN=YcQ$P$>Wm``Qi9FFqod<`Z%-pNaC2&CVq&K%Qwa;Eo6E!Qb9FLseYF&^>%h*=Ua1m~J40}%M5Z0F z+`rIqzlqM+wxeAt=!YpODJenXdSVqC&81)Dj6f`-HHczjt}z(Q+egCR*VlU^&kk6x zPw{r7ygx~74eA$51#QjTWU;xK^`j``X+c3jjqamAb>q~6=P%~gpICNoA_lI4w`OWy z=Wu^T?5~Z!&Er2=f1Lw1I$irBWcOeavU$4y^<$e|rb}orHJpzuLlP&f6QcFnPx~S4 z%~32voYp=W5fRaO#NmcMnS+N1--XY=nmui97O--gYo?cYv-7!&{Ig>CZ5&5 zKKW>*GKwy)?IB)c?HKAh1B+ED5|v0V?y7$K_QmO`*ZgC4MMdV-FTcLLP(E9y)UMzm zE(;${Ah4`As!FP>t4pP$Mujy}@fcToer&ZQ`?e#$+iTL{I#H`%?6cTSzHet^!?Y-! z&~dOg*J3@wjGgxTG6S(PhLujrsz31)JXft$lg>sNzL&pYJT(W%d^A1(Wf3CRNdy= z?34$I6fAoDT}WWG!uJ+mgdid!E(odlB<8H@3`%p?Z?9V8Y?;yoEw;znXCg~bx*%jogiz=l%m30hhHWnBuo@bH<3x;sKcNg z?VX*S$2*^$Dg(D>AoPn8-5Go}h3m~NE!Wo>RDy(fS5}gOR>sE0BT2-s2N*|+-jyq# z92|JOubrT^i>&n8HA1>QQ^Jofq;Z`n`q1w5@_Eot)rwp}Yx8uhp$BV!#;7zBvKhPs zSaD=lc@-2c58o+&XZH8^&%N!v@MLs&7)wtt1}w4-{n)VE6_VIU;Xui4aH|oUTbr2A zUZ{er$?l&Y{lwPxecI*oMQocVcz4OR-Enkt z(=AmgEE$-1L_|cF*8&ABWsX%bJaBJi=;+6X&)@>!@IkOM%vHqi%}Ow~?cx5{mpvNY zCUpkeDE1O?H&K4?4!*sO=Kuyr{5pMLYisM-vuAoaa>V2;`#&FY-1hSF^7VIJ$W;DQ zppr=m=2g6PE8&l;t1DV-w!tJBf$OgXgQ?y``@lpqUw-Zh;C{rvrZAn68lifuS{vIG zs+eCm^QwEnim!DFzPE9XBk9X!i$74I33HVrh`m@D!lp(&Db(jT*U=#qP9tXwBA`6E z1xv`*xb?BcS{mO$K-WG`jy&G{$XjerYzr|_B&kw=N!!jbtONS-M(9x+axCkx7ITQB zBMF@MMmr5_bf`B;PhGw(RLe2%3w{}hv0GNuqFoz6sk=J>L&%yjH#g@ao0wB4v+4Fl zMtOqBz)9ldLOja=&+E@&L^U3H^O-jnq@@w1CKneM^O=t`p{V&x$*xuVX0T3zI2lFk z2S3`yOeloxe3Cq_1MWvaK+q|0lrUipQSBuF9QPCs64|a7gNpUN|(Z* z=;`S#Hy1j%3&ePMP(cL8I2>Xdy}iBQKn2bBFEf)~QG|1Hak(yb`x(prHO#pt3*l+y zdp-V%TI4dD%LB@6bQBcEFM_>m#A~ir+h_$WMSNEVKVnUv61J_Z*kg*iMX7M9V-jzo zrUus4?pk&~e~ycbJ6CVy^uAVK2Y+VrLz6|!_tFq}Y6gSka1pTe8LoyT4V>~D(t_US z2XBS>%^Is=ZBwHtumzgR!}ZscckbNLa*9fZt92rlSx7qXcDRP@E-{O{LJ<_nhuUzA zd&aF-v9XZSdd28V8Pd1LNVlZp_ji=9R*`8m`giVhJ$WJ*^dnb^`-R_E%`6zPb(w4c z7a}`pA&r^Fokxi=gfA!fz1z=uW+o;K!!B@@orR7%uZ1Uz78Wyuw!>h6>qJYBBR%y9gLX{WLi``lvt;uu5(88U;# z$w>pW**#ZG6?Ced`%YQ2Ngc@tP8B8WlL~L(D=rp`!%m5?Z}>_vV5~dkN~KLz0)m1K zUouM$(&@#eyyh#;zWN%2@W06da$r0jscP(D`~LnuF{9M@>(?o1Y1kVO&qnq-@(bu3 zNIX{7*7CBl4N(I`iM~~{Fqq-Ji&b{7oSYnj#8`vi;A2wdOGqhuDk&TE0+Lu{@igA+ zk+2=t{8OJVe?oLlnwRFt6@mC%q7Q0mx z?-SgCQ&ep2?kaoE30TP@mU`#sEm^*X9B<#<_d?-S=Qt7DC|l+W?QCwMvMO{R3Gv|& zJ@ll>z}0KH+mXchXkpMJ>iqZq-d?>$TNzSZ;9f5sezAmmcDMf;CI!TqTW!QRU-{%} z_7A_mv+i`8uGME`sIRbEy$M?wNhYlnXQLuvRVpbgTxhkG=P_3g!Z?SCXtAOwu+Zh@ z%bU|x#2A7`VRK}GFs^@#Srd(*MT^zZr>CBLv$J&5v$$8t*v$Nv=H|&#`8u@WO|&-g z4OWGSL_+G;dwr?PyZslx)<)B^Bmd@xGaqej?I|8X>t_k4-b=k<4nDL-$oirmMTgG9 zcKzw;>6hOg+11P2`|No-&#UnUld4&5x`EWwJCAT zaD)4!E{;K>#gGWMx3>c;kCw-y=j7(TQz$k%GU5aPkTLPv*O!?ZXW2zX3^X*yuDdkq zD=RCH!wxsP>ViH8ww{5A$1E3^WgfjhN(&H@@voA+JhKj0{YX_{ln4YO!48-Rq%|Xh z*tuc8>s!X>9PT@099&#n2SsBUjI1)gv5dBnQBkF(rM!poZ;W3)U~U(=KUuQ%zOML> z&%O?~UcqDc_gn%eJD)?|<_jWH#-z!~R47hGW@{45OA4HJm->vKnRoAcd}sveU8}Gq zd?@awan4w=BvnD9S<{R>)$X(KqaU-~P$FXDow*jq*+4_XDHJ)!={!gR#?L7*eBPfr zUnBhAynZbUU|Q@A?9;T9?S+7g;~fM6nf`iFo9zo+Dhln(KX2S}($dmo%2?k92M3>L zw*>sj>cVJdvSf%jfkOo;V(m+9O^wk{aU=!l&G{6bS-0ez=s#!Q@km)D^zj}8%Ud-Y zc=~Bp9iEOt!7tUz>zrR_UvsX*H1;0m3tErysGp*RDL;Z`RsX3&%JWu8g$}Z-CGjMe4z3;+H8$WI)q3XXz%Tw(|=o?n?E{#?gO?Kba zH7OyX(`!M@!UD7U;K2isG$#h=>Os(oyzbT}K#l(d=^4G!4HlPspebQ8$zW>ZnaF@b zyEr?Km&((USV0@jn=O$D-nd$~X*Ag+errvq?bv*w_Oh%hA4lB_Y04G8so`M4kXSw~x2W!~V+FO7@sj(53M7k1a@7C!Gt;g6w@a6f)S z+)Vg03$sBqk6*j5MOq-d&8ws#>V`M9+ChlR7MAy4*8+Hm1z(Nn8B|wKZ@o7OUhPoo zX3u|rvI9L1}y6wlR0c1=o>v#@R6+n*3a$d{0s9;ww@!mmb0 zIlEeaEcHcPogY!+h5J8~vB9tCY;Pa>JR7!+NujKyc8g4L1|HIA({lhUKcmhe%F~yz zMknu0F-L#IiI5M)&^NS38kC7>>UwX4w8grM=Im%F9xqh<;$-*Tn>U2``12k2NxSd* zPptisQC2+zh{$WHmp*xMAcl1fH+)%r=`yhaI?C`S1h~NQ@o}hpXSN4TSV@iM=W|T5 zLd+kgXq#n%)eZFu_|#OmK{{{$(6_gbbd%Ev;=2&bLO$pFFImHKUc8VOO2{+(-OU;$ zjoqxy&SK9Yh^Dw@zqS`TY$Q2u zhzbZmEmw7Q?W_pYMdS$SoF|f5qj|n)e;v#4OYUTZ;aw^L7IJv87vx7hsWkeN0E71U z1<=MoJD_YlvJtPc*tx#)QuerlASHT-D^nRUjn)9bKm!jc%}@D9K~kbQzWeoBz<>ge$N{H$g2 zA|*XN;kKGcBU8rc2WhtAk`gAFpM!&N>@t$f*cq%o(sFzqB2v3X9m(RREKPKSB zdFQ`5#lAJOV&CkHxi~wUKD%L;Lhi2UhQ-ds5&%+CuvM{qh>*-dBEbX|+%&j?l#q}j zWM#GQvK4TnHzFTsG0oOpB>X)*IkIwcseZ*c>gSyzuENhtGBY#j!c&V~#|tWVdt`R% z4Csg8>1k0F8{-HN=7@@Bm~~y8+v;DYRBxOQq&V*@E0;*6yg$ zFh=BwQPA!b0U@WCi|~2PE91+wD_*T(EV2}y)DBWCV~LlP*biTviS%yzqmyC-xN)Yq zu%Eg$!;^^_lP(_lWD<8JJh|`Ul1Mu4BhhsvlZ}&4F`v?5 z+bmZlIF8JUFu)YIy{emoID*L=I3*;gc1Pja=Cw3DEIf1OEmlK`e#ZJ4&xAAaNyzxH zjn+h__mPGfCFBRii2h2kqzaZ3VU_&rHS&s_6&l|hN-n*MqaJU=hegiS^5dU-XL#6W zev6QhkRTejMgyro0c$N+2osZh!CSn9q&rq(;(h-7IRjnwFfZ=DDu6sU+v*frPOV0% zh;T2RUT1S=TxJ0vv;F0Tw3&6B<54N)BH&{iR}Upc?E9@BfX=&`}}fcJ_MkRp&{ zL!CZftd^B#Y<$l9v%0NYm6TKG@K_@uxN&Na!tVx{$sUXPuhCF4e#xt=<7QIqAqo#Z z6?*>;d4d~@&s!&+Cf6_kU`OiG-EypoQ|8IhK`8m&tYeaWG1S;aI7uFw*H{ce#!H{DHj#AUhjSOnN%>w4u7XdT-A+N>S$-h|byQSw3L` zw$l5tRn-#8Ua9KLPLAQRT+8c(#`x(au71t}dM#wIhKg#wMwfP< z;^$mTT4tuS8XH!yAzxP4R2|6DCbfDu(v_}$n|v#IWeAz_8BccdCVl%U#Ml zs0QxevdO*Fk=LSw8CUDm3fYL@rr{P?Q|%^6HiX({z=->PD-oLpt5!0`TeLsI&5QAq zPWW=x(ym900r>K+we`itMOxLjeXq*ON`Q^5pLq=(fSlgVj^h~!yW=%J`gYjUKRB3X zd8KXO520K1@xuMZbzvCPV!7LoqtB)FPsKntEQ4{@ttqU~i0u08?2KN`9oJcguE=)4 z-=^Tzy=wPvW>T!+)!{@rY+PQpN*`CIcY6@k3D%$AYnnzl-t&)ksJR22d^fTWWcsVO zc7M>*=4HC2R78Aa#gd-54oxMnLU88}%<{p_4U*As7hOk_7kdI;j*TTfvGhzRa{`Wh zufvs?4(l=QpZc&^6}?hid`{tey@RXw?%mTN1ZW(ITjv*I6F^T!Mn+3pCtMQMVn`j} z5)hU8BrfGGv>H3>_TkCFdll`=qqdk)ESDd1Zg_BHwXKcKDRhr7!6IDmGWuet3*g!a zAWuACmJemoTO0#mVYGstvjfP2^EpKwwzjsMe2MXzk5M5msr0D_FNpn?`=i=|?g6Nr z^I&ah8gP_q$qGFyGI`Fumt)C85w!2J^7Dg1YPB~F>jB_*`ZD5;e)s44dLA4-z_BJj zIIUS{k5il_NnIV5U-w2|$qDkyuVN9;5;8F}>nq;M4UzO+fm5+3NW3xd1Gp04VxWRn z8)w}ZLcMaAu3)OTJpG!P$G!a2leRpgsc>@?J@11Ep& z{?tEbR*_%`{p5OMy6Uz{j^!X;ek&avoz?|rY>ZFaYP-<0mzUqIKAvNHWhj0zM?>c% zUbtoZCm~H;!^iohs1w_$tNVa6x~t64^!N8057<5@du4pf$wpU>om&-|CgOru5{U;h zM3aZ#g1?Jac$I z6zlmAcOfCz4m5=D(9lpzOS)HdWz6tGX#~q$MZIAhd6d^J#TPj_ls)9V{Cq}jk}NZs zmJ5SEv%l;HqN7S>uD4r0jk}-6EvkVuFjStY%(xQ`a%R)MlpR@JX zCaKg6bp`*J)h<`fh4!;Zi$q_Bx+KKL-FUDK^wEBO78bI0+I3}&(n~1X0PhL=&6NW- zBzfRLEuUHApbIIT$lzdMe0)3*1)zG2^%AFUQ{O$s$z!XHyf8o5r+vGogt*Fj#Fmlx zW?Gc_@HZ)n6yswR%_l17~v8p4c zsgH50b$d}RRBwS~3BOsq(8L4zAiY!ad9zsrV{=cNUM^c1WI!aQpDar3`XL| z-$NQ|KnYJ$(fGT|0I33a5T}mR07!~DrZ!*#y?Pj{Y}MuCEky~3GRx)SiNHxe)Ei;{ z;Fgp$voldoq2Lq{5P)ZymPUx{yQ--u?mZB34hy8LUr*}aj3sw z0-vgxuy9)<5iMU1`?m=ofR4JK{FZde9^#eun$N=R5%cUfYq(9Mn_h4yc>UGGii!%L z8o-I|J}oUREiBLz$uUx|(g4+#l7;2h?(RFmkJlXMb$W$s-@n%_n)ZbUEhYiOI4TyX zdOB01Tdo|lG&F>KE??nQAZAfVh>2`(Zf-79j5v^ymGa-_hy56I-+Yw>O3_ffzj-5{>g{-g`8a+St*X8g=vCpf?Di z5)`Jg*APaG02zT*`1REZlJwOF0!pr_ib|lS@69`#FwnIFUYfxvPjC?BTgQO%3`W&4P6H8U2&hLaGtgY zZW(8kO^zgpyHom(9kx!B^o1Y6sA_9#DR5Swj_&iHIRgsJcQCFl3HYC}BXLG>MTEWm z%BzPQO=eBCnarF8#`-KNdAYe%nwmLW`WU9WjSa15lE(nRgY>&R5OWRc3<|4*2rFF! zgL^<(2mCjeK2trw&u;Cw|9&(3#8+#fd&-@*!80Q%x<1Fajc zcjo>3tIJEwIm4UPFpxSx>{M4*|Gm4+%AlbanwOV%v;08?Ws#hiSoZDY`dX}M%c@_y zG&D5Hq^w}ae*iC&Elkt=%)9Yow;!Z5`c(>)scSyhi|DKKTwas7xVWV1s$6X&h2GYVk; z3JMD8+7SofSOJBaERoH*IACL=VOAY_68FU+3Zx2&uUwA(O%`q7q-oaTYqJcWJ>7g8 z6@L`_Br}uLQJt5P-(;&d?69}5k5S5tj+t3-gG<481;TlBM_ZdbUYBX@#}5V;mj2Lv z$I~cmHFpgk>w)O20#PT4PyJL9-L}hRhE_mJ#=ZxHny#4ZXi$yjxdOILyBPiQri><_ zQtaFl@bq~gk~OleF9f~ne!yV8|Fn9{j_t3&TeA2y=Z?~kk=3`PUgSzMp0;i=xRfCNGY?`XNun9|ool{L?UclgX1SGNL5d;mGXTHzT; zeDYYuzwc?sPGO5Di;OSZ?NA_4vC%e(sr=y0 znHr+XEIx+SL?pJl6QFtQRQ~2kAa}B>R|#z2mKrlOsZ`>YZOuNBrA zQxDU*zmi3XqI%rl*Fxkh?TXAys+iks;YO#d5k?{z{wY~NT2B4Q{|!H*&#udd`6}@O zSL`ttKmSiaA5lbM2dtoQEM09yF(slQBq&h%beXpZw= z2_+E5;Jrpwl9in;T7aRa#%!%INVvgA9DS(_?)8T51LfgR0eW+m(BlS0-Sd@v#nPlK zl2;W==BHjOc_2O;yFLc4H)6!15NhaUGwsHB?n@;V^lP!lrpG@eCB>}CoSHK1u9cPJ zeRaTi9t;eKWk~6YLSM$wA~i%i%4EJW(63ZH{WoUmx38cLhi$@qTjH zhwk>BkeN{YvS_v(Dlj+eXmBCS$&er@o2f#&1N};Sxf{$tHh?A?(dLQjLUBJVT)}ad zf&?edo<_F)Wq z^etQH6hZ6J{h(%3WC4+`zW%ob>IS(_gOdr+1as8b$^aUT&ZY0=y^F^I=Uu7h(=5Yf z@G%<4#CrNYt;rqGbYJr}RPt@qSd#}8T#{7c9X6d3Ae)P!$n7CjsHmWgTw`RxK$0-~ zq$Ib#9J=jISMbg!yO^t|lTjE<27~RE#MiYo%n;9_8lD2ThxH=$Ay0_x`->kp&Bwxc zZZME(n`BIuD=RB0m0bv=*7x~+#dV=ljZI5NuiB#&0Wm$AnE}s24kDq52|u9+A19Xt;+odddom8~tz}3am;XjjRr>^t2Yd&i+(tkloNdJkSo> zin+d6&SX_4NhT3EKq@IIb>A7Te}k$O!9+SbCm~3?nl7KOG=f}WdH3!<7rDb}=OWwj zCxU=#KEFu6LC3{*!94abO4Dj`OB zfh>RDc_JYN4dtj-C}mW#Qo6Ify;lHqN7#w}$0&~Xo75g3wl_C<%x5(; zHRGsOSB6JM2F^AZPX#~>aW4~TXU1A$k}G;`d@!m5Rmn+h%|F5WHCps`d)v!MlkQr^ zqU~NH1hDTMBm?B}0SLB5lAih5*)YE9UYGYK$kXqZ)JIUreYAQyKSuk)O)@7 z#GbSD4tgaOSkqLvAIF>FmI)^|T|TAA-uTmb`zN40V3KP2=0|Hs_MNSj0<5j3Gxo*gR7=(oH-YE@rj!$`HbpQswMYqnwvl<6!I!9ueQU$YiqF^I?^3XdI3xP_8Ov8cJD~(vhSqD8R33UVVXI{@UJ# zdXRsF++S&I>p#~i2`6SDBj&Z%W$rd94!E~eqpm)({>pL|o7~;mAtrI%Hg7cjtJ(>f znNq8ZCwB%4C=fh!jKOb>^aH--@1M=5l#3gjkXa_>U1VU8=vFG}NrRSlxi)FO+^ov< z^7hWVEok|;0@R4uWU)VL5D*X(6XWAgNuMcH;0BF4wSqblkAjA+1ag>=)h7 z!^3mH+|1a9EBm>3#NHj;=MUs_G*^gF;f_>W5{?>(CS!RFJV@?XNpk|)6KjJ-dj$Kx z!Rqkv>{P&`9I1|oGcXK^06=fs0D=g9Tr>}lj((6I8smedO1fh`@kCu|_Om8wNxX-y zw1Wmh4dG{m^}?Hlkg>KQRwzt}4+iQXt*| z1EnSZGNJnDO8<+LBLXRDL?UA)H2|8b7?8S#q!tta(uAl(p(>JKHP9)b+9@Ciq6*T4 zsjI=jV98&XG;k1coI=^+aubY6hPIL<}&?P2n0U_;%~=9%CAImQw9t| z`vE}!H6Veo9oJvh6sisO-!%Twnt}@U!vbxv6jA^g!>tGI=CcI|8V&hM^Jk6vWubKnrrpNK5(`*5eGtA#S6Yw?>#x&xd5N<&$+?CNt!BrBTVBpdBN z0QWaA*yV2^cnzK^jyWoF0XHJiJN}86LGi@IUTnP6rvE;4o;E*~{bM~RbbfEM`@@4g z&hV>BJe7xd9QR(3;>zcSJQt)c#qe+??;l(#yn`!M{^Ux>y*w&^{@)p%mZA=3y|OOY z7qcVp^z%^3%ro|?70WCP`%AC++k_zL3jJWkb$>)ouGs)9<1s$zSx)Iqc&YYRVY`-d zJ*(pePDFpK)BUG)h38%6lg+R;ai~1rLvhh{(s`E~UpJfev@!5axIYz^8%PRNd`f_snbJH^aojuB}kJsnm%8NONZ z6Z#=yS&NstWd$_Zrp2P`O#_1sS!n{ANbwWTGR*CyCK^-fLS|ORfXA4#-rX---0s*- z`<*M(&gKZbzYYp_uE#?ceThM4*#ZkD_f!uGq_mN5SrJv-Oq8pyhI{)@xHR?JW2 zzNM&s>vM0u4uQZyjOV#e$hopovZODMFx3G9G?1xFUtq&C{eY7*RxjFIy8VT6p-nhBml_4SQ1ZI|uC3i|n+5!{p`{KD&WW3?i}0-Ad*Zt1#sWL)Jrn)=pX-ja z2N{oD+nB@vJmrTKec90O*#Sj1kS)|YdYtt2tXuJ_3^8IcCuA4o#O~waXEwZ-Woele zG+bLvqb|-%tBdjZHXEp1*Ad^#J2z~|tT?vs%De1_HKelbK4^@cQ|+WT^!>Y}r}Skv zZ2HX4NX{4sliEQ^lT-rO#>F@I(^m#!I%x!{ZC@a>{B#OG_KQ zo3kI*m*0QG*cT=?*U6{YhfnOmlEsj{UKuDQi^4t)yZOyartMrHPqkL;0jQ`th{$^^ps z35_>xb~pFiqvFyDQ+#ZNBcn&BEptI@Y+#`5N-)eN0Bkb}P8CbWf^*uenYXNt4|K%n z(^fA`vRm$3zlVS=u&y^xMor`@;1@iGYIse$^*8QbO8dz7tx{hE zoL5wJ|0|us>5gXHQ>rMp4I5sg))3c1pLf1U98xV6+!KBNJ^8v$d*AA~;?Lj&aab6M z{p}NB>GN@9{%NI_p?k6N!dWYq43pcL&L-xfk;`E-KJEoY!MjQbtnqNM2?k@|3G1!F z{L+@DjB)bB>S9?vnc!@ulKF1ygWkr@_W0fehray*x%lbTv*$Cj?bV^5PmOETTyC7M z!tYcNM>icNY8xJ`9NCQ!8you2UFP(?o7iB{8Cp7M=)UF9D0sTEU8>kP|*^uY-eT1KHOzSz84$Bn12>LOJ+nVw4)THsWZPs@}rZHFn7I1u>|U?2SO@#x7Nv!j-x(wf1W@10NSWCIQP5 z2DtOJ2}VWJgz@0fm*smK?z+=Tf*e#`L zZmG)b&<{z2!AIOFk?!v#Zt30>)|4G0_PE5Bi_I)P zvjX3P^`#Fz&R>05w8+8*_|AU92us}mmVTDCyi#V~aj*Ct>LR}!zqT|H{Nz?@|4OI6 ztKGQ{jxiqxju@3Pue~F3fO^xku^2f&D(B;^5Iejn5>c3Pdv%I&*A{loXU#5q&bI$z z-Vma&d%Sn;tr3&WgNINx293e1OS&XVyM+M*Y^Xb_1AhgCr zcm`g&(X(O1Qi--v+WK52o;VqjfPF4b@ZD!!=veS9zqX=y?33hbXti9Ga;XoUp>&EY zms5Hy##re(C+|)Z+P$Fdcs=k_xRi2@Yr`F9+>`^$!z9|!MC)kA9@MInqXMN-HNZBOT1cG~?q0Oo}sH5@%RI%OLrCt8L0m!`6uyZXVrT5N6=paa~O zmQj{+6Y!Dg6ltB4U0n-WpWEfX=o&&ZXsNjqsy%f3K~QTbzeWC$`6`)1`|v6c9Q^7v zd;76_BBoL(3TernwMiAbZ?`B|PboGM*WW+9+gjT6s^Ya^S5GZ6_Qm=w*SxDv)(%fY zsbYDE=$=L*Vu)c+L!j7qot^XnXK>g0@ z6};Lv5mo^su3JXeBf_o5&)rRwo~pf)vb-K+S_HDEb9ZXjPGxQ0N>BJmp7@&C9)I{? zj-9w`@fgu*qb^p68ancw0>$MBPKHVJpHntjFbS^?Na1&YUr~JaAopij4tF)f*~(3i zuZRk;=SRhB^SUx`#L?7Qx4PW zn>u3o9(|^zt2a(mMPxj0Wn?ta?7Br1Mxs>s^zv<7&GJo3*`D{oBJ7S!_Q5^ROgHl% zur@59O^_5bY!t%pxp`^$UfStkF+VkPX4Rs@#S4Zys@(Dje`8*A%*W)XV2)g}nFwZ=cztET z+D3JD3603zYskON$6vfWLLQo}ZtQvMR&3SEH;41SH_GId4~ZPFcYPXu_pDUmS{-&W zEx|{&T;KMx6?C)?ciC}6g?@4O*4~ALm;Zl9f&YBCP-u +

CASE STUDY:
Finding Millions in Potential Savings in a Tough Retail Climate + +

+ + --> + +
+

案例研究:
在艰难的零售环境下寻找数百万的潜在成本节约 + + +

+ +
+ + + +
+ 公司  Nordstrom     地点  西雅图, 华盛顿     行业  零售 +
+ +
+
+
+
+ + +

挑战

+Nordstrom 希望提高其技术运营的效率和速度,其中包括 Nordstrom.com 电子商务网站。与此同时,Nordstrom 技术公司正在寻找压缩技术运营成本的方法。 + +
+ + +

解决方案

+在四年前采用 DevOps 转型并启动持续集成/部署 (CI/CD)项目后,该公司将部署时间从 3 个月缩短到 30 分钟。但是他们想在部署环境上走得更快,所以他们开始他们的云原生之旅,采用与 Kubernetes 协调的Docker容器。 + +
+ + +
+ +
+ + + +

影响

+为 Nordstrom 构建 Kubernetes 企业平台的团队高级工程师 Dhawal Patel 说,“使用 Kubernetes 的 Nordstrom 技术开发人员现在项目部署得更快,并且能够只专注于编写应用程序。”此外,该团队还提高了运营效率,根据工作负载将 CPU 利用率从 5 倍提高到 12 倍。Patel 说:“我们运行了数千台虚拟机 (VM),但无法有效地使用所有这些资源。借助 Kubernetes ,我们甚至不需要尝试去提高群集的效率,就能使运营效率增长 10 倍。” + +
+
+
+
+
+ +“我们一直在寻找通过技术进行优化和提供更多价值的方法。通过 Kubernetes ,我们在开发效率和运营效率这两方面取得了示范性的提升。这是一个双赢。” + +

-— Dhawal Patel, Nordstrom 高级工程师
+
+
+
+
+ +当 Dhawal Patel 五年前加入 Nordstrom ,担任该零售商网站的应用程序开发人员时,他意识到有机会帮助加快开发周期。 +

+ +在早期的 DevOps 时代,,Nordstrom 技术仍然遵循传统的孤岛团队和功能模型。Patel 说:“作为开发人员,我花在维护环境上的时间比编写代码和为业务增加价值的时间要多。我对此充满热情,因此我有机会参与帮助修复它。” +

+ +公司也渴望加快步伐,并在 2013 年启动了首个持续集成/部署 (CI/CD)项目。该项目是 Nordstrom 云原生之旅的第一步。 +

+ +开发人员和运营团队成员构建了一个 CI/CD 管道,在内部使用公司的服务器。团队选择了 Chef ,并编写了自动虚拟 IP 创建、服务器和负载均衡的指导手册。Patel 说:“项目完成后,部署时间从 3 个月减少到 30 分钟。我们仍有开发、测试、暂存、然后生产等多个环境需要重新部署。之后,每个运行 Chef 说明书的环境部署都只花 30 分钟。在那个时候,这是一个巨大的成就。” +

+ +但是,新环境仍然需要很长时间才能出现,因此下一步是在云中工作。如今,Nordstrom Technology 已经构建了一个企业平台,允许公司的1500 名开发人员在云中部署以 Docker 容器身份运行的应用程序,这些应用程序由 Kubernetes 进行编排。 +
+
+
+
+ +“了解到早期的社区支持和项目迭代指标,我们肯定 Kubernetes 一定会成功的,因此我们以 Kubernetes 为核心重建了我们的系统。” +
+
+
+
+ + +Patel 说:“云提供了对资源的更快访问,因为我们在内部需要花数周时间才能部署一个虚拟机 (VM)来提供服务。但现在我们可以做同样的事情,只需五分钟。” +

+ +Nordstrom 首次尝试在集群上调度容器,是基于 CoreOS fleet 的原生系统。他们开始使用该系统做一些概念验证项目,直到 Kubernetes 1.0发布时才将正式项目迁移到里面。Nordstrom 的 Kubernetes 团队经理 Marius Grigoriu 表示:“了解到早期的社区支持和项目迭代指标,我们肯定 Kubernetes 一定会成功的,因此我们以 Kubernetes 为核心重建了我们的系统。” + +虽然 Kubernetes 通常被视为微服务的平台,但在 Nordstrom 担任关键生产角色的 Kubernetes 上推出的第一个应用程序是 Jira。Patel 承认:“这不是我们希望作为第一个应用程序获得的理想微服务,但致力于此应用程序的团队对 Docker 和 Kubernetes 非常热情,他们希望尝试一下。他们的应用程序部署在内部运行,并希望将其移动到 Kubernetes。 +

+ +对于加入的团队来说,这些好处是立竿见影的。Grigoriu 说:“在我们的 Kubernetes 集群中运行的团队喜欢这样一个事实,即他们担心的问题更少,他们不需要管理基础设施或操作系统。早期使用者喜欢 Kubernetes 的声明特性,让他们不得不处理的面积减少。 +
+
+
+
+ +Grigoriu 说:“在我们的 Kubernetes 集群中运行的团队喜欢这样一个事实,即他们担心的问题更少,他们不需要管理基础设施或操作系统。早期使用者喜欢 Kubernetes 的声明特性,让他们不得不处理的面积减少。” +
+
+ +
+
+ +为了支持这些早期使用者,Patel 的团队开始发展集群并构建生产级服务。“我们与 Prometheus 集成了监控功能,并配有 Grafana 前端;我们使用 Fluentd 将日志推送到 Elasticsearch ,从而提供日志聚合”Patel 说。该团队还增加了数十个开源组件,包括 CNCF 项目,而且把这些成果都贡献给了 Kubernetes 、Terraform 和 kube2iam 。 +

+ +现在有60多个开发团队在 Nordstrom 上运行 Kubernetes ,随着成功案例的涌现,更多的团队加入 +进来。Patel 说:“我们最初的客户群,那些愿意尝试这些的客户群,现在已经开始向后续用户宣传。一个早期使用者拥有 Docker 容器,他不知道如何在生产中运行它。我们和他坐在一起,在15分钟内,我们将其部署到生产中。他认为这是惊人的,他所在的组织更多的人开始加入进来。” +

+ +对于 Nordstrom 而言,云原生极大地提高了开发和运营 +效率。现在,使用 Kubernetes 的开发人员部署速度更快,可以专注于在其应用程序中构建价值。一个团队从 25 分钟的合并开始,通过在云中启动虚拟机来进行部署。切换到 Kubernetes 的过程速度是原来 5 倍,将合并时间缩短为 5 分钟。 +
+ +
+
+ +“借助 Kubernetes ,我们甚至不需要尝试去提高群集的效率,目前 CPU 利用率为 40%,较之前增长了 10 倍。我们正在运行 2600 多个客户 pod ,如果它们直接进入云,这些 Pod 将是 2600 多个 VM。我们现在在 40 台 VM 上运行它们,因此这大大降低了运营开销。 +
+
+ +
+ +速度是伟大的,并且很容易证明,但也许更大的影响在于运营效率。Patel 说:“我们在 AWS 上运行了数千个 VM ,它们的总体平均 CPU 利用率约为 4%。借助 Kubernetes ,我们甚至不需要尝试去提高群集的效率,目前 CPU 利用率为 40%,较之前增长了 10 倍。我们正在运行 2600 多个客户 pod ,如果它们直接进入云,这些 Pod 将是 2600 多个 VM。我们现在在 40 台 VM 上运行它们,因此这大大降低了运营开销。 +

+ +Patel 说:“如果我们能构建一个本地 Kubernetes 集群,我们就能将云的力量带到本地快速调配资源。然后,对于开发人员,他们的接口是Kubernetes;他们甚至可能没有意识到或不关心他们的服务现在部署在内部,因为他们只与 Kubernetes 合作。 + +因此,Patel 热切关注 Kubernetes 多集群能力的发展。他说:“有了集群联合,我们可以将内部部署作为主群集,将云作为辅助可突发集群。因此,当有周年销售或黑色星期五销售,我们需要更多的容器时,我们可以去云。” +

+ +这种可能性以及 Grigoriu 和 Patel 的团队已经使用Kubernetes所提供的影响,是 Nordstrom 最初在云原生之旅中所起 +的作用。Grigoriu 说:“在当下的零售模式下,我们正在努力在力所能及的地方建立响应能力和灵活性。Kubernetes 使得为开发端和运维端同时带来效率的提升,这是一个双赢。” +
+
diff --git a/content/zh/case-studies/nordstrom/nordstrom_featured_logo.png b/content/zh/case-studies/nordstrom/nordstrom_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a557ffa82f12e9172639a30014f60c19cee74e22 GIT binary patch literal 7352 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%0DTu4DD-z2Zi$SC(#VDWNxd`Y@D(?mqm+rbw00h z(BY=OF1U!1D*yhII}>^&$(Kv1Lp|BPd-$O!9!3B8-b8lTH(zAI+EgR6jVyq4%C^qg zcgHZ2_-@qiQO{fgECcz2Qnx5*|NC-<&aTm=^8}St<3`N1`DYh516$*pTa4y_Q+GWQ zy?(1AUF;_&nvQ#M`bBy=OWILbv31kl=KGlX4J0hd5t9(ilKNvIx zV@zU~ZNi>WwJe%aD6~#vTWBfNRQ3ag&^WWr869AT>t1h65#fPGKSTh)e)_CXx`->`tJ{TVEb4MXl-?TK|q`Ab7=9&)PdrFhm_=M8Q?rwH7doK2;9Df?9G8YyVU3picX52CgZBqbMn(tKYfc*r zjthCbzC|?)@#Db>mZ#xv6CvTy&UnJhS`#agpRkr}OS)l_m4`PeHiw-LROQ*xQZ9 z4Bb<$XQ5Y%`b1O0sm_<_8XwcE4=YK6Lms7SsOe<{^l)%?P5>Cb#PP#QeIwe4oEn2VFHo!}GZq4Th>MHjqQ zNl;&Na9+hXk+(n3)_VZ%NU|6G2{ar*bVY_0QXIAwX4mvOl{ZTIJ;C09Gf(9+UK0gYvsQnF;dnaGKRD0O*x`Fv<`O_-oo@9_Z0 z*WbT+SK)HnQ+G!_CZYY;InIs!o}UAe&79&08O35P6I0XS=e%7G`pF^hMzf&;a&nfb z$qe1^>?CQUF6j@k?e1H!Bp>>VC`>N;lMVEu;dry4sKkUD<9=5Y2d?>5Z4FO1$o8(5jdd8LX~{3#q7XY+t13aX+|}@~6?l(Gu=5Q86J} z+e+T&iXk<7x!EHHi29y*GEE^K zTx;8Q2=>Ib?>V`}Ay@F#qsndd<`YxrO{brEX{h0*o?nxZnRKg9lb}&fU@YK%1N5kX zcH;*CA8$BL38lULOd}`QQpvnkn>N1#AYu0c!k>)=pbp>Uf<5FDce1jY0(#DAsi~(? zI6J#Pg_A$i()^o^beVge-`--HVKTMFfdM63Ad>Po6aq==&84MX#yPKJVGrzE%CfH} z7RFq;ZYD97hH-wS0`!dEXjmj9!$OS!FPp5kmht*Ao{(@k57CWyH%6?)aPm4pex@#J z+t!v8xbzpT=$o?5@ymszkKan{)1MlWP67?0jTQ_F5DQtOMasdqDNi`nSRiyK z2;%Zhidt9IUZ7~KccCb%GDejYrCm3mUS2By-|O=KKQ9LUeyecf4==^VGwg=O3>|al RIZodtYO5O{YgF%s{TI$2raJ%t literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/northwestern-mutual/northwestern_featured_logo.png b/content/zh/case-studies/northwestern-mutual/northwestern_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7c1422f32b86d6f3eb930b33467899db662b14e6 GIT binary patch literal 10083 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

Gda%H|g|!l%DjX=<#=S4tsgEo8jCG$HK^ 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 oBbQYHlkUGZ2Ffi_@% literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/openAI/openai_logo.png b/content/zh/case-studies/openAI/openai_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a85a81ea063d0cd80218f48c376547313a47fd73 GIT binary patch literal 19818 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/pearson/pearson_featured.png b/content/zh/case-studies/pearson/pearson_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..6f8ffec49e6efbba25af84b21319bcdac403a2d0 GIT binary patch literal 7784 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 f|CErfQWf%o9kh9p1%7(>cv?e literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/pingcap/pingcap_featured_logo.png b/content/zh/case-studies/pingcap/pingcap_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8b57f417ae813fd368487bdaf0e2649bbbf49893 GIT binary patch literal 7082 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/pinterest/pinterest_feature.png b/content/zh/case-studies/pinterest/pinterest_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..ea5d6257894681f6afb0f969c3d0cb5b4bd371ac GIT binary patch literal 9118 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 bDj9+}Co@&exntg+KV}p_DzatL@BRM^K`Oyg literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/pinterest/pinterest_logo.png b/content/zh/case-studies/pinterest/pinterest_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0f744e7828cc2c0643135267fa2a7f1d5fb0813a GIT binary patch literal 9003 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/prowise/prowise_featured_logo.png b/content/zh/case-studies/prowise/prowise_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e6dc1a35ec23820168c566875326b85b11a572a0 GIT binary patch literal 7621 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/ricardo-ch/ricardo-ch_featured_logo.png b/content/zh/case-studies/ricardo-ch/ricardo-ch_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c462c7ba565c222419869dcb5f187965c54d760f GIT binary patch literal 5248 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 S!G9G2$lq0wDU>pK`u_ku*xgnD literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/slamtec/slamtec_featured_logo.png b/content/zh/case-studies/slamtec/slamtec_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..598db9fe43a94cb76ceb9e9273112e633fda1bdd GIT binary patch literal 16423 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/sos/sos_featured_logo.png b/content/zh/case-studies/sos/sos_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a97671af6d8f57c10a2cb52838477c26f7fab706 GIT binary patch literal 6662 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 JR;pqb_Fv7ME!zM9 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/soundcloud/index.html b/content/zh/case-studies/soundcloud/index.html new file mode 100644 index 0000000000..c3c99ba715 --- /dev/null +++ b/content/zh/case-studies/soundcloud/index.html @@ -0,0 +1,4 @@ +--- +title: SoundCloud +content_url: https://www.youtube.com/watch?v=5378N5iLb2Q +--- diff --git a/content/zh/case-studies/soundcloud/soundcloud_logo.png b/content/zh/case-studies/soundcloud/soundcloud_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f8c12f05b5edf6aaac4ef457ca3eae367f2ebb98 GIT binary patch literal 22800 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 LD4rww`04)xu@gFQ literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/spotify/spotify_featured_logo.png b/content/zh/case-studies/spotify/spotify_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..def15c51bfc14be96be75f9064f8d6d7822aa601 GIT binary patch literal 6383 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 MqM$BcBxmmbUj@3=i~s-t literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/squarespace/index.html b/content/zh/case-studies/squarespace/index.html new file mode 100644 index 0000000000..b78180f52c --- /dev/null +++ b/content/zh/case-studies/squarespace/index.html @@ -0,0 +1,224 @@ +--- +title: Squarespace 案例分析 +case_study_styles: true +cid: caseStudies +css: /css/style_case_studies.css +--- + + + + + +

+

案例分析:
+
Squarespace: 借力 Kubernetes 提升效率和可靠性
+

+
+ + + +
+ 公司名  Squarespace     地址  纽约市,纽约州     行业  软件服务,网站构建平台 +
+ +
+
+
+
+ +

挑战

+ 自从 2014 年,我们从 monolith 架构移植到微服务架构, + “虽然解决了开发端的问题,但却带来了架构组的问题”,Squarespace 网站可靠性组的主任工程师 Kevin Lynch 说道。 + “5000 个 VM 主机上的部署过程,让每个人都举步维艰。” + +
+ +

解决方案

+ 网站可靠性组开始尝试使用不同的容器编排平台,然后发现 Kubernetes “解决了我们所有的既有问题”,Lynch 说道。于是整个公司在 2016 年开始在自己的数据中心中运行 Kubernetes 集群。 +
+ +
+ + + +

影响

+自从 Squarespace 开始全面使用 Kubernetes,伴随着网络技术栈的革新,部署时间大幅减少85%。 +以前,他们的 VM 部署需要耗费半个小时;现在,Lynch 提到,“一个人可以生成一个模板应用,在五分钟内部署,并将实例容器化,并在模拟环境下运行。”正因为如此,“开发效率节省了大量的成本。” +他又补充道,“当我们开始用 Kubernetes 时,我们可能只有十几个微服务。而现在的任务栏里面已经有两倍多的微服务正在进行中。” +Kubernetes 也同样提升了可靠性:“如果一个节点宕掉,马上会重新调度一个新的节点,没有任何性能上的影响。” + +
+ +
+
+
+
+ +

“一旦你验证了 Kubernetes 可以解决一个问题,每个人都会立即着手解决其它的问题,无需你的布道。” +

— Kevin Lynch,Squarespace 网站可靠性组的主任工程师
+
+
+
+
+ +

从 2003 年宿舍起步, Squarespace 已经为数百万人提供了网站构建服务。

+ + + + 但在幕后,公司的单体应用却让开发人员在平台创新上举步维艰。所以在 2014 年,公司决定”走微服务之路”,Kevin Lynch 提到,Squarespace 网站稳定性组的主任工程师。 + “但是我们还是一直在自己的 vCenter VMware 虚拟机[我们自己的数据中心]上部署应用。微服务解决了开发端的问题,但是让问题转变到了基础架构组这一边。我们在5000个虚拟机主机上的部署流程让每个人的开发效率都提高不起来。” + + + + 在尝试过另外一个容器编排平台,“非常痛苦地拆解它”,Lynch 说道,我们组开始在 2016 年年中尝试 Kubernetes,发现它“能解决我们所有的问题”。 + 将 Kubernetes 部署在数据中心,而非公有云上是我们最大的挑战,但在当时,并没有很多其它的公司会这么做。 + “我们必须要自己摸索出如何在自己的基础架构中部署它,我们也必须要将其和我们其它的应用做集成,”Lynch补充道。

+ + + + 与此同时,Squarespace 的网络工程组也正在革新它们的网络技术栈,从传统的 L2 网络转变为 L3 脊叶网络架构。 + “” Lynch 说道,“它给了我们服务器直接通过架顶交换机通信的能力。我们使用 Calico 作为 + Kubernetes 的 CNI 网络插件”, + 因而,我们可以为每个 Kubernetes pod 分配 IP 地址,并将它们和其它仍在虚拟机中创建的服务无缝衔接。 + +
+
+ +
+ +
+ 在尝试过另外一个容器编排平台,“非常痛苦地拆解它”,Lynch 说道,我们组开始在 2016 年年中尝试 Kubernetes,发现它“能解决我们所有的问题”。 +
+
+ +
+
+ + + 几个月的时间,它们就有了一个稳定的集群供内部使用,并开始在生产环境下使用 Kubernetes。 + 他们同时还在自己的云原生技术栈中用到了 Zipkin 和 CNCF 项目 Prometheus and fluentd 。 + “我们换到 Kubernetes,就像进入了一个新世界,我们也同时改进了其它的工具,” Lynch 说道。“它让我们简化了流程,因而,我们才能更加方便地从模板中创建整个微服务项目,生成代码和部署管道,生成 Docker 文件, + 并迅速地将可用的、可部署的项目发布到 Kubernetes 集群上。”在 Dev/QA/Stage/Prod 不同环境间的部署也变得 “异常的简单,” Lynch 补充道。 + “现在,环境间的配置差异变得很小。” + +

+ + + 而且整个部署过程只需要五分钟,和虚拟机部署相比,几乎节约了 85% 的时间。 + “从端到端可能要半个小时,这还没有考虑可能需要基础架构工程师来做这方面的工作,因而,也还有一些业务上的延时。” +

+ + + 部署变快之后,“开发效率节省了大量的成本,” Lynch 提到,“我们有个组想要实现新的文件存储服务,他们就径直和我们的存储后来做了集成,而不需要我们的参与”,这在采用 Kubernetes 之前是不可想象的。 + 他又补充道:“在我们开始 Kubernetes 项目时,我们可能只有十几个微服务。而现在的任务栏里面已经有两倍多的微服务正在进行中。” + + + +
+
+
+
+ + + “我们换到 Kubernetes,就像进入了一个新世界....它让我们简化了流程,因而,我们才能更加方便地从模板中创建整个微服务项目,” + Lynch 说道。整个部署过程只需要五分钟,和虚拟机部署相比,几乎节约了 85% 的时间。 +
+
+ +
+
+ + + 同样在应用程序的可靠性方面也有积极的影响。“当我们在部署虚拟机时,我们需要工具来保障服务散布在机架间,可以承受失败,”他说道,“Kubernetes 正好可以做到这一点。如果节点宕掉,可以马上重新调度,没有性能影响。” +

+ + + 另一个很大的好处就是扩缩容。“按照我们使用 VMware 的方式,扩缩容好像不可能实现,”Lynch 说道,“但现在,我们可以直接通过 Kubernetes 加入合适的扩缩容功能,然后,随着需求的增加而扩容。开箱即用!” +

+ + + 针对刚开始使用 Kubernetes 的人,Lynch 说他最后的建议就是“快速失败”:“一旦计划后,马上执行。Kubernetes 真的是非常适合快速实验,看看是否可行。” + +
+ +
+
+ + + “当我们在部署虚拟机时,我们需要工具来保障服务散布在机架间,可以承受失败,”他说道,“Kubernetes 正好可以做到这一点。如果节点宕掉,可以马上重新调度,没有性能影响。” + +
+
+ +
+ + + Lynch 和他的小组正准备开源一些他们的工具,这些工具用来延展 Kubernetes,将其作为 API 使用。 + 第一个工具在 pod 将依赖应用作为容器注入。 + “当你在发布应用时,常常需要一系列的依赖应用,例如,日志用的 fluentd,” 他解释道。 + 有了这个工具,开发人员就不需要担心配置了。 + +

+ + + 自此之后,Squarespace 所有新的微服务都将直接部署到 Kubernetes 上,而最终的目标是要扩大到所有的服务上。 + 现在已经有四分之一的服务已经移植完。“我的单体应用将是最后一个被移植的,仅仅是以为它太大、太复杂,”Lynch 说道。 + “但现在我已经看到其它的服务已经被移植到 Kubernetes 上,例如文件存储服务。有人解决了,而且并不复杂。 + 所以我坚信如果我们着手解决它,很可能回避我们所担心的要轻松许多。也许我应该接受自己的建议,“快速失败”!” + +
+ +
diff --git a/content/zh/case-studies/squarespace/squarespace_featured_logo.png b/content/zh/case-studies/squarespace/squarespace_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..551b6da32119dd8701405202ab8c861d63966a97 GIT binary patch literal 4539 zcmb_gc{tSV*C!MzYY|FgYzZ@F%rFLH8_S5vlBMu4n@pBrX6#9cB1=h;JzMEXNF=gk zP?oYpDWvQzWXm?T-`Dfh^S*!d`@QdbUGH4i%=g^qd$#-B=X1_|O^g-ZbT7XoKL-cL zUYr@$26(;$zTvz(fZrWX=~KW%f@$o?w57Q-0||5rhXI*Jq=0bVgwqro3V|H#*Gkdh z;NYTDPdG9iEiKR_nm2^7EdvSi_64*#ICS)ad(wx1Kt!S0Tkrz<-4N{Viw5XzHWUo{ zON8mE3;sJOM@uV^5sgj(At4&7Bp5;sq^SjgX{aHPFclD74WOwR|Orl6g~A|e zP;c+;ef=fPVA@drD~#VtGfo8iQlK^z2F;&N0?xx-_Lnk{yZ`KHTM&o_eVk4O4u#-_ zrIGx-DLzabRu>GsfsmQ5x^~=uh z^sz7l15Kocmb$T_F$`vm(n1-)4N;m%ga#Y|L%@xG>Ee7COo9)I^2;|B@cmO4^&fT7 zMsx~+Nu!^j(Y$_Dft3f1Nn?1>d_hJ=+oz6%AVEhg2_&k|Hd|@?sQ%tLmO`fnP{<~9 znm6dLT%)PKi9=lrg+;;*wbbDz$n8C#j5Rfk4Al*g>PA3p1}5O2y5!&F@29T8ztx2T z!9ceQ<-ZlqFBVXZ+vGnm02coMiQ)sGhYrBRYB_8efbK^e*5E`?|5QfcwFC#L=Zi<~ zV=K)gJY*e-b6>g*6>Yj>hRz$atti8%g zRqtG`X?|Lx96naP88rEREi7vxgOUBMZsr@NBoU>cppXb!?=b_5^MZ3h(a{mnN45zt zKR^I0fcSr5|KF^!(q-REVYWVZ=e@b_;818KgFy6B>jP(o>cZA?^YVJ~akjbGn3~{) zwmw5c;knI?wM^|m41LUOyzS;)eCCZvA=7*WNJEZxx6`SElO zZ}#`6Ga*AUB94!}-ajP0_&!wIzL!8C#7k*T^!Q5|S*9WG0Ri*y@0&dsX*bq(Gqz}E z)s9RaV=sPt5hpRaXu!`Zr}j8Mf0?S@bN|hscFMu?V{cbh=0<^pvrj=8n=7MNr?W2$ z9?sGZgvfthU6^z)pLmr%*^<~;ad47X$@Y$lO}^QOYJb0!$(6Xrc(XglKMbX;1LdRO*6z?@`y)*F}X+c`%)ubHE`S&qN~`6BZ?c zLp8xY$SJ_tfxQo2ml7I1`-)G7dU>e?ZqB_pT;h!JYZk$0psXJfoBJy~MP2IG=XbZi zNUBS2{3H%>)=%rZXM1|_>ziUuoNlD({nF%{ex491@13zHB?k2iNAU%e9%9k6ezQ}vms$hP6P~EbojCnsvhrS56+ot)4ZuSHNckXxtB3{OTIEc(dZufQY<#6E_zprD>O- z^fjvE@#}K9y0!1xNlRwd3e$vxn6pom#feOX7Qk7FbJhHKdkXb+evV^$56#RZ&j_}- zaOR52apala7V6oV+U0ZWbEc=ePnNoIj$T{sf9#!(pxT^{l0^A}XeTSq?AIE#1Se;p zPj_T=>TMkqndL9$3Qyi3@d-t7OO&LDcmbfxXQ9P!${!Oe=j2}8Qo&1W(dAOTru!@2 zn(a?RdW!jP4bbZM^6?G#FYb$b5#N<|ts_+56m=lyPH;wfxo00lj7!lh`Q#&aN}wzlJX=xXASLr8aORIK zb#l336u%bbyl8FcG9CbUP2nitj+nM%`ZfpnG=VdeLLjRsTp;K1;keykU)-L7Zsc_1bzR=*vspeQ; zjBHaZ`+S?HOI z`%&JbB`#yi7Yy~nH+8Dp)>k*zW*P-;yq*S3>!@=}L_L1#ykIkOZDImItEeKL`2qKB zH1)3D+LZc<_>H8jixY8hL&hb=Mi$FgQoiL|&IM5qY_7N}ww-gmtI?zoGCQEUw9h>UnY#`GCj&W4z0=vr z-2%=tiI3nee3t2_e;t4IqLS_<{%EN!t(eZhq2L$PJ*D2eW0RE~I!+b(n1sAO zQSD=LZX-K3Nq)DWpkl@f^Fync{hudVDf!mEhnk)#_VP#^f?R)iTfsA1C%7z@bM{S{ zs6&!~I=SVUcj1n70lpTXWcy9cAk6X7L9zs6iuLG%C~wNr=k7*NVL`eH;th8u=dwg* zP!!H?o@P2DeNAxFwA7#RCRjHp(yrAWavh86KudD#z3yy`;(Ou%58s=+v}nWzWGE+5-_RV zIG*!~D)bgwHwp>l4J$t-Ug1HuXBg&)k0Pm`%^XXdDm!)_PP;Tz>QM3rez}38S5+dD znqd>w}vDYg}1r`>ko*Aa!_dOOXrrNb> zBDBjGZ}1VooT$6Sn|lb4$y$3H*JHs+(NHN(A10p%om=+`)yQvZu!LXdH?@OF0&`g@4SxceI z-*d#KvR%VB{DC2Y?0%n|R)kX}4S+0xo<8lM6YF*t2WP)77+685YwkM2aBgqW$VeXHa8!Z8uEm-r|%__Zx59pSKUUb47ra zNOeA>tgTBQYl#(yriE;LYT$A|HsSf98abaJFVxj>$|M))#X=`9bLOaozP#~HbRDR7GyXDv^tvGfUGiyB!Byo{U(<^zk+XGiGGddM97TtiO$@ ztj$&8B!b^i2oAm{MXcJSWI@G3Bza`cxjce)!GOtoHP@?JhuH}d zrD}3=Se1Puk3E;Rve8Y?pBFnEJZsCi9|+6%nGKs8wd&W2wMwbu?Ez zwqt2yEZGuS!#mDX=XtO9I`8x6b6?l*zVF|CeLvs(^Id-T^1E(kqRYl2z{0@5z^1RK zZ9#8G=}#mxBfVZXd+J7S_{j)6vL(@j9OOpAFu>46cML!u?}o)#VBF9lelIa<3=GF5 za8`C?J7Xgi6cG<}JCXqg<9+F91_m{aU|%;sOT!ST@-*rLq%=njlssg zaEvETFO-C_3^lPrg?giu(V`ma0JUHhx&l0g>;?$N`w;w9f}x^+=~bckkA^{_fWJh@ z-cZqhk+L&31Hg$S3_u>JAdP~^$paLXfe-~*Ib~%jfD9O-1Oh98AhOaB1r<54ii`~4 zXAz~(MnZe2SZM3~oQwVj74;;OeN{l9pr9aNkSvf$!h#^m%E}56<3xWW_ zAUyuauD_)H$rhM@)A&bef2$B*49EiGPYfWT=<)El_zO(;-G83wNRZA(MVp8Uz+(tx zeQl^HeFTWcp;cgtT1rZa5FJH%IRpfPP=;yA$syoyc^Ec9za5Q-N$iYAPVo10^ z3|fao!~_2FkP7Y}SSY{|UW#rl8J3dbD!ZG zEXYEwTa80VicL+Tp@ylsZ|RK_X1*{)!f)uzAO=D43;d~kfTugpHB5ktK`Z-H{sYQe z{dz+qBP7m;#usW>Ijt^4-Df%TU#K$}c&Yab@&`S+Sx&~oM4TU_*h6dnTnTWnV&D&YBDHn z_Mc>vP>(M_9`5RrYCFkRdn@hg zajg>Cx3uz85lS;t)U74^wRgp)LB76kBDOb5v%9ByW#zY=L|E7L#X`qfjwFBJFWrOkb!#az?Vf|~nMNa=;4=W&S6=hj1bOL;6hlblWgucv(CBkd z3W~lQWt75@G0&ozfKHF?B)Gk*Cfg$;g90}{GXsp5m()AGWUR{B;@;o6WPDHP zJVKW1bA5e%`~L34y035;M-6+|dYqVkS7#^qqSq}Q%fP(`8w#DXd`Zx;fPC&KoD!WY z&nUWJr^B+?#E;zY5NB&^yL?H$jI&0dYtzHPz(B!gtVfOS+4NdebadX~h1$BZW4-5( zM}1u1ktzmne2GsD3=HgIiC#3bwe4DptB24$EHrP>s#a&F%MT z7WVD%TU*1L|L+T_KNzRs+PdT(2I3$BU>eRXVB?(Uzr*QRgr zj6ETKc#G+^EBjrKk?Hlo0C8yyLcAH;(bv}(7=1RX=k=uDc6W!Gx~XdCV}UZX^Co1T2YX$zy>#VLEq3B6TV7h@} zLc8J+4r#elol2V+76>pmH^lkHgUQYfPzE{=CZ%7Kg12*cUFyaAbEyoeoxW$K;K?_UaQJ;@$KWW~r*fBzqaKNhRn zy+WDZF&z_^xw5FrNkAe6wl$WeqGsO+L&GYK^w~K$M)PJW&XrGG`WV0TA=33-k+Hz? zn#p2dLR>>&G%iCqGc$9!v>b;7REJ%i=~mrqU8%{dG9Qn^`|)cvxOu zCi8s?@?;I%EDhP}Hhn4K0)QD@ zjFPXc)KahFkDi%X@+mU36w%N!b6joW6pD3pwsz_m^sY9@NqtP(m>+Bn+iIv_h!x8g zIuG-Wq&mszo97DW!eILa`T2mya?9s82OAJ4}J0a3#UXodM)3+)?+PL4IiDDm^fN>=#{MfT#bzZ_H?#yp_dZr(bO@{ zc#dd5CREv?x;fBxwGad7K1*T&{%84$a$8lS*v zc(o`*|BANf*FU09@k(WYxUTz%YqGPm2L=T_5u>`_YAJvMz_bXjs!*;UKE6fyr$GRD5#W^w7e`NN8!lSYE6=(3o` zkZC4E&#E~`+|a#y_XN^+%gcnz<-MSSHzn(m{2;+R?sp9-8NK{$s4lfKLL#A3Z|2eB zbb5MvO{31$y)SB^kE}}BMbv$a>Lt@8IUFOMPz#?v4X#=1-RAzmw>Ko&_3|Uvi35?C z4h~5X8P?s6wFa8g`0m5xi}%m^Q7Dw!67Wpkh0xwLVf~c>jYA(_%xyg}jUT}onaR_n zm)EXc8)>R9W9;0$Q&IHm=e%*9!Dwp!Rpa|#j;AKIFOcq)*Y z?u5@32YM%ZvC_Um)eCi2ib1*G3NmH={ry3XJ=opuH^)uO$_KKc*hiFWqdG|$U^m9D zo(gUHiaSzN$*&$B9N(gf#m)tIk8YM}Ji~=vN@i#NYHDcc-M5a)LB<{&d|uAvpYBc; zf4Moq(bscDNlED{7Io4muy z{R8|10!a;ksv-K8`ugVS^2q>)${t7H@NjGSGYV)V&xP#wsb#ELigS$G)Fj^qCC$F( zXJ=QzC1oilnq(`v)tp})EI8HMd(k1E>e}B!<~^0tb8Fu-6Sf`RMx|2o@>~v|YS!3E zkNR5(^sv`co=s&!P;sqLSvJFLrOcq(l9JX*Ed(OgaVv9PU0r=yxq0<&=Di2-cy{^$ zza`&nD1wU8r3PO+E<{6hCqZnX)wKN|`x71SzLjV(aVE6zo`w5eE^?^FCU-vSsE}rJ z>uliR=AH>}kIyVS)6~q)uTmHN$SS+PbAs5uyfAntq_EL0^y5buYgt+7x6a*Y7$-|p z3odGQsmWiYKOt{%okNL;1RjATU`K zbm74iH1(!rc*6-@1Oh*izB9juT7K~(k@s+Wnj`(txeGw!;aPBKc)XgIB6fz4&vWE> z(c9FwH*XptyERjdlfUTPbt9-~G zyWhw2z=p-lTC--}d4KUvjFyHXHU=3692^|BvXYz*_*@0wL1+lz=Y`gQ75E_alsEL$ zb$Q|W+R7aUCk=J6hS4ZHS=qvLU{+8cw@H{792_FVUeD0eP+d*L#>I)l>ah)nx05UA z4F@MC>FsJ|;|TMlv4+{&JB!nucK6fK*h9tX4EWW#)Lms^cJ@lX?l4_n4LuuQM;l=% zoumYfn70VHffLNripJaNrL%{Kw>aHD?kfU*f4s~|NAr&+o{r*l|2-%}buAiM7k3y9 zKZgLj4L2V@ji4|Gw*W7nurM194;Qx(CzlW>H!nN4fCwL#2oDdCn3C+F+euQ^`xa=5tLa&ij`3v+VuaPsi5gBI)_KF*$2-t5jE^#8hp z9L&SU-QLyH-o=^b@s3v3E?%DEbYP_a{R&R5>gxZ#v9rfNCkjj%r?-_WCpQNdr<2p; zd;O!eho=tge}?fNTYKpFxWYJfU>+`B?lxdOUeN!mGnl*o{Xvfn!DvL}Tx`6YV9uV( za^iI03J264D#9l#$gjX7BqYesC&SGxFDxy?$0si<%P%c2B+n(w#rvR$Z0wyMFFt#m z;D3%6=5GHA232r(aiaOh42jtPhfxT~%5w>D$;$I_%kVwEfv_CEjI6K_ubiy3Ag_?D zAl*OvLjS|t|Ff^c|FthC7!2p*^8O#o{jWXAtx5Ah^S`q?zI1 zm@Aa!r1iW%9_PRI$Nu#&me{s-&>Kmkf>zRgu&Q99k6vR!WZ;<*=Vfr(`+A6_spM&G zGy{G(jg@RPe(yAkfywpF=7rD3ui2wKUS{-XvR0C;^F+hf~5cL*|)-=zM#JaCj`%Q%J@*o zeen(S3O*Hp4W$%;O}!MxYkYkw-;tozmd@1usn!9k`%1R+t; zZqEL@pV{2*dlT?P7X5+ug@5l9*R*4Ld@i~=JC_?Q`d^)V>~!B>#Iyf%K1yuCz>8tg z=kK#Ok(|zI@RL|+QbSQuv7^pi4Ey5S{LR^! z_vOL+)Be9yPoH|+|Gsiut(VUG^5qLLr#aGFcS@}ZE2mFw`*b1{PNWf&smaQP_4 z&&5|#9%!X;>*4wCco0uyZ|{Ajc4;vEpDUeJ@n(1@)Cp5l)9U9nZO$8AY(~vkBwUZ# ziH9d8$Z@51l3Ov6sx=VLvv@_ZxVZQZIU0^kz0>uJjDf+b=<6Ss-#=7X4u%d#Vt2dk zMw%b~?S{w=oUApKLMKyZbNCUdl>{|4HS@;7)Hy6yM||DQVtHPDMywTh*?zp)o7+z* z`fAUm&;QrN#KXhGx4C?B9;njq%kRW&hFbNe!VrDD`$9H5z{D!YkQwNJ#vF$ zr%8p~p&#C=m-C>RkKEHB*6zI)m+&Ld=}L2p!Dj?P@Vr{DYB&nl&(H5&&}0hZe4%8! zH^vGHL8!s!ABz6;C`MXY^olrfs8UgJMC?QB;7QhJ+k>CSZnlCF6Mb&aig6=(B>_b$YbI=Mqm(bQ+Yjz2R(@8 zV3BO}2Ne?72mZ+BwH2D4oJ3a*iRtvcVyP!e^}G48@%nVriob(RxEBQPfu!C1=4Qc2 z>;c#`%;@(YTOE7gh#aAF1>(~&FF$v`)>K}nmhjKwwi&xU-yQuhlP_w(5_YN7tdwT# z7|*39`+`Eqb-PSC_4xRBsZi(e{?Cm?k2klxMxQ{HTBH!CMPK|ISWpN8awCr$fzzIw zqT=|63e5`D%!KfSQEq$d$Y3)wGg%p#j`rmmgWS9XWW6WpL~+$f-+5{R=@PdY0BcXkXXYU zx;Q%9DUe*`;0vQrYxiX|MM)EeeF(5Sl7w_jqNkKsw?oK>G`l1kJ|B7W<27&VD;e ztaF<0Yr%&Qzp$oR;-VIpEvh>s<>&+XN`m^(wc4dsDSL8(mjnI-%?Dy3qL~4|ewJsv zllBa}S~kdwHb#yv^WIEthD{$rlo1G+;uTTErMMImC<4cn3MKAW>P-Bu4$HmnlIazb zoMj~MMtN-HGT2S@8_at(SE0}|klcncO`l32MoVdVUrwen8>g%EAbu8pCQ3(V4RRud zQH4f+Vhz_KJ*k7kSUhQ1*>H`uB|M!DCjL?la;CK8K~~ z{EjE73Ta5*jcL!6e+W6YxiR#R>>VwZtIp@}PnTIm22C#gxjv!C`*V9cFtr;W(z1PB zAQ4bq%J6=7wqkT|GIg}10OTjl=MV`3N+!PrheorvYT0Y(hE0>VF}${ON!)j7T_Yo!scC;8gr45g;#& zJHT;5jMgXHvMkivEuDAA-nggc3OMofDOK2j4J@=A$Z+m|_GnXQ=hEP%!C7#fvgBnNSV$^pJtOeE>&O4?*E?a#YV8csO z(a55^MsanG#+{|4u^J@M|G7DB7#=0kMw8VNgGe6P4S1_0+Yl(l5hW($n01iG6_&6~ z#@srS=q>bsTz+t1$5$v8HY!!2LfAEmnLx&`!aWW0bc_3A(530ycjzjr(G{Q3J32r{ z8C5eT8gW_kzlVi|ZES257e-=}|M=XgD}tAU>Wor1Hui>GaNB^pt|A@}AOGhkmwq>7 zF5AU~&@bDT6mHAa&y|n%EWZ1yvzc{W0+404&wSeY1A8CiN9SJh1aUJ6(0&69L@tlRB45wAl%KmY`8?S{h9B_D1}(^1!Z z{RFRn0h}!R3b5R`c2F3Q09?sC8nX_!8+{h(DQ>LwZ0kZieI|d(L9j&6NTz7PJwK=Y87;A0QUVMDv)?7rXMkTv3(AHBVIX`z42@8szCSXN|()^U+-+^t-bKUYcsN|{0##Wl%hFVcHY~R z$!UR5rC(>Pyg8r3I1Ok)h<)u=;N^ifj)K8s;vU<4+GBavo8`MHxR!Gh8`LS3Ay4cv z`CY@j$6J~kByok`6w!-OQDqI+!GgYz6qpk&R#dXDN?!Y_GV z#l;~Tg+s_DQx2e3zY)fr6uIZ-!`W%|kT2p@-Gjf-*x%pp?pr7ku%?``TAZ2(L4sPp zu#)zYmI+LvtI8fqog!#rgRT*>>e~@YqSpgjLJhoA4_Siuv?p`?ijsu{S>N(&1AMQG_Y=0frG`OlB^dMsrp$QsP zYK2@@f3B;js1Racbuk9(Sl*?Ls-?4PJfFplxOw=w^PMLi7p_Vdpe!IMt+hFQ65R4H zeTcSpeqVyj0dFoBp8QA4rpya3LiuT9+I=p|RtoMo`Q~MndvDUQ4DB z54`iH>3~gVl!X_GvD|ELZ#O!wa?nH%)11uZi>@Mtjq)P3?_I#77lRCEn$}55QV8AwFJ@I=GF#mn=U2fjz;Z~+JojkB9%h*!pD_wlk0*)&)JA?@o!a5D+;u?y2_E+{w%~HEE-#{Y0xVl;v85Uy(orha10_wPxxzJgf;I8$BFu8}w*LyKAzt`(k=#t6sgDkp}Fj67KYfYm1C zL%FJL(|1xYzUsfa>ZX2 zjMqH2a}+v@KvOJ<77x(MMh+lJNJs$INjIF*%r293c5x9G9qq~=`9|#5Pz2^LOnQge zEZq`0bhvSk)|cxknNgSGAQK~phBrP;XL6RGMo`5ZX$UxdOp^%kwaYt) zvp0xtuI%LTpzJ<*a)5;1!0$=izjJzOQKp0!$4keM`%E?28puP4o^}h7tV6}*$CBV# zM2|6x<`A6H5qT>$HLMp47#I<%O5?@`SzK13gKLYHj+*8*`s^e?sC*D~*=+Ha0*cP3 z`$@EMY1SlSbdupW$(3DQ?dWp(n*pftr03~o?;Vhs>^k`~5yw$iH)`&V~sY zq0B8TVAiD4n&6$nXDbYpG-xoFZ->t2w0fWK7}CYbT4|N6Ne61iiiwDPgz7Wn6aOZE z7W8e7ay=Ey3IJEI3qSsDc?>)<-WOPml}SqJEYBAhfR1~&xr)9tS11{@(dDI+4dc2F z21s&05Q3Qgg|sQ^D&qymICnI2V9|IYb*?9?nE!2Kv?p6*MTISx%KW^%B@H7gxT&Vu zSDu?CK$Uo;I$Y4|*8-ucn!$$Gt6giz9Y^_e5T0n`CYFCxC0#5=a<~Ya zX$KcilT-*oC7mJC8_AbzjikIUAZc?ZXr&aAfq9x%#42&!$!^&KB#**?2ZoXOb!TVj zlSQ!%vYHzpL=ipDUicIP=YWcobg~BR=v}}#$<66j<~f$=t7E&*9d4nYarv0k zr6AP{dwktX1A#WF(TBIl&-`K{u~0Rk>D@bevw={c-J2udNEK46lakn%_boihG)TQv zA-X-XQ*CnJSBVoZ+IIL!V9>blEWb!^1qMV!9fDZfBPo`XC6Hn%vw=I2v6UT{oBE_O z1^)}DVzne0mu2wh=Ro+Y3*j2?^8;!g_e+o2RF0JV*R0@{7IaEc2_b^Uq{YrkVrqPF zP}&N%sk~3W`5g8Jxml(5Uh%K-@M$t7i4(DIQgd%N*5NW;6{Kw_fOOhN5@lMt2Sx+3K2y|L7}zWRBhh$= znm)E=ay-z9f#kzPs4Ee--}TFt$vVt)GiuAKW8Av;AHuaTlO zf>#-0%swrEpAW6$SSvy;QAKG8Sz4jpfdD6ax;Jl4io(+|8Wg-_c@UWkVW6GH=^(3x6+1GJ^57sV^`^; zwz2PwBYWD4HX7E#Ks20^f{|T7a@UD=_Qa^1`!*Y(>fHHEjggcvn}s52B2EeD#FO>l zXOdNYTGfLsOeh)tiQP*M5=4M8)Ez zb%$QH<`=JO(Kmi`3*hUc$x1YD!oH}>G^8#xSV*pC3Az+C>+)Fxy#@rXO&|v8ci?5+ z23#FFqU@SpAEyzns!hrGK+M~`uTu2>k{M@fO;3-JN4VP>r)TgmhNXYl)wa*B9dvXm zx7IIs?_1{=+MpJ)IE3{q#*kf{l9ICZrD(e}71FDYCBW*E*9ql*#*_HmE|wvs3#yYa z*Q-;qOgNO|)s5YFmudx?vMV4%_pHq^*_o0G;c{R8VT16_7~kmyskF1K1NIwByrIDDn@x~5hQfEvjzcL^QK^H^0w$De2IVaJ?fO~SN>pGo? zB>xl#+YlT?|f9mK~)}EvW7hnE`6FDnkivwNl%78ausSqG2CX^cncMWX~${{XNG_D>ia*9yaB zs0^8ClZtnXW=obEl`=F7CBy@M^9i+`*H7?dB{jn*e2qzuXZvwm$-TsuGEb7yppGRi zgRG*#wDML9mZ%-&lbam}`b&@kfzWeQ4g^(vnHBc-FTR-=w$IHV4*iI&(bnhb=wvNXjI%Q}B zwvs=EX=p4T?tXz*`yB8P*S#ANkFRQ4T3X)T9Xjaay(+yq*pV&tsL^`HmNtv;Wp|yM)&vk$frOWeQgj4D{XkD%Iyn$ zk!n?o-5}+S}2Dm>B8Xi)M68Cd)#y)TGYCwBJ@o*b9L8 zwxq=QJa3t6U95=Q3W-`4IR{;gtx?|YuN$qhzxJev2BP)@r?3E0YDAaZBak8nICFkEApNLS+Lc zfAiXLS$RYhEG_!5+GP-(h811Ac)oz7JIB=+G!$fJ8q@~hC7DD0&5 z`pt7>b*iMZ=rcKmXh?qo)+9|j*nqiN>U(HDNP%t5aArJ_@z=~g&t~yUknw1H_VMuW zbSpIEU)v@%=oWFu2n2hV~@YtuO@_Z_)_3ER5tM zHC+b!`*5n?cAQt6~dHYS86=FT=O~zBt06;*ZK@uN`*yNCBbuhCzwwjH!juCfxX zOSZUm%#vN1SlHF2BO=)OH-pzjz-W@~Gk5R;IguX$pLsm=sstSk$} zOmYTs)|pGAplsPp7Vzo9Qnf@Rh2jO0@^Ze3tTe`L#0V%yc}=2EJh@;(xC9_Ti6r^y zN`p=SbwMd)3S`n&Z@AB#%TEE_TQu$h4up6aEvSP~Dil_WSfAh`3@s?%tvJx=goD}& zCbWo)Vh%02UYneVtrthM23gI-0CwE_Z()RobIwiv0>#sB&tZfe!k+l z-eiO7z+g~sYJA^v72Pcw^C8bHYYSk`A_wzJz*sW{%pT?rwmvVUOv*Ncd8Gi`>)O3sWI$aSubm#-WzDd${-Gs-CyVl7q;R z@6Q)nv^g$S!jrbxy_X>kg>kiYeERfh*HWq5__Hgpf~-dAeVn-gxb!eVU0n&vr0!JfiIR?!vju?yoZ^iP1q>%w$^=tMFp ziux>Kw?M;>6hYSg`qY_gPQ|9FzbrG8_!t4{*)2$2Q$2Lb6lkBp7E(SEH~^k!$7lhO zYe7Q;CxIOgH6no$(Izm8BQS}p_3L80wDjW_>EDYt4;o^!^v+CL6Qw>A9Z#Ul1#VRS zm{w4@C=;Gd3p~8L`P;hUyISuQnb zetxo%Zxg;M?&~Z%8k&}~;Y!79CTC&#m4@%l4=1i`p`}a~{4s zv7x4ep|GSH`;rDu54H(ou5XFat0u`}j|uatGo8x(1SyefFiMKeqOYff>3tBu%;lYQ zu&64T9iUt@pC`;~wTjg1z8{;Ln>)C+g@tYx(eDF+UFrfgQXa(WN5p1m`7;aHGiM@W z^5X1qRLVKYump+&F0aES0Hn`}h$C&FYW!8RA3mh!mmr@UA49dDuu7W`uSD<6q_bwK z-CTaZ{qv*ybT8-038-3Fn^l^W6$}b3hN{)o7DWamODrE=C2KQ@c&0p!2-ho~Obb*J zIiJ(A1iM03R<^ul!jY~M=yrn4)}5d~CxSX{9jAH19&@>ZoFXD3eS+6JqnK%s9Ze(F zKrmt^=nL)zlrzSeUQl|3N&f%>P9N$M⋙hHPq-#4ku_Y_n_<1aR~W<`YE*oy zR-Y#U7y80-)&x{IFj7=+cwIeCH^sBAfOTPv_$D0<2M73YOysv^_8;C>Ny@0p1Om6C zhYD@IsHo^@wc(=2m|w`3!TD2+vK9#_*d<#{)YsQ*CHT^DGJ>)+BjyxvYXFrpGoFPZ zH7~w@pNyH3+)04r3oJOWcXU@3Ggu99Ml;0yUcpm0zz1tZW+=;KMq~%O0FMoL#lTUo zm{Ept0~x6C<13DK*BbN!5g5*j5Bu;i5*H9(z&R<~9b?k6yW9#>u83 z7%*Ski-9!DSmi-DVl-nTVr+@9s4oC!Cx}n>)#Es`;#vGAAde z$I8gogc`m6$D$BX{}|utLP<$$Pq6e^j&q@8t?mK9#&Ox`YPFrGx}Xa05iV7Dlf!Kj zITO?moy5P=5=<2edhiFi5|qd+MW-w76Wi!bu*yhcvDsk~&zq434wq{(`}-vw8kCah zKn#N^EuBz5cq+3q0YWOtqqPr{ijLBDIzxSl_ET{Dv~hASPtqqSA$pjb*E)btwR{mm zGz2XUA@4KGI>MrfTfnJML&5VFX|rZdCWsJU3_U5+$S13OcJVrwfhU_BX)hnt@PX6U z;^Xa2LzG@nY>B{!h`a{jFe^hEbo>4eduV$DQ25EAS$rW2{F{gSKVOy*QE>*+dJvNw zfxpcDN`K$^{FJLD#_c`5uw&h__82}CPNs~UPXH)Z4dUo+ zk-zaK(Y~Ud2U?~$846ZxTtdTBkbK-T4zM`dIH@suWveZ|wCJQMp+81)4z8ZHJ-4u< zdMslM3hfu@NK!m`0>@z`lr1dxCLS=R9fLB5Bm%b5DNupjjgVn5rbx^zPP)adl1FgJ zV!3EVWB4@W^Jq!rH@lLZVtqG6jm2)IcSJ^cJVmkg2~-=VyxlRbfF1^~C6|$XiR9tx zx&|(TLC$!UTSAk88hbG|n<>Sr=c72$G`p58%FWVqMsDUwK5*r_n zlx8~ec7^+%e0+R$DGSvItChL;Z*q)r*ra?7GAinD(XHdsCxB{YSDMBWPh0_&iqL|O znpCreu7RqFO#5MH#b#dsD@D9AT_@N*Y9iXQ?vEC$m@qh1Fu2-a(av+A!P4Y5V)|wk zuApuGs`~Qx(Av8TkT3>Qd2R}P;DiiOy(6Ncrd^4oWa}@luQxkAn8g@e8Pe%@V?mXp z(Q**9wXuVPydX+b%i%*Gy#~%ADE!dyP4>{J8D*uihW!M)8XWDA%YHyj9l1~AFeCFe zI!+rc-*%BQ1y-sd*NWG>%SJN-6>)1I11#lmaT9@)m@^ZEygkv6)(R5D^d2fxaVdCoC6t7V{C;W{vhIkvd~4AJsF6~~wemLSfP4C>%$+Y2a?B5m*O0V zwWnU2q~a+E5h%MDH2}CH3zZ^(jL@Iolj(XaU3KC!@n&!6!^?ra430&FYJnpfi=bUe zX=zhE99kO))NZpM0RN*b#wA8JK`oTqm9c@vgnkKCdFfIXjlRG_> zOeKwWk{t~u%>uT+!10^x*ahw>rI4#s1K+QBM+Y{Pm@Id*c4x}HaHB{Z;G)j-cM!#z z)@)pZN?o%vslWX>-1mhdeuK6dtig7>jdV5qC~wA->(ec2L?prC+6g%F>@K;6D&92}g*wzdufNnx|5PSm^@OBt&rG{ixCm16b<3BPYuQcMSl6O zR{$uluF{E!zgtjdE{C>+Vgll+k}*1jIiJltzPwDR$}ruzn+iQF^=1#LQnXeqSy~z) zD!(}$}-YFRB)erjN2NQzq&l`v$u1Arijq86nc*r?bB zen%_p4*`E4#M7>SY>58I%_|UeG3T;%aRKL8&O!AG5S3;{1)?MQno_Q&vN9g>@ObR# zQx+QEH8u>%+;vyNneQh(zUptNd=DT?vWmt3|DO!bcZG0>aASEUGbrrUB9DhzmE|?$ J>SZiL{|oPC!?yqc literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/wepay/index.html b/content/zh/case-studies/wepay/index.html new file mode 100644 index 0000000000..b8ce8201d5 --- /dev/null +++ b/content/zh/case-studies/wepay/index.html @@ -0,0 +1,4 @@ +--- +title: WePay +content_url: http://thenewstack.io/wepay-kubernetes-changed-business/ +--- \ No newline at end of file diff --git a/content/zh/case-studies/wepay/wepay_logo.png b/content/zh/case-studies/wepay/wepay_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4e35dd8fd694a189ca1e03eec452363c9bf8336d GIT binary patch literal 20277 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 +

案例研究:Wikimedia

+ + +
+
+
+ +

利用 Kubernetes 构建工具提升世界的维基

+

+ +非营利的 Wikimedia 基金会运营着一些世界上最大的合作编辑参考项目,包括 Wikipedia。为了帮助用户维护和使用 wiki,它运行 Wikimedia 工具实验室,这是一个托管环境,为社区开发人员工作的工具和机器人,以帮助编辑和其他志愿者做他们的工作,包括减少破坏。Wikimedia 工具实验室周围的社区在近10年前开始形成。 +

+
+ Wikimedia +

+ +“ Wikimedia 工具实验室对于确保世界各地的 wiki 尽可能工作至关重要。因为它有机地生长了近10年,它已成为一个极具挑战性的环境,难以维持。它就像一个大的泥球,你真的看不透它。借助 Kubernetes,可以简化环境,使开发人员能够更轻松地构建使 wiki 运行得更好的工具。” +

+ +

— Yuvi Panda, Wikimedia 基金会和 Wikimedia 工具实验室的运维工程师

+
+
+
+
+ +
+
+
+
+

挑战:

+
    + +
  • 简化复杂、难以管理的基础架构
  • + +
  • 允许开发人员使用现有技术继续编写工具和机器人
  • +
+
+
+ +

为什么要使用 Kubernetes

+
    + +
  • Wikimedia 工具实验室之所以选择 Kubernetes,是因为它可以模仿现有的工作流程,同时降低复杂性。
  • +
+
+
+ +

解决方案:

+
    + +
  • 将旧系统和复杂的基础设施迁移到库贝内特斯
  • +
+
+
+ +

结果:

+
    + +
  • 占 Web 流量 40% 以上的 Web 工具的 20% 现在都在 Kubernetes 上运行
  • + +
  • 一个 25 节点集群可跟上每个新 Kubernetes 版本
  • + +
  • 由于 Kubernetes 数千行旧代码被删除
  • +
+
+
+
+
+ +
+
+
+ +

使用 Kubernetes 提供维护 wiki 的工具

+

+ + Wikimedia 工具实验室由四名半付费员工和两名志愿者管理。基础架构无法使开发人员轻松或直观地构建机器人和其他工具,使 wiki 更易于工作。Yuvi说,“它非常混乱。我们有很多的 Perl 和 Bash 缠绕在上面。一切都是超级脆弱。” +

+

+ + 为了解决这个问题,Wikimedia 工具实验室将其部分基础设施迁移到了 Kubernetes,为最终迁移整个系统做准备。Yuvi 说,Kubernetes 大大简化了维护。目标是允许创建机器人和其他工具的开发人员使用他们想要的任何开发方法,但使 Wikimedia 工具实验室更容易维护托管和共享它们所需的基础结构。 +

+

+ + “借助 Kubernetes,我能够删除大量我们定制的代码,这使得所有内容更易于维护。我们的用户代码也以比以前更稳定的方式运行,” Yuvi 说。 +

+
+
+
+ +
+
+
+ +

简化基础架构让 wiki 更好地运行

+

+ + Wikimedia 工具实验室在最初的 Kubernetes 部署中取得了巨大成功。旧代码正在被简化和消除,使开发人员不必改变他们编写工具和机器人的方式,这些工具和机器人的运行方式比过去更稳定。付费员工和志愿者能够更好地解决问题。 +

+

+ + 将来,随着更完整的迁移到 Kubernetes,Wikimedia 工具实验室希望使托管和维护帮助在世界各地运行 wiki 的机器人和工具变得更加容易。该工具实验室已经托管了来自 800 名志愿者的大约 1300 个工具和机器人,每天提交更多工具和机器人。占 Web 流量 60% 以上的 20% 的工具实验室 Web 工具现在运行在 Kubernetes 上。该工具实验室有一个 25 节点群集,可跟上每个新的 Kubernetes 版本。许多现有的 Web 工具正在迁移到 Kubernetes。 +

+

+ + “我们的目标是确保世界各地的人们能够尽可能轻松地分享知识。Kubernetes 通过让世界各地的 wiki 更容易拥有蓬勃发展所需的工具,从而帮助到您,” Yuvi 说。 +

+
+
+
diff --git a/content/zh/case-studies/wikimedia/wikimedia_featured.png b/content/zh/case-studies/wikimedia/wikimedia_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..7b1f89ac98490d8c64ec722375bbcae0d8ec9880 GIT binary patch literal 21322 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/wikimedia/wikimedia_logo.png b/content/zh/case-studies/wikimedia/wikimedia_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3ad5b630342048494a4ce20f52ea46c310c431a5 GIT binary patch literal 7875 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%0AwOxR>&A$MvnP6#U}J3!Na*I1 zr=6XhJ#Xj-qKb-&auBNE948YUo%b%51_qprHfm}=L(k{^?{Ck40RaFwaP;2f)TAo5 zpr%G2{BI%npcXaG!_ICCDB82E5+^#_!O@Q)e0r~)oSdqHs~v`hGhT3EtP-T}Z;k;< z0P1Go1IhPpIUas-(6CCXHFkBnYJ$U`~Ki;reV3@Ie32 z(0n`kUUbq7FT1KrS0`z3aB!!rd4JZu{gZJA0;Z2ZbkOj^V29VYr6#qKK_@WVr!QUv z1LXteT}z7;DBar_%YMKL1t%pXA=C+pX$0LDS^%TV+pbW6ivUVwCq2N8$ji&))+=C; z326Wd3gsrDZJkUYb*L_Oaj1ZGjE$#DO~o!Jc252FW_-I|kpR$k{uGThc&@_ofl&Eh znK3*p2sRO-&78(a)bh0izreY5@iX98s6LU{R*0 zrvYW(1TrpQX_N1cA5eHv^O=BPK>ap2m?Yt7KB=dt2T1W;t_m3lSX7z7qqVi4A5H6A zxG?|;e)aVs9@#H-M95?b2n$y$7f3gGR!xw;=i-#A>au^E3y + +

案例研究:
+
云原生基础设施让你的智能家居互联
+

+ + + + + +
+ 公司  Wink     位置  纽约,纽约州     行业  物联网平台 +
+ +
+ +
+
+
+ +

挑战

+ +构建低延迟、高度可靠的基础设施,为数百万互联智能家居设备、公司消费者中心、移动应用之间的通信提供服务,强调水平可扩展性,能够快速加密所有内容和强健的连接。 +

+

解决方案

+ +全面使用 Kubernetes-Docker-CoreOS 容器的 Linux 系统。

+ +
+ +
+

影响

+ +“美国最大的两家零售商 [Home Depot 和 Walmart] 正在使用和推广 Wink 品牌和硬件,” Wink 工程主管 Kit Klein 自豪地说,不过他补充道,“这确实带来了很大的压力。这不是普通的零售商客户像技术狂热者一样追求前沿技术。这些人每天都在想要一些行之有效的东西,并且不会容忍技术方面的借口。”这进一步证明了 Klein 对 Wink 团队所构建的基础设施有多大的信心。由于 Wink 80% 的工作量在 Kubernetes-Docker-CoreOS 的统一堆栈上运行,公司已使自己能够不断创新和改进其产品和服务。克莱因说,致力于这项技术“使得在基础设施之上的建设相对容易。” +
+ +
+
+ + +
+
+ +“它不是专有的,它是完全开放的,它非常可移植。你可以跨不同的云提供商运行所有工作负载。你可以轻松地运行混合形式的 AWS,甚至引入你自己的数据中心。这就是在一个开源 Kubernetes-Docker-CoreOS 容器 Linux 系统上统一所有内容的好处。如果你只有一个 Linux 发行版/计算机映像进行验证,则具有巨大的安全优势。好处是巨大的,因为即省钱又省时间。

- KIT KLEIN, WINK 工程主管 + +
+
+ + +
+
+ +

打开一个灯泡需要多少人?

+ + +Kit Klein 拿出他的手机进行演示。只需轻扫几下,Wink 的工程主管打开由一家纽约公司开发的智能家居应用程序,然后轻触灯光按钮。“老实说,当你拿着手机,意味着你控制着灯光,”他说,“当你感觉到你的手指在屏幕上的压力,灯就打开了。开灯就和触觉反馈到你的大脑一样快。”

+ +当然,只需一根手指,不到 200 毫秒即可打开灯,或锁上门或更换恒温器。但是,让 Wink 能够帮助消费者以如此快速和轻松的速度管理其互联智能家居产品的是一个复杂的云原生基础架构,Klein 和他的团队使用开源的 CoreOS 统一系统构建并继续开发专为集群部署设计的操作系统和 Kubernetes,Kubernetes 是一个开源平台,用于跨主机集群自动部署、扩展和操作应用程序容器,提供以容器为中心的基础结构。Klein 说:“当你拥有一个庞大而复杂的相互依赖的微服务网络,需要能够发现彼此,并且需要水平可伸缩和对故障的容忍度时,这就是真正优化的原因。”“很多人最终依靠一些大型云提供商提供的专有服务来执行某些操作,但通过采用 CoreOS/Kubernetes 获得的是可移植性,而不是依赖于固定的某人。你真的可以决定自己的命运。“”

+ +事实上,Wink 做到了。公司的使命是使家庭互联无障碍,即对非技术业主来说,用户友好,价格合理,也许最重要的是,可靠。Klein 说:“如果你不相信,当你点击开关时就可以打开一盏灯,或者你在远处使用手机检查你的房子,但是反馈信息不准确,那么系统的便利性就会丧失。”这就是基础架构的用处。

+ +Wink 是在 Quirky 公司孵化的,该公司开发众包产品。Wink 应用程序于 2013 年首次推出,当时,它只控制了少数消费类产品,如 Quirky 与 GE 合作生产的 PivotPower Strip。随着智能家居产品的激增,Wink 于 2014 年在全国的 Home Depot 商店推出。其第一个项目:可以与 Honeywell 和 Chamberlain 等十几个品牌的智能产品集成的平台。最大的挑战是构建基础设施,为信息中心和产品之间的所有这些通信提供服务,重点是最大限度地提高可靠性和最小化延迟。

+ +Klein 说:“当我们最初推出时,我们正以非常快的速度尝试将第一个产品推向市场,即最低可行产品。”“很多时候,你走一条路,最终不得不回头尝试不同的东西。但是在这个特殊的情况下,我们预先做了许多工作,这导致我们作出了一个真正明智的决定,将其部署到使用 CoreOS 容器的 Linux 上。而且是在项目伊始时就这么做了。” + +
+
+ +
+
+ +“...通过 CoreOS/Kubernetes 带来的可移植性,你可以不依赖于任何人。你真的可以决定自己的命运。” +
+
+ +
+
+ +关注第一:Wink 的产品需要连接到人们家中在防火墙后面的消费设备。Klein 解释道:“由于没有 URL 这样的端点,你甚至不需要知道防火墙后面打开了哪些端口。”“因此,你基本上需要唤醒这些设备,然后与你的系统通信,然后在云和设备之间打开实时、双向通信。持续的连接真的非常重要,因为你希望尽可能减少发送消息的开销,你永远不知道什么时候有人会开灯。”

+ +使用 Wink Hub 的最早版本,当你决定打开或关闭灯光时,请求将发送到云,然后执行。Wink 软件的后续更新启用了本地控制,将许多设备的延迟缩短到大约 10 毫秒。但是,由于需要云支持的智能家居产品生态系统的集成,低延迟互联网连接仍然是一个关键的考虑因素。 +

+ +

“你基本上需要唤醒此设备,然后与你的系统通信,然后在云和设备之间打开实时、双向通信。持续的连接真的非常重要,你永远不知道什么时候有人会开灯。”

+ +此外,Wink 还有其他要求:水平可扩展性、快速加密所有内容的能力、在出现问题时可以轻松恢复的连接。Klein 说:“从一开始的整个结构来看,我们决定提供基于套接字的安全服务。”“我们总是使用某种集群技术来部署我们的服务,因此我们决定,这东西将被容器化,在 Docker 上运行。”

+ +当时,就在两年多前,Docker 还没有被广泛使用,但是正如 Klein 指出的,“技术前沿的人们当然理解它。我们开始研究现有的潜在技术。限制因素之一是我们需要部署多端口非 http/https 服务。它并不真正适合某些早期的集群技术。我们非常喜欢这个项目,最后在其它东西上使用了一段时间,但最初它过于针对 http 工作负载。”

+ +Wink 的后端工程团队决定使用 Docker 化的工作负载后,就不得不就操作系统和容器编排平台做出决定。Klein 笑着说:“很明显,你不能只是启动容器,希望一切顺利。”“你需要有一个有用的系统,以便管理工作负载的分发位置。当容器不可避免地死亡或类似的东西,重新启动它,你得有一个负载平衡器。要拥有强大的基础设施,需要进行各种内部事务管理工作。” + +
+
+ +
+
+ +Klein 笑着说:“很明显,你不能只是启动容器,希望一切顺利。”“你需要有一个有用的系统,以便管理工作负载的分发位置。当容器不可避免地死亡或类似的东西,重新启动它,你得有一个负载平衡器。要拥有强大的基础设施,需要进行各种内部事务管理工作。” +
+
+ +
+
+ +Wink 考虑直接在通用 Linux 发行版(需要安装工具来运行容器化工作负载)和集群管理系统如 Mesos(面向拥有较大团队的企业)的基础上构建,但最终将目光投向了使用 CoreOS 容器的 Linux。“一个容器优化的Linux分发系统正是我们需要的,”他说。“我们不必为了尝试采用 Linux 发行版之类的东西来安装所有内容而四处奔波。它有一个内置的容器编排系统,Fleet ,和一个易于使用的 API。它不像一些较重的解决方案那样具有丰富的功能,但我们意识到,在那一刻,这正是我们需要的。”

+ +Wink 的核心(以及经过改进的应用程序)于 2014 年 7 月推出,并进行了短期部署,并在第一个月内将服务转移到 Docker 化的 CoreOS 上部署。自那时以来,他们几乎将基础设施的其他所有部分(从第三方云到云的集成迁移到其客户服务和支付门户)迁移到使用 CoreOS 容器的 Linux 集群上。

+ +使用此设置确实需要一些额外的配置。Klein 说:“ Fleet 作为一个基本的容器编排系统确实很好,但它不负责服务实例之间的路由、配置共享、加密等。当然,所有这些功能层都可以实现,但如果你不想花费大量时间手动编写单元文件(当然没有人这样做),则需要创建一个工具来自动执行其中一些文件,我们做到了。”

+ +Wink 在 2015 年推出并集成了 CoreOS 核心技术时,很快接受了 Kubernetes 容器集群管理器,正如所承诺的那样,它最终提供了 Wink 想要的功能,并计划构建这些功能。“如果不是 Kubernetes,我们很可能采用我们为所创建的自动化工具实现的逻辑和库,并将它用于更高级别的抽象和工具,这些抽象和工具可供命令行中的非 DevOps 工程师使用,以创建和管理集群,” Klein 说。“但 Kubernetes 完全没有必要这样做,并且由比我们在集群管理方面有经验更丰富的人编写和维护,因此更好。现在,估计 Wink 80% 的工作负载是在使用 CoreOS 容器的 Linux 之上的 Kubernetes 上运行。” + +
+
+ +
+
+ +“同发展保持同步。了解决策原因。如果你了解项目背后的意图,从技术意图到某种哲学意图,那么它可以帮助你了解如何与这些系统和谐地构建系统,而不是试图与之对抗。” +
+
+ +
+
+ +Wink 的去向理由很明确:“它不是专有的,它是完全开放的,它真的很便携,” Klein 说,“它很可移植。你可以跨不同的云提供商运行所有工作负载。你可以轻松地运行混合 AWS,甚至引入你自己的数据中心。这就是在一个使用 Kubernetes-Docker-CoreOS 容器的 Linux 系统上统一所有内容的好处。如果你只有一个 Linux 发行版来尝试验证,则具有巨大的安全优势。好处是巨大的,因为既省钱又省时间。” + +Klein 承认,每个技术决策都有权衡。他表示:“对一些人来说,尖端技术将非常可怕。”“为了利用这一优势,你确实必须跟上技术。你不能把它当作一个黑盒子。同发展保持同步。了解决策原因。如果你了解项目背后的意图,从技术意图到某种哲学意图,那么它可以帮助你了解如何与这些系统和谐地构建系统,而不是试图与之对抗。” + +Wink 于 2015 年被 Flex 收购,目前控制着全国 230 万台联网设备。公司下一步怎么办?去年11月,一款新版的 “Wink Hub 2”上架,除 Home Depot 外,Walmart 商店还首次上市。Klein 自豪地说:“美国最大的两家零售商都正在使用和推广 Wink 品牌和硬件,”不过他补充道,“这确实带来了很大的压力。这不是普通的零售商客户像技术狂热者一样追求前沿技术。这些人每天都在想要一些行之有效的东西,并且不会容忍技术方面的借口。这进一步证明了 Klein 对 Wink 团队所构建的基础设施有多大的信心。” + +Wink 的工程团队从早期起就呈指数级增长,在幕后,Klein 对 Wink 使用的机器学习感到非常兴奋。“我们构建了一个数据管道的容器化小段系统,这些部分对整个团队都是有益的,并且可以有多个输出,”他说。“这就像数据管道作为微服务。”同样,Klein 指出,在使用 CoreOS 容器的 Linux 和 Kubernetes 上运行统一的系统是未来的创新的主要驱动力。“你不是每次都在重新发明轮子,”他说。“你可以专注于业务进行开发。” +
+
diff --git a/content/zh/case-studies/wink/wink_featured.png b/content/zh/case-studies/wink/wink_featured.png new file mode 100644 index 0000000000000000000000000000000000000000..3c01133bef701699285d864d8b1924ad6e6b8e10 GIT binary patch literal 21292 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 E07V|h3jhEB literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/workiva/index.html b/content/zh/case-studies/workiva/index.html new file mode 100644 index 0000000000..9b6a811c1c --- /dev/null +++ b/content/zh/case-studies/workiva/index.html @@ -0,0 +1,147 @@ +--- +title: 案例研究:Workiva + +case_study_styles: true +cid: caseStudies +css: /css/style_workiva.css +--- + +
+ +

案例研究:
使用 OpenTracing 帮助查找瓶颈 + +

+ + +
+ + +
+ 公司  Workiva     Location  艾姆斯,爱荷华州     行业  企业软件 +
+ + +
+
+
+
+ +使用 OpenTracing,我的团队能够查看跟踪,并针对其他团队提出优化建议,而无需查看他们的代码。
— MacLeod Broad, Workiva 高级软件架构师
+ +
+
+
+
+ +

去年秋天,MacLeod Broad 在 Workiva 的平台团队在准备该公司的首批产品之一,当遇到障碍时就使用 Amazon Web Services

+ +早期,Workiva 的后端主要运行在Google App Engine上。但随着 Workiva 的 SaaS 产品,Wdesk,一种基于云的管理和报告业务数据平台,将客户群增长到财富 500 强公司的 70% 以上,情况发生了变化。“随着客户需求的增长和产品供应的扩大,我们开始利用更广泛的服务,如 Amazon Web Services 以及其他 Google Cloud Platform 服务,从而创建一个多供应商环境。” + + +有了这个新产品,具备“同步和链接”功能,通过它,数据“经历了一大堆服务,从新的电子表格系统[Amazon Aurora]到我们所谓的链接系统,然后通过 http 推送到我们现有的系统,然后进行一些计算,结果将传回新系统,”Broad 说。“我们当时进行优化是为了速度。我们认为做了这种极好的优化,然后它会变成一个微观优化,这并没有真正影响系统的整体速度。”

+ +Broad 团队面临的挑战听起来可能为其他公司所熟悉,这些公司也从单体系统转向更分散的基于微服务的系统。Broad 说:“我们有许多人从事这方面的工作,他们都在不同的团队中,因此很难了解问题是什么以及瓶颈在哪里。”

+ +“每个服务团队都经历着不同的架构迭代,很难了解每个团队系统中的实际内容,”他补充道。“我们有循环依赖关系,其中有三个或四个不同的服务团队不确定问题的真正位置,需要大量的来回沟通。因此,我们浪费了很多时间说,‘这个哪一部分比较慢?根据应用场景的不同,哪一部分有时很慢?随着时间推移,哪一部分会逐渐变慢?这个进程的哪一部分是异步的,因此,它是否长时间运行并不重要?我们在做的哪些是多余的,其中哪一部分是错误?’” + + +
+
+
+
+ + “跟踪系统可以一目了然地解释体系结构,缩小性能瓶颈并归零,通常只是帮助指导高级别的调查。一眼就能做到这一点,比在会议或三天的调试中要快得多,而且比从来不找出问题得过且过要快得多。”
— MACLEOD BROAD, WORKIVA 高级软件架构师
+ +
+
+
+
+ + +简而言之,它是跟踪的理想用例。Broad 说:“跟踪系统可以一目了然地解释体系结构,缩小性能瓶颈并归零,通常只是帮助在高级别指导调查。”“一眼就能做到这一点,比在会议或三天的调试中要快得多,而且比从不找出问题得过且过要快得多。”

+ +Workiva 的后端代码在 Google Compute Engine 、App Engine 和 AWS 上运行,Broad 知道他需要一个与平台无关的跟踪系统。“我们正在研究不同的追踪解决方案,”他说,“我们决定,由于市场似乎是一个不断发展的市场,我们不想被一个供应商卡住。因此,OpenTracing 似乎是避免供应商限制我们实际使用的后端的最简捷方法。”

+ +Broad 说,一旦他们将 OpenTrace 引入到第一个用例中,“跟踪使得瓶颈所在位置变得非常明显。”尽管每个人都认为是 Workiva 的现有代码减缓了速度,但事实并非如此。Broad 说:“看起来现有代码速度很慢,只是因为它能够达到到我们下一代服务的水平,而且它们需要很长时间才能处理所有这些请求。”“在瀑布图上,你可以看到每个请求在得到响应时所做的完全相同的工作。因此,对于被分页的每个响应,每个服务请求看起来都完全相同。然后,就不用费神去思考‘为什么它再次做所有这些工作?’”

+ +使用 OpenTrace 的跟踪功能,“我的团队能够查看跟踪,并针对另一个团队提出优化建议,而无需查看他们的代码,”Broad 说。“我们命名跟踪的方式可以说明请求是执行 SQL 调用还是创建 RPC。因此,可以非常简单地说,‘好吧,我们知道它能处理所有这些请求。处理一次缓存一次。’我们基本上完成了。所有这些调用立即变成了亚秒级的调用。”

+ +
+
+ +
+
+ +“我们正在研究不同的跟踪解决方案,我们决定使用 OpenTracing,由于市场似乎是一个不断发展的市场,我们不想被一个供应商卡住。因此,OpenTracing 似乎是避免供应商限制我们实际使用的后端的最简捷方法。”
— MACLEOD BROAD, WORKIVA 高级软件架构师
+ +
+
+ +
+
+ +在第一个用例成功后,参与尝试的每个人都回去重新编排了他们的产品。跟踪功能已添加到几个更多的用例中。Broad 说:“我们希望尽早度过最初的实施难关,而不会让整个部门一起渡过难关。”“现在,许多团队在启动新服务时添加它。我们现在确实比以前更将推动采用。”

+ +一些团队很快就赢了。软件工程师 Michael Davis 说:“跟踪让我们能够立即了解如何改进我们的(工作空间)服务。通过查看每个调用的花费时间以及最常使用哪些调用的组合,我们能够在单个修复中将平均响应时间减少 95%(从 600ms 到 30ms)”。

+ +Workiva 的大部分主要产品现在都使用 OpenTracing 进行跟踪,将数据推送到 Google StackDriver。即使未完全使用跟踪功能的产品,也具有一些组件和库。

+ +Broad 指出,由于一些工程师正在使用 App Engine,并且已经拥有平台的 Appstats 库分析性能的经验,因此他们不需要花太多时间才能习惯使用 OpenTracing。但其他人则有点不情愿。“我认为,使用 OpenTracing 的最大障碍是担心引入跟踪和 StackDriver 的成本会是多少,”他说。“人们也非常关心将中间件添加到他们正在处理的任何内容中。有关传递上下文以及如何完成这些工作的问题很常见。我们的许多 Go 开发人员对此都很好,因为他们已经以这样或那样的形式这样做了。我们的 Java 开发人员并不热衷于这样做,因为他们使用了其他不需要该功能的系统。”

+ +但好处显然超过了人们的担忧,而今天,Workiva 的官方政策是使用追踪。 + +事实上,Broad 认为跟踪天然符合 Workiva 现有的日志记录和指标系统。“这是我们在内部展示的方式,也是我们设计使用方式的方式,”他说。“我们的跟踪记录在与我们的应用指标和日志记录数据完全相同的机制中,并且它们被推送的方式完全相同。因此,在创建和记录所有数据时,我们对待这些数据完全一样。我们有一个内部库,用于日志记录、遥测、分析和跟踪。” + + +
+
+ +
+
+ +“跟踪让我们能够立即、可操作地洞察如何改进我们的(工作空间)服务。通过查看每个调用花费的时间以及最常使用哪些调用的组合,我们能够在单个修复中将平均响应时间减少 95%(从 600ms 到 30ms)。”
— Michael Davis, 软件工程师, Workiva
+ +
+
+ +
+
+ +对于 Workiva,OpenTracing 已成为一种重要工具,通过观察使用模式来聚焦最佳优化和确定什么是微观优化。Broad 说:“在某些项目中,我们经常假设客户正在做什么,我们针对这些疯狂的测试案例进行优化,这些案例的 1% 是同用户实际非常相符的。”“这样是非常有益的,‘好吧,我们在每个执行 X 的请求上添加 100 毫秒,如果最坏的情况,我们也只需要添加 100 毫秒,这仅发生在千分之一的请求或一百万个请求中的一个。’”

+ +与许多其他公司不同,Workiva 还跟踪客户端。Broad 说:“对我们来说,用户体验很重要,如果 RPC 执行后还需要 5 秒才能在浏览器中显示,则 RPC 执行需要 100 毫秒就不重要了。”“因此,对于我们而言,这些客户端响应时间非常重要。我们跟踪它,看看加载的哪些部分需要很长时间。我们正在研究什么是“加载”的定义。是当你访问到它,还是当它被渲染时,或者当你可以与它交互时?我们计划使用跟踪来关注和更好地了解这些内容。”

+ +这还需要根据外部和内部时钟的差异进行调整。“在时间纠正之前,这是非常恐怖的;我们的跟踪比什么都更具有误导性,” Broad 说。“因此,我们决定在响应标头上返回一个时间戳,然后让客户端根据该时间调整其时间,而不是更改其内部时钟,而只需计算客户端收到时响应时间的偏移量。如果最终出现一种不可能的情况,客户端的 RPC 调用持续了 210 毫秒但响应返回时间并不在这个范围内,那就必须得重新调用请求。”

+ +Broad 对 OpenTracing 对公司产生的影响感到兴奋,并且也在展望该技术还能实现什么。一种可能性是使用跟踪实时更新文档。他表示:“使文档与现实保持同步是一项重大挑战。”“例如,我们刚刚运行了跟踪模拟,或者我们刚刚在此新部署上运行了烟雾测试,但是结果显示架构与文档不匹配。我们可以找到是谁的责任,并通知他们进行更新。这是我希望在未来通过追踪获得的功能之一。” + +
+ +
diff --git a/content/zh/case-studies/workiva/workiva_featured_logo.png b/content/zh/case-studies/workiva/workiva_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9998b471049e5e561af77feca573b2eb4c77e95d GIT binary patch literal 5980 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/ygrene/index.html b/content/zh/case-studies/ygrene/index.html new file mode 100644 index 0000000000..969483ba07 --- /dev/null +++ b/content/zh/case-studies/ygrene/index.html @@ -0,0 +1,130 @@ +--- +title: 案例研究:Ygrene + +case_study_styles: true +cid: caseStudies +css: /css/style_ygrene.css +--- + + +
+

案例研究:
Ygrene: 使用原生云为金融行业带来安全性和可扩展性 + +

+ + +
+ + +
+ 公司  Ygrene     位置  佩塔卢马,加利福尼亚州     行业  清洁能源融资 +
+ +
+
+
+ + +
+ +

影响

+ +以前,部署通常需要三到四个小时,而且每周或每两周要把一些两三个月工作量的任务在系统占用低的时候进行部署。现在,他们用5分钟来配置 Kubernetes,然后用一个小时进行整体部署与烟雾测试。Adams 说:“我们每周可以部署三到四次,只需一周或两天的工作量。”“我们在工作周、白天的任意时间进行部署,甚至不需要停机。以前我们不得不请求企业批准,以关闭系统,因为即使在半夜,人们也可能正在访问服务。现在,我们可以部署、上传代码和迁移数据库,而无需关闭系统。公司获得新功能,而不必担心某些业务会丢失或延迟。”此外,通过使用 kops 项目,Ygrene 现在可以用以前成本的十分之一使用 AWS EC2 Spot 运行其 Kubernetes 集群。Adams 说,这些云原生技术“改变了可扩展性、可观察性和安全性(我们正在添加新的非常安全的数据源)的游戏。”“没有 Kubernetes、Notary 和 Fluent,我们就无法告诉投资者和团队成员,我们知道刚刚发生了什么事情。” + +
+ +
+
+
+
+ +“CNCF 项目正在帮助 Ygrene 确定整个 PACE 行业的安全性和可观察性标准。我们是一个新兴的金融企业,没有这些项目,尤其是 Kubernetes,我们不可能成为今天的行业领导者。”

— Austin Adams, Ygrene 能源基金会开发经理
+ +
+
+ +
+
+ +

在不到十年的时间里, Ygrene 就为可再生能源项目提供了超过10亿美元的贷款。

PACE (清洁能源物业评估)融资公司开发经理 Austin Adams 表示:“我们抵押房屋或商业建筑,用贷款来为任何可以节约电力、生产电力、节约用水或减少碳排放的项目提供资金支持。”

+ + +为了批准这些贷款,公司需要处理大量的承销数据。Adams 说:“我们必须要验证有关财产、公司或人员的问题,像这样的工作数以千计。因此,我们有很多正在聚合的数据源,并且我们也有大量系统需要实时对这些数据进行改动。”

+ +到 2017 年,部署和可扩展性已成为痛点。该公司已经使用了大量服务器,“我们刚刚达到能够垂直扩展的极限,”他说。迁移到 AWS Elastic Beanstalk 并不能解决问题:“Scala 服务需要来自主 Ruby on Rails 服务和不同供应商提供的大量数据,因此他们要求从我们的 Ruby 服务以一种服务器无法承受的速率获取信息。在 Elastic Beanstalk 上我们也有许多配置与应用不匹配。这仅仅是一个开始,我们也意识到我们这个系统非常不稳定。” +
+
+
+
+ +“CNCF 是众多项目惊人的孵化器。现在,我们定期查看其网页,了解是否有任何新的、可敬的高质量项目可以应用到我们的系统中。它实际上已成为我们了解自身需要什么样的软件以使我们的系统更加安全和具有可伸缩性的信息中心。”

— Austin Adams, Ygrene 能源基金会开发经理
+
+
+
+
+ + +Adams 和其他团队一起着手寻找一种具有变革性的解决方案,但“不需要我们对代码库进行巨大的重构,”他说。作为一家金融公司,和可伸缩性一样,Ygrene 需要更好的安全性。他们通过采用云原生技术找到了答案:Kubernetes 帮助纵向扩展和分配工作负载,Notary 在各个级别实现可靠的安全性,Fluentd 来提供可观察性。Adams 说:“ Kubernetes 是社区前进的方向,也是我们展望未来的证明。”

+ +有了 Kubernetes,该团队能够快速将 Ygrene 应用程序用 Docker 容器化。“我们必须改变一些实现和代码,以及系统的构建方式,” Adams 说,“但我们已经能够在一个月左右的时间内将主要系统引入 Kubernetes,然后在两个月内投入生产。对于一家金融公司来说,这已经非常快了。”

+ +怎么样?Adams 说,这些云原生技术“改变了可扩展性、可观察性和安全性(我们正在添加新的非常安全的数据源)的游戏。”“没有 Kubernetes、Notary 和 Fluent,我们就无法告诉投资者和团队成员,我们知道刚刚发生了什么事情。”

+ +Adams 说,尤其 Notary 简直就是“天赐之物”。“我们要清楚,我们针对第三方依赖项的攻击面较低,或者至少是托管的。因为我们使用 Notary 作为一个信任系统,我们也使用它作为区分,所以生产镜像由 Notary 签名,但一些开发镜像就不签署。这是为了确保未签名镜像无法进入生产集群。我们已经在测试集群中使用它,以使构建的应用更安全。” + + +
+
+
+
+ +“我们必须改变一些实现和代码,以及系统的构建方式,” Adams 说,“但我们已经能够在一个月左右的时间内将主要系统引入 Kubernetes,然后在两个月内投入生产。对于一家金融公司来说,这已经非常快了。” +
+
+ +
+
+ +通过使用 kops 项目,Ygrene 能够用以前成本的十分之一从 Elastic Beanstalk 迁移到 AWS EC2 Spot 上运行其 Kubernetes 群集。Adams 说:“以前为了扩展,我们需要增加实例大小,导致高成本产出低价值。现在,借助 Kubernetes 和 kops,我们能够在具有多个实例组的 Spot 上水平缩放。”

+ +这也帮助他们降低了在公共云中运行所带来的风险。“我们发现,基本上,如果我们能够使用中断可能性极低、无中断历史的 EC2 Spot 选择实例类,并且我们愿意付出足够高的价格,我们几乎可以得到和使用 Kubernetes 相同的保证,因为我们有足够的节点,”软件工程师 Zach Arnold 说,他领导了向 Kubernetes 的迁移。“现在,我们已经重新架构了应用程序的这些部分,使之不再位于同一台服务器上,我们可以推送到许多不同的服务器,并实现更稳定的部署。”

+ +因此,团队现在可以在一天中的任何时间传输代码。阿诺德说:“以前这样做是很危险的,因为它会拖慢整个贷款管理软件。”“但现在,我们可以在白天安全部署。” + +
+
+
+
+ +Adams 说:“以前为了扩展,我们需要增加实例大小,导致高成本产出低价值。现在,借助 Kubernetes 和 kops,我们能够在具有多个实例组的 Spot 上水平缩放。” +
+
+ +
+
+ +以前,部署通常需要三到四个小时,而且每周或每两周要把一些两三个月工作量的任务在系统占用低的时候进行部署。现在,他们用5分钟来配置 Kubernetes,然后用一个小时进行整体部署与烟雾测试。Adams 说:“我们每周可以部署三到四次,只需一周或两天的工作量。”“我们在工作周、白天的任意时间进行部署,甚至不需要停机。以前我们不得不请求企业批准,以关闭系统,因为即使在半夜,人们也可能正在访问服务。现在,我们可以部署、上传代码和迁移数据库,而无需关闭系统。公司增加新项目,而不必担心某些业务会丢失或延迟。”

+ +云原生也影响了 Ygrene 的 50 多名开发人员和承包商的工作方式。Adams 和 Arnold 花了相当长的时间“教人们思考开箱即用的”,Arnold 说。“我们最终选择了称之为“航运四S”:安全、可靠、稳妥、快速。”(有关其安全部分的更多内容,请参阅他们关于"持续黑客攻击"策略的文章。至于工程师,Adams 说,“他们已经能够跟上软件进步的步伐。我想一天结束时,开发人员会感觉更好,他们也会感觉与现代软件开发社区的联系更加紧密。”

+ +展望未来,Adams 很高兴能探索更多的 CNCF 项目,包括 SPIFFE 和 SPIRE。“ CNCF 是众多项目惊人的孵化器。现在,我们定期查看其网页,了解是否有任何新的、可敬的高质量项目可以应用到我们的系统中。它实际上已成为我们了解自身需要什么样的软件以使我们的系统更加安全和具有可伸缩性的信息中心。” + + +
+ +
diff --git a/content/zh/case-studies/ygrene/ygrene_featured_logo.png b/content/zh/case-studies/ygrene/ygrene_featured_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d0d69114784c8d418e8c0958229d301b3fe00505 GIT binary patch literal 11569 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 literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/zalando/index.html b/content/zh/case-studies/zalando/index.html new file mode 100644 index 0000000000..39fc63ab1d --- /dev/null +++ b/content/zh/case-studies/zalando/index.html @@ -0,0 +1,132 @@ +--- +title: 案例研究:Zalando +case_study_styles: true +cid: caseStudies +css: /css/style_zalando.css +--- + +
+ +

案例研究:
欧洲领先的在线时尚平台通过云原生获得突破性进展 +

+ +
+ + +
+ 公司  Zalando     位置  柏林, 德国     行业  在线时尚平台 +
+ +
+
+
+
+

挑战

+ +Zalando 是欧洲领先的在线时尚平台,自 2008 年成立以来,经历了指数级增长。2015 年,Zalando 计划进一步扩展其原有的电子商务站点,以扩展新的服务和产品,从而开始了彻底的变革,因此形成了自主的自组织团队。这次扩展需要可以随工程组织的增长而扩展的基础架构。Zalando 的技术部门开始重写其应用程序,使其能够在云端运行,并开始将其基础架构从内部数据中心迁移到云。虽然编排没有立即被考虑,因为团队迁移到亚马逊网络服务(AWS):“我们体验过团队在 AWS 上进行基础设施架构和使用云资源时遇到的痛苦,”开发人员生产力主管 Henning Jacobs 说,“我们遇到了一些难题。对于团队和合规性来说,运营开销仍然过多。为了提供更好的支持,项目引入了集群管理。” + +
+ +
+

解决方案

+ +该公司现在使用 Kubernetes 编排在 AWS 上运行的 Docker 容器。 +
+

影响

+ +Jacobs 说,由于旧基础设施“很难正确采用新技术,而 DevOps 团队被视为瓶颈。”“现在,有了这个云基础架构,它们有了这种打包格式,可以包含任何在Linux内核上运行的东西。这使得很多人相当高兴。工程师喜欢自主。” +
+
+
+
+
+ +“我们设想所有 Zalando 交付团队在 Kubernetes 提供的最先进的、可靠且可扩展的群集基础架构上运行其容器化应用程序。”

- Henning Jacobs, Zalando 开发人员生产力主管 +
+
+
+
+
+ +

当 Henning Jacobs 于2010年来到 Zalando 时,该公司刚成立两年,有180名员工经营一家网上商店,供欧洲消费者购买时尚商品。

+ +Zalando 的开发人员生产力主管 Jacobs 说:“它最初是一个 PHP 电子商务网站,很容易上手,但无法随业务需求扩展。”

+ +当时,公司开始从德国以外扩展到其他欧洲市场。快进到今天,Zalando 现在拥有超过 14000 名员工,2016 年收入为 36 亿欧元,业务遍及 15 个国家/地区。他表示:“这种全面快速的增长和不断扩展,一生只能有一次。”

+ +能拥有像 Jacobs 这样的基础设施专家的机会是非常独特的。就在他加入公司后,公司开始在内部重写他们的所有应用。“这通常是我们的策略,”他表示。“例如,我们从我们自己的物流仓库开始,但起初不知道如何做物流软件,所以得用一些供应商软件。然后我们用自己的软件替换了它,因为使用现成的软件是没有竞争力的。需要根据特定业务需求优化这些流程。”

+ +在重写其应用程序的同时,Zalando 设定了一个目标,即从基本电子商务扩展到提供多租户的平台、大量增加的分类和样式、当天送达,甚至您自己的平台个人在线造型师

+ +扩展的需求最终引领了公司踏上云原生之旅。它采用基于微服务的软件架构,使工程团队拥有更多的项目自主权和所有权。“迁移到云是必要的,因为在数据中心中,团队不可能随心所欲。使用相同的基础架构,因此只能运行 Java 或 Python 应用,”Jacobs 说。 + +
+
+
+
+ +“迁移到云是必要的,因为在数据中心中,团队不可能随心所欲。使用相同的基础架构,因此只能运行 Java 或 Python 应用。” + +
+
+
+
+ +Zalando 开始将其基础架构从两个内部数据中心迁移到云,这需要迁移较旧的应用程序使其在云中准备就绪。“我们决定果断一些,” Jacobs 说。“我们的亚马逊网络服务基础设施是这样的:每个团队都有自己的 AWS 账户,该账户是完全隔离的,这意味着没有'提升和转移'。基本上必须重写应用程序,使其在云中准备就绪,甚至到持久层也是如此。我们勇敢地回到绘图板,重做一切,首先选择 Docker 作为通用容器化,然后从那里构建基础结构。”

+ +公司最初决定推迟编排,但随着团队迁移到 AWS,“我们看到团队在 AWS 上的基础设施和使用云资源方面遇到了难题,” Jacobs 说。

+ +Zalando 200多人的自主工程团队研究使用哪些技术,并可以使用自己的 AWS 账户操作自己的应用程序。事实证明,此设置是一项合规性挑战。即使制定了严格的游戏规则和自动化的合规性检查,工程团队和 IT 合规性在解决合规性问题方面也负担过重。Jacobs 说:"违规行为会出现,我们在扫描云基础架构时会检测到这些行为。“一切皆有可能,没有强制实施,因此您必须忍受违规行为(并解决它们),而不是一开始就防止错误。这些都会增加团队的开销,以及合规性和操作的开销。在 AWS 上启动新的 EC2 实例也需要时间,这会影响我们的部署速度。”

+ +Jacobs 说,团队意识到他们需要“利用从集群管理中获得的价值”。当他们在2015年首次将平台视为服务(PaaS)选项时,市场是支离破碎的;但“现在似乎有一个明确的赢家。使用 Kubernetes 似乎是一个很好的尝试。”

+ +Kubernetes 的过渡始于 2016 年 Zalando 的极客周期间,参与者将他们的项目部署到 Kubernetes 集群。60名技术基础设施部门的成员开始使用这项技术,之后每次会加入一支工程团队。Jacobs 说:“我们总是从与他们交谈开始,确保每个人的期望都清晰。然后,我们进行一些 Kubernetes 培训,这主要是针对我们的 CI/CD 设置的培训,因为我们的用户界面主要通过 CI/CD 系统。但是他们必须知道Kubernetes的基本概念和API。之后每周与每个团队同步,以检查其进度。一旦出现什么状况,就可以确定我们所做的改进是否正常。” + +
+
+
+
+ +一旦Zalando开始将应用迁移到Kubernetes,效果立竿见影。“Kubernetes 是我们无缝端到端开发人员体验的基石。我们能够使用单一一致且声明性的 API 将创意运送到生产中,” Jacobs 说。 +
+
+ +
+
+ +目前,Zalando正在运行最初的40个Kubernetes集群,并计划在可预见的将来进行扩展。一旦Zalando开始将申请迁移到Kubernetes,效果立竿见影。“ Kubernetes 是我们无缝端到端开发人员体验的基石。我们能够使用单一一致且声明性的 API 将创意运送到生产中,” Jacobs 说。“自愈基础架构提供了无摩擦体验,基于低级最佳实践构建了更高级别的抽象。我们设想所有 Zalando 交付团队都将在 Kubernetes 提供的最先进的可靠和可扩展群集基础架构上运行其容器化应用程序。” + +Jacobs 说,使用旧的内部基础设施,“很难正确采用新技术,而 DevOps 团队被视为瓶颈。”“现在,有了这个云基础架构,它们有了这种打包格式,可以包含运行在 Linux 内核中的任何内容。这使得很多人相当高兴。工程师喜欢自主性。”在Zalando的Kubernetes实施中出现了一些挑战。Jacobs 说:“我们是一支由七人组成的团队,为不同的工程团队提供集群,我们的目标是为所有团队提供坚如磐石的体验。”“我们不想要宠物集群。我们不想了解他们的工作量;它应该只是开箱即用。考虑到这一点,集群自动缩放非常重要。执行集群管理的方法有很多种,这不是核心的一部分。因此,我们创建了两个组件来预配群集,具有集群的注册表,并管理整个集群生命周期。”

+ +Jacobs 的团队还致力于改进Kubernetes-AWS 集成。“由于许多限制条件,需要通过基础设施来扩展每个自主团队的想法。” + +此外,“仍然缺少很多最佳实践,”Jacobs说。例如,该团队最近解决了 pod 安全策略问题。“在Kubernetes已经有一个概念,但没有记录,所以有点棘手,”他说。大型的Kubernetes社区是解决这个问题的一大帮助。为了帮助其他公司走上同样的道路,Jacobs在一份名为“在生产中运行 Kubernetes ”的文件中汇编了他的团队的经验教训。 + +
+
+ +
+
+ +“ Kubernetes API 允许我们以与云提供商无关的方式运行应用程序,这使我们能够在未来几年中自由访问 IaaS 提供商...我们期望 Kubernetes API 成为 PaaS 基础设施的全球标准,并对未来的继续旅程感到兴奋。” +
+
+
+
+ +最后,Kubernetes 使 Zalando 能够引进和维护公司为发展其平台而设想的新产品。Jacobs 说:“时尚咨询产品使用 Scala,而我们以前的基础设施也难以实现这一点。”这是一个解决方法,该团队需要平台团队提供越来越多的支持,只是因为他们使用了不同的技术。现在有了Kubernetes,它就自主了。无论工作负载是什么,该团队都可以走自己的路,而 Kubernetes 可以防止其他瓶颈。

+ +展望未来,Jacobs 将 Zalando 的新基础设施视为公司在进行的其他工程中的巨大推动因素,从新的物流软件到连接品牌的平台功能,以及数据科学家梦寐以求的产品。Jacobs说:“一个愿景是,如果你看下一部 James Bond 的电影,看看他穿的西装,你就应该能够自动订购,并在一小时内把它送到你身边。”“这是关于连接整个时尚领域。如果您遇到瓶颈,因为每个人都在同一个数据中心运行,因此限制很大,则这绝对是不可能的。需要基础设施来扩展每个自主团队的想法。”

+ +对于考虑这项技术的其他公司,Jacobs 说,他不一定建议像 Zalando 那样做。他表示:“如果你准备尝试失败,那么这样做是可以的。”“设定正确的期望是必须的。并不是一切都会起作用。重写应用和这种类型的组织更改可能会造成中断。我们移动的第一个产品至关重要。存在大量依赖关系,而且时间比预期长。也许我们应该从不那么复杂、不是业务关键的东西开始,只是为了开个好头。”

+ +但是,一旦他们到了另一边,“每个人都很清楚,没有大的选择,” Jacobs 补充说。“ Kubernetes API 允许我们以与云提供商无关的方式运行应用程序,这使我们能够在未来几年中自由访问 IaaS 提供商。Zalando 受益于迁移到 Kubernetes,因为我们能够利用现有知识创建工程平台,为我们的工程师提供灵活性和速度,同时显著降低运营开销。我们期望 Kubernetes API 成为 PaaS 基础设施的全球标准,并对未来的旅程感到兴奋。” + +
+ +
diff --git a/content/zh/case-studies/zalando/zalando_feature_logo.png b/content/zh/case-studies/zalando/zalando_feature_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ba6251050d15abb523d009ad79df06cc1fa0779e GIT binary patch literal 7643 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 R?Uet&{~zE#M<{wb`#*xsh{XT^ literal 0 HcmV?d00001 diff --git a/content/zh/case-studies/zulily/index.html b/content/zh/case-studies/zulily/index.html index d41671470f..d5caf422aa 100644 --- a/content/zh/case-studies/zulily/index.html +++ b/content/zh/case-studies/zulily/index.html @@ -1,4 +1,4 @@ ---- -title: Zulily -content_url: https://www.youtube.com/embed/of45hYbkIZs ---- +--- +title: Zulily +content_url: https://www.youtube.com/embed/of45hYbkIZs +--- diff --git a/content/zh/community/_index.html b/content/zh/community/_index.html new file mode 100644 index 0000000000..53cbbd0682 --- /dev/null +++ b/content/zh/community/_index.html @@ -0,0 +1,133 @@ +--- +title: 社区 +layout: basic +cid: community +--- + + + +
+
+ + +
+

保证 Kubernetes 到处都适用,每个人都喜欢。

+

在我们的Slack channel, + 讨论版, 或者 + Kubernetes-dev Google 群主上和 Kubernetes 互动。 + 同时,每周我们也有社区视频会议,讨论最新进展。参见 + 这些指导了解如何参与其中。

+

你也可以在世界各地通过我们的 + Kubernetes Meetup 社区 以及 + Kubernetes Cloud Native Meetup 社区来参与。

+
+ + + +
+

特殊兴趣小组 (Special Interest Groups,SIGs)

+

对于 Kubernetes 是如何和另外的技术协作感兴趣?了解下我们不停发展的 + SIGs 群组, + 从 AWS 和 Openstack 到 大数据和可扩展性,总会有一个适合你,如果你所关注的不在其列,也有指导帮助你成立新的 SIG。

+ +

作为 Kubernetes 社区的一员,你可以随意加入任何你感兴趣的 SIG 会议。不需要额外注册。

+
+ + + +
+

行为规范

+

Kubernetes 社区重视尊重和包容,并要求在所有场合都遵循 + 行为规范。 + 如果你在活动、会议、Slack 或是其它场合发现有任何违反行为规范的行为,请联系 + Kubernetes 行为规范委员会 + conduct@kubernetes.io. + 我们会确保您的匿名性。

+
+
+
+ + + +
+
+

与我们联系!

+

我们很希望听到你的声音,你是如何使用 Kubernetes 的,
以及我们可以将 Kubernetes 变得更美好。

+
+
+ @kubernetesio +

获取更多的资讯和更新。

+
+
+ Github 项目 +

了解项目,作出贡献。

+
+
+ #kubernetes-users +

Slack channel 是联系工程师,分享想法的最佳方法。

+
+
+ Stack Overflow +

我们的论坛是获得社区支持的最佳地点。

+
+
+
+
diff --git a/content/zh/community/code-of-conduct.md b/content/zh/community/code-of-conduct.md new file mode 100644 index 0000000000..848c58832e --- /dev/null +++ b/content/zh/community/code-of-conduct.md @@ -0,0 +1,44 @@ +--- +title: 社区 +layout: basic +cid: community +css: /css/community.css +--- + + + +
+ +

Kubernetes 社区行为规范

+ + + +Kubernetes 遵循 +CNCF 行为规范。 +CNCF 社区规范文本如下链接 +commit 0ce4694。 +如果您发现这个 CNCF 社区规范文本已经过时,请 +提交 issue。 + + + +如果你在活动、会议、Slack 或是其它场合发现有任何违反行为规范的行为,请联系[Kubernetes 行为规范委员会](https://github.com/kubernetes/community/tree/master/committee-code-of-conduct)。 +我们会确保您的匿名性。 + +
+{{< include "/static/cncf-code-of-conduct.md" >}} +
+
diff --git a/content/zh/community/static/README.md b/content/zh/community/static/README.md new file mode 100644 index 0000000000..6d65182dcc --- /dev/null +++ b/content/zh/community/static/README.md @@ -0,0 +1,5 @@ + + +本路径下的文件从其它地方导入。 +除了版本更新,不要直接修改。 diff --git a/content/zh/community/static/cncf-code-of-conduct.md b/content/zh/community/static/cncf-code-of-conduct.md new file mode 100644 index 0000000000..3ee025ba34 --- /dev/null +++ b/content/zh/community/static/cncf-code-of-conduct.md @@ -0,0 +1,46 @@ + +## CNCF Community Code of Conduct v1.0 + +### Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of fostering +an open and welcoming community, we pledge to respect all people who contribute +through reporting issues, posting feature requests, updating documentation, +submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for +everyone, regardless of level of experience, gender, gender identity and expression, +sexual orientation, disability, personal appearance, body size, race, ethnicity, age, +religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, such as physical or electronic addresses, + without explicit permission +* Other unethical or unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are not +aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers +commit themselves to fairly and consistently applying these principles to every aspect +of managing this project. Project maintainers who do not follow or enforce the Code of +Conduct may be permanently removed from the project team. + +This code of conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting +the [Kubernetes Code of Conduct Committee](https://github.com/kubernetes/community/tree/master/committee-code-of-conduct) . + +This Code of Conduct is adapted from the Contributor Covenant +(http://contributor-covenant.org), version 1.2.0, available at +http://contributor-covenant.org/version/1/2/0/ + +### CNCF Events Code of Conduct + +CNCF events are governed by the Linux Foundation [Code of Conduct](http://events.linuxfoundation.org/events/cloudnativecon/attend/code-of-conduct) available on the event page. This is designed to be compatible with the above policy and also includes more details on responding to incidents. diff --git a/content/zh/docs/.gitkeep b/content/zh/docs/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/content/zh/docs/_index.md b/content/zh/docs/_index.md index e31ea1aea7..0b9545eaa6 100644 --- a/content/zh/docs/_index.md +++ b/content/zh/docs/_index.md @@ -1,3 +1,9 @@ --- title: 文档 +weight: 5 --- + + diff --git a/content/zh/docs/concepts/architecture/_index.md b/content/zh/docs/concepts/architecture/_index.md index 5c12c896ab..d64618a958 100755 --- a/content/zh/docs/concepts/architecture/_index.md +++ b/content/zh/docs/concepts/architecture/_index.md @@ -1,4 +1,11 @@ --- title: "Kubernetes 架构" weight: 30 ---- \ No newline at end of file +--- + + diff --git a/content/zh/docs/concepts/architecture/cloud-controller.md b/content/zh/docs/concepts/architecture/cloud-controller.md index e72e68ccb3..f3bdc03e1f 100644 --- a/content/zh/docs/concepts/architecture/cloud-controller.md +++ b/content/zh/docs/concepts/architecture/cloud-controller.md @@ -225,8 +225,6 @@ Route 控制器负责适当地配置云中的路由,以便 Kubernetes 集群 The Service controller is responsible for listening to service create, update, and delete events. Based on the current state of the services in Kubernetes, it configures cloud load balancers (such as ELB , Google LB, or Oracle Cloud Infrastructure LB) to reflect the state of the services in Kubernetes. Additionally, it ensures that service backends for cloud load balancers are up to date. --> -服务控制器负责监听服务的创建、更新和删除事件。根据 Kubernetes 中各个服务的当前状态,它配置云负载均衡器(如 ELB, Google LB 或者 Oracle Cloud Infrastructure LB)以反映 Kubernetes 中的服务状态。此外,它还确保云负载均衡器的服务后端是最新的。 - @@ -249,6 +247,12 @@ In this new model, the kubelet initializes a node without cloud-specific informa ## Plugin mechanism --> +在这个新模型中,kubelet 初始化一个没有特定于云的信息的节点。但是,它会为新创建的节点添加污点,使节点不可调度,直到 CCM 使用特定于云的信息初始化节点后,才会清除这种污点,便得该节点可被调度。 + + + ## 插件机制 -{{< toc >}} +{{% capture overview %}} + + +在 Kubernetes 中,节点(Node)是执行工作的机器,以前叫做 `minion`。根据你的集群环境,节点可以是一个虚拟机或者物理机器。每个节点都包含用于运行 [pods](/docs/concepts/workloads/pods/pod/) 的必要服务,并由主控组件管理。节点上的服务包括 [容器运行时](/docs/concepts/overview/components/#node-components)、kubelet 和 kube-proxy。查阅架构设计文档中 [Kubernetes 节点](https://git.k8s.io/community/contributors/design-proposals/architecture/architecture.md#the-kubernetes-node) 一节获取更多细节。 -## Node 是什么? +{{% /capture %}} -`Node` 是 Kubernetes 的工作节点,以前叫做 `minion`。取决于你的集群,Node 可以是一个虚拟机或者物理机器。每个 node 都有用于运行 [pods](/docs/user-guide/pods) 的必要服务,并由 master 组件管理。Node 上的服务包括 Docker、kubelet 和 kube-proxy。请查阅架构设计文档中 [The Kubernetes Node](https://git.k8s.io/community/contributors/design-proposals/architecture/architecture.md#the-kubernetes-node) 一节获取更多细节。 - - -## Node 状态 - - - 一个 node 的状态包含以下信息: - -* [地址](#地址) -* ~~[阶段](#阶段)~~ **已废弃** -* [条件](#条件) -* [容量](#容量) -* [信息](#信息) +{{% capture body %}} + + +## 节点状态 + + +一个节点的状态包含以下信息: + +* [地址](#addresses) +* [条件](#condition) +* [容量与可分配](#capacity) +* [信息](#info) + +可以使用以下命令显示节点状态和有关节点的其他详细信息: +```shell +kubectl describe node +``` + 下面对每个章节进行详细描述。 - + ### 地址 - + 这些字段组合的用法取决于你的云服务商或者裸机配置。 -* HostName:HostName 和 node 内核报告的相同。可以通过 kubelet 的 `--hostname-override` 参数覆盖。 -* ExternalIP:通常是可以外部路由的 node IP 地址(从集群外可访问)。 -* InternalIP:通常是仅可在集群内部路由的 node IP 地址。 + +* HostName:由节点的内核指定。可以通过 kubelet 的 `--hostname-override` 参数覆盖。 +* ExternalIP:通常是可以外部路由的节点 IP 地址(从集群外可访问)。 +* InternalIP:通常是仅可在集群内部路由的节点 IP 地址。 -### 阶段 + +### 条件 {#condition} + +`conditions` 字段描述了所有 `Running` 节点的状态。条件的示例包括: -已废弃:node 阶段已经不再使用。 + +| 节点条件 | 描述 | +|----------------|-------------| +| `OutOfDisk` | `True` 表示节点的空闲空间不足以用于添加新 pods, 否则为 `False` | +| `Ready` | 表示节点是健康的并已经准备好接受 pods;`False` 表示节点不健康而且不能接受 pods;`Unknown` 表示节点控制器在最近 40 秒内没有收到节点的消息 | +| `MemoryPressure` | `True` 表示节点存在内存压力 -- 即节点内存用量低,否则为 `False` | +| `PIDPressure` | `True` 表示节点存在进程压力 -- 即进程过多;否则为 `False` | +| `DiskPressure` | `True` 表示节点存在磁盘压力 -- 即磁盘用量低,否则为 `False` | +| `NetworkUnavailable` | `True` 表示节点网络配置不正确;否则为 `False` | - -### 条件 - - -`conditions` 字段描述了所有 `Running` nodes 的状态。 - - -| Node 条件 | 描述 | -| ---------------- | ---------------------------------------- | -| `OutOfDisk` | `True` 表示 node 的空闲空间不足以用于添加新 pods, 否则为 `False` | -| `Ready` | `True` 表示 node 是健康的并已经准备好接受 pods;`False` 表示 node 不健康而且不能接受 pods;`Unknown` 表示 node 控制器在最近 40 秒内没有收到 node 的消息 | -| `MemoryPressure` | `True` 表示 node 不存在内存压力 -- 即 node 内存用量低, 否则为 `False` | -| `DiskPressure` | `True` 表示 node 不存在磁盘压力 -- 即磁盘用量低, 否则为 `False` | - - -Node 条件使用一个 JSON 对象表示。例如,下面的响应描述了一个健康的 node。 + +节点条件使用一个 JSON 对象表示。例如,下面的响应描述了一个健康的节点。 ```json "conditions": [ { - "kind": "Ready", - "status": "True" + "type": "Ready", + "status": "True", + "reason": "KubeletReady", + "message": "kubelet is posting ready status", + "lastHeartbeatTime": "2019-06-05T18:38:35Z", + "lastTransitionTime": "2019-06-05T11:41:27Z" } ] ``` - -如果 Ready 条件处于状态 "Unknown" 或者 "False" 的时间超过了 `pod-eviction-timeout`(一个传递给 [kube-controller-manager](/docs/admin/kube-controller-manager/) 的参数),node 上的所有 Pods 都会被 Node 控制器计划删除。默认的删除超时时长为**5分钟**。某些情况下,当 node 不可访问时,apiserver 不能和其上的 kubelet 通信。删除 pods 的决定不能传达给 kubelet,直到它重新建立和 apiserver 的连接为止。与此同时,被计划删除的 pods 可能会继续在分区 node 上运行。 + +如果 Ready 条件处于状态 `Unknown` 或者 `False` 的时间超过了 `pod-eviction-timeout`(一个传递给 [kube-controller-manager](/docs/admin/kube-controller-manager/) 的参数),节点上的所有 Pods 都会被节点控制器计划删除。默认的删除超时时长为**5 分钟**。某些情况下,当节点不可访问时,apiserver 不能和其上的 kubelet 通信。删除 pods 的决定不能传达给 kubelet,直到它重新建立和 apiserver 的连接为止。与此同时,被计划删除的 pods 可能会继续在分区节点上运行。 -在 1.5 版本之前的 Kubernetes 里,node 控制器会将不能访问的 pods 从 apiserver 中[强制删除](/docs/concepts/workloads/pods/pod/#force-deletion-of-pods)。但在 1.5 或更高的版本里,在node 控制器确认这些 pods 已经在集群里停运行前不会强制删除它们。你可以看到这些处于 "Terminating" 或者 "Unknown" 状态的 pods 可能在无法访问的 node 上运行。为了防止 kubernetes 不能从底层基础设施中推断出一个 node 是否已经永久的离开了集群,集群管理员可能需要手动删除这个 node 对象。从 Kubernetes 删除 node 对象将导致 apiserver 删除 node 上所有运行的 Pod 对象并释放它们的名字。 + +在 1.5 版本之前的 Kubernetes 里,节点控制器会将不能访问的 pods 从 apiserver 中[强制删除](/docs/concepts/workloads/pods/pod/#force-deletion-of-pods)。但在 1.5 或更高的版本里,在节点控制器确认这些 pods 已经在集群停止运行前不会强制删除它们。你可以看到这些处于 `Terminating` 或者 `Unknown` 状态的 pods 可能在无法访问的节点上运行。为了防止 kubernetes 不能从底层基础设施中推断出一个节点是否已经永久的离开了集群,集群管理员可能需要手动删除这个节点对象。从 Kubernetes 删除节点对象将导致 apiserver 删除节点上所有运行的 Pod 对象并释放它们的名字。 -### 容量 + +在版本 1.12 中,`TaintNodesByCondition` 功能已升级为 Beta 功能,因此节点生命周期控制器会自动创建代表条件的 [污点](/docs/concepts/configuration/taint-and-toleration/)。同样,scheduler 在考虑节点时会忽略条件,而是查看节点的污点和 Pod 的容忍度。 + +现在用户可以在旧的调度模型和新的、更灵活的调度模型之间进行选择,一个没有任何容忍度的 Pod 会根据旧模型进行调度。但是能够容忍特定节点的污点的 Pod 则可以在该节点上调度执行。 -描述 node 上的可用资源:CPU、内存和可以调度到 node 上的 pods 的最大数量。 +{{< caution >}} +启用此功能会在观察条件与到产生污点之间产生较小的延迟。此延迟通常少于一秒,但会增加成功调度但被 kubelet 拒绝的 Pod 数量。 +{{< /caution >}} + +### 容量与可分配 {#capacity} + +描述节点上的可用资源:CPU、内存和可以调度到节点上的 pods 的最大数量。 + + +capacity 块中的字段指示节点拥有的资源总量。allocatable 块指示节点上可供普通 Pod 消耗的资源量。 + + +可以在学习如何在节点上[保留计算资源](/docs/tasks/administer-cluster/reserve-compute-resources/#node-allocatable)的同时阅读有关容量和可分配资源的更多信息。 + + ### 信息 + +关于节点的通用信息,例如内核版本、Kubernetes 版本(kubelet 和 kube-proxy 版本)、Docker 版本(如果使用了)和操作系统名称。这些信息由 kubelet 从节点上搜集而来。 -关于 node 的通用信息,例如内核版本、Kubernetes 版本(kubelet 和 kube-proxy 版本)、Docker 版本 (如果使用了)和 OS 名。这些信息由 Kubelet 从 node 搜集而来。 - - + ## 管理 + +与 [pods](/docs/concepts/workloads/pods/pod/) 和 [services](/docs/concepts/services-networking/service/) 不同,节点并不是在 Kubernetes 内部创建的:它是被外部的云服务商创建,例如 Google Compute Engine 或者你的集群中的物理或者虚拟机。这意味着当 Kubernetes 创建一个节点时,它其实仅仅创建了一个对象来代表这个节点。创建以后,Kubernetes 将检查这个节点是否可用。例如,如果你尝试使用如下内容创建一个节点: -与 [pods](/docs/user-guide/pods) 和 [services](/docs/user-guide/services) 不同,node 并不是在 Kubernetes 内部创建的:它是被外部的云服务商创建,例如 Google Compute Engine 或者你的集群中的物理或者虚拟机。这意味着当 Kubernetes 创建一个 node 时,它其实仅仅创建了一个对象来代表这个 node。创建以后,Kubernetes 将检查这个 node 是否可用。例如,如果你尝试使用如下内容创建一个 node: ```json { @@ -113,121 +236,293 @@ Node 条件使用一个 JSON 对象表示。例如,下面的响应描述了一 } ``` + +Kubernetes 会在内部创一个 Node 对象(用以表示节点),并基于 `metadata.name` 字段执行健康检查,对节点进行验证。如果节点可用,意即所有必要服务都已运行,它就符合了运行一个 pod 的条件;否则它将被所有的集群动作忽略直到变为可用。 -Kubernetes 会在内部创一个 node 对象(象征 node),并基于 `metadata.name` 字段(我们假设 `metadata.name` 能够被解析)通过健康检查来验证 node。如果 node 可用,意即所有必要服务都已运行,它就符合了运行一个 pod 的条件;否则它将被所有的集群动作忽略直到变为可用。请注意,Kubernetes 将保存不可用 node 的对象,除非它被客户端显式的删除。Kubernetes 将持续检查 node 是否变的可用。 +{{< note >}} + Kubernetes 保留无效节点的对象,并继续检查它是否有效。必须显式删除 Node 对象以停止此过程。 +{{< /note >}} + + +当前,有 3 个组件同 Kubernetes 节点接口交互:节点控制器、kubelet 和 kubectl。 + + +### 节点控制器 + + +节点控制器是一个 Kubernetes master 组件,管理节点的方方面面。 + + +节点控制器在节点的生命周期中扮演了多个角色。第一个是当节点注册时为它分配一个 CIDR block(如果打开了 CIDR 分配)。 + + +第二个是使用云服务商提供了可用节点列表保持节点控制器内部的节点列表更新。如果在云环境下运行,任何时候当一个节点不健康时节点控制器将询问云服务节点的虚拟机是否可用。如果不可用,节点控制器会将这个节点从它的节点列表删除。 + + +第三个是监控节点的健康情况。节点控制器负责在节点不能访问时(也即是节点控制器因为某些原因没有收到心跳,例如节点宕机)将它的 NodeStatus 的 NodeReady 状态更新为 ConditionUnknown。后续如果节点持续不可访问,节点控制器将删除节点上的所有 pods(使用优雅终止)。(默认情况下 40s 开始报告 ConditionUnknown,在那之后 5m 开始删除 pods。)节点控制器每隔 `--node-monitor-period` 秒检查每个节点的状态。 + + +在 1.13 之前的 Kubernetes 版本中,NodeStatus 是来自节点的心跳信号。从 1.14 开始,默认情况下已启用节点租赁功能作为 beta 功能(功能特性开关 `NodeLease`、[KEP-0009](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/0009-node-heartbeat.md))。 + + +启用节点租赁功能后,每个节点在 `kube-node-lease` 命名空间中都有一个关联的 `Lease` 租赁对象,该对象由节点定期更新,并且 NodeStatus 和节点租赁都被视为来自节点的心跳信号。仅当发生某些更改或经过了足够的时间(默认值为 1 分钟,比无法访问的节点的默认超时 40 秒)时,才会频繁更新节点租约,同时将 NodeStatus 从节点报告给主节点。由于节点租赁比 NodeStatus 轻得多,因此从可伸缩性和性能的角度来看,此功能使节点心跳明显便利。 + + +在 Kubernetes 1.4 中我们更新了节点控制器逻辑以更好地处理大批量节点访问 master 出问题的情况(例如 master 的网络出了问题)。从 1.4 开始,节点控制器在决定删除 pod 之前会检查集群中所有节点的状态。 + + +大部分情况下,节点控制器把驱逐频率限制在每秒 `--node-eviction-rate` 个(默认为 0.1)。这表示它每 10 秒钟内之多从一个节点驱逐 Pods。 + + +当一个可用区域中的节点变为不健康时,它的驱逐行为将发生改变。节点控制器会同时检查可用区域中不健康(NodeReady 状态为 ConditionUnknown 或 ConditionFalse)的节点的百分比。如果不健康节点的部分超过 `--unhealthy-zone-threshold` (默认为 0.55),驱逐速率将会减小:如果集群较小(意即小于等于 `--large-cluster-size-threshold` 个 节点 - 默认为 50),驱逐操作将会停止,否则驱逐速率将降为每秒 `--secondary-node-eviction-rate` 个(默认为 0.01)。在单个可用区域实施这些策略的原因是当一个可用区域可能从 master 分区时其它的仍然保持连接。如果你的集群没有跨越云服务商的多个可用区域,那就只有一个可用区域整个集群)。 + + +在多个可用区域分布你的节点的一个关键原因是当整个可用区域故障时,工作负载可以转移到健康的可用区域。因此,如果一个可用区域中的所有节点都不健康时,节点控制器会以正常的速率 `--node-eviction-rate` 进行驱逐操作。在所有的可用区域都不健康(也即集群中没有健康节点)的极端情况下,节点控制器将假设 master 的连接出了某些问题,它将停止所有驱逐动作直到一些连接恢复。 + + +从 Kubernetes 1.6 开始,NodeController 还负责驱逐运行在拥有 `NoExecute` 污点的节点上的 pods,如果这些 pods 没有容忍这些污点。此外,作为一个默认禁用的 alpha 特性,NodeController 还负责根据节点故障(例如节点不可访问或没有 ready)添加污点。请查看[这个文档](/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature)了解关于 `NoExecute` 污点和这个 alpha 特性。 -当前,有3个组件同 Kubernetes node 接口交互:node 控制器、kubelet 和 kubectl。 - - -### Node 控制器 - - -Node 控制器是一个 Kubernetes master 组件,管理 nodes 的方方面面。 - - -Node 控制器在 node 的生命周期中扮演了多个角色。第一个是当 node 注册时为它分配一个 CIDR block(如果打开了 CIDR 分配)。 - - -第二个是使用云服务商提供了可用节点列表保持 node 控制器内部的 nodes 列表更新。如果在云环境下运行,任何时候当一个 node 不健康时 node 控制器将询问云服务 node 的虚拟机是否可用。如果不可用,node 控制器会将这个 node 从它的 nodes 列表删除。 - - -第三个是监控 nodes 的健康情况。Node 控制器负责在 node 不能访问时(也即是 node 控制器因为某些原因没有收到心跳,例如 node 宕机)将它的 NodeStatus 的 NodeReady 状态更新为 ConditionUnknown。后续如果 node 持续不可访问,Node 控制器将删除 node 上的所有 pods(使用优雅终止)。(默认情况下 40s 开始报告 ConditionUnknown,在那之后 5m 开始删除 pods。)Node 控制器每隔 `--node-monitor-period` 秒检查每个 node 的状态。 - - -在 Kubernetes 1.4 中我们更新了 node 控制器逻辑以更好的处理大批量 nodes 访问 master 出问题的情况(例如 master 的网络出了问题)。从 1.4 开始,node 控制器在决定删除 pod 之前会检查集群中所有 nodes 的状态。 - - -大部分情况下, node 控制器把删除频率限制在每秒 `--node-eviction-rate` 个(默认为 0.1)。这表示它在 10 秒钟内不会从超过一个 node 上删除 pods。 - - -当一个 availability zone 中的 node 变为不健康时,它的删除行为将发生改变。Node 控制器会同时检查 zone 中不健康(NodeReady 状态为 ConditionUnknown 或 ConditionFalse)的 nodes 的百分比。如果不健康 nodes 的部分超过 `--unhealthy-zone-threshold` (默认为 0.55),删除速率将会减小:如果集群较小(意即小于等于 `--large-cluster-size-threshold` 个 nodes - 默认为50),删除将会停止,否则删除速率将降为每秒 `--secondary-node-eviction-rate` 个(默认为 0.01)。在单个 availability zone 实施这些策略的原因是当一个 availability zone 可能从 master 分区时其它的仍然保持连接。如果你的集群没有跨越云服务商的多个 availability zones,那就只有一个 availability zone(整个集群)。 - - -在多个 availability zones 分布你的 nodes 的一个关键原因是当整个 zone 故障时,工作负载可以转移到健康的 zones。因此,如果一个 zone 中的所有 nodes 都不健康时,node 控制器会以正常的速率 `--node-eviction-rate` 删除。在所有的 zones 都不健康(也即集群中没有健康 node)的极端情况下,node 控制器将假设 master 的连接出了某些问题,它将停止所有删除动作直到一些连接恢复。 - - -从 Kubernetes 1.6 开始,NodeController 还负责删除运行在拥有 `NoExecute` taints 的 nodes 上的 pods,如果这些 pods 没有 tolerate 这些 taints。此外,作为一个默认禁用的 alpha 特性,NodeController 还负责根据 node 故障(例如 node 不可访问或没有 ready)添加 taints。请查看 [这个文档](/docs/concepts/configuration/assign-pod-node/#taints-and-tolerations-beta-feature)了解关于 `NoExecute` taints 和这个 alpha 特性。 - - -### Nodes 自注册 + +从版本 1.8 开始,可以使节点控制器负责创建代表节点条件的污点。这是版本 1.8 的 Alpha 功能。 + +### 节点自注册 + 当 kubelet 标志 `--register-node` 为 true (默认)时,它会尝试向 API 服务注册自己。这是首选模式,被绝大多数发行版选用。 - + 对于自注册模式,kubelet 使用下列参数启动: - - `--api-servers` - apiservers 地址。 + - `--kubeconfig` - 用于向 apiserver 验证自己的凭据路径。 - `--cloud-provider` - 如何从云服务商读取关于自己的元数据。 - - `--register-node` - 自动向 API 服务注册。 - - `--register-with-taints` - 使用 taints 列表(逗号分隔的 `=:`)注册 node。当 `register-node` 为 false 时无效。 - - `--node-ip` - node IP 地址。 - - `--node-labels` - 向集群注册时给 node 添加的 labels。 + - `--register-node` - 自动向 API 服务注册。 + - `--register-with-taints` - 使用 taints 列表(逗号分隔的 `=:`)注册节点。当 `register-node` 为 false 时无效。 + - `--node-ip` - 节点 IP 地址。 + - `--node-labels` - 在集群中注册节点时要添加的标签(请参阅 [NodeRestriction 准入插件](/docs/reference/access-authn-authz/admission-controllers/#noderestriction) 在 1.13+ 中实施的标签限制)。 - `--node-status-update-frequency` - 指定 kubelet 向 master 发送状态的频率。 + +启用[节点授权模式](/docs/reference/access-authn-authz/node/) 和 [NodeRestriction 准入插件](/docs/reference/access-authn-authz/admission-controllers/#noderestriction)时,仅授权小组件创建或修改其自己的节点资源。 -目前,任何 kubelet 都被授权可以创建/修改任意 node 资源,但通常只对自己的进行创建/修改。(未来我们计划只允许一个 kubelet 修改它自己 node 的资源。) + +#### 手动节点管理 + +集群管理员可以创建及修改节点对象。 -#### 手动 Node 管理 + +如果管理员希望手动创建节点对象,请设置 kubelet 标记 `--register-node=false`。 + +管理员可以修改节点资源(忽略 `--register-node` 设置)。修改包括在节点上设置 labels 及标记它为不可调度。 -集群管理员可以创建及修改 node 对象。 + +节点上的 labels 可以和 pods 的节点 selectors 一起使用来控制调度,例如限制一个 pod 只能在一个符合要求的节点子集上运行。 + +标记一个节点为不可调度的将防止新建 pods 调度到那个节点之上,但不会影响任何已经在它之上的 pods。这是重启节点等操作之前的一个有用的准备步骤。例如,标记一个节点为不可调度的,执行以下命令: -如果管理员希望手动创建 node 对象,请设置 kubelet 标记 `--register-node=false`。 - - -管理员可以修改 node 资源(忽略 `--register-node` 设置)。修改包括在 node 上设置 labels及标记它为不可调度。 - - -Nodes 上的 labels 可以和 pods 的 node selectors 一起使用来控制调度,例如限制一个 pod 只能在一个符合要求的 nodes 子集上运行。 - - -标记一个 node 为不可调度的将防止新建 pods 调度到那个 node 之上,但不会影响任何已经在它之上的 pods。这是重启 node 等操作之前的一个有用的准备步骤。例如,标记一个 node 为不可调度的,执行以下命令: ```shell kubectl cordon $NODENAME ``` +{{< note >}} + +请注意,被 daemonSet 控制器创建的 pods 将忽略 Kubernetes 调度器,且不会遵照节点上不可调度的属性。这个假设基于守护程序属于节点机器,即使在准备重启而隔离应用的时候。 +{{< /note >}} -请注意,被 daemonSet 控制器创建的 pods 将忽略 Kubernetes 调度器,且不会遵照 node 上不可调度的属性。这个假设基于守护程序属于节点机器,即使在准备重启而隔离应用的时候。 + +### 节点容量 + +节点的容量(cpu 数量和内存容量)是节点对象的一部分。通常情况下,在创建节点对象时,它们会注册自己并报告自己的容量。如果你正在执行[手动节点管理](#manual-node-administration),那么你需要在添加节点时手动设置节点容量。 -### Node 容量 + +Kubernetes 调度器保证一个节点上有足够的资源供其上的所有 pods 使用。它会检查节点上所有容器要求的总和不会超过节点的容量。这包括由 kubelet 启动的所有容器,但不包括由 [container runtime](/docs/concepts/overview/components/#node-components) 直接启动的容器,也不包括在容器外部运行的任何进程。 + +如果要为非 Pod 进程显式保留资源。请按照本教程[为系统守护程序保留资源](/docs/tasks/administer-cluster/reserve-compute-resources/#system-reserved)。 -Node 的容量(cpu 数量和内存容量)是 node 对象的一部分。通常情况下,在创建 node 对象时,它们会注册自己并报告自己的容量。如果你正在执行[手动 node 管理](#manual-node-administration),那么你需要在添加 node 时手动设置 node 容量。 + +## 节点拓扑 +{{< feature-state state="alpha" >}} -Kubernetes 调度器保证一个 node 上有足够的资源供其上的所有 pods 使用。它会检查 node 上所有容器要求的总和不会超过 node 的容量。这包括所有 kubelet 启动的容器,但不包含 Docker 启动的容器和不在容器中的进程。 - - -如果希望显式的为非 pod 进程预留资源,你可以创建一个占位 pod。使用如下模板: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: resource-reserver -spec: - containers: - - name: sleep-forever - image: k8s.gcr.io/pause:0.8.0 - resources: - requests: - cpu: 100m - memory: 100Mi -``` - - -设置 `cpu` 和 `memory` 值为你希望预留的资源量。将文件放在清单文件夹中(kubelet 的 `--config=DIR` 标志)。当你希望预留资源时,在每个 kubelet 上都这样执行。 - + +如果启用了 `TopologyManager` [功能开关](/docs/reference/command-line-tools-reference/feature-gates/),则 kubelet 可以在做出资源分配决策时使用拓扑提示。 + ## API 对象 + +节点是 Kubernetes REST API 的顶级资源。更多关于 API 对象的细节可以在这里找到:[节点 API 对象](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#node-v1-core)。 -Node 是 Kubernetes REST API 的顶级资源。更多关于 API 对象的细节可以在这里找到: [Node API -object](/docs/api-reference/{{< param "version" >}}/#node-v1-core).`` +{{% /capture %}} +{{% capture whatsnext %}} + +* 了解有关[节点组件](https://kubernetes.io/docs/concepts/overview/components/#node-components)的信息。 +* 阅读有关节点级拓扑的信息:[控制节点上的拓扑管理策略](/docs/tasks/administer-cluster/topology-manager/)。 +{{% /capture %}} diff --git a/content/zh/docs/concepts/cluster-administration/_index.md b/content/zh/docs/concepts/cluster-administration/_index.md index b96947faec..ae2be0cb1f 100644 --- a/content/zh/docs/concepts/cluster-administration/_index.md +++ b/content/zh/docs/concepts/cluster-administration/_index.md @@ -1,4 +1,11 @@ --- title: "计算、存储和网络扩展" weight: 30 ---- \ No newline at end of file +--- + + diff --git a/content/zh/docs/concepts/cluster-administration/cloud-providers.md b/content/zh/docs/concepts/cluster-administration/cloud-providers.md index 71bfccb753..4b6f6a36e1 100644 --- a/content/zh/docs/concepts/cluster-administration/cloud-providers.md +++ b/content/zh/docs/concepts/cluster-administration/cloud-providers.md @@ -1,17 +1,105 @@ --- -title: 云供应商 +title: 云驱动 content_template: templates/concept +weight: 30 --- + + {{% capture overview %}} -本文介绍了如何管理运行在特定云供应商上的 Kubernetes 集群。 + +本文介绍了如何管理运行在特定云驱动上的 Kubernetes 集群。 {{% /capture %}} {{% capture body %}} + +### kubeadm +[kubeadm](/docs/reference/setup-tools/kubeadm/kubeadm/) 是创建 kubernetes 集群的一种流行选择。 +kubeadm 通过提供配置选项来指定云驱动的配置信息。例如,一个典型的适用于“树内”云驱动的 kubeadm 配置如下: + +```yaml +apiVersion: kubeadm.k8s.io/v1beta2 +kind: InitConfiguration +nodeRegistration: + kubeletExtraArgs: + cloud-provider: "openstack" + cloud-config: "/etc/kubernetes/cloud.conf" +--- +apiVersion: kubeadm.k8s.io/v1beta2 +kind: ClusterConfiguration +kubernetesVersion: v1.13.0 +apiServer: + extraArgs: + cloud-provider: "openstack" + cloud-config: "/etc/kubernetes/cloud.conf" + extraVolumes: + - name: cloud + hostPath: "/etc/kubernetes/cloud.conf" + mountPath: "/etc/kubernetes/cloud.conf" +controllerManager: + extraArgs: + cloud-provider: "openstack" + cloud-config: "/etc/kubernetes/cloud.conf" + extraVolumes: + - name: cloud + hostPath: "/etc/kubernetes/cloud.conf" + mountPath: "/etc/kubernetes/cloud.conf" +``` + + + +“树内”的云驱动通常需要在命令行中为 [kube-apiserver](/docs/admin/kube-apiserver/)、[kube-controller-manager](/docs/admin/kube-controller-manager/) 和 [kubelet](/docs/admin/kubelet/) 指定 `--cloud-provider` 和 `--cloud-config`。在 `--cloud-config` 中为每个供应商指定的文件的内容也同样需要写在下面。 +对于所有外部云驱动,请遵循独立云存储库的说明,或浏览[所有版本库清单](https://github.com/kubernetes?q=cloud-provider-&type=&language=) + + + # AWS 本节介绍在 Amazon Web Services 上运行 Kubernetes 时可以使用的所有配置。 +如果希望使用此外部云驱动,其代码库位于 [kubernetes/cloud-provider-aws](https://github.com/kubernetes/cloud-provider-aws#readme) + + +### 节点名称 + +云驱动 AWS 使用 AWS 实例的私有 DNS 名称作为 Kubernetes 节点对象的名称。 + + +### 负载均衡器 -## 负载均衡器 用户可以通过配置注解(annotations)来设置 [外部负载均衡器](/docs/tasks/access-application-cluster/create-external-load-balancer/),以在 AWS 中使用特定功能,如下所示: ```yaml @@ -34,35 +122,210 @@ spec: selector: app: example ``` -可以使用 _注解_ 将不同的设置应用于 AWS 中的负载平衡器服务。 下面描述了 AWS ELB 所支持的注解: + + +可以使用 _注解_ 将不同的设置应用于 AWS 中的负载均衡器服务。下面描述了 AWS ELB 所支持的注解: + + * `service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval`:用于指定访问日志的间隔。 -* `service.beta.kubernetes.io/aws-load-balancer-access-log-enabled`:用于在服务中启用或禁用日志访问。 +* `service.beta.kubernetes.io/aws-load-balancer-access-log-enabled`:用于在服务中启用或禁用访问日志。 * `service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name`:用于指定访问日志的 S3 桶名称。 * `service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix`:用于指定访问日志的 S3 桶前缀。 -* `service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags`:用于在服务中指定一个逗号分隔的键值对列表,它将作为附加标签被记录在 ELB 中。 例如: `"Key1=Val1,Key2=Val2,KeyNoVal1=,KeyNoVal2"`。 -* `service.beta.kubernetes.io/aws-load-balancer-backend-protocol`:用于在服务中指定监听器后端(pod)所使用的协议。 如果指定 `http` (默认) 或 `https`, 将创建一个终止连接和解析头的 HTTPS 监听器。 如果设置为 `ssl` 或 `tcp`, 将会使用 “原生的” SSL 监听器。 如果设置为 `http` 且不使用 `aws-load-balancer-ssl-cert`,将使用 HTTP 监听器。 -* `service.beta.kubernetes.io/aws-load-balancer-ssl-cert`:用于在服务中请求安全监听器,其值为合法的证书 ARN(Amazon Resource Name)。 更多内容,请参考 [ELB 监听器配置](http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-listener-config.html)。 证书 ARN 是 IAM(身份和访问管理) 或 CM(证书管理)类型的 ARN,例如 `arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012`。 +* `service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags`:用于在服务中指定一个逗号分隔的键值对列表,它将作为附加标签被记录在 ELB 中。例如: `"Key1=Val1,Key2=Val2,KeyNoVal1=,KeyNoVal2"`。 +* `service.beta.kubernetes.io/aws-load-balancer-backend-protocol`:用于在服务中指定监听器后端(pod)所使用的协议。如果指定 `http`(默认)或 `https`,将创建一个终止连接和解析头的 HTTPS 监听器。 如果设置为 `ssl` 或 `tcp`,将会使用 “原生的” SSL 监听器。如果设置为 `http`且不使用 `aws-load-balancer-ssl-cert`,将使用 HTTP 监听器。 +* `service.beta.kubernetes.io/aws-load-balancer-ssl-cert`:用于在服务中请求安全监听器,其值为合法的证书 ARN(Amazon Resource Name)。更多内容,请参考 [ELB 监听器配置](http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-listener-config.html)。证书 ARN 是 IAM(身份和访问管理)或 CM(证书管理)类型的 ARN,例如 `arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012`。 * `service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled`:用于在服务中启用或禁用连接耗尽(connection draining)。 * `service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout`:用于在服务中指定连接耗尽超时时间。 * `service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout`:用于在服务中指定空闲连接超时时间。 * `service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled`:用于在服务中启用或禁用跨区域负载平衡。 * `service.beta.kubernetes.io/aws-load-balancer-extra-security-groups`:用于在服务中指定要添加到创建的 ELB 中的其他安全组。 * `service.beta.kubernetes.io/aws-load-balancer-internal`:用于在服务中表明需要内部 ELB。 -* `service.beta.kubernetes.io/aws-load-balancer-proxy-protocol`:用于在 ELB 上启用代理协议。 当前仅接受 `*` 值,也就是在所有 ELB 后端启用代理协议。 将来可能进行调整,只允许特定的后端设置代理协议。 -* `service.beta.kubernetes.io/aws-load-balancer-ssl-ports`:用于在服务中指定一个逗号分隔的端口列表,这些端口会使用 SSL/HTTPS 监听器。 默认为 `*`(全部) +* `service.beta.kubernetes.io/aws-load-balancer-proxy-protocol`:用于在 ELB 上启用代理协议。 当前仅接受 `*`值,也就是在所有 ELB 后端启用代理协议。将来可能进行调整,只允许特定的后端设置代理协议。 +* `service.beta.kubernetes.io/aws-load-balancer-ssl-ports`:用于在服务中指定一个逗号分隔的端口列表,这些端口会使用 SSL/HTTPS 监听器。默认为 `*`(全部) + + AWS 相关的注解信息取自 [aws.go](https://github.com/kubernetes/cloud-provider-aws/blob/master/pkg/cloudprovider/providers/aws/aws.go) 文件的注释。 -# OpenStack +## Azure + + +如果希望使用此外部云驱动,其代码库位于 [kubernetes/cloud-provider-azure](https://github.com/kubernetes/cloud-provider-azure#readme) + + + +### 节点名称 + +云驱动 Azure 使用节点的主机名(由 kubelet 决定,或者用 `--hostname-override` 覆盖)作为 Kubernetes 节点对象的名称。 +注意 Kubernetes 节点名必须与 Azure 虚拟机的名称匹配。 + +## CloudStack + + + +如果希望使用此外部云驱动,其代码库位于 [apache/cloudstack-kubernetes-provider](https://github.com/apache/cloudstack-kubernetes-provider)。 + + + +### 节点名称 + +云驱动 CloudStack 使用节点的主机名(由 kubelet 决定,或者用 `--hostname-override` 覆盖)作为 Kubernetes 节点对象的名称。 +注意 Kubernetes 节点名必须与 CloudStack 虚拟机名匹配。 + +## GCE + + +如果希望使用此外部云驱动,其代码库位于 [kubernetes/cloud-provider-gcp](https://github.com/kubernetes/cloud-provider-gcp#readme) + + + +### 节点名称 + +GCE 云驱动使用节点的主机名(由 kubelet 确定,或者用 `--hostname-override` 覆盖)作为 Kubernetes 节点对象的名称。 +注意,Kubernetes 节点名的第一个字段必须匹配 GCE 实例名(例如,名为 `kubernetes-node-2.c.my-proj.internal` 的节点必须对应于一个名为 `kubernetes-node-2` 的实例)。 + +## OpenStack + + 本节介绍了使用 OpenStack 运行 Kubernetes 时所有可用的配置。 +如果希望使用此外部云驱动,其代码库位于 [kubernetes/cloud-provider-openstack](https://github.com/kubernetes/cloud-provider-openstack#readme) -## cloud.conf -Kubernetes 知道如何通过文件 cloud.conf 与 OpenStack 进行交互。 该文件会为 Kubernetes 提供证书和 OpenStack 认证端点的区位信息。 -用户可以通过在其中指定以下信息来创建 cloud.conf 文件。 + + +### 节点名称 + +OpenStack 云驱动使用实例名(由 OpenStack 元数据确定)作为 Kubernetes 节点对象的名称。 +请注意,实例名必须是一个有效的 Kubernetes 节点名,以便 kubelet 成功注册其节点对象。 + + +### 服务 + +Kubernetes 的 OpenStack 云驱动实现支持从底层云使用这些 OpenStack 服务: + +| 服务 | API 版本 | 必需 | +|--------------------------|----------------|----------| +| 块存储 (Cinder) | V1†, V2, V3 | No | +| 计算 (Nova) | V2 | No | +| 身份认证 (Keystone) | V2‡, V3 | Yes | +| 负载均衡器 (Neutron) | V1§, V2 | No | +| 负载均衡器 (Octavia) | V2 | No | + + + +† Block Storage V1 版本的 API 被弃用,从 Kubernetes 1.9 版本开始加入了 Block Storage V3 版本 API。 + +‡ Identity V2 API 支持已被弃用,将在未来的版本中从供应商中移除。从 “Queens” 版本开始,OpenStack 将不再支持 Identity V2 版本的 API。 + +§ Kubernetes 1.9 中取消了对 V1 版本 Load Balancing API 的支持。 + + + +服务发现是通过使用供应商配置中提供的 `auth-url` 所列出 OpenStack 身份认证(Keystone)管理的服务目录来实现的。 +当除 Keystone 外的 OpenStack 服务不可用时,供应商将优雅地降低功能,并简单地放弃对受影响特性的支持。 +某些功能还可以根据 Neutron 在底层云中发布的扩展列表启用或禁用。 + +### cloud.conf + + +Kubernetes 知道如何通过 cloud.conf 文件与 OpenStack 交互。该文件将为 Kubernetes 提供 OpenStack 验证端点的凭据和位置。 +用户可在创建 cloud.conf 文件时指定以下信息: + + +#### 典型配置 + +下面是一个典型配置的例子,它涉及到最常设置的值。它将供应商指向 OpenStack 云的 Keystone 端点,提供如何使用它进行身份验证的细节,并配置负载均衡器: ```yaml [Global] @@ -75,35 +338,352 @@ domain-id=2a73b8f597c04551a0fdc8e95544be8a [LoadBalancer] subnet-id=6937f8fa-858d-4bc9-a3a5-18d2c957166a ``` + -#### 全局配置 -* `username`:指 keystone 中设置的一个合法用户的用户名。 -* `password`:指 keystone 中设置的一个合法用户的密码。 -* `auth-url`:用于认证的 keystone API 的 URL 。 在 OpenStack 控制面板上,可以在 “访问和安全(Access and Security)> api 访问(API Access)> 凭证(Credentials)” 路径下找到它。 -* `tenant-id`:用于指定要创建资源的项目 ID。 -* `domain-id`:用于指定用户所属的域(domain)ID。 +##### 全局配置 + +这些配置选项属于 OpenStack 驱动的全局配置,并且应该出现在 `cloud.conf` 文件中的 `[global]` 部分: + + + +* `auth-url` (必需): 用于认证的 keystone API 的 URL。在 OpenStack 控制面板中,这可以在“访问和安全(Access and Security)> API 访问(API Access)> 凭证(Credentials)”中找到。 +* `username` (必需): 指 keystone 中一个有效用户的用户名。 +* `password` (必需): 指 keystone 中一个有效用户的密码。 +* `tenant-id` (必需): 用于指定要创建资源的租户 ID。 +* `tenant-name` (可选): 用于指定要在其中创建资源的租户的名称。 +* `trust-id` (可选): 用于指定用于授权的信任的标识符。信任表示用户(委托人)将角色委托给另一个用户(受托人)的授权,并可选的允许受托人模仿委托人。可用的信任可以在 Keystone API 的 `/v3/OS-TRUST/trusts` 端点下找到。 +* `domain-id` (可选): 用于指定用户所属域的 ID。 +* `domain-name` (可选): 用于指定用户所属域的名称。 +* `region` (可选): 用于指定在多区域 OpenStack 云上运行时使用的区域标识符。区域是 OpenStack 部署的一般性划分。虽然区域没有严格的地理含义,但部署可以使用地理名称表示区域标识符,如 `us-east`。可用区域位于 Keystone API 的 `/v3/regions` 端点之下。 +* `ca-file` (可选): 用于指定自定义 CA 文件的路径。 + + + +当使用 Keystone V3 时(它将tenant更改为project),`tenant-id` 值会自动映射到 API 中的项目。 + + #### 负载均衡器 -* `subnet-id`:用于指定要创建的负载均衡器所在的子网 ID。 可以在 “Network > Networks” 路径下找到它。 点击相应的网络获取其子网。 -### 可选配置 +这些配置选项属于 OpenStack 驱动的全局配置,并且应该出现在 `cloud.conf` 文件中的 `[LoadBalancer]` 部分: -#### 块存储 + -Kubernetes 利用 OpenStack 服务目录对它知道如何使用的服务进行定位,包括 Cinder 块存储服务。 然而,云供应商的配置中包含一个附加选项,可以影响块存储 API 的使用方式: +* `lb-version` (可选): 用于覆盖自动版本检测。有效值为 `v1` 或 `v2`。如果没有提供值,则自动选择底层 OpenStack 云所支持的最高版本。 +* `use-octavia` (可选): 用于确定是否查找和使用 Octavia LBaaS V2 服务目录端点。有效值是 `true` 或 `false`。 +如果指定了“true”,并且无法找到 Octaiva LBaaS V2 入口,则提供者将退回并尝试寻找一个 Neutron LBaaS V2 端点。默认值是 `false`。 +* `subnet-id` (可选): 用于指定要在其上创建负载均衡器的子网的 ID。 +可以在 “Network > Networks” 上找到。 +单击相应的网络以获得其子网。 +* `floating-network-id` (可选): 如果指定,将为负载均衡器创建一个浮动 IP。 +* `lb-method` (可选): 用于指定将负载分配到负载均衡器池成员的算法。值可以是 `ROUND_ROBIN`、`LEAST_CONNECTIONS` 或 `SOURCE_IP`。如果没有指定,默认行为是 `ROUND_ROBIN`。 +* `lb-provider` (可选): 用于指定负载均衡器的提供程序。如果没有指定,将使用在 Neutron 中配置的默认提供者服务。 +* `create-monitor` (可选): 指定是否为 Neutron 负载均衡器创建健康监视器。有效值是 `true` 和 `false`。 +默认为 `false`。当指定 `true` 时,还必须设置 `monitor-delay`、`monitor-timeout` 和 `monitor-max-retries`。 +* `monitor-delay` (可选): 向负载均衡器的成员发送探测之间的时间间隔。 +确保您指定了一个有效的时间单位。 +有效时间单位为 `ns`、`us` (或 `µs`)、`ms`、`s`、`m`、`h`。 +* `monitor-timeout` (可选): 在超时之前,监视器等待 ping 响应的最长时间。该值必须小于延迟值。确保您指定了一个有效的时间单位。有效时间单位为 `ns`、 `us` (或 `µs`)、`ms`、`s`、`m`、 `h`。 +* `monitor-max-retries` (可选): 在将负载均衡器成员的状态更改为非活动之前,允许 ping 失败的次数。 +必须是 1 到 10 之间的数字。 +* `manage-security-groups` (可选): 确定负载均衡器是否应自动管理安全组规则。有效值是 `true` 和 `false`。默认为 `false`。当指定 `true` 时,还必须提供 `node-security-group`。 +* `node-security-group` (可选): 要管理的安全组的 ID。 -* `bs-version`:指所使用的块存储 API 版本。 其合法值为 - `v1`、 `v2`、 `v3` 和 `auto`。 `auto` 为默认值,将使用底层 Openstack 所支持的块存储 API 的最新版本。 + -如果在 OpenStack 上部署 Kubernetes <= 1.8 的版本,同时使用路径而不是端口来区分端点(endpoints),那么可能需要显式设置 `bs-version` 参数。 基于路径的端点形如 `http://foo.bar/volume` ,而基于端口的的端点形如 +##### 块存储 + +这些配置选项属于 OpenStack 驱动的全局配置,并且应该出现在 `cloud.conf` 文件中的 `[BlockStorage]` 部分: + + + +* `bs-version` (可选): 指所使用的块存储 API 版本。其合法值为 `v1`、`v2`、`v3`和 `auto`。 `auto` 为默认值,将使用底层 Openstack 所支持的块存储 API 的最新版本。 +* `trust-device-path` (可选): 在大多数情况下,块设备名称由 Cinder 提供(例如:`/dev/vda`)不可信任。此布尔值切换此行为。将其设置为 `true` 将导致信任 Cinder 提供的块设备名称。默认值 `false` 会根据设备序列号和 `/dev/disk/by-id` 映射发现设备路径,推荐这种方法。 +* `ignore-volume-az` (可选): 用于在附加 Cinder 卷时影响可用区使用。 +当 Nova 和 Cinder 有不同的可用区域时,应该将其设置为 `true`。 +最常见的情况是,有许多 Nova 可用区,但只有一个 Cinder 可用区。 +默认值是 `false`,以保持在早期版本中使用的行为,但是将来可能会更改。 +* `node-volume-attach-limit` (可选): 可连接到节点的最大卷数,对于 Cinder 默认为 256。 + + + +如果在 OpenStack 上部署 Kubernetes <= 1.8 的版本,同时使用路径而不是端口来区分端点(Endpoints),那么可能需要显式设置 `bs-version` 参数。 基于路径的端点形如 `http://foo.bar/volume`,而基于端口的的端点形如 `http://foo.bar:xxx`。 -在使用基于路径的端点,并且 Kubernetes 使用较旧的自动检索逻辑的环境中,尝试卷卸载(detachment)会返回 `BS API version autodetection failed.` 错误。 为了解决这个问题,可以通过添加以下内容到云供应商配置中,来强制使用 Cinder API V2 版本。 +在使用基于路径的端点,并且 Kubernetes 使用较旧的自动检索逻辑的环境中,尝试卷卸载(Detachment)会返回 `BS API version autodetection failed.` 错误。为了解决这个问题,可以通过添加以下内容到云驱动配置中,来强制使用 Cinder API V2 版本。 + ```yaml [BlockStorage] bs-version=v2 ``` + + +##### 元数据 + +这些配置选项属于 OpenStack 提供程序的全局配置,并且应该出现在 `cloud.conf` 文件中的 `[Metadata]` 部分: + +* `search-order` (可选): 此配置键影响提供者检索与其运行的实例相关的元数据的方式。 +`configDrive,metadataService` 的默认值导致供应商首先从配置驱动器中检索与实例相关的元数据(如果可用的话),然后检索元数据服务。 +他们的替代值: + * `configDrive` - 仅从配置驱动器检索实例元数据。 + * `metadataService` - 仅从元数据服务检索实例元数据。 + * `metadataService,configDrive` - 如果可用,首先从元数据服务检索实例元数据,然后从配置驱动器检索。 + +影响这种行为可能是可取的,因为配置驱动器上的元数据可能会随着时间的推移而变得陈旧,而元数据服务总是提供最新的数据视图。并不是所有的 OpenStack 云都同时提供配置驱动和元数据服务,可能只有一个或另一个可用,这就是为什么默认情况下要同时检查两个。 + + + +##### 路由 + +这些配置选项属于 OpenStack 驱动为 Kubernetes 网络插件 [kubenet] 提供的设置,并且应该出现在 `cloud.conf` 文件中的 `[Route]` 部分: + +* `router-id` (可选):如果底层云的 Neutron 部署支持 `extraroutes` 扩展,则使用 `router-id` 指定要添加路由的路由器。选择的路由器必须跨越包含集群节点的私有网络(通常只有一个节点网络,这个值应该是节点网络的默认路由器)。在 OpenStack 上使用 [kubenet] 时需要这个值。 + +[kubenet]: /docs/concepts/cluster-administration/network-plugins/#kubenet + {{% /capture %}} +## OVirt + + +### 节点名称 + +OVirt 云驱动使用节点的主机名(由 kubelet 确定,或者用 `--hostname-override` 覆盖)作为 Kubernetes 节点对象的名称。 +注意 Kubernetes 节点名必须与 VM FQDN 匹配(OVirt 在`...`中说明)。 + +## Photon + + +### 节点名称 + +Photon 云驱动使用节点的主机名(由 kubelet 决定,或者用 `--hostname-override` 覆盖)作为 Kubernetes 节点对象的名称。 +注意,Kubernetes 节点名必须与 Photon VM名匹配(或者,如果在 `--cloud-config` 中将 `overrideIP` 设置为 `true`,则 Kubernetes 节点名必须与 Photon VM IP 地址匹配)。 + +## VSphere + + +### 节点名称 + +VSphere 云驱动使用节点检测到的主机名(由 kubelet 确定)作为 Kubernetes 节点对象的名称。 +VSphere 云驱动会忽略 `--hostname-override` 参数。 + +## IBM Cloud Kubernetes Service + + +### 计算节点 + +通过使用 IBM Cloud Kubernetes Service 驱动,您可以在单个区域或跨区域的多个区(Region)中创建虚拟和物理(裸金属)节点的集群。 +有关更多信息,请参见[规划您的集群和工作节点设置](https://cloud.ibm.com/docs/containers?topic=containers-plan_clusters#plan_clusters)。 + +Kubernetes 节点对象的名称是 IBM Cloud Kubernetes Services 工作节点实例的私有IP地址。 + + +### 网络 + +IBM Cloud Kubernetes Services 驱动提供 VLAN,用于提供高质量的网络性能和节点间的网络隔离。您可以设置自定义防火墙和 Calico 网络策略来为您的集群添加额外的安全层,或者通过 VPN 将您的集群连接到自有数据中心。有关更多信息,请参见[规划集群内和私有网络](https://cloud.ibm.com/docs/containers?topic=containers-cs_network_cluster#cs_network_cluster)。 + +要向公众或集群内部公开应用程序,您可以利用 NodePort、LoadBalancer 或 Ingress 服务。您还可以使用注释自定义 Ingress 应用程序负载均衡器。有关更多信息,请参见[计划使用外部网络公开您的应用程序](https://cloud.ibm.com/docs/containers?topic=containers-cs_network_planning#cs_network_planning)。 + + + +### 存储 + +IBM Cloud Kubernetes Services 驱动利用 Kubernetes 原生的持久卷,使用户能够将文件、块和云对象存储装载到他们的应用程序中。还可以使用 database-as-a-service 和第三方附加组件来持久存储数据。有关更多信息,请参见[规划高可用性持久存储](https://cloud.ibm.com/docs/containers?topic=containers-storage_planning#storage_planning)。 + + + +## 百度云容器引擎 + +### 节点名称 + +Baidu 云驱动使用节点的私有 IP 地址(由 kubelet 确定,或者用 `--hostname-override` 覆盖)作为 Kubernetes 节点对象的名称。 +注意 Kubernetes 节点名必须匹配百度 VM 的私有 IP。 diff --git a/content/zh/docs/concepts/cluster-administration/cluster-administration-overview.md b/content/zh/docs/concepts/cluster-administration/cluster-administration-overview.md index 44fcdf103d..020581f4d1 100644 --- a/content/zh/docs/concepts/cluster-administration/cluster-administration-overview.md +++ b/content/zh/docs/concepts/cluster-administration/cluster-administration-overview.md @@ -143,5 +143,3 @@ Note: Not all distros are actively maintained. Choose distros which have been te * [记录和监控集群活动](/docs/concepts/cluster-administration/logging/)阐述了 Kubernetes 的日志如何工作以及怎样实现。 {{% /capture %}} - - diff --git a/content/zh/docs/concepts/cluster-administration/controller-metrics.md b/content/zh/docs/concepts/cluster-administration/controller-metrics.md index ebfe7c5f7b..85a46101ff 100644 --- a/content/zh/docs/concepts/cluster-administration/controller-metrics.md +++ b/content/zh/docs/concepts/cluster-administration/controller-metrics.md @@ -58,8 +58,6 @@ cloudprovider_gce_api_request_duration_seconds { request = "detach_disk"} cloudprovider_gce_api_request_duration_seconds { request = "list_disk"} ``` - - {{% capture overview %}} +垃圾回收是 kubelet 的一个有用功能,它将清理未使用的镜像和容器。 + -垃圾回收是 kubelet 的一个有用功能,它将清理未使用的镜像和容器。Kubelet 将每分钟对容器执行一次垃圾回收,每五分钟对镜像执行一次垃圾回收。 +Kubelet 将每分钟对容器执行一次垃圾回收,每五分钟对镜像执行一次垃圾回收。 + 不建议使用外部垃圾收集工具,因为这些工具可能会删除原本期望存在的容器进而破坏 kubelet 的行为。 @@ -44,13 +51,22 @@ of cadvisor. --> 镜像垃圾回收策略只考虑两个因素:`HighThresholdPercent` 和 `LowThresholdPercent`。 -磁盘使用率超过上限阈值(HighThresholdPercent)将触发垃圾回收。 -垃圾回收将删除最近最少使用的镜像,直到磁盘使用率满足下限阈值(LowThresholdPercent)。 + +磁盘使用率超过上限阈值(HighThresholdPercent)将触发垃圾回收。 + + + +垃圾回收将删除最近最少使用的镜像,直到磁盘使用率满足下限阈值(LowThresholdPercent)。 + + diff --git a/content/zh/docs/concepts/cluster-administration/logging.md b/content/zh/docs/concepts/cluster-administration/logging.md index b34c949524..da727e4113 100755 --- a/content/zh/docs/concepts/cluster-administration/logging.md +++ b/content/zh/docs/concepts/cluster-administration/logging.md @@ -1,4 +1,7 @@ --- +reviewers: +- piosz +- x13n title: 日志架构 content_template: templates/concept weight: 60 @@ -9,7 +12,6 @@ weight: 60 - 应用和系统日志可以让您了解集群内部的运行状况。日志对调试问题和监控集群活动非常有用。大部分现代化应用都有某种日志记录机制;同样地,大多数容器引擎也被设计成支持某种日志记录机制。针对容器化应用,最简单且受欢迎的日志记录方式就是写入标准输出和标准错误流。 输出结果为: + ``` pod/counter created ``` @@ -74,6 +76,7 @@ kubectl logs counter The output is: --> 输出结果为: + ``` 0: Mon Jan 1 00:00:00 UTC 2001 1: Mon Jan 1 00:00:01 UTC 2001 @@ -384,7 +387,7 @@ However, it's recommended to use `stdout` and `stderr` directly and leave rotati and retention policies to the kubelet. --> 应用本身如果不具备轮转日志文件的功能,可以通过 sidecar 容器实现。 -该方式的 [例子](https://github.com/samsung-cnct/logrotate) 是运行一个定期轮转日志的容器。 +该方式的一个例子是运行一个定期轮转日志的容器。 然而,还是推荐直接使用 `stdout` 和 `stderr`,将日志的轮转和保留策略交给 kubelet。 diff --git a/content/zh/docs/concepts/cluster-administration/sysctl-cluster.md b/content/zh/docs/concepts/cluster-administration/sysctl-cluster.md deleted file mode 100644 index 2bcd589ac3..0000000000 --- a/content/zh/docs/concepts/cluster-administration/sysctl-cluster.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -approvers: -- sttts -title: Kubernetes集群中使用Sysctls ---- - -{{< toc >}} - -这篇文章描述了如何在Kubernetes集群中使用Sysctls。 - -## 什么是Sysctl? - -在Linux中,Sysctl接口允许管理员在内核运行时修改内核参数。这些可用参数都存在于虚拟进程文件系统中的`/proc/sys/`目录。这些内核参数作用于各种子系统中,例如: - -- 内核 (通用前缀:`kernel.`) -- 网络 (通用前缀:`net.`) -- 虚拟内存 (通用前缀:`vm.`) -- 设备专用 (通用前缀:`dev.`) -- 更多子系统描述见 [Kernel docs](https://www.kernel.org/doc/Documentation/sysctl/README). - -获取所有参数列表,可运行 - -``` -$ sudo sysctl -a -``` - -## 命名空间级vs.节点级Sysctls - -在今天的Linux内核系统中有一些Sysctls是 _命名空间级_ 的。这意味着他们在同节点的不同pod间是可配置成独立的。在kubernetes里,命名空间级是Sysctls的一个必要条件,以使其在一个pod语境里易于理解。 - -以下列出了Sysctls中已知的 _命名空间级_ : - -- `kernel.shm*`(内核中共享内存相关参数), -- `kernel.msg*`(内核中SystemV消息队列相关参数), -- `kernel.sem`(内核中信号量参数), -- `fs.mqueue.*`(内核中POSIX消息队列相关参数), -- `net.*`(内核中网络配置项相关参数),如果它可以在容器命名空间里被更改。然而,也有一些特例 - (例如,`net.netfilter.nf_conntrack_max` 和 - `net.netfilter.nf_conntrack_expect_max` - 可以在容器命名空间里被更改,但它们是非命名空间的)。 - -Sysctls中非命名空间级的被称为 _节点级_ ,其必须由集群管理员手动设置,要么通过节点的底层Linux分布方式(例如,通过 `/etc/sysctls.conf`),亦或在特权容器中使用Daemonset。 - -**注意**: 这是很好的做法,考虑在一个集群里给有特殊sysctl的节点设置为 _污点_ ,并且给他们安排仅需要这些sysctl设置的pods。 建议采用Kubernetes [_污点和容点_ -特征](/docs/user-guide/kubectl/{{< param "version" >}}/#taint) 来实现。 - -## 安全的 vs. 不安全的 Sysctls - -Sysctls被分为 _安全的_ 和 _不安全的_ sysctls。同一节点上的pods间除了适当命名空间命名一个 _安全的_ sysctl,还必须适当的 _隔离_ 。 这意味着给一个pod设置一个 _安全的_ sysctl - -- 不能对相同节点上其他pod产生任何影响 -- 不能对节点的健康造成损害 -- 不能在pod资源限制以外获取更多的CPU和内存资源 - -目前看来,大多数的 _命名空间级_ sysctls 不一定被认为是 _安全的_ 。 - -在Kubernetes 1.4版本中,以下sysctls提供了 _安全的_ 配置: - -- `kernel.shm_rmid_forced`, -- `net.ipv4.ip_local_port_range`, -- `net.ipv4.tcp_syncookies`. - -该列表在未来的Kubernetes版本里还会继续扩充,当kubelet提供更好的隔离机制时。 - -所有 _安全的_ sysctls 都是默认启用的。 - -所有 _不安全的_ sysctls 默认是关闭的,且必须通过每个节点基础上的集群管理手动开启。禁用不安全的sysctls的Pods将会被计划,但不会启动。 - -**警告**: 由于他们的本质是 _不安全的_ ,使用 _不安全的_ sysctls是自担风险的,并且会导致严重的问题,例如容器的错误行为,资源短缺或者是一个节点的完全破损。 - -## 使能不安全的Sysctls - -牢记上面的警告, 在非常特殊的情况下,例如高性能指标或是实时应用程序优化,集群管理员可以允许 _不安全的_ -sysctls。 _不安全的_ sysctls 会打上kubelet标识,在逐节点的基础上被启用,例如: - -```shell -$ kubelet --experimental-allowed-unsafe-sysctls 'kernel.msg*,net.core.somaxconn' ... -``` - -只有 _命名空间级_ sysctls 可以使用该方法启用。 - -## 给Pod配置Sysctls - -在Kubernetes 1.4版本中,sysctl特性是一个alpha API。因此,sysctls被设置为在pods上使用注释。它们适用于同一个pod上的所有容器。 - -这里列举了一个例子, _安全的_ 和 _不安全的_ sysctls使用不同的注释: - -```yaml -apiVersion: v1 -kind: Pod -metadata: - name: sysctl-example - annotations: - security.alpha.kubernetes.io/sysctls: kernel.shm_rmid_forced=1 - security.alpha.kubernetes.io/unsafe-sysctls: net.core.somaxconn=1024,kernel.msgmax=1 2 3 -spec: - ... -``` - -**注意**: 包含以上规定的 _不安全的_ sysctls的一个Pod, 将无法启动任何不能使这两个 _不安全的_ sysctls明确的节点。 推荐 -_节点级_ sysctls使用 [_容点和污点_ -特征](/docs/user-guide/kubectl/v1.6/#taint) or [taints on nodes](/docs/concepts/configuration/taint-and-toleration/) -来将这些pods分配到正确的nodes上。 diff --git a/content/zh/docs/concepts/configuration/_index.md b/content/zh/docs/concepts/configuration/_index.md index 265da88a94..d717de50f5 100644 --- a/content/zh/docs/concepts/configuration/_index.md +++ b/content/zh/docs/concepts/configuration/_index.md @@ -1,4 +1,11 @@ --- title: "配置" weight: 70 ---- \ No newline at end of file +--- + + diff --git a/content/zh/docs/concepts/configuration/assign-pod-node.md b/content/zh/docs/concepts/configuration/assign-pod-node.md new file mode 100644 index 0000000000..a566d55deb --- /dev/null +++ b/content/zh/docs/concepts/configuration/assign-pod-node.md @@ -0,0 +1,690 @@ +--- +title: 将 Pod 分配给节点 +content_template: templates/concept +weight: 30 +--- + + + + +{{% capture overview %}} + + + +你可以约束一个 {{< glossary_tooltip text="Pod" term_id="pod" >}} 只能在特定的 {{< glossary_tooltip text="Node(s)" term_id="node" >}} 上运行,或者优先运行在特定的节点上。有几种方法可以实现这点,推荐的方法都是用[标签选择器](/docs/concepts/overview/working-with-objects/labels/)来进行选择。通常这样的约束不是必须的,因为调度器将自动进行合理的放置(比如,将 pod 分散到节点上,而不是将 pod 放置在可以资源不足的节点上等等),但在某些情况下,你可以需要更多控制 pod 停靠的节点,例如,确保 pod 最终落在连接了 SSD 的机器上,或者将来自两个不通的服务且有大量通信的 pod 放置在同一个可用区。 + +{{% /capture %}} + +{{% capture body %}} + +## nodeSelector + + + +`nodeSelector` 是节点选择约束的最简单推荐形式。`nodeSelector` 是 PodSpec 的一个字段。它指定键值对的映射。为了使 pod 可以在节点上运行,节点必须具有每个指定的键值对作为标签(它也可以具有其他标签)。最常用的是一对键值对。 + + + +让我们来看一个使用 `nodeSelector` 的例子。 + + + +### 步骤零:先决条件 + + + +本示例假设你已基本了解 Kubernetes 的 pod 并且已经[建立一个 Kubernetes 集群](/docs/setup/)。 + + + +### 步骤一:添加标签到节点 + + + +执行 `kubectl get nodes` 命令获取集群的节点名称。选择一个你要增加标签的节点,然后执行 `kubectl label nodes =` 命令将标签添加到你所选择的节点上。例如,如果你的节点名称为 'kubernetes-foo-node-1.c.a-robinson.internal' 并且想要的标签是 'disktype=ssd',则可以执行 `kubectl label nodes kubernetes-foo-node-1.c.a-robinson.internal disktype=ssd` 命令。 + + + +你可以通过重新运行 `kubectl get nodes --show-labels` 并且查看节点当前具有了一个标签来验证它是否有效。你也可以使用 `kubectl describe node "nodename"` 命令查看指定节点的标签完整列表。 + + + +### 步骤二:添加 nodeSelector 字段到 pod 配置中 + + + +拿任意一个你想运行的 pod 的配置文件,并且在其中添加一个 nodeSelector 部分。例如,如果下面是我的 pod 配置: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx + labels: + env: test +spec: + containers: + - name: nginx + image: nginx +``` + + + +然后像下面这样添加 nodeSelector: + +{{< codenew file="pods/pod-nginx.yaml" >}} + + + +当你之后运行 `kubectl apply -f https://k8s.io/examples/pods/pod-nginx.yaml` 命令,pod 将会调度到将标签添加到的节点上。你可以通过运行 `kubectl get pods -o wide` 并查看分配给 pod 的 “NODE” 来验证其是否有效。 + + + +## 插曲:内置的节点标签 {#内置的节点标签} + + + +除了你[附加](#添加标签到节点)的标签外,节点还预先填充了一组标准标签。这些标签是 + +* [`kubernetes.io/hostname`](/docs/reference/kubernetes-api/labels-annotations-taints/#kubernetes-io-hostname) +* [`failure-domain.beta.kubernetes.io/zone`](/docs/reference/kubernetes-api/labels-annotations-taints/#failure-domain-beta-kubernetes-io-zone) +* [`failure-domain.beta.kubernetes.io/region`](/docs/reference/kubernetes-api/labels-annotations-taints/#failure-domain-beta-kubernetes-io-region) +* [`beta.kubernetes.io/instance-type`](/docs/reference/kubernetes-api/labels-annotations-taints/#beta-kubernetes-io-instance-type) +* [`kubernetes.io/os`](/docs/reference/kubernetes-api/labels-annotations-taints/#kubernetes-io-os) +* [`kubernetes.io/arch`](/docs/reference/kubernetes-api/labels-annotations-taints/#kubernetes-io-arch) + + +{{< note >}} + +这些标签的值特定于云供应商的,因此不能保证可靠。例如,`kubernetes.io/hostname` 的值在某些环境中可能与节点名称相同,但在其他环境中可能是一个不同的值。 +{{< /note >}} + + + +## 节点隔离/限制 + + + +向 Node 对象添加标签可以将 pod 定位到特定的节点或节点组。这可以用来确保指定的 pod 只能运行在具有一定隔离性,安全性或监管属性的节点上。当为此目的使用标签时,强烈建议选择节点上的 kubelet 进程无法修改的标签键。这可以防止受感染的节点使用其 kubelet 凭据在自己的 Node 对象上设置这些标签,并影响调度器将工作负载调度到受感染的节点。 + + + +`NodeRestriction` 准入插件防止 kubelet 使用 `node-restriction.kubernetes.io/` 前缀设置或修改标签。要使用该标签前缀进行节点隔离: + + + +1. 检查是否在使用 Kubernetes v1.11+,以便 NodeRestriction 功能可用。 +2. 确保你在使用[节点授权](/docs/reference/access-authn-authz/node/)并且已经_启用_ [NodeRestriction 准入插件](/docs/reference/access-authn-authz/admission-controllers/#noderestriction)。 +3. 将 `node-restriction.kubernetes.io/` 前缀下的标签添加到 Node 对象,然后在节点选择器中使用这些标签。例如,`example.com.node-restriction.kubernetes.io/fips=true` 或 `example.com.node-restriction.kubernetes.io/pci-dss=true`。 + + + +## 亲和与反亲和 + + + +`nodeSelector` 提供了一种非常简单的方法来将 pod 约束到具有特定标签的节点上。亲和/反亲和功能极大地扩展了你可以表达约束的类型。关键的增强点是 + + + +1. 语言更具表现力(不仅仅是“完全匹配的 AND”) +2. 你可以发现规则是“软”/“偏好”,而不是硬性要求,因此,如果调度器无法满足该要求,仍然调度该 pod +3. 你可以使用节点上(或其他拓扑域中)的 pod 的标签来约束,而不是使用节点本身的标签,来允许哪些 pod 可以或者不可以被放置在一起。 + + + +亲和功能包含两种类型的亲和,即“节点亲和”和“pod 间亲和/反亲和”。节点亲和就像现有的 `nodeSelector`(但具有上面列出的前两个好处),然而 pod 间亲和/反亲和约束 pod 标签而不是节点标签(在上面列出的第三项中描述,除了具有上面列出的第一和第二属性)。 + + + +### 节点亲和 + + + +节点亲和概念上类似于 `nodeSelector`,它使你可以根据节点上的标签来约束 pod 可以调度到哪些节点。 + + + +目前有两种类型的节点亲和,分别为 `requiredDuringSchedulingIgnoredDuringExecution` 和 +`preferredDuringSchedulingIgnoredDuringExecution`。你可以视它们为“硬”和“软”,意思是,前者指定了将 pod 调度到一个节点上*必须*满足的规则(就像 `nodeSelector` 但使用更具表现力的语法),后者指定调度器将尝试执行单不能保证的*偏好*。名称的“IgnoredDuringExecution”部分意味着,类似于 `nodeSelector` 的工作原理,如果节点的标签在运行时发生变更,从而不再满足 pod 上的亲和规则,那么 pod 将仍然继续在该节点上运行。将来我们计划提供 `requiredDuringSchedulingRequiredDuringExecution`,它将类似于 `requiredDuringSchedulingIgnoredDuringExecution`,除了它会将 pod 从不再满足 pod 的节点亲和要求的节点上驱逐。 + + + +因此,`requiredDuringSchedulingIgnoredDuringExecution` 的示例将是“仅将 pod 运行在具有 Intel CPU 的节点上”,而 `preferredDuringSchedulingIgnoredDuringExecution` 的示例为“尝试将这组 pod 运行在 XYZ 故障区域,如果这不可能的话,则允许一些 pod 在其他地方运行”。 + + + +节点亲和通过 PodSpec 的 `affinity` 字段下的 `nodeAffinity` 字段进行指定。 + + + +下面是一个使用节点亲和的 pod 的实例: + +{{< codenew file="pods/pod-with-node-affinity.yaml" >}} + + + +此节点亲和规则表示,pod 只能放置在具有标签键为 `kubernetes.io/e2e-az-name` 且 标签值为 `e2e-az1` 或 `e2e-az2` 的节点上。另外,在满足这些标准的节点中,具有标签键为 `another-node-label-key` 且标签值为 `another-node-label-value` 的节点应该优先使用。 + + + +你可以在上面的例子中看到 `In` 操作符的使用。新的节点亲和语法支持下面的操作符: `In`,`NotIn`,`Exists`,`DoesNotExist`,`Gt`,`Lt`。你可以使用 `NotIn` 和 `DoesNotExist` 来实现节点反亲和行为,或者使用[节点污点](/docs/concepts/configuration/taint-and-toleration/)将 pod 从特定节点中驱逐。 + + + +如果你同时指定了 `nodeSelector` 和 `nodeAffinity`,*两者*必须都要满足,才能将 pod 调度到候选节点上。 + + + +如果你指定了多个与 `nodeAffinity` 类型关联的 `nodeSelectorTerms`,则**如果其中一个** `nodeSelectorTerms` 满足的话,pod将可以调度到节点上。 + + + +如果你指定了多个与 `nodeSelectorTerms` 关联的 `matchExpressions`,则**如果其中一个** `matchExpressions` 满足的话,pod 才可以调度到节点上。 + + + +如果你修改或删除了 pod 所调度到的节点的标签,pod 不会被删除。换句话说,亲和选择只在 pod 调度期间有效。 + + + +`preferredDuringSchedulingIgnoredDuringExecution` 中的 `weight` 字段值的范围是 1-100。对于每个符合所有调度要求(资源请求,RequiredDuringScheduling 亲和表达式等)的节点,调度器将遍历该字段的元素来计算总和,并且如果节点匹配对应的MatchExpressions,则添加“权重”到总和。然后将这个评分与该节点的其他优先级函数的评分进行组合。总分最高的节点是最优选的。 + + + +### pod 间亲和与反亲和 + + + +pod 间亲和与反亲和使你可以*基于已经在节点上运行的 pod 的标签*来约束 pod 可以调度到的节点,而不是基于节点上的标签。规则的格式为“如果 X 节点上已经运行了一个或多个 满足规则 Y 的pod,则这个 pod 应该(或者在非亲和的情况下不应该)运行在 X 节点”。Y 表示一个具有可选的关联命令空间列表的 LabelSelector;与节点不同,因为 pod 是命名空间限定的(因此 pod 上的标签也是命名空间限定的),因此作用于 pod 标签的标签选择器必须指定选择器应用在哪个命名空间。从概念上讲,X 是一个拓扑域,如节点,机架,云供应商地区,云供应商区域等。你可以使用 `topologyKey` 来表示它,`topologyKey` 是节点标签的键以便系统用来表示这样的拓扑域。请参阅上面[插曲:内置的节点标签](#内置的节点标签)部分中列出的标签键。 + +{{< note >}} + +Pod 间亲和与反亲和需要大量的处理,这可能会显著减慢大规模集群中的调度。我们不建议在超过数百个节点的集群中使用它们。 +{{< /note >}} + +{{< note >}} + +Pod 反亲和需要对节点进行一致的标记,即集群中的每个节点必须具有适当的标签能够匹配 `topologyKey`。如果某些或所有节点缺少指定的 `topologyKey` 标签,可能会导致意外行为。 +{{< /note >}} + + + +与节点亲和一样,当前有两种类型的 pod 亲和与反亲和,即 `requiredDuringSchedulingIgnoredDuringExecution` 和 +`preferredDuringSchedulingIgnoredDuringExecution`,分表表示“硬性”与“软性”要求。请参阅前面节点亲和部分中的描述。`requiredDuringSchedulingIgnoredDuringExecution` 亲和的一个示例是“将服务 A 和服务 B 的 pod 放置在同一区域,因为它们之间进行大量交流”,而 `preferredDuringSchedulingIgnoredDuringExecution` 反亲和的示例将是“将此服务的 pod 跨区域分布”(硬性要求是说不通的,因为你可能拥有的 pod 数多于区域数)。 + + + +Pod 间亲和通过 PodSpec 中 `affinity` 字段下的 `podAffinity` 字段进行指定。而 pod 间反亲和通过 PodSpec 中 `affinity` 字段下的 `podAntiAffinity` 字段进行指定。 + + + +### Pod 使用 pod 亲和 的示例: + +{{< codenew file="pods/pod-with-pod-affinity.yaml" >}} + + + +在这个 pod 的 affinity 配置定义了一条 pod 亲和规则和一条 pod 反亲和规则。在此示例中,`podAffinity` 配置为 `requiredDuringSchedulingIgnoredDuringExecution`,然而 `podAntiAffinity` 配置为 `preferredDuringSchedulingIgnoredDuringExecution`。pod 亲和规则表示,仅当节点和至少一个已运行且有键为“security”且值为“S1”的标签的 pod 处于同一区域时,才可以将该 pod 调度到节点上。(更确切的说,如果节点 N 具有带有键 `failure-domain.beta.kubernetes.io/zone` 和某个值 V 的标签,则 pod 有资格在节点 N 上运行,以便集群中至少有一个节点具有键 `failure-domain.beta.kubernetes.io/zone` 和值为 V 的节点正在运行具有键“security”和值“S1”的标签的 pod。)pod 反亲和规则表示,如果节点已经运行了一个具有键“security”和值“S2”的标签的 pod,则该 pod 不希望将其调度到该节点上。(如果 `topologyKey` 为 `failure-domain.beta.kubernetes.io/zone`,则意味着当节点和具有键“security”和值“S2”的标签的 pod 处于相同的区域,pod 不能被调度到该节点上。)查阅[设计文档](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md)来获取更多 pod 亲和与反亲和的样例,包括 `requiredDuringSchedulingIgnoredDuringExecution` +和 `preferredDuringSchedulingIgnoredDuringExecution` 两种配置。 + + + +Pod 亲和与反亲和的合法操作符有 `In`,`NotIn`,`Exists`,`DoesNotExist`。 + + + +原则上,`topologyKey` 可以是任何合法的标签键。然而,出于性能和安全原因,topologyKey 受到一些限制: + + + +1. 对于亲和与 `requiredDuringSchedulingIgnoredDuringExecution` 要求的 pod 反亲和,`topologyKey` 不允许为空。 +2. 对于 `requiredDuringSchedulingIgnoredDuringExecution` 要求的 pod 反亲和,准入控制器 `LimitPodHardAntiAffinityTopology` 被引入来限制 `topologyKey` 不为 `kubernetes.io/hostname`。如果你想使它可用于自定义拓扑结构,你必须修改准入控制器或者禁用它。 +3. 对于 `preferredDuringSchedulingIgnoredDuringExecution` 要求的 pod 反亲和,空的 `topologyKey` 被解释为“所有拓扑结构”(这里的“所有拓扑结构”限制为 `kubernetes.io/hostname`,`failure-domain.beta.kubernetes.io/zone` 和 `failure-domain.beta.kubernetes.io/region` 的组合)。 +4. 除上述情况外,`topologyKey` 可以是任何合法的标签键。 + + + +除了 `labelSelector` 和 `topologyKey`,你也可以指定表示命名空间的 `namespaces` 队列,`labelSelector` 也应该匹配它(这个与 `labelSelector` 和 `topologyKey` 的定义位于相同的级别)。如果忽略或者为空,则默认为 pod 亲和/反亲和的定义所在的命名空间。 + + + +所有与 `requiredDuringSchedulingIgnoredDuringExecution` 亲和与反亲和关联的 `matchExpressions` 必须满足,才能将 pod 调度到节点上。 + + + +#### 更实际的用例 + + + +Pod 间亲和与反亲和在与更高级别的集合(例如 ReplicaSets,StatefulSets,Deployments 等)一起使用时,它们可能更加有用。可以轻松配置一组应位于相同定义拓扑(例如,节点)中的工作负载。 + + + +##### 始终放置在相同节点上 + + + +在三节点集群中,一个 web 应用程序具有内存缓存,例如 redis。我们希望 web 服务器尽可能与缓存放置在同一位置。 + + + +下面是一个简单 redis deployment 的 yaml 代码段,它有三个副本和选择器标签 `app=store`。Deployment 配置了 `PodAntiAffinity`,用来确保调度器不会将副本调度到单个节点上。 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: redis-cache +spec: + selector: + matchLabels: + app: store + replicas: 3 + template: + metadata: + labels: + app: store + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - store + topologyKey: "kubernetes.io/hostname" + containers: + - name: redis-server + image: redis:3.2-alpine +``` + + + +下面 webserver deployment 的 yaml 代码段中配置了 `podAntiAffinity` 和 `podAffinity`。这将通知调度器将它的所有副本与具有 `app=store` 选择器标签的 pod 放置在一起。这还确保每个 web 服务器副本不会调度到单个节点上。 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: web-server +spec: + selector: + matchLabels: + app: web-store + replicas: 3 + template: + metadata: + labels: + app: web-store + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - web-store + topologyKey: "kubernetes.io/hostname" + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app + operator: In + values: + - store + topologyKey: "kubernetes.io/hostname" + containers: + - name: web-app + image: nginx:1.12-alpine +``` + + + +如果我们创建了上面的两个 deployment,我们的三节点集群将如下表所示。 + +| node-1 | node-2 | node-3 | +|:--------------------:|:-------------------:|:------------------:| +| *webserver-1* | *webserver-2* | *webserver-3* | +| *cache-1* | *cache-2* | *cache-3* | + + + +如你所见,`web-server` 的三个副本都按照预期那样自动放置在同一位置。 + +``` +kubectl get pods -o wide +``` + +输出类似于如下内容: +``` +NAME READY STATUS RESTARTS AGE IP NODE +redis-cache-1450370735-6dzlj 1/1 Running 0 8m 10.192.4.2 kube-node-3 +redis-cache-1450370735-j2j96 1/1 Running 0 8m 10.192.2.2 kube-node-1 +redis-cache-1450370735-z73mh 1/1 Running 0 8m 10.192.3.1 kube-node-2 +web-server-1287567482-5d4dz 1/1 Running 0 7m 10.192.2.3 kube-node-1 +web-server-1287567482-6f7v5 1/1 Running 0 7m 10.192.4.3 kube-node-3 +web-server-1287567482-s330j 1/1 Running 0 7m 10.192.3.2 kube-node-2 +``` + + + +##### 永远不放置在相同节点 + + + +上面的例子使用 `PodAntiAffinity` 规则和 `topologyKey: "kubernetes.io/hostname"` 来部署 redis 集群以便在同一主机上没有两个实例。参阅 [ZooKeeper 教程](/docs/tutorials/stateful-application/zookeeper/#tolerating-node-failure),以获取配置反亲和来达到高可用性的 StatefulSet 的样例(使用了相同的技巧)。 + +## nodeName + + + +`nodeName` 是节点选择约束的最简单方法,但是由于其自身限制,通常不使用它。`nodeName` 是 PodSpec 的一个字段。如果它不为空,调度器将忽略 pod,并且运行在它指定节点上的 kubelet 进程尝试运行该 pod。因此,如果 `nodeName` 在 PodSpec 中指定了,则它优先于上面的节点选择方法。 + + + +使用 `nodeName` 来选择节点的一些限制: + + + +- 如果指定的节点不存在, +- 如果指定的节点没有资源来容纳 pod,pod 将会调度失败并且其原因将显示为,比如 OutOfmemory 或 OutOfcpu。 +- 云环境中的节点名称并非总是可预测或稳定的。 + + + +下面的是使用 `nodeName` 字段的 pod 配置文件的例子: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx + nodeName: kube-01 +``` + + + +上面的 pod 将运行在 kube-01 节点上。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + + +[污点](/docs/concepts/configuration/taint-and-toleration/)允许节点*排斥*一组 pod。 + + + +[节点亲和](https://git.k8s.io/community/contributors/design-proposals/scheduling/nodeaffinity.md)与 [pod 间亲和/反亲和](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md)的设计文档包含这些功能的其他背景信息。 + + + +一旦 pod 分配给 节点,kubelet 应用将运行该 pod 并且分配节点本地资源。[拓扑管理](/docs/tasks/administer-cluster/topology-manager/) + +{{% /capture %}} diff --git a/content/zh/docs/concepts/configuration/manage-compute-resources-container.md b/content/zh/docs/concepts/configuration/manage-compute-resources-container.md index d436fafbe8..627e27a2ad 100644 --- a/content/zh/docs/concepts/configuration/manage-compute-resources-container.md +++ b/content/zh/docs/concepts/configuration/manage-compute-resources-container.md @@ -8,6 +8,18 @@ feature: 根据资源需求和其他约束自动放置容器,同时不会牺牲可用性,将任务关键工作负载和尽力服务工作负载进行混合放置,以提高资源利用率并节省更多资源。 --- + + {{% capture overview %}} @@ -116,7 +123,6 @@ CPU 总是要用绝对数量,不可以使用相对数量;0.1 的 CPU 在单 @@ -373,7 +376,6 @@ system daemons use a portion of the available resources. The `allocatable` field [NodeStatus](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#nodestatus-v1-core) gives the amount of resources that are available to Pods. For more information, see [Node Allocatable Resources](https://git.k8s.io/community/contributors/design-proposals/node/node-allocatable.md). - The [resource quota](/docs/concepts/policy/resource-quotas/) feature can be configured to limit the total amount of resources that can be consumed. If used in conjunction with namespaces, it can prevent one team from hogging all the resources. @@ -391,7 +393,6 @@ Pod 可用的资源量小于节点容量,因为系统守护程序使用一部 {{% capture overview %}} @@ -80,7 +87,7 @@ clusters and namespaces. A *context* element in a kubeconfig file is used to group access parameters under a convenient name. Each context has three parameters: cluster, namespace, and user. By default, the `kubectl` command-line tool uses parameters from -the *current context* to communicate with the cluster. +the *current context* to communicate with the cluster. ---> 通过 kubeconfig 文件中的 *context* 元素,使用简便的名称来对访问参数进行分组。每个上下文都有三个参数:cluster、namespace 和 user。默认情况下,`kubectl` 命令行工具使用 *当前上下文* 中的参数与集群进行通信。 @@ -121,7 +128,6 @@ listed in the `KUBECONFIG` environment variable. - 要查看配置,输入以下命令: ```shell kubectl config view @@ -156,7 +162,7 @@ Here are the rules that `kubectl` uses when it merges kubeconfig files: Even if the second file has non-conflicting entries under `red-user`, discard them. ---> 1. 如果设置了 `--kubeconfig` 参数,则仅使用指定的文件。不进行合并。此参数只能使用一次。 - + 否则,如果设置了 `KUBECONFIG` 环境变量,将它用作应合并的文件列表。根据以下规则合并 `KUBECONFIG` 环境变量中列出的文件: * 忽略空文件名。 @@ -179,12 +185,12 @@ Here are the rules that `kubectl` uses when it merges kubeconfig files: 1. Determine the context to use based on the first hit in this chain: 1. Use the `--context` command-line flag if it exists. - 1. Use the `current-context` from the merged kubeconfig files. + 2. Use the `current-context` from the merged kubeconfig files. ---> 1. 根据此链中的第一个匹配确定要使用的上下文。 1. 如果存在,使用 `--context` 命令行参数。 - 1. 使用合并的 kubeconfig 文件中的 `current-context`。 + 2. 使用合并的 kubeconfig 文件中的 `current-context`。 1. 确定集群和用户。此时,可能有也可能没有上下文。根据此链中的第一个匹配确定集群和用户,这将运行两次:一次用于用户,一次用于集群。 1. 如果存在,使用命令行参数:`--user` 或者 `--cluster`。 - 1. 如果上下文非空,从上下文中获取用户或集群。 + 2. 如果上下文非空,从上下文中获取用户或集群。 1. 确定要使用的实际集群信息。此时,可能有也可能没有集群信息。基于此链构建每个集群信息;第一个匹配项会被采用: 1. 如果存在:`--server`、`--certificate-authority` 和 `--insecure-skip-tls-verify`,使用命令行参数。 - 1. 如果合并的 kubeconfig 文件中存在集群信息属性,则使用它们。 - 1. 如果没有 server 配置,则配置无效。 + 2. 如果合并的 kubeconfig 文件中存在集群信息属性,则使用它们。 + 3. 如果没有 server 配置,则配置无效。 -1. 确定要使用的实际用户信息。使用与集群信息相同的规则构建用户信息,但每个用户只允许一种身份认证技术: +2. 确定要使用的实际用户信息。使用与集群信息相同的规则构建用户信息,但每个用户只允许一种身份认证技术: 1. 如果存在:`--client-certificate`、`--client-key`、`--username`、`--password` 和 `--token`,使用命令行参数。 - 1. 使用合并的 kubeconfig 文件中的 `user` 字段。 - 1. 如果存在两种冲突技术,则配置无效。 + 2. 使用合并的 kubeconfig 文件中的 `user` 字段。 + 3. 如果存在两种冲突技术,则配置无效。 -1. 对于仍然缺失的任何信息,使用其对应的默认值,并可能提示输入身份认证信息。 +3. 对于仍然缺失的任何信息,使用其对应的默认值,并可能提示输入身份认证信息。 * [配置对多集群的访问](/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) * [`kubectl config`](/docs/reference/generated/kubectl/kubectl-commands#config) - {{% /capture %}} diff --git a/content/zh/docs/concepts/configuration/overview.md b/content/zh/docs/concepts/configuration/overview.md index bb7f53f8c1..f27c44a3e5 100644 --- a/content/zh/docs/concepts/configuration/overview.md +++ b/content/zh/docs/concepts/configuration/overview.md @@ -5,6 +5,15 @@ title: 配置最佳实践 content_template: templates/concept weight: 10 --- + {{% capture overview %}} - 在推送到集群之前,配置文件应存储在版本控制中。 这允许您在必要时快速回滚配置更改。 - 它还有助于集群重新创建和恢复。 + 它还有助于集群重新创建和恢复。 - +{{< note >}} 要确保容器始终使用相同版本的镜像,你可以指定其 [摘要](https://docs.docker.com/engine/reference/commandline/pull/#pull-an-image-by-digest-immutable-identifier), 例如`sha256:45b23dee08af5e43a7fea6c4cf9c25ccf269ee113168c19722f87876677c5cb2`。 摘要唯一地标识出镜像的指定版本,因此除非您更改摘要值,否则 Kubernetes 永远不会更新它。 {{< /note >}} -{{< note >}} - -在生产中部署容器时应避免使用 `:latest` 标记,因为更难跟踪正在运行的镜像版本,并且更难以正确回滚。 +{{< note >}} +在生产中部署容器时应避免使用 `:latest` 标记,因为更难跟踪正在运行的镜像版本,并且更难以正确回滚。 {{< /note >}} -{{< note >}} +{{< note >}} 底层镜像提供程序的缓存语义甚至使 `imagePullPolicy: Always`变得高效。 例如,对于 Docker,如果镜像已经存在,则拉取尝试很快,因为镜像层都被缓存并且不需要镜像下载。 {{< /note >}} @@ -250,7 +257,7 @@ The caching semantics of the underlying image provider make even `imagePullPolic - Use label selectors for `get` and `delete` operations instead of specific object names. See the sections on [label selectors](/docs/concepts/overview/working-with-objects/labels/#label-selectors) and [using labels effectively](/docs/concepts/cluster-administration/manage-deployment/#using-labels-effectively). --> - 使用标签选择器进行`get`和`delete`操作,而不是特定的对象名称。 -- 请参阅[标签选择器](/docs/concepts/overview/working-with-objects/labels/#label-selectors)和[有效使用标签](/docs/concepts/cluster-administration/manage-deployment/#using-labels-effectively)部分。 +- 请参阅[标签选择器](/docs/concepts/overview/working-with-objects/labels/#label-selectors)和[有效使用标签]部分(/docs/concepts/cluster-administration/manage-deployment/#using-labels-effectively)。 + +在节点上运行 Pod 时,Pod 本身占用大量系统资源。这些资源是运行 Pod 内容器所需资源的附加资源。 +_POD 开销_ 是一个特性,用于计算 Pod 基础设施在容器请求和限制之上消耗的资源。 + +{{% /capture %}} + + +{{% capture body %}} + + + +## Pod 开销 + + + +在 Kubernetes 中,Pod 的开销是根据与 Pod 的 [RuntimeClass](/docs/concepts/containers/runtime-class/) 相关联的开销在[准入](/docs/reference/access-authn-authz/extensible-admission-controllers/#what-are-admission-webhooks)时设置的。 + + +当启用 Pod 开销时,在调度 Pod 时,除了考虑容器资源请求的总和外,还要考虑 Pod 开销。类似地,Kubelet 将在确定 pod cgroup 的大小和执行 Pod 驱逐排序时包含 Pod 开销。 + + +### 设置 + + +您需要确保在集群中启用了 `PodOverhead` [特性门](默认情况下是关闭的)。这意味着: + + +- 在 {{< glossary_tooltip text="kube-scheduler" term_id="kube-scheduler" >}} +- 在 {{< glossary_tooltip text="kube-apiserver" term_id="kube-apiserver" >}} +- 在每一个 Node 的 {{< glossary_tooltip text="kubelet" term_id="kubelet" >}} +- 在任何使用特性门的自定义api服务器中 + + +{{< note >}} + +能够写入运行时类资源的用户能够对工作负载性能产生集群范围的影响。可以使用 Kubernetes 访问控制来限制对此功能的访问。 +有关详细信息,请参见[授权概述](/docs/reference/access-authn-authz/authorization/)。 +{{< /note >}} + + +{{% /capture %}} + +{{% capture whatsnext %}} + + + +{{% /capture %}} diff --git a/content/zh/docs/concepts/configuration/resource-bin-packing.md b/content/zh/docs/concepts/configuration/resource-bin-packing.md new file mode 100644 index 0000000000..1a3bb9c2ce --- /dev/null +++ b/content/zh/docs/concepts/configuration/resource-bin-packing.md @@ -0,0 +1,258 @@ +--- +reviewers: +- bsalamat +- k82cn +- ahg-g +title: 扩展资源的资源箱打包 +content_template: templates/concept +weight: 10 +--- + + +{{% capture overview %}} + +{{< feature-state for_k8s_version="1.16" state="alpha" >}} + + +可以将 kube-scheduler 配置为使用 `RequestedToCapacityRatioResourceAllocation` 优先级函数启用资源箱打包以及扩展资源。 +优先级函数可用于根据自定义需求微调 kube-scheduler 。 + +{{% /capture %}} + +{{% capture body %}} + + +## 使用 RequestedToCapacityRatioResourceAllocation 启用装箱 + + +在 Kubernetes 1.15 之前,Kube-scheduler 用于允许根据主要资源,如 CPU 和内存对容量之比的请求对节点进行评分。 +Kubernetes 1.16 在优先级函数中添加了一个新参数,该参数允许用户指定资源以及每个资源的权重,以便根据容量之比的请求为节点评分。 +这允许用户通过使用适当的参数来打包扩展资源,从而提高了大型集群中稀缺资源的利用率。 +`RequestedToCapacityRatioResourceAllocation` 优先级函数的行为可以通过名为 `requestedToCapacityRatioArguments` 的配置选项进行控制。 +这个论证由两个参数 `shape` 和 `resources` 组成。 +Shape 允许用户根据 `utilization` 和 `score` 值将功能调整为要求最少或要求最高的功能。 +资源由 `name` 和 `weight` 组成,`name` 指定评分时要考虑的资源,`weight` 指定每种资源的权重。 + + +以下是一个配置示例,该配置将 `requestedToCapacityRatioArguments` 设置为扩展资源 `intel.com/foo` 和 `intel.com/bar` 的装箱行为 + +```json +{ + "kind" : "Policy", + "apiVersion" : "v1", + + ... + + "priorities" : [ + + ... + + { + "name": "RequestedToCapacityRatioPriority", + "weight": 2, + "argument": { + "requestedToCapacityRatioArguments": { + "shape": [ + {"utilization": 0, "score": 0}, + {"utilization": 100, "score": 10} + ], + "resources": [ + {"name": "intel.com/foo", "weight": 3}, + {"name": "intel.com/bar", "weight": 5} + ] + } + } + } + ], + } +``` + + +**默认情况下禁用此功能** + + +### 调整 RequestedToCapacityRatioResourceAllocation 优先级函数 + + +`shape` 用于指定 `RequestedToCapacityRatioPriority` 函数的行为。 + +```yaml + {"utilization": 0, "score": 0}, + {"utilization": 100, "score": 10} +``` + + +上面的参数在利用率为 0% 时给节点评分为0,在利用率为 100% 时给节点评分为10,因此启用了装箱行为。 +要启用最少请求,必须按如下方式反转得分值。 + +```yaml + {"utilization": 0, "score": 100}, + {"utilization": 100, "score": 0} +``` + + +`resources` 是一个可选参数,默认情况下设置为: + +``` yaml +"resources": [ + {"name": "CPU", "weight": 1}, + {"name": "Memory", "weight": 1} + ] +``` + + +它可以用来添加扩展资源,如下所示: + +```yaml +"resources": [ + {"name": "intel.com/foo", "weight": 5}, + {"name": "CPU", "weight": 3}, + {"name": "Memory", "weight": 1} + ] +``` + + +weight 参数是可选的,如果未指定,则设置为1。 +同样, weight 不能设置为负值。 + + +### RequestedToCapacityRatioResourceAllocation 优先级函数如何对节点评分 + + +本部分适用于希望了解此功能的内部细节的人员。 +以下是如何针对给定的一组值计算节点得分的示例。 + +``` +Requested Resources + +intel.com/foo : 2 +Memory: 256MB +CPU: 2 + +Resource Weights + +intel.com/foo : 5 +Memory: 1 +CPU: 3 + +FunctionShapePoint {{0, 0}, {100, 10}} + +Node 1 Spec + +Available: +intel.com/foo : 4 +Memory : 1 GB +CPU: 8 + +Used: +intel.com/foo: 1 +Memory: 256MB +CPU: 1 + + +Node Score: + +intel.com/foo = resourceScoringFunction((2+1),4) + = (100 - ((4-3)*100/4) + = (100 - 25) + = 75 + = rawScoringFunction(75) + = 7 + +Memory = resourceScoringFunction((256+256),1024) + = (100 -((1024-512)*100/1024)) + = 50 + = rawScoringFunction(50) + = 5 + +CPU = resourceScoringFunction((2+1),8) + = (100 -((8-3)*100/8)) + = 37.5 + = rawScoringFunction(37.5) + = 3 + +NodeScore = (7 * 5) + (5 * 1) + (3 * 3) / (5 + 1 + 3) + = 5 + + +Node 2 Spec + +Available: +intel.com/foo: 8 +Memory: 1GB +CPU: 8 + +Used: + +intel.com/foo: 2 +Memory: 512MB +CPU: 6 + + +Node Score: + +intel.com/foo = resourceScoringFunction((2+2),8) + = (100 - ((8-4)*100/8) + = (100 - 25) + = 50 + = rawScoringFunction(50) + = 5 + +Memory = resourceScoringFunction((256+512),1024) + = (100 -((1024-768)*100/1024)) + = 75 + = rawScoringFunction(75) + = 7 + +CPU = resourceScoringFunction((2+6),8) + = (100 -((8-8)*100/8)) + = 100 + = rawScoringFunction(100) + = 10 + +NodeScore = (5 * 5) + (7 * 1) + (10 * 3) / (5 + 1 + 3) + = 7 + +``` + +{{% /capture %}} + diff --git a/content/zh/docs/concepts/configuration/scheduling-framework.md b/content/zh/docs/concepts/configuration/scheduling-framework.md new file mode 100644 index 0000000000..40ad637ed4 --- /dev/null +++ b/content/zh/docs/concepts/configuration/scheduling-framework.md @@ -0,0 +1,542 @@ +--- +reviewers: +- ahg-g +title: 调度框架 +content_template: templates/concept +weight: 70 +--- + + + +{{% capture overview %}} + +{{< feature-state for_k8s_version="1.15" state="alpha" >}} + + + +调度框架是 Kubernetes Scheduler 的一种新的可插入架构,可以简化调度器的自定义。它向现有的调度器增加了一组新的“插件” API。插件被编译到调度器程序中。这些 API 允许大多数调度功能以插件的形式实现,同时使调度“核心”保持简单且可维护。请参考[调度框架的设计提案][kep]获取框架设计的更多技术信息。 + +[kep]: https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/20180409-scheduling-framework.md + +{{% /capture %}} + +{{% capture body %}} + + + +# 框架工作流程 + + + +调度框架定义了一些扩展点。调度器插件注册后在一个或多个扩展点处被调用。这些插件中的一些可以改变调度决策,而另一些仅用于提供信息。 + + + +每次调度一个 pod 的尝试都分为两个阶段,即**调度周期**和**绑定周期**。 + + + +## 调度周期和绑定周期 + + + +调度周期为 pod 选择一个节点,绑定周期将该决策应用于集群。调度周期和绑定周期一起被称为“调度上下文”。 + + + +调度周期是串行运行的,而绑定周期可能是同时运行的。 + + + +如果确定 pod 不可调度或者存在内部错误,则可以终止调度周期或绑定周期。Pod 将返回队列并重试。 + + + +## 扩展点 + + + +下图显示了一个 pod 的调度上下文以及调度框架公开的扩展点。在此图片中,“过滤器”等同于“断言”,“评分”相当于“优先级函数”。 + + + +一个插件可以在多个扩展点处注册,以执行更复杂或有状态的任务。 + + + +{{< figure src="/images/docs/scheduling-framework-extensions.png" title="调度框架扩展点" >}} + + + +### 队列排序 + + + +队列排序插件用于对调度队列中的 pod 进行排序。队列排序插件本质上将提供 "less(Pod1, Pod2)" 函数。一次只能启动一个队列插件。 + + + +### 前置过滤 + + + +前置过滤插件用于预处理 pod 的相关信息,或者检查集群或 pod 必须满足的某些条件。如果前置过滤插件返回错误,则调度周期将终止。 + + + +### 过滤 + + + +过滤插件用于过滤出不能运行该 pod 的节点。对于每个节点,调度器将按照其配置顺序调用这些过滤插件。如果任何过滤插件将节点标记为不可行,则不会为该节点调用剩下的过滤插件。节点可以被同时进行评估。 + + + +### 后置过滤 + + + +后置过滤是一个信息性的扩展点。通过过滤阶段的节点列表将调用这些后置过滤。插件将使用这些数据来更新内部的状态或者生成日志/指标。 + + + +**注意:**希望执行“预评分”工作的插件应该使用后置过滤扩展点。 + + + +### 评分 + + + +评分插件用于对通过过滤阶段的节点进行排名。调度器将为每个节点调用每个评分插件。将有一个定义明确的整数范围,代表最小和最大分数。在[标准化评分](#标准化评分)阶段之后,调度器将根据配置的插件权重合并所有插件的节点分数。 + + + +### 标准化评分 + + + +标准化评分插件用于在调度器计算节点的排名之前修改分数。在此扩展点注册的插件将使用同一插件的[评分](#评分)结果被调用。每个插件在每个调度周期调用一次。 + + + +例如,假设一个 `BlinkingLightScorer` 插件基于具有的闪烁指示灯数量来对节点进行排名。 + +```go +func ScoreNode(_ *v1.pod, n *v1.Node) (int, error) { + return getBlinkingLightCount(n) +} +``` + + + +然而,最大的闪烁灯个数值可能比 `NodeScoreMax` 小。要解决这个问题,`BlinkingLightScorer` 插件还应该注册该扩展点。 + +```go +func NormalizeScores(scores map[string]int) { + highest := 0 + for _, score := range scores { + highest = max(highest, score) + } + for node, score := range scores { + scores[node] = score*NodeScoreMax/highest + } +} +``` + + + +如果任何标准化评分插件返回错误,则调度阶段将终止。 + + + +**注意:**希望执行“预保留”工作的插件应该使用标准化评分扩展点。 + + + +### 保留 + + + +保留是一个信息性的扩展点。管理运行时状态的插件(也成为“有状态插件”)应该使用此扩展点,以便调度器在节点给指定 pod 预留了资源时能够通知该插件。这是在调度器真正将 pod 绑定到节点之前发生的,并且它存在是为了防止在调度器等待绑定成功时发生竞争情况。 + + + +这个是调度周期的最后一步。一旦 pod 处于保留状态,它将在绑定周期结束时触发[不保留](#不保留)插件(失败时)或 +[绑定后](#绑定后)插件(成功时)。 + + + +*注意:此概念曾被称为“假设”。* + + + +### 允许 + + + +允许插件用于防止或延迟 pod 的绑定。一个允许插件可以做以下三件事之一。 + + + +1. **批准** \ + 一旦所有允许插件批准 pod 后,该 pod 将被发送以进行绑定。 + + + +1. **拒绝** \ + 如果任何允许插件拒绝 pod,则该 pod 将被返回到调度队列。这将触发[不保留](#不保留)插件。 + + + +1. **等待**(带有超时) \ + 如果一个允许插件返回“等待”结果,则 pod 将保持在允许阶段,直到插件批准它。如果超时发生,**等待**变成**拒绝**,并且 pod 将返回调度队列,从而触发[不保留](#不保留)插件。 + + + +**批准 pod 绑定** + + + +尽管任何插件可以从缓存中访问“等待”状态的 pod 列表并批准它们。我们希望只有允许插件可以批准处于“等待”状态的 预留 pod 的绑定。一旦 pod 被批准了,它将发送到预绑定阶段。 + + + +### 预绑定 + + + +预绑定插件用于执行 pod 绑定前所需的任何工作。例如,一个预绑定插件可能需要提供网络卷并且在允许 pod 运行在该节点之前将其挂载到目标节点上。 + + + +如果任何预绑定插件返回错误,则 pod 将被[拒绝](#不保留)并且返回到调度队列中。 + + + +### 绑定 + + + +绑定插件用于将 pod 绑定到节点上。直到所有的预绑定插件都完成,绑定插件才会被调用。每个绑定插件按照配置顺序被调用。绑定插件可以选择是否处理指定的 pod。如果绑定插件选择处理 pod,**剩余的绑定插件将被跳过**。 + + + +### 绑定后 + + + +这是个信息性的扩展点。绑定后插件在 pod 成功绑定后被调用。这是绑定周期的结尾,可用于清理相关的资源。 + + + +### 不保留 + + + +这是个信息性的扩展点。如果 pod 被保留,然后在后面的阶段中被拒绝,则不保留插件将被通知。不保留插件应该清楚保留 pod 的相关状态。 + + + +使用此扩展点的插件通常也使用[保留](#保留)。 + + + +## 插件 API + + + +插件 API 分为两个步骤。首先,插件必须注册并配置,然后才能使用扩展点接口。扩展点接口具有以下形式。 + +```go +type Plugin interface { + Name() string +} + +type QueueSortPlugin interface { + Plugin + Less(*v1.pod, *v1.pod) bool +} + +type PreFilterPlugin interface { + Plugin + PreFilter(PluginContext, *v1.pod) error +} + +// ... +``` + + + +# 插件配置 + + + +可以在调度器配置中启用插件。另外,默认的插件可以在配置中禁用。在 1.15 版本,调度框架没有默认的插件。 + + + +调度器配置也可以包含插件的配置。这些配置在调度器初始化插件时传给插件。配置是一个任意值。接收插件应该解码并处理配置信息。 + + + +下面的例子显示一个调度器配置,该配置在 `reserve` 和 `preBind` 扩展点启用了一些插件并且禁用了一个插件。它还提供了 `foo` 插件的配置。 + +```yaml +apiVersion: kubescheduler.config.k8s.io/v1alpha1 +kind: KubeSchedulerConfiguration + +... + +plugins: + reserve: + enabled: + - name: foo + - name: bar + disabled: + - name: baz + preBind: + enabled: + - name: foo + disabled: + - name: baz + +pluginConfig: +- name: foo + args: > + Arbitrary set of args to plugin foo +``` + + + +当配置省略扩展点时,将使用该扩展点的默认插件。当存在扩展掉并且配置为 `enabled`,则 `enabled` 的插件将和默认插件一同调用。首先调用默认插件,然后以配置中指定的顺序来调用其他已启用的插件。如果希望以不同的顺序来调用默认插件,默认插件必须 `disabled`,然后以期望的顺序 `enabled`。 + + + +假设在 `reserve` 扩展点有一个默认的 `foo` 插件,且添加 `bar` 插件并且希望在 `foo` 插件之前执行,我们应该禁用 `foo` 并且按顺序启用 `bar` 和 `foo`。下面的例子显示了实现此目的的配置: + +```yaml +apiVersion: kubescheduler.config.k8s.io/v1alpha1 +kind: KubeSchedulerConfiguration + +... + +plugins: + reserve: + enabled: + - name: bar + - name: foo + disabled: + - name: foo +``` + +{{% /capture %}} diff --git a/content/zh/docs/concepts/containers/_index.md b/content/zh/docs/concepts/containers/_index.md index bd322c2129..083fad7a49 100644 --- a/content/zh/docs/concepts/containers/_index.md +++ b/content/zh/docs/concepts/containers/_index.md @@ -1,4 +1,11 @@ --- title: "容器" weight: 50 ---- \ No newline at end of file +--- + + diff --git a/content/zh/docs/concepts/containers/container-lifecycle-hooks.md b/content/zh/docs/concepts/containers/container-lifecycle-hooks.md index 9c85be9626..378ecf640b 100644 --- a/content/zh/docs/concepts/containers/container-lifecycle-hooks.md +++ b/content/zh/docs/concepts/containers/container-lifecycle-hooks.md @@ -1,9 +1,22 @@ --- +reviewers: +- mikedanese +- thockin title: 容器生命周期钩子 content_template: templates/concept weight: 30 --- + + + {{% capture overview %}} {{% capture overview %}} -在Kubernetes pod中引用镜像前,请创建Docker镜像,并将之推送到镜像仓库中。 -容器的“image”属性支持和Docker命令行相同的语法,包括私有仓库和标签。 + +创建 Docker 镜像并将其推送到仓库,然后在 Kubernetes pod 中引用它。 + +容器的 `image` 属性支持与 `docker` 命令相同的语法,包括私有仓库和标签。 {{% /capture %}} -{{< toc >}} {{% capture body %}} + ## 升级镜像 -默认的镜像拉取策略是“IfNotPresent”,在镜像已经存在的情况下,kubelet将不在去拉取镜像。 -如果总是想要拉取镜像,必须设置拉取策略为“Always”或者设置镜像标签为“:latest”。 -如果没有指定镜像的标签,它会被假定为“:latest”,同时拉取策略为“Always”。 + +默认的镜像拉取策略是 `IfNotPresent`,在镜像已经存在的情况下,kubelet 将不再去拉取镜像。如果总是想要拉取镜像,您可以执行以下操作: -注意应避免使用“:latest”标签,参见 [Best Practices for Configuration](/docs/concepts/configuration/overview/#container-images) 获取更多信息。 + +- 设置容器的 `imagePullPolicy` 为 `Always`。 +- 省略 `imagePullPolicy`,并使用 `:latest` 作为要使用的镜像的标签。 +- 省略 `imagePullPolicy` 和要使用的镜像标签。 +- 启用 [AlwaysPullImages](/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages) 准入控制器(admission controller)。 + +注意应避免使用 `:latest` 标签,参见[配置镜像最佳实践](/docs/concepts/configuration/overview/#container-images) 获取更多信息。 + + +## 使用清单(manifest)构建多架构镜像 + + +Docker CLI 现在支持以下命令 `docker manifest` 以及 `create`、`annotate`、`push` 等子命令。这些命令可用于构建和推送清单。您可以使用 `docker manifest inspect` 来查看清单。 + + +请在此处查看 docker 清单文档: +https://docs.docker.com/edge/engine/reference/commandline/manifest/ + + +查看有关如何在构建工具中使用清单的示例: +https://cs.k8s.io/?q=docker%20manifest%20(create%7Cpush%7Cannotate)&i=nope&files=&repos= + + +这些命令依赖于 Docker CLI 并仅在 Docker CLI 上实现。需要编辑 `$HOME/.docker/config.json` 并将 `experimental` 设置为 `enabled`,或者仅在调用 CLI 命令时将 `DOCKER_CLI_EXPERIMENTAL` 环境变量设置为 `enabled`。 + +{{< note >}} + +请使用 Docker *18.06 或更高版本*,低版本存在错误或不支持实验性命令行选项。导致容器问题示例 https://github.com/docker/cli/issues/1135。 +{{< /note >}} + + +如果在上传旧清单时遇到麻烦,只需删除 `$HOME/.docker/manifests` 中旧的清单即可重新开始。 + + +对于 Kubernetes,通常使用带有后缀 `-$(ARCH)` 的镜像。为了向后兼容,请生成带有后缀的旧镜像。想法是生成具有所有 arch(es) 清单的 `pause` 镜像,并生成 `pause-amd64` 镜像,该镜像向后兼容较早的配置或者可能已对带有后缀的镜像进行硬编码的 YAML 文件。 + + ## 使用私有仓库 + 从私有仓库读取镜像时可能需要密钥。 凭证可以用以下方式提供: - - 使用Google Container Registry - - 每个集群分别配置 - - 在Google Compute Engine 或者 Google Kubernetes Engine上自动配置 - - 所有的pod都能读取项目的私有仓库 - - 使用 AWS EC2 Container Registry (ECR) - - 使用IAM角色和策略来控制对ECR仓库的访问 - - 自动刷新ECR的登录凭证 + + - 使用 Google Container Registry + - 每个集群 + - 在 Google Compute Engine 或 Google Kubernetes Engine 上自动配置 + - 所有 Pod 均可读取项目的私有仓库 + - 使用 Amazon Elastic Container Registry(ECR) + - 使用 IAM 角色和策略来控制对 ECR 仓库的访问 + - 自动刷新 ECR 登录凭据 + - 使用 Oracle Cloud Infrastructure Registry(OCIR) + - 使用 IAM 角色和策略来控制对 OCIR 仓库的访问 - 使用 Azure Container Registry (ACR) - - 配置节点对私有仓库认证 - - 所有的pod都可以读取已配置的私有仓库 - - 需要集群管理员提供node的配置 - - 提前拉取镜像 - - 所有的pod都可以使用node上缓存的镜像 - - 需要以root进入node操作 - - pod上指定 ImagePullSecrets - - 只有提供了密钥的pod才能接入私有仓库 -下面将详细描述每一项 + - 使用 IBM Cloud Container Registry + - 配置节点用于私有仓库进行身份验证 + - 所有 Pod 均可读取任何已配置的私有仓库 + - 需要集群管理员配置节点 + - 预拉镜像 + - 所有 Pod 都可以使用节点上缓存的任何镜像 + - 需要所有节点的 root 访问权限才能进行设置 + - 在 Pod 上指定 ImagePullSecrets + - 只有提供自己密钥的 Pod 才能访问私有仓库 + + +下面将详细描述每一项。 + ### 使用 Google Container Registry -Kuberetes运行在Google Compute Engine (GCE)时原生支持[Google ContainerRegistry (GCR)] -(https://cloud.google.com/tools/container-registry/)。如果kubernetes集群运行在GCE -或者Google Kubernetes Engine 上,使用镜像全名(e.g. gcr.io/my_project/image:tag)即可。 -集群中的所有pod都会有读取这个仓库中镜像的权限。 + +Kuberetes 运行在 Google Compute Engine (GCE) 时原生支持 [Google Container +Registry (GCR)](https://cloud.google.com/tools/container-registry/)。如果 kubernetes 集群运行在 GCE 或者 Google Kubernetes Engine,使用镜像全名(例如 gcr.io/my_project/image:tag) 即可。 -Kubelet将使用实例的Google service account向GCR认证。实例的service account拥有 -`https://www.googleapis.com/auth/devstorage.read_only`,所以它可以从项目的GCR拉取,但不能推送。 - -### 使用 AWS EC2 Container Registry + +集群中所有 pod 都会有读取这个仓库镜像的权限。 -当Node是AWS EC2实例时,Kubernetes原生支持[AWS EC2 ContainerRegistry](https://aws.amazon.com/ecr/)。 + +kubelet 将使用实例的 Google service account 向 GCR 认证。实例的 Google service account 拥有 `https://www.googleapis.com/auth/devstorage.read_only`,所以它可以从项目的 GCR 拉取,但不能推送。 -在pod定义中,使用镜像全名即可 (例如 `ACCOUNT.dkr.ecr.REGION.amazonaws.com/imagename:tag`) + +### 使用 Amazon Elastic Container Registry -集群中可以创建pod的用户都可以使用ECR中的任意镜像运行pod。 + +当 Node 是 AWS EC2 实例时,Kubernetes 原生支持 [Amazon Elastic Container Registry](https://aws.amazon.com/ecr/)。 + +在 pod 定义中,使用镜像全名即可 (例如 `ACCOUNT.dkr.ecr.REGION.amazonaws.com/imagename:tag`) + + +集群中所有可以创建 Pod 的用户都将能够运行使用 ECR 仓库中任何镜像的 Pod。 + +kubelet 将获取并定期刷新 ECR 凭据。它需要以下权限才能执行此操作: - `ecr:GetAuthorizationToken` - `ecr:BatchCheckLayerAvailability` @@ -77,65 +223,192 @@ Kubelet会获取并且定期刷新ECR的凭证。它需要以下权限 - `ecr:ListImages` - `ecr:BatchGetImage` + 要求: -- 必须使用kubelet 1.2.0及以上版本 -- 如果node在区域A,而镜像仓库在另一个区域B,需要1.3.0及以上版本 -- 区域中必须提供ECR +- 必须使用 kubelet `v1.2.0` 及以上版本。(例如 运行 `/usr/bin/kubelet --version=true`)。 +- 如果 Node 在区域 A,而镜像仓库在另一个区域 B,需要 `v1.3.0` 及以上版本。 +- 区域中必须提供 ECR。 -诊断 + +故障排除: + +- 验证是否满足以上要求。 +- 获取工作站的 $REGION (例如 `us-west-2`) 凭证,使用凭证 SSH 到主机手动运行 Docker。它行得通吗? +- 验证 kubelet 是否使用参数 `--cloud-provider=aws` 运行。 +- 检查 kubelet 日志(例如 `journalctl -u kubelet`)是否有类似的行: - `plugins.go:56] Registering credential provider: aws-ecr-key` - `provider.go:91] Refreshing cache for provider: *aws_credentials.ecrProvider` + ### 使用 Azure Container Registry (ACR) -当使用[Azure Container Registry](https://azure.microsoft.com/en-us/services/container-registry/)时,可以使用admin user或者service principal认证。 -任何一种情况,认证都通过标准的Docker authentication完成。本指南假设使用[azure-cli](https://github.com/azure/azure-cli) -命令行工具。 -首先,需要创建仓库并获取凭证,完整的文档请参考 -[Azure container registry documentation](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-azure-cli)。 + +当使用 [Azure Container Registry](https://azure.microsoft.com/en-us/services/container-registry/) 时,可以使用管理员用户或者 service principal 进行身份验证。任何一种情况,认证都通过标准的 Docker 授权完成。本指南假设使用 [azure-cli](https://github.com/azure/azure-cli) 命令行工具。 -创建好容器仓库后,可以使用以下凭证登录: + +首先,需要创建仓库并获取凭证,完整的文档请参考 [Azure container registry 文档](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-azure-cli)。 + + +创建好容器仓库后,可以使用以下凭证登录: + * `DOCKER_USER` : service principal,或管理员用户名称 + * `DOCKER_PASSWORD`: service principal 密码,或管理员用户密码 + * `DOCKER_REGISTRY_SERVER`: `${some-registry-name}.azurecr.io` + * `DOCKER_EMAIL`: `${some-email-address}` + + 填写以上变量后,就可以 -[configure a Kubernetes Secret and use it to deploy a Pod](/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod)。 +[配置 Kubernetes Secret 并使用它来部署 Pod](/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod)。 + +### 使用 IBM Cloud Container Registry +IBM Cloud Container Registry 提供了一个多租户私有镜像仓库,可以使用它来安全地存储和共享 Docker 仓库。默认情况下,集成的 Vulnerability Advisor 会扫描私有仓库中的镜像,以检测安全问题和潜在的漏洞。IBM Cloud 帐户中的用户可以访问您的镜像,也可以创建令牌来授予对仓库命名空间的访问权限。 -### 配置Nodes对私有仓库认证 + +要安装 IBM Cloud Container Registry CLI 插件并为镜像创建命名空间,请参阅 [IBM Cloud Container Registry 入门](https://cloud.ibm.com/docs/services/Registry?topic=registry-index#index)。 -**注意:** 如果在Google Kubernetes Engine 上运行集群,每个节点上都会有`.dockercfg`文件,它包含对Google Container Registry的凭证。 -不需要使用以下方法。 + +可以使用 IBM Cloud Container Registry 将容器从 [IBM Cloud 公共镜像](https://cloud.ibm.com/docs/services/Registry?topic=registry-public_images#public_images) 和私有镜像部署到 IBM Cloud Kubernetes Service 集群的默认命名空间。要将容器部署到其他命名空间,或使用来自其他 IBM Cloud Container 的仓库区域或 IBM Cloud 帐户的镜像,请创建 Kubernetes `imagePullSecret`。有关更多信息,请参阅[从镜像构建容器](https://cloud.ibm.com/docs/containers?topic=containers-images#images)。 -**注意:** 如果在AWS EC2上运行集群且准备使用EC2 Container Registry (ECR),每个node上的kubelet会管理和更新ECR的登录凭证。不需要使用以下方法。 + +### 配置 Node 对私有仓库认证 -**注意:** 该方法适用于能够对节点进行配置的情况。该方法在GCE及在其它能自动配置节点的云平台上并不适合。 +{{< note >}} + +如果在 Google Kubernetes Engine 上运行集群,每个节点上都会有 `.dockercfg` 文件,它包含 Google Container Registry 的凭证。不需要使用以下方法。 +{{< /note >}} -Docker将私有仓库的密钥存放在`$HOME/.dockercfg`或`$HOME/.docker/config.json`文件中。Kubelet上,docker会使用root用户`$HOME`路径下的密钥。 +{{< note >}} + +如果在 AWS EC2 上运行集群且准备使用 EC2 Container Registry (ECR),每个 node 上的 kubelet 会管理和更新 ECR 的登录凭证。不需要使用以下方法。 +{{< /note >}} -推荐如下步骤来为node配置私有仓库。以下示例在PC或笔记本电脑中操作 +{{< note >}} + +该方法适用于能够对节点进行配置的情况。该方法在 GCE 及在其它能自动配置节点的云平台上并不适合。 +{{< /note >}} - 1.对于想要使用的每一种凭证,运行 `docker login [server]`,它会更新`$HOME/.docker/config.json`。 - 1.使用编辑器查看`$HOME/.docker/config.json`,保证文件中包含了想要使用的凭证 - 1.获取node列表,例如 - - 如果使用node名称,`nodes=$(kubectl get nodes -o jsonpath='{range.items[*].metadata}{.name} {end}')` - - 如果使用node IP ,`nodes=$(kubectl get nodes -o jsonpath='{range .items[*].status.addresses[?(@.type=="ExternalIP")]}{.address} {end}')` - 1.将本地的`.docker/config.json`拷贝到每个节点root用户目录下 - - 例如: `for n in $nodes; do scp ~/.docker/config.json root@$n:/root/.docker/config.json; done` - -创建使用私有仓库的pod来验证,例如: +{{< note >}} + +截至目前,Kubernetes 仅支持 docker config 的 `auths` 和 `HttpHeaders` 部分。这意味着不支持凭据助手(`credHelpers` 或 `credsStore`)。 +{{< /note >}} + + +Docker 将私有仓库的密钥存放在 `$HOME/.dockercfg` 或 `$HOME/.docker/config.json` 文件中。Kubelet 上,docker 会使用 root 用户 `$HOME` 路径下的密钥。 + +* `{--root-dir:-/var/lib/kubelet}/config.json` +* `{cwd of kubelet}/config.json` +* `${HOME}/.docker/config.json` +* `/.docker/config.json` +* `{--root-dir:-/var/lib/kubelet}/.dockercfg` +* `{cwd of kubelet}/.dockercfg` +* `${HOME}/.dockercfg` +* `/.dockercfg` + +{{< note >}} + +可能必须在环境变量文件中为 kubelet 显式设置 `HOME=/root`。 +{{< /note >}} + + +推荐如下步骤来为 node 配置私有仓库。以下示例在 PC 或笔记本电脑中操作: + + 1. 对于想要使用的每一种凭证,运行 `docker login [server]`,它会更新 `$HOME/.docker/config.json`。 + 2. 使用编辑器查看 `$HOME/.docker/config.json`,保证文件中包含了想要使用的凭证。 + 3. 获取 node 列表,例如 + - 如果想要 node 名称,`nodes=$(kubectl get nodes -o jsonpath='{range.items[*].metadata}{.name} {end}')` + - 如果想要 node IP ,`nodes=$(kubectl get nodes -o jsonpath='{range .items[*].status.addresses[?(@.type=="ExternalIP")]}{.address} {end}')` + 4. 将本地的 `.docker/config.json` 拷贝到每个节点 root 用户目录下 + - 例如: `for n in $nodes; do scp ~/.docker/config.json root@$n:/root/.docker/config.json; done` + + +创建使用私有仓库的 pod 来验证,例如: ```yaml -$ cat < /tmp/private-image-test-1.yaml +kubectl apply -f - < 如果一切正常,一段时间后,可以看到: ```shell -$ kubectl logs private-image-test-1 +kubectl logs private-image-test-1 SUCCESS ``` + 如果失败,则可以看到: ```shell -$ kubectl describe pods/private-image-test-1 | grep "Failed" +kubectl describe pods/private-image-test-1 | grep "Failed" Fri, 26 Jun 2015 15:36:13 -0700 Fri, 26 Jun 2015 15:39:13 -0700 19 {kubelet node-i2hq} spec.containers{uses-private-image} failed Failed to pull image "user/privaterepo:v1": Error: image user/privaterepo:v1 not found ``` + +必须保证集群中所有的节点都有相同的 `.docker/config.json` 文件。否则, pod 会在一些节点上正常运行而在另一些节点上无法启动。例如,如果使用 node 自动缩放,那么每个实例模板都需要包含 `.docker/config.json`,或者挂载一个包含这个文件的驱动器。 -必须保证集群中所有的节点都有相同的`.docker/config.json`文件。否则,pod会在一些节点上正常运行而在另一些节点上无法启动 -例如,如果使用node自动弹缩,那么每个实例模板都需要包含`.docker/config.json`,或者挂载一个包含这个文件的驱动器。 - -在`.docker/config.json`中配置了私有仓库密钥后,所有pod都会能读取私有仓库中的镜像。 - -**该方法已在6月26日的docker私有仓库和kubernetes v0.19.3上测试通过,其他私有仓库,如quay.io应该也可以运行,但未测试过。** + +在 `.docker/config.json` 中配置了私有仓库密钥后,所有 pod 都会能读取私有仓库中的镜像。 + ### 提前拉取镜像 -**注意:** 如果在Google Kubernetes Engine 上运行集群,每个节点上都会有`.dockercfg`文件,它包含对Google Container Registry的凭证。 -不需要使用以下方法。 +{{< note >}} + +如果在 Google Kubernetes Engine 上运行集群,每个节点上都会有 `.dockercfg` 文件,它包含 Google Container Registry 的凭证。不需要使用以下方法。 +{{< /note >}} -**注意:** 该方法适用于能够对节点进行配置的情况。该方法在GCE及在其它能自动配置节点的云平台上并不适合。 +{{< note >}} + +该方法适用于能够对节点进行配置的情况。该方法在 GCE 及在其它能自动配置节点的云平台上并不适合。 +{{< /note >}} -默认情况下,kubelet会尝试从指定的仓库拉取每一个镜像 -但是,如果容器属性`imagePullPolicy`设置为`IfNotPresent`或者`Never`, -则会使用本地镜像(优先、唯一、分别)。 + +默认情况下,kubelet 会尝试从指定的仓库拉取每一个镜像。但是,如果容器属性 `imagePullPolicy` 设置为 `IfNotPresent `或者 `Never`,则会使用本地镜像(优先、唯一、分别)。 -如果依赖提前拉取镜像代替仓库认证, -必须保证集群所有的节点提前拉取的镜像是相同的。 + +如果依赖提前拉取镜像代替仓库认证,必须保证集群所有的节点提前拉取的镜像是相同的。 -### 在pod上指定ImagePullSecrets +可以用于提前载入指定的镜像以提高速度,或者作为私有仓库认证的一种替代方案。 -**注意:** Google Kubernetes Engine,GCE及其他自动创建node的云平台上,推荐使用本方法。 +所有的 pod 都可以使用 node 上缓存的镜像。 -Kubernetes支持在pod中指定仓库密钥。 + +### 在 pod 上指定 ImagePullSecrets -#### 使用Docker Config创建Secret +{{< note >}} + +Google Kubernetes Engine、GCE 及其他自动创建 node 的云平台上,推荐使用本方法。 +{{< /note >}} -运行以下命令,将大写字母代替为合适的值 + +Kubernetes 支持在 pod 中指定仓库密钥。 + + +#### 使用 Docker Config 创建 Secret + + +运行以下命令,将大写字母代替为合适的值: ```shell -$ kubectl create secret docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL -secret "myregistrykey" created. +kubectl create secret docker-registry --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL ``` -如果需要接入多个仓库,可以为每个仓库创建一个secret。 -当为pod拉取镜像时,kubelet会将`imagePullSecrets`合入一个独立虚拟的`.docker/config.json`。 + +如果已经有 Docker 凭证文件,则可以将凭证文件作为 Kubernetes secret 导入而不是使用上面的命令。[根据现有 Docker 凭证创建 Secret](/docs/tasks/configure-pod-container/pull-image-private-registry/#registry-secret-existing-credentials) 解释了如何安装。如果使用多个私有容器仓库,这将特别有用,因为 `kubectl create secret docker-registry` 创建了一个仅适用于单个私有仓库的 Secret。 -Pod只能引用和它相同namespace的ImagePullSecrets, -所以需要为每一个namespace做配置 +{{< note >}} + +Pod 只能引用和它相同命名空间的 ImagePullSecrets,所以需要为每一个命名空间做配置。 +{{< /note >}} -#### 通过kubectl创建secret + +#### 引用 Pod 上的 imagePullSecrets -由于某种原因在一个`.docker/config.json`中需要多个项或者需要非上述命令给出的secret,可以[create a secret using -json or yaml](/docs/user-guide/secrets/#creating-a-secret-manually)。 + +现在,在创建 pod 时,可以在 pod 定义中增加 `imagePullSecrets` 部分来引用 secret。 -请保证: - -- 设置data项的名称为`.dockerconfigjson` -- 使用base64对docker文件编码,并将字符准确黏贴到`data[".dockerconfigjson"]`里 -- 设置`type`为`kubernetes.io/dockerconfigjson` - -示例: - -```yaml -apiVersion: v1 -kind: Secret -metadata: - name: myregistrykey - namespace: awesomeapps -data: - .dockerconfigjson: UmVhbGx5IHJlYWxseSByZWVlZWVlZWVlZWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGxsbGx5eXl5eXl5eXl5eXl5eXl5eXl5eSBsbGxsbGxsbGxsbGxsbG9vb29vb29vb29vb29vb29vb29vb29vb29vb25ubm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg== -type: kubernetes.io/dockerconfigjson -``` - -如果收到错误消息`error: no objects passed to create`,可能是 base64 编码后的字符串非法。 -如果收到错误消息类似`Secret "myregistrykey" is invalid: data[.dockerconfigjson]: invalid value ...`, -说明数据已经解码成功,但是不满足`.docker/config.json`文件的语法。 - -#### 在pod中引用imagePullSecrets - -现在,在创建pod时,可以在pod定义中增加`imagePullSecrets`小节来引用secret - -```yaml +```shell +cat < pod.yaml apiVersion: v1 kind: Pod metadata: @@ -257,41 +572,98 @@ spec: image: janedoe/awesomeapp:v1 imagePullSecrets: - name: myregistrykey +EOF + +cat <> ./kustomization.yaml +resources: +- pod.yaml +EOF ``` -对每一个使用私有仓库的pod,都需要做以上操作。 + +对每一个使用私有仓库的 pod,都需要做以上操作。 -`imagePullSecrets`可以和每个node上的`.docker/config.json`一起使用,他们将共同生效。本方法在Google Kubernetes Engine -也能正常工作。 +但是,可以通过在 [serviceAccount](/docs/user-guide/service-accounts) 资源中设置 imagePullSecrets 来自动设置 `imagePullSecrets`。检查 [将 ImagePullSecrets 添加 Service Account](/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account) 以获取详细说明。 + +可以将其与每个节点 `.docker/config.json` 结合使用。凭据将被合并。这种方法适用于 Google Kubernetes Engine。 + + ### 使用场景 + 配置私有仓库有多种方案,以下是一些常用场景和建议的解决方案。 + 1. 集群运行非专有(例如 开源镜像)镜像。镜像不需要隐藏。 - - 使用Docker hub上的公有镜像 + - 使用 Docker hub 上的公有镜像 - 无需配置 - - 在GCE/GKE上会自动使用高稳定性和高速的Docker hub的本地mirror -1. 集群运行一些专有镜像,这些镜像对外部公司需要隐藏,对集群用户可见 - - 使用自主的私有[Docker registry](https://docs.docker.com/registry/). - - 可以放置在[Docker Hub](https://hub.docker.com/account/signup/),或者其他地方。 - - 按照上面的描述,在每个节点手动配置.docker/config.json - - 或者,在防火墙内运行一个内置的私有仓库,并开放读取权限 - - 不需要配置Kubenretes - - 或者,在GCE/GKE上时,使用项目的Google Container Registry - - 使用集群自动伸缩比手动配置node工作的更好 - - 或者,在更改集群node配置不方便时,使用`imagePullSecrets` -1. 使用专有镜像的集群,有更严格的访问控制 - - 保证[AlwaysPullImages admission controller](/docs/admin/admission-controllers/#alwayspullimages)开启。否则,所有的pod都可以使用镜像 - - 将敏感数据存储在"Secret"资源中,而不是打包在镜像里 -1. 多租户集群下,每个租户需要自己的私有仓库 - - 保证[AlwaysPullImages admission controller](/docs/admin/admission-controllers/#alwayspullimages)开启。否则,所有租户的所有的pod都可以使用镜像 - - 私有仓库开启认证 - - 为每个租户获取仓库凭证,放置在secret中,并发布到每个租户的namespace下 - - 租户将secret增加到每个namespace下的imagePullSecrets中 + - 在 GCE/GKE 上会自动使用高稳定性和高速的 Docker hub 的本地 mirror + +2. 集群运行一些专有镜像,这些镜像对外部公司需要隐藏,对集群用户可见 + - 使用自主的私有 [Docker registry](https://docs.docker.com/registry/)。 + - 可以放置在 [Docker Hub](https://hub.docker.com/account/signup/),或者其他地方。 + - 按照上面的描述,在每个节点手动配置 .docker/config.json。 + - 或者,在防火墙内运行一个内置的私有仓库,并开放读取权限。 + - 不需要配置 Kubenretes。 + - 或者,在 GCE/GKE 上时,使用项目的 Google Container Registry。 + - 使用集群自动伸缩比手动配置 node 工作的更好。 + - 或者,在更改集群 node 配置不方便时,使用 `imagePullSecrets`。 + +3. 使用专有镜像的集群,有更严格的访问控制。 + - 保证开启 [AlwaysPullImages admission controller](/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages)。否则,所有的 pod 都可以使用镜像。 + - 将敏感数据存储在 "Secret" 资源中,而不是打包在镜像里。 + +4. 多租户集群下,每个租户需要自己的私有仓库。 + - 开启保证 [AlwaysPullImages admission controller](/docs/reference/access-authn-authz/admission-controllers/#alwayspullimages)。否则,所有租户的所有的 pod 都可以使用镜像。 + - 私有仓库开启认证。 + - 为每个租户获取仓库凭证,放置在 secret 中,并发布到每个租户的命名空间下。 + - 租户将 secret 增加到每个命名空间下的 imagePullSecrets 中。 {{% /capture %}} - + +如果需要访问多个仓库,则可以为每个仓库创建一个 secret。Kubelet 将任何 `imagePullSecrets` 合并为单个虚拟 `.docker/config.json` 文件。 diff --git a/content/zh/docs/concepts/containers/runtime-class.md b/content/zh/docs/concepts/containers/runtime-class.md index 6099164aca..53bb567960 100644 --- a/content/zh/docs/concepts/containers/runtime-class.md +++ b/content/zh/docs/concepts/containers/runtime-class.md @@ -1,4 +1,7 @@ --- +reviewers: +- tallclair +- dchen1107 title: 容器运行时类(Runtime Class) content_template: templates/concept weight: 20 @@ -8,22 +11,19 @@ weight: 20 {{< feature-state for_k8s_version="v1.14" state="beta" >}} - - -这个文档主要说明了 RuntimeClass 资源和 kubernetes 指定容器运行时的功能。 +本页面描述了 RuntimeClass 资源和运行时的选择机制。 {{< warning >}} - -Kubernetes1.14 的 β 版的升级包含了 RuntimeClass 的 *破坏性* 的变更。 -如果用户在使用 Kubernetes1.14 以前的 RuntimeClass 版本, -请参考文档[从 RuntimeClass 的 α 版升级到β版](#upgrading-runtimeclass-from-alpha-to-beta)。 +-->RuntimeClass 特性在 v1.14 版本升级为 beta 特性时引入了不兼容的改变。 +如果你在 v1.14 以前的版本中使用 RuntimeClass,请查阅 +[Upgrading RuntimeClass from Alpha to Beta](#upgrading-runtimeclass-from-alpha-to-beta)。 {{< /warning >}} {{% /capture %}} @@ -31,101 +31,105 @@ Kubernetes1.14 的 β 版的升级包含了 RuntimeClass 的 *破坏性* 的变 {{% capture body %}} - +RuntimeClass 是用于选择容器运行时配置的特性,容器运行时配置用于运行 Pod 中的容器。 -## 关于RuntimeClass - -RuntimeClass 是可以让用户选择容器运行时的功能。用户通过设定容器运行时可以选择 Pod 的容器运行在那种容器运行时之上。 - - +您可以在不同的 pod 之间设置不同的 RuntimeClass,以提供性能与安全性之间的平衡。 +例如,如果您的部分工作负载需要高级别的信息安全保证,那么您可以选择性地调度这些 pod, +使它们在使用硬件虚拟化的容器运行时中运行。 +然后,您将从可选运行时的额外隔离中获益,代价是一些额外的开销。 + -## 使用场景 -用户可以为不同的 Pod 设定不同的 RuntimeClass ,以达到动态调整容器安全和容器性能间的平衡的目的。例如, -如果用户的一部分工作需要确保高安全性,那么可以选择调度Pod使用到硬件虚拟化的容器运行时。 -受益于硬件虚拟化带来的附加的容器隔离特性的同时,也会带来性能上的额外开销。 +您还可以使用 RuntimeClass 运行具有相同容器运行时但具有不同设置的pod。 -用户也可以通过这种方式,为Pod提供不同设定的同一种容器运行时。 + +### 设置 +确保 RuntimeClass 特性开关处于开启状态(默认为开启状态)。 +关于特性开关的详细介绍,请查阅 +[Feature Gates](/docs/reference/command-line-tools-reference/feature-gates/)。 +`RuntimeClass` 特性开关必须在 apiservers 和 kubelets 同时开启。 + -### 设定 - -首先要先确认 RuntimeClass 功能的 Feature Gate 被设定为开启(默认是有效状态)。设定 Feature Gate 为有效的文档请参考[Feature Gates](/docs/reference/command-line-tools-reference/feature-gates/)。 -`RuntimeClass`的 Feature Gate 开启需要 ApiServer 和 kubelet 同时将相关配置开启。 - -1. 配置节点的 CRI。(依赖于容器运行时) -2. 创建相应的 RuntimeClass 资源。 +1. 在节点上配置 CRI 的实现(取决于所选用的运行时) +2. 创建相应的 RuntimeClass 资源 +#### 1. 在节点上配置 CRI 实现 + -#### 1. 实现节点上的CRI设定。 - -通过 RuntimeClass 进行设定的有效化,依赖于 Container Runtime Interface (CRI) 组件。 -在用户环境中,CRI 的设定方法请参考([见下面](#cri-configuration))文档。 +RuntimeClass 的配置依赖于 运行时接口(CRI)的实现。 +根据你使用的 CRI 实现,查阅相关的文档([下方](#cri-configuration))来了解如何配置。 {{< note >}} -<!-- + - -默认情况下,RuntimeClass 被假设为所有节点上的配置均为一致。(这意味着所有的 Node 节点的容器运行时必须以相同的方式进行设定)。 -要支持不同配置构节点配置,请参见下面的[Scheduling](#scheduling)。 - +heterogenous node configurations, see [Scheduling](#scheduling) below.-->RuntimeClass 假设集群中的节点配置是同构的 +(换言之,所有的节点在容器运行时方面的配置是相同的)。 +如果需要支持异构节点,配置方法请参阅下面的 [Scheduling](#scheduling)。 {{< /note >}} -配置需要具有相应的 `handler` 名称,被用于 RuntimeClass 的设定。 -被定义的 Handler 名称必须是有效的 DNS-1123 标准。(只能使用英文字母,数字 和 `-`)。 +所有这些配置都具有相应的 `handler` 名,并被 RuntimeClass 引用。 +handler 必须符合 DNS-1123 命名规范(字母、数字、或 `-`)。 +#### 2. 创建相应的 RuntimeClass 资源 + +在上面步骤 1 中,每个配置都需要有一个用于标识配置的 `handler`。 +针对每个 handler 需要创建一个 RuntimeClass 对象。 + -#### 2. 创建对应的RuntimeClass资源 - -为了便于识别各个项目,安装配置的第一步需要每个项目有一个关联的 `handler` 名称。这样就可以为每个 `handler` 创建对应的 RuntimeClass 资源了。 - -所以当前 RuntimeClass 资源有两个重要的设定项。一个是 RuntimeClass 的名称( `metadata.name` )和 Handler (`handler`)。RuntimeClass 的资源定义可以参考下面的内容。 +RuntimeClass 资源当前只有两个重要的字段:RuntimeClass 名 (`metadata.name`) 和 handler (`handler`)。 +对象定义如下所示: ```yaml apiVersion: node.k8s.io/v1beta1 # RuntimeClass is defined in the node.k8s.io API group @@ -140,22 +144,21 @@ handler: myconfiguration # The name of the corresponding CRI configuration -推荐只有集群管理员具有针对 RuntimeClass 的各项操作权限(create/update/patch/delete)。 -这通常是默认值。具体内容可以[授权概况](/docs/reference/access-authn-authz/authorization/)文档了解详细信息。 +Overview](/docs/reference/access-authn-authz/authorization/) for more details.-->建议将 RuntimeClass 写操作(create、update、patch 和 delete)限定于集群管理员使用。 +通常这是默认配置。参阅[授权概述](/docs/reference/access-authn-authz/authorization/)了解更多信息。 {{< /note >}} +### 使用说明 + -### 使用方法 - -一旦集群中的 RuntimeClass 的设定完成,接下来的使用就变得非常简单了。只需要设定 PodSpec 的 `runtimeClassName` 设定项。 -例如: +一旦完成集群中 RuntimeClasses 的配置,使用起来非常方便。 +在 Pod spec 中指定 `runtimeClassName` 即可。例如: ```yaml apiVersion: v1 @@ -173,44 +176,39 @@ RuntimeClass does not exist, or the CRI cannot run the corresponding handler, th `Failed` terminal [phase](/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase). Look for a corresponding [event](/docs/tasks/debug-application-cluster/debug-application-introspection/) for an error message. +--> +这一设置会告诉 Kubelet 使用所指的 RuntimeClass 来运行该 pod。 +如果所指的 RuntimeClass 不存在或者 CRI 无法运行相应的 handler,那么 pod 将会进入 `Failed` 终止[阶段](/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase)。 +你可以查看相应的[事件](/docs/tasks/debug-application-cluster/debug-application-introspection/),获取出错信息。 + +如果未指定 `runtimeClassName` ,则将使用默认的 RuntimeHandler,相当于禁用 RuntimeClass 功能特性。 -这个设定将让Kubelet使用指定的 RuntimeClass 来运行 Pod。如果 RuntimeClass 不存在, 或者 CRI 不能执行相应的 Handler,Pod 将会变成`Failed`[状态](/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase)。 -请参考对应的相关[事件](/docs/tasks/debug-application-cluster/debug-application-introspection/)文档,确定错误信息。 - -如果 `runtimeClassName` 没有被设定的情况下,将会使用默认的 RuntimeHandler,这里的运行效果和 RuntimeClass 功能被禁止的情况下是一样的。 - - -### CRI的设定 +关于如何安装 CRI 运行时,请查阅[CRI installation](/docs/setup/production-environment/container-runtimes/)。 -CRI 运行时的相关设定详细内容请参考[CRI的安装](/docs/setup/cri/)。 - - -#### dockershim +Kubernetes 内置 dockershim CRI 不支持配置运行时 handler。 -Kubernetes 的内置 dockershim CRI 不支持容器运行时 handlers。 - - -#### [containerd](https://containerd.io/) - -运行时 handler 可以通过 containerd 的配置文件 `/etc/containerd/config.toml` 进行设定。 -有效的 handlers 被设定在 runtimes 部分的下一层级。 +通过 containerd 的 `/etc/containerd/config.toml` 配置文件来配置运行时 handler。 +handler 需要配置在 runtimes 块中: ``` [plugins.cri.containerd.runtimes.${HANDLER_NAME}] @@ -220,7 +218,7 @@ Runtime handlers are configured through containerd's configuration at See containerd's config documentation for more details: https://github.com/containerd/cri/blob/master/docs/config.md --> -`containerd` 的具体设定请参考下面的文档信息。 +更详细信息,请查阅 containerd 配置文档: https://github.com/containerd/cri/blob/master/docs/config.md #### [cri-o](https://cri-o.io/) @@ -230,8 +228,9 @@ Runtime handlers are configured through cri-o's configuration at `/etc/crio/crio handlers are configured under the [crio.runtime table](https://github.com/kubernetes-sigs/cri-o/blob/master/docs/crio.conf.5.md#crioruntime-table): --> -运行时处理程序通过cri-o的配置在 `/etc/crio/crio.conf` 中进行配置。 -有效的处理程序在[crio.runtime表](https://github.com/kubernetes-sigs/cri-o/blob/master/docs/crio.conf.5.md#crioruntime-table)下配置。 +通过 cri-o 的 `/etc/crio/crio.conf` 配置文件来配置运行时 handler。 +handler 需要配置在[crio.runtime 表](https://github.com/kubernetes-sigs/cri-o/blob/master/docs/crio.conf.5.md#crioruntime-table) +下方: ``` [crio.runtime.runtimes.${HANDLER_NAME}] @@ -242,14 +241,10 @@ table](https://github.com/kubernetes-sigs/cri-o/blob/master/docs/crio.conf.5.md# See cri-o's config documentation for more details: https://github.com/kubernetes-sigs/cri-o/blob/master/cmd/crio/config.go --> -有关更多详细信息,请参见cri-o的配置文档: +更详细信息,请查阅 containerd 配置文档: https://github.com/kubernetes-sigs/cri-o/blob/master/cmd/crio/config.go - - -### 调度 {{< feature-state for_k8s_version="v1.16" state="beta" >}} @@ -258,75 +253,69 @@ As of Kubernetes v1.16, RuntimeClass includes support for heterogenous clusters `scheduling` fields. Through the use of these fields, you can ensure that pods running with this RuntimeClass are scheduled to nodes that support it. To use the scheduling support, you must have the RuntimeClass [admission controller][] enabled (the default, as of 1.16). +--> +在 Kubernetes v1.16 版本里,RuntimeClass 特性引入了 `scheduling` 字段来支持异构集群。 +通过该字段,可以确保 pod 被调度到支持指定运行时的节点上。 +该调度支持,需要确保 RuntimeClass [admission controller][] 处于开启状态(1.16 版本默认开启)。 + - -从Kubernetes v1.16开始,RuntimeClass 通过 `scheduling` 字段添加了对异构集群的支持。 -通过使用这些字段,可以确保将与此 RuntimeClass一 起运行的 Pod 调度到支持它的节点上。 -要使用计划支持,您必须启用 RuntimeClass [admission controller] [](默认值,自1.16开始)。 - -为了确保 Pod 被调度到支持特定 RuntimeClass 的节点上, -那组节点应该具有一个公共标签,然后由 `runtimeclass.scheduling.nodeSelector` 字段选择该标签。 -RuntimeClass 的 nodeSelector 在调度时与 Pod 的 nodeSelector 合并,有效地进行节点选择,并且调度到相应节点。 -如果有冲突,则将拒绝该 Pod 被调度。 +为了确保 pod 会被调度到支持指定运行时的 node 上,每个 node 需要设置一个通用的 label 用于被 +`runtimeclass.scheduling.nodeSelector` 挑选。在 admission 阶段,RuntimeClass 的 nodeSelector 将会于 +pod 的 nodeSelector 合并,取二者的交集。如果有冲突,pod 将会被拒绝。 - -如果受支持的节点被污染以防止其他 RuntimeClass 容器在该节点上运行,则可以向RuntimeClass添加 `tolerations` 设定。 -与 `nodeSelector` 一样,容忍度在接纳时与容器的容忍度合并,从而有效地吸收了每个容忍度的节点集的并集。 - -要了解有关配置节点选择器和容差的更多信息,请参阅[分配 Pod 到节点](/docs/concepts/configuration/assign-pod-node/)。 - -[准入控制器]: /docs/reference/access-authn-authz/admission-controllers/ +如果 node 需要阻止某些需要特定 RuntimeClass 的 pod,可以在 `tolerations` 中指定。 +与 `nodeSelector` 一样,tolerations 也在 admission 阶段与 pod 的 tolerations 合并,取二者的并集。 +更多有关 node selector 和 tolerations 的配置信息,请查阅 +[Assigning Pods to Nodes](/docs/concepts/configuration/assign-pod-node/)。 -### Pod 开销 +[admission controller]: /docs/reference/access-authn-authz/admission-controllers/ + +### Pod Overhead {{< feature-state for_k8s_version="v1.16" state="alpha" >}} +在 Kubernetes v1.16 版本中,RuntimeClass 开始支持 pod 的 overhead,作为 [`PodOverhead`](/docs/concepts/configuration/pod-overhead) +特性的一部分。 +若要使用 `PodOverhead` 特性,你需要确保 PodOverhead 特性开关处于开启状态(默认为关闭状态)。 - + +Pod 的 overhead 在 RuntimeClass 的 `Overhead` 字段定义,该字段用于指定使用 RuntimeClass 特性时带来的 overhead。 -从 Kubernetes v1.16 开始,RuntimeClass 包含了对指定与运行 Pod 相关的开销的支持, -这是[`Pod 开销`](/docs/concepts/configuration/pod-overhead.md)功能的一部分。 -要使用 `PodOverhead` ,您必须确保 PodOverhead [功能](/docs/reference/command-line-tools-reference/feature-gates/) 已启用(默认情况下处于关闭状态)。 - -Pod 的开销是在 RuntimeClass 中通过 `Overhead` 字段定义的。 通过使用这些字段, -您可以使用此 RuntimeClass 指定运行 Pod 的开销,并确保在Kubernetes中考虑了这些开销。 - - +RuntimeClass Beta 特性包含如下几个改变: + - -### 将 RuntimeClass 从 Alpha 升级到 Beta - -RuntimeClass Beta 功能包括以下更改: - -- `node.k8s.io` API 组和 `runtimeclasses.node.k8s.io` 资源已从 `CustomResourceDefinition` 迁移到内置API。 -- 已在 RuntimeClass 定义中内联了 `spec`(即不再有RuntimeClassSpec)。 -- `runtimeHandler` 字段已重命名为 `handler`。 -- 所有 API 版本中现在都需要 `handler` 字段。 这意味着 Alpha API 中的 `runtimeHandler` 字段也是必须设定项。 -- `handler`字段必须是有效的DNS标签([RFC 1123](https://tools.ietf.org/html/rfc1123)),这意味着它不再包含 `.` 字符(在所有版本中)。 - 有效的处理程序匹配以下正则表达式:`^ [a-z0-9]([-a-z0-9] * [a-z0-9])?$`。 +- `node.k8s.io` API 组和 `runtimeclasses.node.k8s.io` 资源已从 CRD 中迁移到内置的 API 中; +- `spec` 被放置到 RuntimeClass 中(例如,没有 RuntimeClassSpec 了); +- `runtimeHandler` 字段重命名为 `handler`; +- `handler` 字段需要在所有版本的 API 提供,这意味着 `runtimeHandler` 字段在 Alpha API 中也需要提供; +- `handler` 字段必须是一个合法的 DNS 标识([RFC 1123](https://tools.ietf.org/html/rfc1123)), + 这意味着不可以包含 `.` 字符。合法的 handler 必须满足如下规则:`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`。 +**Action Required:** RuntimeClass 特性从 alpha 版本升级到 beta 版本,需要做如下动作: + - -**需要采取的措施:** 要从 RuntimeClass 功能的 Alpha 版本升级到 Beta 版本,需要执行以下操作: - -- 在升级到v1.14之后,必须重新创建 RuntimeClass 资源,并且应该手动删除 runtimeclasses.node.k8s.io 的 CRD: +- RuntimeClass 资源必须在升级到 v1.14 *之后* 再创建,并且 CRD 资源 `runtimeclasses.node.k8s.io` 必须要手动删除: ``` kubectl delete customresourcedefinitions.apiextensions.k8s.io runtimeclasses.node.k8s.io ``` -- 在处理程序中具有未指定或为空的 `runtimeHandler` 字段或使用 `.` 字符的 Alpha RuntimeClass 不再有效, - 必须将其迁移到有效的处理程序配置中(请参见上文)。 - - - -### 进一步阅读 - -- [运行时类设计](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/runtime-class.md) -- [RuntimeClass 计划设计](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/runtime-class-scheduling.md) -- 了解有关 [Pod 开销](/docs/concepts/configuration/pod-overhead/) 概念 -- [Pod 开销功能设计](https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/20190226-pod-overhead.md) {{% /capture %}} diff --git a/content/zh/docs/concepts/extend-kubernetes/_index.md b/content/zh/docs/concepts/extend-kubernetes/_index.md index 44a8ee8361..9eef5fffc5 100644 --- a/content/zh/docs/concepts/extend-kubernetes/_index.md +++ b/content/zh/docs/concepts/extend-kubernetes/_index.md @@ -1,4 +1,11 @@ --- title: 扩展 Kubernetes weight: 40 ---- \ No newline at end of file +--- + + diff --git a/content/zh/docs/concepts/extend-kubernetes/api-extension/_index.md b/content/zh/docs/concepts/extend-kubernetes/api-extension/_index.md index 206de59684..51c5bdcc7a 100644 --- a/content/zh/docs/concepts/extend-kubernetes/api-extension/_index.md +++ b/content/zh/docs/concepts/extend-kubernetes/api-extension/_index.md @@ -1,4 +1,11 @@ --- title: 扩展 Kubernetes API weight: 20 ---- \ No newline at end of file +--- + + diff --git a/content/zh/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation.md b/content/zh/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation.md index 63b869058a..4f7376b084 100644 --- a/content/zh/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation.md +++ b/content/zh/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation.md @@ -3,13 +3,23 @@ title: 通过聚合层扩展 Kubernetes API content_template: templates/concept weight: 10 --- + {{% capture overview %}} - 聚合层允许 Kubernetes 通过额外的 API 进行扩展,而不局限于 Kubernetes 核心 API 提供的功能。 {{% /capture %}} @@ -28,13 +38,11 @@ The aggregation layer enables installing additional Kubernetes-style APIs in you - 聚合层在 kube-apiserver 进程内运行。在扩展资源注册之前,聚合层不做任何事情。要注册 API,用户必须添加一个 APIService 对象,用它来申领 Kubernetes API 中的 URL 路径。自此以后,聚合层将会把发给该 API 路径的所有内容(例如 /apis/myextension.mycompany.io/v1/…)代理到已注册的 APIService。 - 正常情况下,APIService 会实现为运行于集群中某 Pod 内的 extension-apiserver。如果需要对增加的资源进行动态管理,extension-apiserver 经常需要和一个或多个控制器一起使用。因此,apiserver-builder 同时提供用来管理新资源的 API 框架和控制器框架。另外一个例子,当安装了 service-catalog 时,它会为自己提供的服务提供 extension-apiserver 和控制器。 -扩展 api 服务与 kube-apiserver 之间的连接应该具有低延迟的特性。 -特别是,发现请求和 kube-apiserver 的请求响应时间需要在五秒钟或更短的时间内。 -如果您的部署无法实现此目的,则应考虑如何进行改进。 -现在,利用 kube-apiserver 上的`EnableAggregatedDiscoveryTimeout = false`功能可以禁用超时限制。但是,它将在将来的版本中删除。 +extension-apiserver 与 kube-apiserver 之间的连接应具有低延迟。 +特别是,发现请求需要在五秒钟或更短的时间内从 kube-apiserver 往返。 +如果您的部署无法实现此目的,则应考虑如何进行更改。目前,在 kube-apiserver 上设置 `EnableAggregatedDiscoveryTimeout=false` 功能开关将禁用超时限制。它将在将来的版本中被删除。 + {{% /capture %}} {{% capture whatsnext %}} @@ -58,7 +66,6 @@ will disable the timeout restriction. It will be removed in a future release. * Then, [setup an extension api-server](/docs/tasks/access-kubernetes-api/setup-extension-api-server/) to work with the aggregation layer. * Also, learn how to [extend the Kubernetes API using Custom Resource Definitions](/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/). --> - * 阅读[配置聚合层](/docs/tasks/access-kubernetes-api/configure-aggregation-layer/) 文档,了解如何在自己的环境中启用聚合器(aggregator)。 * 然后[安装扩展的 api-server](/docs/tasks/access-kubernetes-api/setup-extension-api-server/) 来开始使用聚合层。 * 也可以学习怎样 [使用客户资源定义扩展 Kubernetes API](/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/)。 diff --git a/content/zh/docs/concepts/extend-kubernetes/compute-storage-net/_index.md b/content/zh/docs/concepts/extend-kubernetes/compute-storage-net/_index.md index f442ce7faf..1b46b18dd2 100644 --- a/content/zh/docs/concepts/extend-kubernetes/compute-storage-net/_index.md +++ b/content/zh/docs/concepts/extend-kubernetes/compute-storage-net/_index.md @@ -1,4 +1,11 @@ --- title: 计算、存储和网络扩展 weight: 30 ---- \ No newline at end of file +--- + + diff --git a/content/zh/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md b/content/zh/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md index bbf72b68c2..506539c3be 100644 --- a/content/zh/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md +++ b/content/zh/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md @@ -3,6 +3,11 @@ title: 网络插件 content_template: templates/concept weight: 10 --- + {{% capture overview %}} @@ -172,7 +177,6 @@ CNI 网络插件还支持 pod 入口和出口流量整形。 ] } ``` - + +{{% capture overview %}} + + +Kubernetes 是高度可配置和可扩展的。因此,极少需要分发或提交补丁代码给 Kubernetes 项目。 + +本文档介绍自定义 Kubernetes 集群的选项。本文档的目标读者 {{< glossary_tooltip text="cluster operators" term_id="cluster-operator" >}} 是希望了解如何使 Kubernetes 集群满足其业务环境需求的集群运维人员。Kubernetes 项目的贡献者 {{< glossary_tooltip text="Contributors" term_id="contributor" >}} 或潜在的平台开发人员 {{< glossary_tooltip text="Platform Developers" term_id="platform-developer" >}} 也可以从本文找到有用的信息,如对已存在扩展点和模式的介绍,以及它们的权衡和限制。 + +{{% /capture %}} + + +{{% capture body %}} + + +## 概述 + +定制方法可以大致分为 *配置* 和 *扩展* 。*配置* 只涉及更改标志参数、本地配置文件或 API 资源;*扩展* 涉及运行额外的程序或服务。本文档主要内容是关于扩展。 + + +## 配置 + + +关于 *配置文件* 和 *标志* 的说明文档位于在线文档的参考部分,按照二进制组件各自描述: + +* [kubelet](/docs/admin/kubelet/) +* [kube-apiserver](/docs/admin/kube-apiserver/) +* [kube-controller-manager](/docs/admin/kube-controller-manager/) +* [kube-scheduler](/docs/admin/kube-scheduler/). + + +在托管的 Kubernetes 服务或受控安装的 Kubernetes 版本中,标志和配置文件可能并不总是可以更改的。而且当它们可以进行更改时,它们通常只能由集群管理员进行更改。此外,标志和配置文件在未来的 Kubernetes 版本中可能会发生变化,并且更改设置后它们可能需要重新启动进程。出于这些原因,只有在没有其他选择的情况下才使用它们。 + + +*内置策略 API* ,例如 [ResourceQuota](/docs/concepts/policy/resource-quotas/)、[PodSecurityPolicy](/docs/concepts/policy/pod-security-policy/)、[NetworkPolicy](/docs/concepts/services-networking/network-policies/) 和基于角色的权限控制 ([RBAC](/docs/reference/access-authn-authz/rbac/)),是内置的 Kubernetes API。API 通常与托管的 Kubernetes 服务和受控的 Kubernetes 安装一起使用。 +它们是声明性的,并使用与其他 Kubernetes 资源(如 Pod )相同的约定,所以新的集群配置可以重复使用,并以与应用程序相同的方式进行管理。而且,当他们变稳定后,他们和其他 Kubernetes API 一样享受[定义支持政策](/docs/reference/deprecation-policy/)。出于这些原因,在合适的情况下它们优先于 *配置文件* 和 *标志* 被使用。 + + +## 扩展程序 + +扩展程序是指对 Kubernetes 进行扩展和深度集成的软件组件。它们适合用于支持新的类型和新型硬件。 + +大多数集群管理员会使用托管的或统一分发的 Kubernetes 实例。因此,大多数 Kubernetes 用户需要安装扩展程序,而且还有少部分用户甚至需要编写新的扩展程序。 + + +## 扩展模式 + + +Kubernetes 的设计是通过编写客户端程序来实现自动化的。任何读和(或)写 Kubernetes API 的程序都可以提供有用的自动化工作。*自动化* 程序可以运行在集群之中或之外。按照本文档的指导,您可以编写出高可用的和健壮的自动化程序。自动化程序通常适用于任何 Kubernetes 集群,包括托管集群和受管理安装的集群。 + + +*控制器* 模式是编写适合 Kubernetes 的客户端程序的一种特定模式。控制器通常读取一个对象的 `.spec` 字段,可能做出一些处理,然后更新对象的 `.status` 字段。 + +一个控制器是 Kubernetes 的一个客户端。而当 Kubernetes 作为客户端调用远程服务时,它被称为 *Webhook* ,远程服务称为 *Webhook* 后端。 和控制器类似,Webhooks 增加了一个失败点。 + + +在 webhook 模型里,Kubernetes 向远程服务发送一个网络请求。在 *二进制插件* 模型里,Kubernetes 执行一个二进制(程序)。二进制插件被 kubelet(如 [Flex 卷插件](https://github.com/kubernetes/community/blob/master/contributors/devel/flexvolume.md)和[网络插件](/docs/concepts/cluster-administration/network-plugins/))和 kubectl 所使用。 + + +下图显示了扩展点如何与 Kubernetes 控制平面进行交互。 + + + + + + +## 扩展点 + +下图显示了 Kubernetes 系统的扩展点。 + + + + + + +1. 用户通常使用 `kubectl` 与 Kubernetes API 进行交互。[kubectl 插件](/docs/tasks/extend-kubectl/kubectl-plugins/)扩展了 kubectl 二进制程序。它们只影响个人用户的本地环境,因此不能执行站点范围的策略。 +2. apiserver 处理所有请求。apiserver 中的几种类型的扩展点允许对请求进行身份认证或根据其内容对其进行阻止、编辑内容以及处理删除操作。这些内容在[API 访问扩展](/docs/concepts/overview/extending#api-access-extensions)小节中描述。 + +3. apiserver 提供各种 *资源* 。 *内置的资源种类* ,如 `pods`,由 Kubernetes 项目定义,不能更改。您还可以添加您自己定义的资源或其他项目已定义的资源,称为 自定义资源,如[自定义资源](/docs/concepts/overview/extending#user-defined-types)部分所述。自定义资源通常与 API 访问扩展一起使用。 +4. Kubernetes 调度器决定将 Pod 放置到哪个节点。有几种方法可以扩展调度器。这些内容在 [Scheduler Extensions](/docs/concepts/overview/extending#scheduler-extensions) 小节中描述。 + +5. Kubernetes 的大部分行为都是由称为控制器的程序实现的,这些程序是 API-Server 的客户端。控制器通常与自定义资源一起使用。 +6. kubelet 在主机上运行,并帮助 pod 看起来就像在集群网络上拥有自己的 IP 的虚拟服务器。[网络插件](/docs/concepts/overview/extending#network-plugins)让您可以实现不同的 pod 网络。 +7. kubelet 也挂载和卸载容器的卷。新的存储类型可以通过[存储插件](/docs/concepts/overview/extending#storage-plugins)支持。 + + +如果您不确定从哪里开始扩展,此流程图可以提供帮助。请注意,某些解决方案可能涉及多种类型的扩展。 + + + + + + +## API 扩展 +### 用户自定义类型 + +如果您想定义新的控制器、应用程序配置对象或其他声明式 API,并使用 Kubernetes 工具(如 `kubectl`)管理它们,请考虑为 Kubernetes 添加一个自定义资源。 + +不要使用自定义资源作为应用、用户或者监控数据的数据存储。 + +有关自定义资源的更多信息,请查看[自定义资源概念指南](/docs/concepts/api-extension/custom-resources/)。 + + +### 将新的 API 与自动化相结合 + +自定义资源 API 和控制循环的组合称为 [操作者模式](/docs/concepts/extend-kubernetes/operator/)。操作者模式用于管理特定的,通常是有状态的应用程序。这些自定义 API 和控制循环还可用于控制其他资源,例如存储或策略。 + + +### 改变内置资源 + +当您通过添加自定义资源来扩展 Kubernetes API 时,添加的资源始终属于新的 API 组。您不能替换或更改已有的 API 组。添加 API 不会直接影响现有 API(例如 Pod )的行为,但是 API 访问扩展可以。 + + +### API 访问扩展 + +当请求到达 Kubernetes API Server 时,它首先被要求进行用户认证,然后要进行授权检查,接着受到各种类型的准入控制的检查。有关此流程的更多信息,请参阅 [Kubernetes API访问控制](/docs/reference/access-authn-authz/controlling-access/)。 + +上述每个步骤都提供了扩展点。 + +Kubernetes 有几个它支持的内置认证方法。它还可以位于身份验证代理之后,并将授权 header 中的令牌发送给远程服务进行验证(webhook)。所有这些方法都在[身份验证文档](/docs/reference/access-authn-authz/authentication/)中介绍。 + + +### 身份认证 + +[身份认证](/docs/reference/access-authn-authz/authentication/)将所有请求中的 header 或证书映射为发出请求的客户端的用户名。 + +Kubernetes 提供了几种内置的身份认证方法,如果这些方法不符合您的需求,可以使用[身份认证 webhook](/docs/reference/access-authn-authz/authentication/#webhook-token-authentication) 方法。 + + +### 授权 + +[授权](/docs/reference/access-authn-authz/webhook/)决定特定用户是否可以对 API 资源执行读取、写入以及其他操作。它只是在整个资源的层面上工作 -- 它不基于任意的对象字段进行区分。如果内置授权选项不能满足您的需求,[授权 webhook](/docs/reference/access-authn-authz/webhook/) 允许调用用户提供的代码来作出授权决定。 + + +### 动态准入控制 + +在请求被授权之后,如果是写入操作,它还将进入[准入控制](/docs/reference/access-authn-authz/admission-controllers/)步骤。除了内置的步骤之外,还有几个扩展: + +* [镜像策略 webhook](/docs/reference/access-authn-authz/admission-controllers/#imagepolicywebhook) 限制了哪些镜像可以在容器中运行。 +* 为了进行灵活的准入控制决策,可以使用通用的 [Admission webhook](/docs/reference/access-authn-authz/extensible-admission-controllers/#admission-webhooks)。Admission Webhooks 可以拒绝创建或更新操作。 + + +## 基础设施扩展 + + +### 存储插件 + +[Flex Volumes](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/flexvolume-deployment.md +) 允许用户挂载无内置插件支持的卷类型,它通过 Kubelet 调用一个二进制插件来挂载卷。 + + +### 设备插件 + +设备插件允许节点通过[设备插件](/docs/concepts/cluster-administration/device-plugins/)发现新的节点资源(除了内置的 CPU 和内存之外)。 + + +### 网络插件 + +不同的网络结构可以通过节点级的[网络插件](/docs/admin/network-plugins/)支持。 + + +### 调度器扩展 + +调度器是一种特殊类型的控制器,用于监视 pod 并将其分配到节点。默认的调度器可以完全被替换,而继续使用其他 Kubernetes 组件,或者可以同时运行[多个调度器](/docs/tasks/administer-cluster/configure-multiple-schedulers/)。 + +这是一个重要的任务,几乎所有的 Kubernetes 用户都发现他们不需要修改调度器。 + +调度器也支持 [webhook](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduling/scheduler_extender.md),它允许一个 webhook 后端(调度器扩展程序)为 pod 筛选节点和确定节点的优先级。 + +{{% /capture %}} + + +{{% capture whatsnext %}} + + +* 详细了解[自定义资源](/docs/concepts/api-extension/custom-resources/) +* 了解[动态准入控制](/docs/reference/access-authn-authz/extensible-admission-controllers/) +* 详细了解基础设施扩展 + * [网络插件](/docs/concepts/cluster-administration/network-plugins/) + * [设备插件](/docs/concepts/cluster-administration/device-plugins/) +* 了解 [kubectl 插件](/docs/tasks/extend-kubectl/kubectl-plugins/) +* 了解[操作者模式](/docs/concepts/extend-kubernetes/operator/) + +{{% /capture %}} diff --git a/content/zh/docs/concepts/extend-kubernetes/service-catalog.md b/content/zh/docs/concepts/extend-kubernetes/service-catalog.md new file mode 100644 index 0000000000..ab8494e637 --- /dev/null +++ b/content/zh/docs/concepts/extend-kubernetes/service-catalog.md @@ -0,0 +1,457 @@ +--- +title: 服务目录 +reviewers: +- chenopis +content_template: templates/concept +weight: 40 +--- + + +{{% capture overview %}} +{{< glossary_definition term_id="service-catalog" length="all" prepend="" >}} + + +服务代理是由[开放服务代理 API 规范](https://github.com/openservicebrokerapi/servicebroker/blob/v2.13/spec.md)定义的一组托管服务的终结点,由第三方提供并维护,其中的第三方可以是 AWS,GCP 或 Azure 等云服务提供商。 +托管服务的一些示例是 Microsoft Azure Cloud Queue,Amazon Simple Queue Service 和 Google Cloud Pub/Sub,但它们是可以使用应用程序的任何软件产品。 + +使用服务目录,集群操作者可以浏览其提供的托管服务列表,提供托管服务实例并与之绑定,以使其可以被 Kubernetes 集群中的应用程序使用。 + +{{% /capture %}} + + +{{% capture body %}} + +## 示例用例 + +应用开发者希望使用消息队列作为其在 Kubernetes 集群中运行的应用程序的一部分。 +但是,它们不想承受建立这种服务的开销,也不想自行管理。幸运的是,有一家云服务提供商通过它们的服务代理将消息队列作为托管服务提供。 + +集群运维人员可以设置服务目录并使用它与云服务提供商的服务代理 通信,以此提供消息队列服务的实例并使其对 Kubernetes 中的应用程序可用。 +因此,应用开发者可以不用关心消息队列的实现细节,也不用对其进行管理。它们的应用程序可以简单的将其作为服务使用。 + + +## 架构 +服务目录使用[开放服务代理 API](https://github.com/openservicebrokerapi/servicebroker) 与服务代理进行通信,并作为 Kubernetes API Server 的中介,以便协商首要规定并获取应用程序使用托管服务的必要凭据。 + +它被实现为一个扩展 API 服务和一个控制器管理器,使用 Etcd 作为存储。它还使用了 Kubernetes 1.7+ 版本中提供的 [aggregation layer](/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/) 来呈现其 API。 + +
+ +![Service Catalog Architecture](/images/docs/service-catalog-architecture.svg) + + +## API 资源 + +服务目录安装 `servicecatalog.k8s.io` API 并提供以下 Kubernetes 资源: + +* `ClusterServiceBroker`:服务目录的集群内代表,封装了它的服务连接细节。集群运维人员创建和管理这些资源,并希望使用该代理服务在集群中提供新类型的托管服务。 +* `ClusterServiceClass`:由特定服务代理提供的托管服务。当新的 `ClusterServiceBroker` 资源被添加到集群时,服务目录控制器将连接到服务代理以获取可用的托管服务列表。然后为每个托管服务创建对应的新 `ClusterServiceClass` 资源。 +* `ClusterServicePlan`:托管服务的特定产品。例如托管服务可能有不同的计划可用,如免费版本和付费版本,或者可能有不同的配置选项,例如使用 SSD 存储或拥有更多资源。与 `ClusterServiceClass` 类似,当一个新的 `ClusterServiceBroker` 被添加到集群时,服务目录会为每个托管服务的每个可用服务计划创建对应的新 `ClusterServicePlan` 资源。 +* `ServiceInstance`:`ClusterServiceClass` 提供的示例。由集群运维人员创建,以使托管服务的特定实例可供一个或多个集群内应用程序使用。当创建一个新的 `ServiceInstance` 资源时,服务目录控制器将连接到相应的服务代理并指示它调配服务实例。 +* `ServiceBinding`:`ServiceInstance` 的访问凭据。由希望其应用程序使用服务 `ServiceInstance` 的集群运维人员创建。创建之后,服务目录控制器将创建一个 Kubernetes `Secret`,其中包含服务实例的连接细节和凭据,可以挂载到 Pod 中。 + + +### 认证 + +服务目录支持这些认证方法: + +* 基础认证(用户名/密码) +* [OAuth 2.0 不记名令牌](https://tools.ietf.org/html/rfc6750) + + +## 使用方式 + +集群运维人员可以使用服务目录 API 资源来提供托管服务并使其在 Kubernetes 集群内可用。涉及的步骤有: + +1. 列出服务代理提供的托管服务和服务计划。 +2. 配置托管服务的新实例。 +3. 绑定到托管服务,它将返回连接凭证。 +4. 将连接凭证映射到应用程序中。 + + +### 列出托管服务和服务计划 + +首先,集群运维人员在 `servicecatalog.k8s.io` 组内创建一个 `ClusterServiceBroker` 资源。此资源包含访问服务代理终结点所需的 URL 和连接详细信息。 + +这是一个 `ClusterServiceBroker` 资源的例子: + +```yaml +apiVersion: servicecatalog.k8s.io/v1beta1 +kind: ClusterServiceBroker +metadata: + name: cloud-broker +spec: + # Points to the endpoint of a service broker. (This example is not a working URL.) + url: https://servicebroker.somecloudprovider.com/v1alpha1/projects/service-catalog/brokers/default + ##### + # Additional values can be added here, which may be used to communicate + # with the service broker, such as bearer token info or a caBundle for TLS. + ##### +``` + +下面的顺序图展示了从一个服务代理列出可用托管服务和计划所有涉及的步骤: + +![List Services](/images/docs/service-catalog-list.svg) + +1. 一旦 `ClusterServiceBroker` 资源被添加到了服务目录之后,将会触发一个到外部服务代理的 List Services 调用。 +1. 服务代理返回可用的托管服务和服务计划列表,这些列表将本地缓存在 `ClusterServiceClass` 和 `ClusterServicePlan` 资源中。 +1. 然后集群运维人员可以使用以下命令获取可用托管服务的列表: + + kubectl get clusterserviceclasses -o=custom-columns=SERVICE\ NAME:.metadata.name,EXTERNAL\ NAME:.spec.externalName + + 它应该输出一个和以下格式类似的服务名称列表: + + SERVICE NAME EXTERNAL NAME + 4f6e6cf6-ffdd-425f-a2c7-3c9258ad2468 cloud-provider-service + ... ... + + 他们还可以使用以下命令查看可用的服务计划: + + kubectl get clusterserviceplans -o=custom-columns=PLAN\ NAME:.metadata.name,EXTERNAL\ NAME:.spec.externalName + + 它应该输出一个和以下格式类似的服务计划列表: + + PLAN NAME EXTERNAL NAME + 86064792-7ea2-467b-af93-ac9694d96d52 service-plan-name + ... ... + + +### 配置一个新实例 + +集群运维人员 可以通过创建一个 `ServiceInstance` 资源来启动一个新实例的配置。 + +这是一个 `ServiceInstance` 资源的例子: + +```yaml +apiVersion: servicecatalog.k8s.io/v1beta1 +kind: ServiceInstance +metadata: + name: cloud-queue-instance + namespace: cloud-apps +spec: + # References one of the previously returned services + clusterServiceClassExternalName: cloud-provider-service + clusterServicePlanExternalName: service-plan-name + ##### + # Additional parameters can be added here, + # which may be used by the service broker. + ##### +``` + +以下顺序图展示了配置托管服务新实例所涉及的步骤: + +![Provision a Service](/images/docs/service-catalog-provision.svg) + +1. 当创建 `ServiceInstance` 资源时,服务目录将启动一个到外部服务代理的配置实例调用。 +1. 服务代理创建一个托管服务的新实例并返回 HTTP 响应。 +1. 然后集群运维人员可以检查实例的状态是否就绪。 + + +### 绑定到托管服务 + +在设置新实例之后,集群运维人员必须绑定到托管服务才能获取应用程序使用服务所需的连接凭据和服务账户的详细信息。该操作通过创建一个 `ServiceBinding` 资源完成。 + +以下是 `ServiceBinding` 资源的示例: + +```yaml +apiVersion: servicecatalog.k8s.io/v1beta1 +kind: ServiceBinding +metadata: + name: cloud-queue-binding + namespace: cloud-apps +spec: + instanceRef: + name: cloud-queue-instance + ##### + # Additional information can be added here, such as a secretName or + # service account parameters, which may be used by the service broker. + ##### +``` + +以下顺序图展示了绑定到托管服务实例的步骤: + +![Bind to a managed service](/images/docs/service-catalog-bind.svg) + +1. 在创建 `ServiceBinding` 之后,服务目录调用外部服务代理,请求绑定服务实例所需的信息。 +1. 服务代理为相应服务账户启用应用权限/角色。 +1. 服务代理返回连接和访问托管服务示例所需的信息。这是由提供商和服务特定的,故返回的信息可能因服务提供商和其托管服务而有所不同。 + + +### 映射连接凭据 + +完成绑定之后的最后一步就是将连接凭据和服务特定的信息映射到应用程序中。这些信息存储在 secret 中,集群中的应用程序可以访问并使用它们直接与托管服务进行连接。 + +
+ +![Map connection credentials](/images/docs/service-catalog-map.svg) + + +#### Pod 配置文件 + +执行此映射的一种方法是使用声明式 Pod 配置。 + +以下示例描述了如何将服务账户凭据映射到应用程序中。名为 `sa-key` 的密钥保存在一个名为 `provider-cloud-key` 的卷中,应用程序会将该卷挂载在 `/var/secrets/provider/key.json` 路径下。环境变量 `PROVIDER_APPLICATION_CREDENTIALS` 将映射为挂载文件的路径。 + +```yaml +... + spec: + volumes: + - name: provider-cloud-key + secret: + secretName: sa-key + containers: +... + volumeMounts: + - name: provider-cloud-key + mountPath: /var/secrets/provider + env: + - name: PROVIDER_APPLICATION_CREDENTIALS + value: "/var/secrets/provider/key.json" +``` + +以下示例描述了如何将 secret 值映射为应用程序的环境变量。在这个示例中,消息队列的主题名从 secret `provider-queue-credentials` 中名为 `topic` 的 key 项映射到环境变量 `TOPIC` 中。 + + +```yaml +... + env: + - name: "TOPIC" + valueFrom: + secretKeyRef: + name: provider-queue-credentials + key: topic +``` + +{{% /capture %}} + + +{{% capture whatsnext %}} + +* 如果您熟悉{{< glossary_tooltip text="Helm Charts" term_id="helm-chart" >}},您可以[使用 Helm 将服务目录](/docs/tasks/service-catalog/install-service-catalog-using-helm/)安装到 Kubernetes 集群中。或者,您可以[使用 SC 工具安装服务目录](/docs/tasks/service-catalog/install-service-catalog-using-sc/)。 +* 查看[服务代理示例](https://github.com/openservicebrokerapi/servicebroker/blob/master/gettingStarted.md#sample-service-brokers)。 +* 浏览 [kubernetes-incubator/service-catalog](https://github.com/kubernetes-incubator/service-catalog) 项目。 +* 查看 [svc-cat.io](https://svc-cat.io/docs/)。 +{{% /capture %}} + + + diff --git a/content/zh/docs/concepts/overview/_index.md b/content/zh/docs/concepts/overview/_index.md index dd4f784acd..87550923ff 100644 --- a/content/zh/docs/concepts/overview/_index.md +++ b/content/zh/docs/concepts/overview/_index.md @@ -1,4 +1,11 @@ --- title: 概述 weight: 20 ---- \ No newline at end of file +--- + + diff --git a/content/zh/docs/concepts/overview/components.md b/content/zh/docs/concepts/overview/components.md index 124f5a2d78..495982a463 100644 --- a/content/zh/docs/concepts/overview/components.md +++ b/content/zh/docs/concepts/overview/components.md @@ -1,126 +1,221 @@ --- -approvers: -- lavalamp title: Kubernetes 组件 -redirect_from: -- "/docs/admin/cluster-components/" -- "/docs/admin/cluster-components.html" content_template: templates/concept weight: 20 +card: + name: concepts + weight: 20 --- + + {{% capture overview %}} -本文档概述了 Kubernetes 所需的各种二进制组件, 用于提供齐全的功能。 + +本文档概述了交付正常运行的 Kubernetes 集群所需的各种二进制组件。 {{% /capture %}} {{% capture body %}} - + ## Master 组件 -Master 组件提供的集群控制。Master 组件对集群做出全局性决策(例如:调度),以及检测和响应集群事件(副本控制器的`replicas`字段不满足时,启动新的副本)。 + +Master 组件提供集群的控制平面。Master 组件对集群进行全局决策(例如,调度),并检测和响应集群事件(例如,当不满足部署的 `replicas` 字段时,启动新的 {{< glossary_tooltip text="pod" term_id="pod">}})。 -Master 组件可以在集群中的任何节点上运行。然而,为了简单起见,设置脚本通常会启动同一个虚拟机上所有 Master 组件,并且不会在此虚拟机上运行用户容器。请参阅[构建高可用性群集](/docs/admin/high-availability)示例对于多主机 VM 的设置。 + +Master 组件可以在集群中的任何节点上运行。然而,为了简单起见,安装脚本通常会启动同一个计算机上所有 Master 组件,并且不会在计算机上运行用户容器。请参阅[构建高可用性集群](/docs/admin/high-availability/)示例对于多主机 VM 的安装。 -### API服务器 +### kube-apiserver -[kube-apiserver](/docs/admin/kube-apiserver)对外暴露了Kubernetes API。它是的 Kubernetes 前端控制层。它被设计为水平扩展,即通过部署更多实例来缩放。请参阅[构建高可用性群集](/docs/admin/high-availability). +{{< glossary_definition term_id="kube-apiserver" length="all" >}} ### etcd -[etcd](/docs/admin/etcd) 用于 Kubernetes 的后端存储。所有集群数据都存储在此处,始终为您的 Kubernetes 集群的 etcd 数据提供备份计划。 +{{< glossary_definition term_id="etcd" length="all" >}} + +### kube-scheduler + +{{< glossary_definition term_id="kube-scheduler" length="all" >}} ### kube-controller-manager -[kube-controller-manager](/docs/admin/kube-controller-manager)运行控制器,它们是处理集群中常规任务的后台线程。逻辑上,每个控制器是一个单独的进程,但为了降低复杂性,它们都被编译成独立的可执行文件,并在单个进程中运行。 +{{< glossary_definition term_id="kube-controller-manager" length="all" >}} + 这些控制器包括: -* 节点控制器: 当节点移除时,负责注意和响应。 -* 副本控制器: 负责维护系统中每个副本控制器对象正确数量的 Pod。 -* 端点控制器: 填充 端点(Endpoints) 对象(即连接 Services & Pods)。 -* 服务帐户和令牌控制器: 为新的命名空间创建默认帐户和 API 访问令牌. +* 节点控制器(Node Controller): 负责在节点出现故障时进行通知和响应。 +* 副本控制器(Replication Controller): 负责为系统中的每个副本控制器对象维护正确数量的 Pod。 +* 端点控制器(Endpoints Controller): 填充端点(Endpoints)对象(即加入 Service 与 Pod)。 +* 服务帐户和令牌控制器(Service Account & Token Controllers): 为新的命名空间创建默认帐户和 API 访问令牌. + ### 云控制器管理器-(cloud-controller-manager) -cloud-controller-manager 是用于与底层云提供商交互的控制器。云控制器管理器可执行组件是 Kubernetes v1.6 版本中引入的 Alpha 功能。 + +[cloud-controller-manager](/docs/tasks/administer-cluster/running-cloud-controller/) 运行与基础云提供商交互的控制器。cloud-controller-manager 二进制文件是 Kubernetes 1.6 版本中引入的 alpha 功能。 -cloud-controller-manager 仅运行云提供商特定的控制器循环。您必须在 kube-controller-manager 中禁用这些控制器循环,您可以通过在启动 kube-controller-manager 时将 `--cloud-provider` 标志设置为`external`来禁用控制器循环。 + +cloud-controller-manager 仅运行云提供商特定的控制器循环。您必须在 kube-controller-manager 中禁用这些控制器循环,您可以通过在启动 kube-controller-manager 时将 `--cloud-provider` 参数设置为 `external` 来禁用控制器循环。 -cloud-controller-manager 允许云供应商代码和 Kubernetes 核心彼此独立发展,在以前的版本中,Kubernetes 核心代码依赖于云提供商特定的功能代码。在未来的版本中,云供应商的特定代码应由云供应商自己维护,并与运行 Kubernetes 的云控制器管理器相关联。 + +cloud-controller-manager 允许云供应商的代码和 Kubernetes 代码彼此独立地发展。在以前的版本中,核心的 Kubernetes 代码依赖于特定云提供商的代码来实现功能。在将来的版本中,云供应商专有的代码应由云供应商自己维护,并与运行 Kubernetes 的云控制器管理器相关联。 -以下控制器具有云提供商依赖关系: + +以下控制器具有云提供商依赖性: -### 调度器 - (kube-scheduler) + * 节点控制器(Node Controller): 用于检查云提供商以确定节点是否在云中停止响应后被删除 + * 路由控制器(Route Controller): 用于在底层云基础架构中设置路由 + * 服务控制器(Service Controller): 用于创建、更新和删除云提供商负载均衡器 + * 数据卷控制器(Volume Controller): 用于创建、附加和装载卷、并与云提供商进行交互以编排卷 -[kube-scheduler](/docs/admin/kube-scheduler)监视没有分配节点的新创建的 Pod,选择一个节点供他们运行。 + +## Node 组件 -### 插件(addons) + +节点组件在每个节点上运行,维护运行的 Pod 并提供 Kubernetes 运行环境。 -插件是实现集群功能的 Pod 和 Service。 Pods 可以通过 Deployments,ReplicationControllers 管理。插件对象本身是受命名空间限制的,被创建于 `kube-system` 命名空间。 +### kubelet -Addon 管理器用于创建和维护附加资源. 有关详细信息,请参阅[here](http://releases.k8s.io/HEAD/cluster/addons). +{{< glossary_definition term_id="kubelet" length="all" >}} -#### DNS +### kube-proxy -虽然其他插件并不是必需的,但所有 Kubernetes 集群都应该具有[Cluster DNS](/docs/concepts/services-networking/dns-pod-service/),许多示例依赖于它。 +{{< glossary_definition term_id="kube-proxy" length="all" >}} + + +### 容器运行环境(Container Runtime) + +{{< glossary_definition term_id="container-runtime" length="all" >}} + + +## 插件(Addons) + + +插件使用 Kubernetes 资源 ({{< glossary_tooltip term_id="daemonset" >}}, +{{< glossary_tooltip term_id="deployment" >}}等) 实现集群功能。因为这些提供集群级别的功能,所以插件的命名空间资源属于 `kube-system` 命名空间。 + + +所选的插件如下所述:有关可用插件的扩展列表,请参见[插件 (Addons)](/docs/concepts/cluster-administration/addons/)。 + +### DNS + + +尽管并非严格要求其他附加组件,但所有示例都依赖[集群 DNS](/docs/concepts/services-networking/dns-pod-service/),因此所有 Kubernetes 集群都应具有 DNS。 + +除了您环境中的其他 DNS 服务器之外,集群 DNS 还是一个 DNS 服务器,它为 Kubernetes 服务提供 DNS 记录。 Cluster DNS 是一个 DNS 服务器,和您部署环境中的其他 DNS 服务器一起工作,为 Kubernetes 服务提供DNS记录。 Kubernetes 启动的容器自动将 DNS 服务器包含在 DNS 搜索中。 -#### 用户界面 + +### 用户界面(Dashboard) -dashboard 提供了集群状态的只读概述。有关更多信息,请参阅[使用HTTP代理访问 Kubernetes API](/docs/tasks/access-kubernetes-api/http-proxy-access-api/) + +[Dashboard](/docs/tasks/access-application-cluster/web-ui-dashboard/) 是 Kubernetes 集群的通用基于 Web 的 UI。它使用户可以管理集群中运行的应用程序以及集群本身并进行故障排除。 + +### 容器资源监控 -#### 容器资源监控 + +[容器资源监控](/docs/tasks/debug-application-cluster/resource-usage-monitoring/)将关于容器的一些常见的时间序列度量值保存到一个集中的数据库中,并提供用于浏览这些数据的界面。 -[容器资源监控](/docs/user-guide/monitoring)将关于容器的一些常见的时间序列度量值保存到一个集中的数据库中,并提供用于浏览这些数据的界面。 + +### 集群层面日志 -#### 集群层面日志 - -[集群层面日志](/docs/user-guide/logging/overview) 机制负责将容器的日志数据保存到一个集中的日志存储中,该存储能够提供搜索和浏览接口。 - -## 节点组件 - -节点组件在每个节点上运行,维护运行的 Pod 并提供 Kubernetes 运行时环境。 - -### kubelet - -[kubelet](/docs/admin/kubelet)是主要的节点代理,它监测已分配给其节点的 Pod(通过 apiserver 或通过本地配置文件),提供如下功能: - -* 挂载 Pod 所需要的数据卷(Volume)。 -* 下载 Pod 的 secrets。 -* 通过 Docker 运行(或通过 rkt)运行 Pod 的容器。 -* 周期性的对容器生命周期进行探测。 -* 如果需要,通过创建 *镜像 Pod(Mirror Pod)* 将 Pod 的状态报告回系统的其余部分。 -* 将节点的状态报告回系统的其余部分。 - -### kube-proxy - -[kube-proxy](/docs/admin/kube-proxy)通过维护主机上的网络规则并执行连接转发,实现了Kubernetes服务抽象。 - - -### docker - -Docker 用于运行容器。 - -### rkt - -支持 rkt 运行容器作为 Docker 的试验性替代方案。 - -### supervisord - -supervisord 是一个轻量级的进程监控系统,可以用来保证 kubelet 和 docker 运行。 - -### fluentd - -fluentd 是一个守护进程,它有助于提供[集群层面日志](#cluster-level-logging) 集群层面的日志。 + +[集群层面日志](/docs/concepts/cluster-administration/logging/) 机制负责将容器的日志数据保存到一个集中的日志存储中,该存储能够提供搜索和浏览接口。 {{% /capture %}} - - +{{% capture whatsnext %}} + +* 进一步了解 [Nodes](/docs/concepts/architecture/nodes/) +* 进一步了解 [kube-scheduler](/docs/concepts/scheduling/kube-scheduler/) +* 阅读 etcd 官方[文档](https://etcd.io/docs/) +{{% /capture %}} diff --git a/content/zh/docs/concepts/overview/what-is-kubernetes.md b/content/zh/docs/concepts/overview/what-is-kubernetes.md index 53cef26eca..24fef5243b 100644 --- a/content/zh/docs/concepts/overview/what-is-kubernetes.md +++ b/content/zh/docs/concepts/overview/what-is-kubernetes.md @@ -1,119 +1,217 @@ --- -approvers: -- k8s-merge-robot - -title: 认识 Kubernetes? +title: Kubernetes 是什么? +content_template: templates/concept weight: 10 +card: + name: concepts + weight: 10 --- + -Kubernetes 是一个跨主机集群的 [开源的容器调度平台,它可以自动化应用容器的部署、扩展和操作](http://www.slideshare.net/BrianGrant11/wso2con-us-2015-kubernetes-a-platform-for-automating-deployment-scaling-and-operations) , 提供以容器为中心的基础架构。 +{{% capture overview %}} + +此页面是 Kubernetes 的概述。 +{{% /capture %}} -使用 Kubernetes, 您可以快速高效地响应客户需求: +{{% capture body %}} + +Kubernetes 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。Kubernetes 拥有一个庞大且快速增长的生态系统。Kubernetes 的服务、支持和工具广泛可用。 - - 快速、可预测地部署您的应用程序 - - 拥有即时扩展应用程序的能力 - - 不影响现有业务的情况下,无缝地发布新功能 - - 优化硬件资源,降低成本 + +名称 **Kubernetes** 源于希腊语,意为 "舵手" 或 "飞行员"。Google 在 2014 年开源了 Kubernetes 项目。Kubernetes 建立在 [Google 在大规模运行生产工作负载方面拥有十几年的经验](https://ai.google/research/pubs/pub43438)的基础上,结合了社区中最好的想法和实践。 -我们的目标是构建一个软件和工具的生态系统,以减轻您在公共云或私有云运行应用程序的负担。 + +## 言归正传 +让我们回顾一下为什么 Kubernetes 如此有用。 -#### Kubernetes 具有如下特点: + +![部署演进](/images/docs/Container_Evolution.svg) -* **便携性**: 无论公有云、私有云、混合云还是多云架构都全面支持 -* **可扩展**: 它是模块化、可插拔、可挂载、可组合的,支持各种形式的扩展 -* **自修复**: 它可以自保持应用状态、可自重启、自复制、自缩放的,通过声明式语法提供了强大的自修复能力 + +**传统部署时代:** +早期,组织在物理服务器上运行应用程序。无法为物理服务器中的应用程序定义资源边界,这会导致资源分配问题。例如,如果在物理服务器上运行多个应用程序,则可能会出现一个应用程序占用大部分资源的情况,结果可能导致其他应用程序的性能下降。一种解决方案是在不同的物理服务器上运行每个应用程序,但是由于资源利用不足而无法扩展,并且组织维护许多物理服务器的成本很高。 -Kubernetes 项目由 Google 公司在 2014 年启动。Kubernetes 建立在 [Google 公司超过十余年的运维经验基础之上,Google 所有的应用都运行在容器上](https://research.google.com/pubs/pub43438.html), 再与社区中最好的想法和实践相结合,也许它是最受欢迎的容器平台。 + +**虚拟化部署时代:** +作为解决方案,引入了虚拟化功能,它允许您在单个物理服务器的 CPU 上运行多个虚拟机(VM)。虚拟化功能允许应用程序在 VM 之间隔离,并提供安全级别,因为一个应用程序的信息不能被另一应用程序自由地访问。 -##### 准备好 [开始](/docs/getting-started-guides/)? + +因为虚拟化可以轻松地添加或更新应用程序、降低硬件成本等等,所以虚拟化可以更好地利用物理服务器中的资源,并可以实现更好的可伸缩性。 -查看此文,可以了解为什么您要使用容器 [容器](http://aucouranton.com/2014/06/13/linux-containers-parallels-lxc-openvz-docker-and-more/)? +每个 VM 是一台完整的计算机,在虚拟化硬件之上运行所有组件,包括其自己的操作系统。 -![为什么是容器?](/images/docs/why_containers.svg) + +**容器部署时代:** +容器类似于 VM,但是它们具有轻量级的隔离属性,可以在应用程序之间共享操作系统(OS)。因此,容器被认为是轻量级的。容器与 VM 类似,具有自己的文件系统、CPU、内存、进程空间等。由于它们与基础架构分离,因此可以跨云和 OS 分发进行移植。 -*传统* 部署应用程序的方式,一般是使用操作系统自带的包管理器在主机上安装应用依赖,之后再安装应用程序。这无疑将应用程序的可执行文件、应用的配置、应用依赖库和应用的生命周期与宿主机操作系统进行了紧耦合。在此情境下,可以通过构建不可改变的虚拟机镜像版本,通过镜像版本实现可预测的发布和回滚,但是虚拟机实在是太重量级了,且镜像体积太庞大,便捷性差。 + +容器因具有许多优势而变得流行起来。下面列出了容器的一些好处: -*新方式* 是基于操作系统级虚拟化而不是硬件级虚拟化方法来部署容器。容器之间彼此隔离并与主机隔离:它们具有自己的文件系统,不能看到彼此的进程,并且它们所使用的计算资源是可以被限制的。它们比虚拟机更容易构建,并且因为它们与底层基础架构和主机文件系统隔离,所以它们可以跨云和操作系统快速分发。 + +* 敏捷应用程序的创建和部署:与使用 VM 镜像相比,提高了容器镜像创建的简便性和效率。 +* 持续开发、集成和部署:通过快速简单的回滚(由于镜像不可变性),提供可靠且频繁的容器镜像构建和部署。 +* 关注开发与运维的分离:在构建/发布时而不是在部署时创建应用程序容器镜像,从而将应用程序与基础架构分离。 +* 可观察性不仅可以显示操作系统级别的信息和指标,还可以显示应用程序的运行状况和其他指标信号。 +* 跨开发、测试和生产的环境一致性:在便携式计算机上与在云中相同地运行。 +* 云和操作系统分发的可移植性:可在 Ubuntu、RHEL、CoreOS、本地、Google Kubernetes Engine 和其他任何地方运行。 +* 以应用程序为中心的管理:提高抽象级别,从在虚拟硬件上运行 OS 到使用逻辑资源在 OS 上运行应用程序。 +* 松散耦合、分布式、弹性、解放的微服务:应用程序被分解成较小的独立部分,并且可以动态部署和管理 - 而不是在一台大型单机上整体运行。 +* 资源隔离:可预测的应用程序性能。 +* 资源利用:高效率和高密度。 -由于容器体积小且启动快,因此可以在每个容器镜像中打包一个应用程序。这种一对一的应用镜像关系拥有很多好处。使用容器,不需要与外部的基础架构环境绑定, 因为每一个应用程序都不需要外部依赖,更不需要与外部的基础架构环境依赖。完美解决了从开发到生产环境的一致性问题。 + +#### 为什么需要 Kubernetes,它能做什么? -容器同样比虚拟机更加透明,这有助于监测和管理。尤其是容器进程的生命周期由基础设施管理,而不是由容器内的进程对外隐藏时更是如此。最后,每个应用程序用容器封装,管理容器部署就等同于管理应用程序部署。 + +容器是打包和运行应用程序的好方式。在生产环境中,您需要管理运行应用程序的容器,并确保不会停机。例如,如果一个容器发生故障,则需要启动另一个容器。如果系统处理此行为,会不会更容易? -容器优点摘要: + +这就是 Kubernetes 的救援方法!Kubernetes 为您提供了一个可弹性运行分布式系统的框架。Kubernetes 会满足您的扩展要求、故障转移、部署模式等。例如,Kubernetes 可以轻松管理系统的 Canary 部署。 -* **敏捷的应用程序创建和部署**: - 与虚拟机镜像相比,容器镜像更容易创建,提升了硬件的使用效率。 -* **持续开发、集成和部署**: - 提供可靠与频繁的容器镜像构建和部署,可以很方便及快速的回滚 (由于镜像不可变性). -* **关注开发与运维的分离**: - 在构建/发布时创建应用程序容器镜像,从而将应用程序与基础架构分离。 -* **开发、测试和生产环境的一致性**: - 在笔记本电脑上运行与云中一样。 -* **云和操作系统的可移植性**: - 可运行在 Ubuntu, RHEL, CoreOS, 内部部署, Google 容器引擎和其他任何地方。 -* **以应用为中心的管理**: - 提升了操作系统的抽象级别,以便在使用逻辑资源的操作系统上运行应用程序。 -* **松耦合、分布式、弹性伸缩 [微服务](http://martinfowler.com/articles/microservices.html)**: - 应用程序被分成更小,更独立的部分,可以动态部署和管理 - 而不是巨型单体应用运行在专用的大型机上。 -* **资源隔离**: - 通过对应用进行资源隔离,可以很容易的预测应用程序性能。 -* **资源利用**: - 高效率和高密度。 + +Kubernetes 为您提供: -#### 为什么我们需要 Kubernetes,它能做什么? + +* **服务发现和负载均衡** +Kubernetes 可以使用 DNS 名称或自己的 IP 地址公开容器,如果到容器的流量很大,Kubernetes 可以负载均衡并分配网络流量,从而使部署稳定。 -最基础的,Kubernetes 可以在物理或虚拟机集群上调度和运行应用程序容器。然而,Kubernetes 还允许开发人员从物理和虚拟机'脱离',从以**主机为中心**的基础架构转移到以**容器为中心**的基础架构,这样可以提供容器固有的全部优点和益处。Kubernetes 提供了基础设施来构建一个真正以**容器为中心**的开发环境。 + +* **存储编排** +Kubernetes 允许您自动挂载您选择的存储系统,例如本地存储、公共云提供商等。 -Kubernetes 满足了生产中运行应用程序的许多常见的需求,例如: + +* **自动部署和回滚** +您可以使用 Kubernetes 描述已部署容器的所需状态,它可以以受控的速率将实际状态更改为所需状态。例如,您可以自动化 Kubernetes 来为您的部署创建新容器,删除现有容器并将它们的所有资源用于新容器。 -* [Pod](/docs/user-guide/pods/) 提供复合应用并保留一个应用一个容器的容器模型, -* [挂载外部存储](/docs/user-guide/volumes/), -* [Secret管理](/docs/user-guide/secrets/), -* [应用健康检查](/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/), -* [副本应用实例](/docs/user-guide/replication-controller/), -* [横向自动扩缩容](/docs/user-guide/horizontal-pod-autoscaling/), -* [服务发现](/docs/user-guide/connecting-applications/), -* [负载均衡](/docs/user-guide/services/), -* [滚动更新](/docs/user-guide/update-demo/), -* [资源监测](/docs/user-guide/monitoring/), -* [日志采集和存储](/docs/user-guide/logging/overview/), -* [支持自检和调试](/docs/user-guide/introspection-and-debugging/), -* [认证和鉴权](/docs/admin/authorization/). + +* **自动二进制打包** +Kubernetes 允许您指定每个容器所需 CPU 和内存(RAM)。当容器指定了资源请求时,Kubernetes 可以做出更好的决策来管理容器的资源。 -这提供了平台即服务 (PAAS) 的简单性以及基础架构即服务 (IAAS) 的灵活性,并促进跨基础设施供应商的可移植性。 + +* **自我修复** +Kubernetes 重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器,并且在准备好服务之前不将其通告给客户端。 -有关详细信息,请参阅 [用户指南](/docs/user-guide/). + +* **密钥与配置管理** +Kubernetes 允许您存储和管理敏感信息,例如密码、OAuth 令牌和 ssh 密钥。您可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥。 -#### 为什么 Kubernetes 是一个平台? + +## Kubernetes 不是什么 -Kubernetes 提供了很多的功能,总会有新的场景受益于新特性。它可以简化应用程序的工作流,加快开发速度。被大家认可的应用编排通常需要有较强的自动化能力。这就是为什么 Kubernetes 被设计作为构建组件和工具的生态系统平台,以便更轻松地部署、扩展和管理应用程序。 + +Kubernetes 不是传统的、包罗万象的 PaaS(平台即服务)系统。由于 Kubernetes 在容器级别而不是在硬件级别运行,因此它提供了 PaaS 产品共有的一些普遍适用的功能,例如部署、扩展、负载均衡、日志记录和监视。但是,Kubernetes 不是单一的,默认解决方案是可选和可插拔的。Kubernetes 提供了构建开发人员平台的基础,但是在重要的地方保留了用户的选择和灵活性。 -[Label](/docs/user-guide/labels/) 允许用户按照自己的方式组织管理对应的资源。 [注解](/docs/user-guide/annotations/) 使用户能够以自定义的描述信息来修饰资源,以适用于自己的工作流,并为管理工具提供检查点状态的简单方法。 + +Kubernetes: -此外,[Kubernetes 控制面 (Control Plane)](/docs/admin/cluster-components) 是构建在相同的 [APIs](/docs/api/) 上面,开发人员和用户都可以用。用户可以编写自己的控制器, [调度器](https://github.com/kubernetes/kubernetes/tree/{{< param "githubbranch" >}}/docs/devel/scheduler.md)等等,如果这么做,根据新加的[自定义 API](https://github.com/kubernetes/kubernetes/blob/{{< param "githubbranch" >}}/docs/design/extending-api.md) ,可以扩展当前的通用 [CLI 命令行工具](/docs/user-guide/kubectl-overview/)。 + +* Kubernetes 不限制支持的应用程序类型。Kubernetes 旨在支持极其多种多样的工作负载,包括无状态、有状态和数据处理工作负载。如果应用程序可以在容器中运行,那么它应该可以在 Kubernetes 上很好地运行。 +* Kubernetes 不部署源代码,也不构建您的应用程序。持续集成(CI)、交付和部署(CI/CD)工作流取决于组织的文化和偏好以及技术要求。 +* Kubernetes 不提供应用程序级别的服务作为内置服务,例如中间件(例如,消息中间件)、数据处理框架(例如,Spark)、数据库(例如,mysql)、缓存、集群存储系统(例如,Ceph)。这样的组件可以在 Kubernetes 上运行,并且/或者可以由运行在 Kubernetes 上的应用程序通过可移植机制(例如,开放服务代理)来访问。 -这种 [设计](https://git.k8s.io/community/contributors/design-proposals/architecture/principles.md) 使得许多其他系统可以构建在 Kubernetes 之上。 + +* Kubernetes 不指定日志记录、监视或警报解决方案。它提供了一些集成作为概念证明,并提供了收集和导出指标的机制。 +* Kubernetes 不提供或不要求配置语言/系统(例如 jsonnet),它提供了声明性 API,该声明性 API 可以由任意形式的声明性规范所构成。 +* Kubernetes 不提供也不采用任何全面的机器配置、维护、管理或自我修复系统。 +* 此外,Kubernetes 不仅仅是一个编排系统,实际上它消除了编排的需要。编排的技术定义是执行已定义的工作流程:首先执行 A,然后执行 B,再执行 C。相比之下,Kubernetes 包含一组独立的、可组合的控制过程,这些过程连续地将当前状态驱动到所提供的所需状态。从 A 到 C 的方式无关紧要,也不需要集中控制,这使得系统更易于使用且功能更强大、健壮、弹性和可扩展性。 -#### Kubernetes 不是什么: +{{% /capture %}} -Kubernetes 不是一个传统意义上,包罗万象的 PaaS (平台即服务) 系统。我们保留用户选择的自由,这非常重要。 - -* Kubernetes 不限制支持的应用程序类型。 它不插手应用程序框架 (例如 [Wildfly](http://wildfly.org/)), 不限制支持的语言运行时 (例如 Java, Python, Ruby),只迎合符合 [12种因素的应用程序](http://12factor.net/),也不区分"应用程序"与"服务"。Kubernetes 旨在支持极其多样化的工作负载,包括无状态、有状态和数据处理工作负载。如果应用可以在容器中运行,它就可以在 Kubernetes 上运行。 -* Kubernetes 不提供作为内置服务的中间件 (例如 消息中间件)、数据处理框架 (例如 Spark)、数据库 (例如 mysql)或集群存储系统 (例如 Ceph)。这些应用可以运行在 Kubernetes 上。 -* Kubernetes 没有提供点击即部署的服务市场 -* Kubernetes 从源代码到镜像都是非垄断的。 它不部署源代码且不构建您的应用程序。 持续集成 (CI) 工作流是一个不同用户和项目都有自己需求和偏好的领域。 所以我们支持在 Kubernetes 分层的 CI 工作流,但不指定它应该如何工作。 -* Kubernetes 允许用户选择其他的日志记录,监控和告警系统 (虽然我们提供一些集成作为概念验证) -* Kubernetes 不提供或授权一个全面的应用程序配置语言/系统 (例如 [jsonnet](https://github.com/google/jsonnet)). -* Kubernetes 不提供也不采用任何全面机器配置、保养、管理或自我修复系统 - -另一方面,许多 PaaS 系统*运行* 在 Kubernetes 上面,例如 [Openshift](https://github.com/openshift/origin), [Deis](http://deis.io/), and [Eldarion](http://eldarion.cloud/)。 您也可以自定义您自己的 PaaS, 与您选择的 CI 系统集成,或与 Kubernetes 一起使用: 将您的容器镜像部署到 Kubernetes。 - -由于 Kubernetes 在应用级别而不仅仅在硬件级别上运行,因此它提供 PaaS 产品通用的一些功能,例如部署、扩展、负载均衡、日志记录、监控等。但是,Kubernetes 不是单一的,默认解决方案是可选和可插拔的。 - -此处,Kubernetes 不仅仅是一个 "编排系统";它消除了编排的需要。 "编排"技术定义的是工作流的执行: 从 A 到 B,然后到 C。相反,Kubernetes 是包括一套独立、可组合的控制过程,通过声明式语法使其连续地朝着期望状态驱动当前状态。 不需要告诉它具体从 A 到 C 的过程,只要告诉到 C 的状态即可。 也不需要集中控制;该方法更类似于"编舞"。这使得系统更容易使用并且更强大、更可靠、更具弹性和可扩展性。 - -#### *Kubernetes* 是什么意思? K8s? - -名称 **Kubernetes** 源于希腊语,意为 "舵手" 或 "飞行员", 且是英文 "governor" 和 ["cybernetic"](http://www.etymonline.com/index.php?term=cybernetics)的词根。 **K8s** 是通过将 8 个字母 "ubernete" 替换为 8 而导出的缩写。另外,在中文里,k8s 的发音与 Kubernetes 的发音比较接近。 +{{% capture whatsnext %}} + +* 查阅 [Kubernetes 组件](/docs/concepts/overview/components/) +* 开始 [Kubernetes 入门](/docs/setup/)? +{{% /capture %}} diff --git a/content/zh/docs/concepts/overview/working-with-objects/_index.md b/content/zh/docs/concepts/overview/working-with-objects/_index.md index 5dcf6e4ed5..477bdc5b18 100644 --- a/content/zh/docs/concepts/overview/working-with-objects/_index.md +++ b/content/zh/docs/concepts/overview/working-with-objects/_index.md @@ -1,4 +1,11 @@ --- title: "使用 Kubernetes 对象" weight: 40 ---- \ No newline at end of file +--- + + diff --git a/content/zh/docs/concepts/overview/working-with-objects/common-labels.md b/content/zh/docs/concepts/overview/working-with-objects/common-labels.md index 2a33f64fcb..9e7334bab8 100644 --- a/content/zh/docs/concepts/overview/working-with-objects/common-labels.md +++ b/content/zh/docs/concepts/overview/working-with-objects/common-labels.md @@ -15,8 +15,7 @@ You can visualize and manage Kubernetes objects with more tools than kubectl and the dashboard. A common set of labels allows tools to work interoperably, describing objects in a common manner that all tools can understand. --> -除了 kubectl 和 dashboard 之外,您可以其他工具来可视化和管理 Kubernetes 对象。 -一组通用的标签可以让多个工具之间互操作,用所有工具都能理解的通用方式描述对象。 +除了 kubectl 和 dashboard 之外,您可以使用其他工具来可视化和管理 Kubernetes 对象。一组通用的标签可以让多个工具之间相互操作,用所有工具都能理解的通用方式描述对象。 | 键 | 描述 | 示例 | 类型 | | ----------------------------------- | --------------------- | -------- | ---- | @@ -182,7 +180,6 @@ The start to the following `Deployment` is used for WordPress: 以下 `Deployment` 的开头用于 WordPress: - ```yaml apiVersion: apps/v1 kind: Deployment @@ -219,7 +216,6 @@ metadata: - MySQL 作为一个 `StatefulSet` 暴露,包含它和它所属的较大应用程序的元数据: ```yaml apiVersion: apps/v1 @@ -228,17 +224,16 @@ metadata: labels: app.kubernetes.io/name: mysql app.kubernetes.io/instance: mysql-abcxzy + app.kubernetes.io/version: "5.7.21" app.kubernetes.io/managed-by: helm app.kubernetes.io/component: database app.kubernetes.io/part-of: wordpress - app.kubernetes.io/version: "5.7.21" ... ``` - `Service` 用于将 MySQL 作为 WordPress 的一部分暴露: ```yaml apiVersion: v1 @@ -247,10 +242,10 @@ metadata: labels: app.kubernetes.io/name: mysql app.kubernetes.io/instance: mysql-abcxzy + app.kubernetes.io/version: "5.7.21" app.kubernetes.io/managed-by: helm app.kubernetes.io/component: database app.kubernetes.io/part-of: wordpress - app.kubernetes.io/version: "5.7.21" ... ``` diff --git a/content/zh/docs/concepts/overview/working-with-objects/field-selectors.md b/content/zh/docs/concepts/overview/working-with-objects/field-selectors.md index 07c7a76301..a7bb9b1794 100644 --- a/content/zh/docs/concepts/overview/working-with-objects/field-selectors.md +++ b/content/zh/docs/concepts/overview/working-with-objects/field-selectors.md @@ -2,7 +2,6 @@ title: 字段选择器 weight: 60 --- - -字段选择器允许您根据一个或多个资源字段的值[筛选 Kubernetes 资源](/docs/concepts/overview/working-with-objects/kubernetes-objects)。 -下面是一些使用字段选择器查询的例子: +_字段选择器_(_Field selectors_)允许您根据一个或多个资源字段的值[筛选 Kubernetes 资源](/docs/concepts/overview/working-with-objects/kubernetes-objects)。 +下面是一些使用字段选择器查询的例子: * `metadata.name=my-service` * `metadata.namespace!=default` * `status.phase=Pending` -下面这个 `kubectl` 命令将筛选出[`status.phase`](/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase)字段值为 `Running` 的所有 Pod: +下面这个 `kubectl` 命令将筛选出 [`status.phase`](/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase) 字段值为 `Running` 的所有 Pod: + ```shell kubectl get pods --field-selector status.phase=Running ``` {{< note >}} - -字段选择器本质上是资源*过滤器*。默认情况下,字段选择器/过滤器是未被应用的,这意味着指定类型的所有资源都会被筛选出来。 -这使得以下的两个 `kubectl` 查询是等价的: +字段选择器本质上是资源*过滤器*。默认情况下,字段选择器/过滤器是未被应用的,这意味着指定类型的所有资源都会被筛选出来。 +这使得以下的两个 `kubectl` 查询是等价的: ```shell kubectl get pods @@ -43,17 +42,15 @@ kubectl get pods --field-selector "" ``` {{< /note >}} -## 支持的字段 +## 支持的字段 -不同的 Kubernetes 资源类型支持不同的字段选择器。 -所有资源类型都支持 `metadata.name` 和 `metadata.namespace` 字段。 -使用不被支持的字段选择器会产生错误,例如: +不同的 Kubernetes 资源类型支持不同的字段选择器。所有资源类型都支持 `metadata.name` 和 `metadata.namespace` 字段。使用不被支持的字段选择器会产生错误,例如: ```shell kubectl get ingress --field-selector foo.bar=baz @@ -62,46 +59,43 @@ kubectl get ingress --field-selector foo.bar=baz Error from server (BadRequest): Unable to find "ingresses" that match label selector "", field selector "foo.bar=baz": "foo.bar" is not a known field selector: only "metadata.name", "metadata.namespace" ``` -## 支持的运算符 +## 支持的运算符 -您可以使用 `=`、`==`和 `!=` 对字段选择器进行运算(`=` 和 `==` 的意义是相同的)。 -例如,下面这个 `kubectl` 命令将筛选所有不属于 `default` 名称空间的 Kubernetes Service: +您可以使用 `=`、`==`和 `!=` 对字段选择器进行运算(`=` 和 `==` 的意义是相同的)。例如,下面这个 `kubectl` 命令将筛选所有不属于 `default` 命名空间的 Kubernetes Service: ```shell kubectl get services --all-namespaces --field-selector metadata.namespace!=default ``` -## 链式选择器 +## 链式选择器 -同[标签](/docs/concepts/overview/working-with-objects/labels)和其他选择器一样,字段选择器可以通过使用逗号分隔的列表组成一个选择链。 -下面这个 `kubectl` 命令将筛选 `status.phase` 字段不等于 `Running` 同时 `spec.restartPolicy` 字段等于 `Always` 的所有 Pod: +同[标签](/docs/concepts/overview/working-with-objects/labels)和其他选择器一样,字段选择器可以通过使用逗号分隔的列表组成一个选择链。下面这个 `kubectl` 命令将筛选 `status.phase` 字段不等于 `Running` 同时 `spec.restartPolicy` 字段等于 `Always` 的所有 Pod: ```shell kubectl get pods --field-selector=status.phase!=Running,spec.restartPolicy=Always ``` -## 多种资源类型 +## 多种资源类型 -您能够跨多种资源类型来使用字段选择器。 -下面这个 `kubectl` 命令将筛选出所有不在 `default` 命名空间中的 StatefulSet 和 Service: +您能够跨多种资源类型来使用字段选择器。下面这个 `kubectl` 命令将筛选出所有不在 `default` 命名空间中的 StatefulSet 和 Service: ```shell kubectl get statefulsets,services --all-namespaces --field-selector metadata.namespace!=default diff --git a/content/zh/docs/concepts/overview/working-with-objects/labels.md b/content/zh/docs/concepts/overview/working-with-objects/labels.md new file mode 100644 index 0000000000..3bc5554c5e --- /dev/null +++ b/content/zh/docs/concepts/overview/working-with-objects/labels.md @@ -0,0 +1,378 @@ +--- +title: 标签和选择器 +content_template: templates/concept +weight: 40 +--- + +{{% capture overview %}} + + +_标签_ 是附加到 Kubernetes 对象(比如 Pods)上的键值对。 +标签旨在用于指定对用户有意义且相关的对象的标识属性,但不直接对核心系统有语义含义。 +标签可以用于组织和选择对象的子集。标签可以在创建时附加到对象,随后可以随时添加和修改。 +每个对象都可以定义一组键/值标签。每个键对于给定对象必须是唯一的。 + +```json +"metadata": { + "labels": { + "key1" : "value1", + "key2" : "value2" + } +} +``` + + + +我们最终将标签索引和反向索引,用于高效查询和监视,使用它们在 UI 和 CLI 中进行排序和分组等。我们不希望将非标识性的、尤其是大型或结构化数据用作标签,给后者带来污染。应使用 [注解](/docs/concepts/overview/working-with-objects/annotations/) 记录非识别信息 + +{{% /capture %}} + + +{{% capture body %}} + + + +## 动机 + + +标签使用户能够以松散耦合的方式将他们自己的组织结构映射到系统对象,而无需客户端存储这些映射。 + + +服务部署和批处理流水线通常是多维实体(例如,多个分区或部署、多个发行序列、多个层,每层多个微服务)。管理通常需要交叉操作,这打破了严格的层次表示的封装,特别是由基础设施而不是用户确定的严格的层次结构。 + + +示例标签: + + * `"release" : "stable"`, `"release" : "canary"` + * `"environment" : "dev"`, `"environment" : "qa"`, `"environment" : "production"` + * `"tier" : "frontend"`, `"tier" : "backend"`, `"tier" : "cache"` + * `"partition" : "customerA"`, `"partition" : "customerB"` + * `"track" : "daily"`, `"track" : "weekly"` + + +这些只是常用标签的例子; 您可以任意制定自己的约定。请记住,对于给定对象标签的键必须是唯一的。 + + +## 语法和字符集 + + + +_标签_ 是键值对。有效的标签键有两个段:可选的前缀和名称,用斜杠(`/`)分隔。名称段是必需的,必须小于等于 63 个字符,以字母数字字符(`[a-z0-9A-Z]`)开头和结尾,带有破折号(`-`),下划线(`_`),点( `.`)和之间的字母数字。前缀是可选的。如果指定,前缀必须是 DNS 子域:由点(`.`)分隔的一系列 DNS 标签,总共不超过 253 个字符,后跟斜杠(`/`)。 +如果省略前缀,则假定标签键对用户是私有的。 向最终用户对象添加标签的自动系统组件(例如 `kube-scheduler`,`kube-controller-manager`,`kube-apiserver`,`kubectl` 或其他第三方自动化)必须指定前缀。`kubernetes.io/` 前缀是为 Kubernetes 核心组件保留的。 + + +有效标签值必须为 63 个字符或更少,并且必须为空或以字母数字字符(`[a-z0-9A-Z]`)开头和结尾,中间可以包含破折号(`-`)、下划线(`_`)、点(`.`)和字母或数字。 + + +## 标签选择器 + + +与 [名称和 UID](/docs/user-guide/identifiers) 不同,标签不提供唯一性。通常,我们希望许多对象携带相同的标签。 + + +通过 _标签选择器_,客户端/用户可以识别一组对象。标签选择器是 Kubernetes 中的核心分组原语。 + + +API 目前支持两种类型的选择器:_基于相等性的_ 和 _基于集合的_。 +标签选择器可以由逗号分隔的多个 _需求_ 组成。在多个需求的情况下,必须满足所有要求,因此逗号分隔符充当逻辑 _与_(`&&`)运算符。 + + +空标签选择器(即,需求为零的选择器)选择集合中的每个对象。 + + +null 值的标签选择器(仅可用于可选选择器字段)不选择任何对象 +{{< note >}} + +**注意**:两个控制器的标签选择器不得在命名空间内重叠,否则它们将互相冲突。 +{{< /note >}} + + +### _基于相等性的_ 需求 + + + +_基于相等性_ 或 _不相等_ 的需求允许按标签键和值进行过滤。匹配对象必须满足所有指定的标签约束,尽管它们也可能具有其他标签。 +可接受的运算符有`=`、`==` 和 `!=` 三种。 前两个表示 _相等_(并且只是同义词),而后者表示 _不相等_。 例如: + +``` +environment = production +tier != frontend +``` + + +前者选择所有资源,其键名等于 `environment`,值等于 `production`。 +后者选择所有资源,其键名等于 `tier`,值不同于 `frontend`,所有资源都没有带有 `tier` 键的标签。 +可以使用逗号运算符来过滤 `production` 环境中的非 `frontend` 层资源:`environment=production,tier!=frontend`。 + + +基于相等性的标签要求的一种使用场景是 Pods 要指定节点选择标准。例如,下面的示例 Pod 选择带有标签 "`accelerator=nvidia-tesla-p100`"。 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: cuda-test +spec: + containers: + - name: cuda-test + image: "k8s.gcr.io/cuda-vector-add:v0.1" + resources: + limits: + nvidia.com/gpu: 1 + nodeSelector: + accelerator: nvidia-tesla-p100 +``` + + +### _基于集合_ 的需求 + + +_基于集合_ 的标签需求允许您通过一组值来过滤键。支持三种操作符:`in`,`notin` and `exists` (只可以用在键标识符上)。例如: + +``` +environment in (production, qa) +tier notin (frontend, backend) +partition +!partition +``` + + + +第一个示例选择了所有键等于 `environment` 并且值等于 `production` 或者 `qa` 的资源。 + + + +第二个示例选择了所有键等于 `tier` 并且值不等于 `frontend` 或者 `backend` 的资源,以及所有没有 `tier` 键标签的资源。 + + + +第三个示例选择了所有包含了有 `partition` 标签的资源;没有校验它的值。 + + + +第三个示例选择了所有没有 `partition` 标签的资源;没有校验它的值。 + + +类似地,逗号分隔符充当 _AND_ 运算符。因此,使用 `partition` 键(无论为何值)和 `environment` 不同于 `qa` 来过滤资源可以使用 `partition,environment notin(qa)` 来实现。 + + + +_基于集合_ 的标签选择器是相等标签选择器的一般形式,因为 `environment = production` 等同于 `environment in(production)`;`!=` 和 `notin` 也是类似的。 + + +_基于集合_ 的要求可以与基于 _相等_ 的要求混合使用。例如:`partition in (customerA, customerB),environment!=qa`。 + +## API + + +### LIST 和 WATCH 过滤 + + +LIST and WATCH 操作可以使用查询参数指定标签选择器过滤一组对象。两种需求都是允许的。(这里显示的是它们出现在 URL 查询字符串中) + + + * _基于相等性_ 的需求: `?labelSelector=environment%3Dproduction,tier%3Dfrontend` + * _基于集合_ 的需求: `?labelSelector=environment+in+%28production%2Cqa%29%2Ctier+in+%28frontend%29` + + +两种标签选择器都可以通过 REST 客户端用于 list 或者 watch 资源。例如,使用 `kubectl` 定位 `apiserver`,可以使用 _基于相等性_ 的标签选择器可以这么写: + + +```shell +$ kubectl get pods -l environment=production,tier=frontend +``` + + +或者使用 _基于集合的_ 需求: + +```shell +$ kubectl get pods -l 'environment in (production),tier in (frontend)' +``` + + +正如刚才提到的,_基于集合_ 的需求更具有表达力。例如,它们可以实现值的 _或_ 操作: + +```shell +$ kubectl get pods -l 'environment in (production, qa)' +``` + + +或者通过 _exists_ 运算符限制不匹配: + +```shell +$ kubectl get pods -l 'environment,environment notin (frontend)' +``` + + +### 在 API 对象上设置引用 + +一些 Kubernetes 对象,例如 [`services`](/docs/user-guide/services) 和 [`replicationcontrollers`](/docs/user-guide/replication-controller) ,也使用了标签选择器去指定了其他资源的集合,例如 [pods](/docs/user-guide/pods)。 + + +#### Service 和 ReplicationController + +一个 `Service` 指向的一组 pods 是由标签选择器定义的。同样,一个 `ReplicationController` 应该管理的 pods 的数量也是由标签选择器定义的。 + +两个对象的标签选择器都是在 `json` 或者 `yaml` 文件中使用映射定义的,并且只支持 _基于相等性_ 需求的选择器: + +```json +"selector": { + "component" : "redis", +} +``` + + +或者 + +```yaml +selector: + component: redis +``` + + +这个选择器(分别在 `json` 或者 `yaml` 格式中) 等价于 `component=redis` 或 `component in (redis)` 。 + + +#### 支持基于集合需求的资源 + +比较新的资源,例如 [`Job`](/docs/concepts/jobs/run-to-completion-finite-workloads/)、[`Deployment`](/docs/concepts/workloads/controllers/deployment/)、[`Replica Set`](/docs/concepts/workloads/controllers/replicaset/) 和[`Daemon Set`](/docs/concepts/workloads/controllers/daemonset/) ,也支持 _基于集合的_ 需求。 + +```yaml +selector: + matchLabels: + component: redis + matchExpressions: + - {key: tier, operator: In, values: [cache]} + - {key: environment, operator: NotIn, values: [dev]} +``` + + + +`matchLabels` 是由 `{key,value}` 对组成的映射。`matchLabels` 映射中的单个 `{key,value }` 等同于 `matchExpressions` 的元素,其 `key`字段为 "key",`operator` 为 "In",而 `values` 数组仅包含 "value"。`matchExpressions` 是 pod 选择器要求的列表。有效的运算符包括 In,NotIn,Exists 和 DoesNotExist。在 In 和 NotIn 的情况下,设置的值必须是非空的。来自 `matchLabels` 和 `matchExpressions` 的所有要求都是合在一起 -- 它们必须都满足才能匹配。 + + +#### 选择节点集 + + +通过标签进行选择的一个用例是确定节点集,方便 pod 调度。 +有关更多信息,请参阅 [选择节点](/docs/concepts/configuration/assign-pod-node/) 上的文档。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/overview/working-with-objects/namespaces.md b/content/zh/docs/concepts/overview/working-with-objects/namespaces.md index 756faeca12..b15f49167c 100644 --- a/content/zh/docs/concepts/overview/working-with-objects/namespaces.md +++ b/content/zh/docs/concepts/overview/working-with-objects/namespaces.md @@ -3,84 +3,89 @@ title: 命名空间 content_template: templates/concept weight: 30 --- + {{% capture overview %}} -Kubernetes 支持多个虚拟集群,它们底层依赖于同一个物理集群。 -这些虚拟集群被称为命名空间。 +Kubernetes 支持多个虚拟集群,它们底层依赖于同一个物理集群。 +这些虚拟集群被称为命名空间。 {{% /capture %}} - {{% capture body %}} -## 何时使用多个命名空间 +## 何时使用多个命名空间 -命名空间适用于存在很多跨多个团队或项目的用户的场景。 -对于只有几到几十个用户的集群,根本不需要创建或考虑命名空间。当您需要命名空间提供的特性时,请开始使用它们。 - -命名空间为名称提供了一个范围。 -资源的名称需要在命名空间内是惟一的,但不能跨命名空间。命名空间不能嵌套在另外一个命名空间内,而且每个 Kubernetes -资源只能属于一个命名空间。 +命名空间适用于存在很多跨多个团队或项目的用户的场景。对于只有几到几十个用户的集群,根本不需要创建或考虑命名空间。当需要名称空间提供的功能时,请开始使用它们。 +命名空间为名称提供了一个范围。资源的名称需要在命名空间内是唯一的,但不能跨命名空间。命名空间不能相互嵌套,每个 Kubernetes 资源只能在一个命名空间中。 -命名空间是在多个用户之间划分集群资源的一种方法(通过[资源配额](/docs/concepts/policy/resource-quotas/))。 +命名空间是在多个用户之间划分集群资源的一种方法(通过[资源配额](/docs/concepts/policy/resource-quotas/))。 -在 Kubernetes 未来版本中,相同命名空间中的对象默认将具有相同的访问控制策略。 +在 Kubernetes 未来版本中,相同命名空间中的对象默认将具有相同的访问控制策略。 -不需要使用多个命名空间来分隔轻微不同的资源,例如同一软件的不同版本: -使用[标签](/docs/user-guide/labels)来区分同一命名空间中的不同资源。 +不需要使用多个命名空间来分隔轻微不同的资源,例如同一软件的不同版本:使用 [labels](/docs/user-guide/labels) 来区分同一命名空间中的不同资源。 -## 使用命名空间 +## 使用命名空间 -命名空间的创建和删除已在[命名空间的管理指南文档](/docs/admin/namespaces)中进行了描述。 +命名空间的创建和删除已在[命名空间的管理指南文档](/docs/admin/namespaces)中进行了描述。 -### 查看命名空间 +### 查看命名空间 -您可以使用以下命令列出集群中现存的命名空间: +您可以使用以下命令列出集群中现存的命名空间: ```shell kubectl get namespace @@ -92,49 +97,54 @@ kube-system Active 1d kube-public Active 1d ``` -Kubernetes 会创建三个初始命名空间: +Kubernetes 会创建三个初始命名空间: + * `default` 没有指明使用其它命名空间的对象所使用的默认命名空间 + * `kube-system` Kubernetes 系统创建对象所使用的命名空间 + * `kube-public` 这个命名空间是自动创建的,所有用户(包括未经过身份验证的用户)都可以读取它。这个命名空间主要用于集群使用,以防某些资源在整个集群中应该是可见和可读的。这个命名空间的公共方面只是一种约定,而不是要求。 -### 为请求设置命名空间 +### 为请求设置命名空间 -要为当前的请求设定一个命名空间,请使用 `--namespace` 参数。 +要为当前请求设置命名空间,请使用 `--namespace` 参数。 -例如: +例如: ```shell kubectl run nginx --image=nginx --namespace= kubectl get pods --namespace= ``` -### 设置命名空间首选项 +### 设置命名空间首选项 -您可以永久保存该上下文中所有后续 kubectl 命令使用的命名空间。 +您可以永久保存该上下文中所有后续 kubectl 命令使用的命名空间。 ```shell kubectl config set-context --current --namespace= @@ -142,20 +152,16 @@ kubectl config set-context --current --namespace= kubectl config view | grep namespace: ``` -## 命名空间和 DNS +## 命名空间和 DNS -当您创建一个[服务](/docs/user-guide/services)时,Kubernetes 会创建一个相应的[DNS 条目](/docs/concepts/services-networking/dns-pod-service/)。 +当您创建一个 [Service](/docs/user-guide/services) 时,Kubernetes 会创建一个相应的 [DNS 条目](/docs/concepts/services-networking/dns-pod-service/)。 -该条目的形式是 `..svc.cluster.local`, -这意味着如果容器只使用 ``,它将被解析到本地命名空间的服务。 -这对于跨多个命名空间(如开发、分级和生产)使用相同的配置非常有用。 -如果您希望跨命名空间访问,则需要使用完全限定域名(FQDN)。 +该条目的形式是 `..svc.cluster.local`,这意味着如果容器只使用 ``,它将被解析到本地命名空间的服务。这对于跨多个命名空间(如开发、分级和生产)使用相同的配置非常有用。如果您希望跨命名空间访问,则需要使用完全限定域名(FQDN)。 -## 并非所有对象都在命名空间中 +## 并非所有对象都在命名空间中 -大多数 kubernetes 资源(例如 Pod、服务、副本控制器等)都位于某些命名空间中。 -但是命名空间资源本身并不在命名空间中。 - -而且底层资源,例如[节点](/docs/admin/node)和持久化卷不属于任何命名空间。 - +大多数 kubernetes 资源(例如 Pod、Service、副本控制器等)都位于某些命名空间中。但是命名空间资源本身并不在命名空间中。而且底层资源,例如 [nodes](/docs/admin/node) 和持久化卷不属于任何命名空间。 -查看哪些 Kubernetes 资源在命名空间中,哪些不在命名空间中: +查看哪些 Kubernetes 资源在命名空间中,哪些不在命名空间中: ```shell # In a namespace @@ -202,8 +204,8 @@ kubectl api-resources --namespaced=false * Learn more about [creating a new namespace](/docs/tasks/administer-cluster/namespaces/#creating-a-new-namespace). * Learn more about [deleting a namespace](/docs/tasks/administer-cluster/namespaces/#deleting-a-namespace). --> +* 进一步了解[建立新的命名空间](/docs/tasks/administer-cluster/namespaces/#creating-a-new-namespace)。 +* 进一步了解[删除命名空间](/docs/tasks/administer-cluster/namespaces/#deleting-a-namespace)。 -* 了解相关内容 [创建一个新的命名空间](/docs/tasks/administer-cluster/namespaces/#creating-a-new-namespace). -* 了解相关内容 [删除一个命名空间](/docs/tasks/administer-cluster/namespaces/#deleting-a-namespace). {{% /capture %}} diff --git a/content/zh/docs/concepts/overview/working-with-objects/object-management.md b/content/zh/docs/concepts/overview/working-with-objects/object-management.md index 1d98c2af1c..27ab353f0e 100644 --- a/content/zh/docs/concepts/overview/working-with-objects/object-management.md +++ b/content/zh/docs/concepts/overview/working-with-objects/object-management.md @@ -19,7 +19,6 @@ details of managing objects by Kubectl. - ## 管理技巧 {{< warning >}} @@ -39,7 +38,6 @@ and matching techniques for the same object results in undefined behavior. - ## 命令式命令 - 使用命令式命令时,用户可以在集群中的活动对象上进行操作。用户将操作传给 `kubectl` 命令作为参数或标志。 - 这是开始或者在集群中运行一次性任务的最简单方法。因为这个技术直接在活动对象上操作,所以它不提供以前配置的历史记录。 - ### 例子 - 通过创建 Deployment 对象来运行 nginx 容器的实例: ```sh @@ -77,7 +71,6 @@ kubectl run nginx --image nginx - 使用不同的语法来达到同样的上面的效果: ```sh @@ -87,27 +80,23 @@ kubectl create deployment nginx --image nginx - ### 权衡 - 与对象配置相比的优点: - - 命令简单,易学且易于记忆。 - 命令仅需一步即可对集群进行更改。 - 与对象配置相比的缺点: - - 命令不与变更审查流程集成。 - 命令不提供与更改关联的审核跟踪。 - 除了实时内容外,命令不提供记录源。 - 命令不提供用于创建新对象的模板。 - - ## 命令式对象配置 - 在命令式对象配置中,kubectl 命令指定操作(创建,替换等),可选标志和至少一个文件名。指定的文件必须包含 YAML 或 JSON 格式的对象的完整定义。 - 有关对象定义的详细信息,请查看 [API 参考](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/)。 {{< warning >}} @@ -160,13 +144,11 @@ independently from the configuration by the cluster. - ### 例子 - 创建在配置文件中定义的对象: ```sh @@ -195,13 +177,11 @@ kubectl replace -f nginx.yaml - ### 权衡 - 与命令式命令相比的优点: - - 对象配置可以存储在源控制系统中,比如 Git。 - 对象配置可以与流程集成,例如在推送和审计之前检查更新。 - 对象配置提供了用于创建新对象的模板。 @@ -217,49 +196,42 @@ Advantages compared to imperative commands: - 与命令式命令相比的缺点: - - 对象配置需要对对象架构有基本的了解。 - 对象配置需要额外的写 YAML 文件的步骤。 - 与声明式对象配置相比的优点: - - 命令式对象配置行为更加简单易懂。 - 从 Kubernetes 1.5 版本开始,命令式对象配置更加成熟。 - 与声明式对象配置相比的缺点: - - 命令式对象配置针对文件而不是目录上效果最佳。 - 对活动对象的更新必须反映在配置文件中,否则将在下一次替换是丢失。 - ## 声明式对象配置 - 使用声明式对象配置时,用户对本地存储的对象配置文件进行操作,但是用户未定义要对该文件执行的操作。会自动通过 `kubectl` 按对象检测来创建、更新和删除对象。这使得可以在目录上工作,其中可能需要对不同的对象执行不同的操作。 {{< note >}} @@ -285,14 +256,14 @@ API operation to replace the entire object configuration. +### 例子 + - -### 例子 - 处理 `configs` 目录中的所有对象配置文件,创建并更新活动对象。可以首先使用 `diff` 子命令查看将要进行的更改,然后在进行应用: ```sh @@ -313,34 +284,29 @@ kubectl apply -R -f configs/ - ### 权衡 - 与命令式对象配置相比的优点: - - 即使未将对活动对象所做的更改未合并回到配置文件中,也将保留这些更改。 - 声明性对象配置更好地支持对目录进行操作并自动检测每个对象的操作类型(创建,修补,删除)。 - 与命令式对象配置相比的缺点: - - 声明式对象配置难于调试并且出现异常时难以理解。 - 使用差异的部分更新会创建复杂的合并和补丁操作。 diff --git a/content/zh/docs/concepts/scheduling/_index.md b/content/zh/docs/concepts/scheduling/_index.md new file mode 100644 index 0000000000..bab0d71988 --- /dev/null +++ b/content/zh/docs/concepts/scheduling/_index.md @@ -0,0 +1,9 @@ +--- +title: "调度" +weight: 90 +--- + + diff --git a/content/zh/docs/concepts/scheduling/kube-scheduler.md b/content/zh/docs/concepts/scheduling/kube-scheduler.md new file mode 100644 index 0000000000..f5a61b3476 --- /dev/null +++ b/content/zh/docs/concepts/scheduling/kube-scheduler.md @@ -0,0 +1,319 @@ +--- +title: Kubernetes 调度器 +content_template: templates/concept +weight: 60 +--- + + +{{% capture overview %}} + + +在 Kubernetes 中,_调度_ 是指将 {{< glossary_tooltip text="Pod" term_id="pod" >}} 放置到合适的 +{{< glossary_tooltip text="Node" term_id="node" >}} 上,然后对应 Node 上的 {{< glossary_tooltip term_id="kubelet" >}} 才能够运行这些 pod。 + +{{% /capture %}} + +{{% capture body %}} + +## 调度概览 {#scheduling} + + +调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被调度到 Node 上的 Pod。调度器会将发现的每一个未调度的 Pod 调度到一个合适的 Node 上来运行。调度器会依据下文的调度原则来做出调度选择。 + + +如果你想要理解 Pod 为什么会被调度到特定的 Node 上,或者你想要尝试实现一个自定义的调度器,这篇文章将帮助你了解调度。 + + +## kube-scheduler + + +[kube-scheduler](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler/) 是 Kubernetes 集群的默认调度器,并且是集群 {{< glossary_tooltip text="控制面" term_id="control-plane" >}} 的一部分。如果你真的希望或者有这方面的需求,kube-scheduler 在设计上是允许你自己写一个调度组件并替换原有的 kube-scheduler。 + + +对每一个新创建的 Pod 或者是未被调度的 Pod,kube-scheduler 会选择一个最优的 Node 去运行这个 Pod。然而,Pod 内的每一个容器对资源都有不同的需求,而且 Pod 本身也有不同的资源需求。因此,Pod 在被调度到 Node 上之前,根据这些特定的资源调度需求,需要对集群中的 Node 进行一次过滤。 + + +在一个集群中,满足一个 Pod 调度请求的所有 Node 称之为 _可调度节点_。如果没有任何一个 Node 能满足 Pod 的资源请求,那么这个 Pod 将一直停留在未调度状态直到调度器能够找到合适的 Node。 + + +调度器先在集群中找到一个 Pod 的所有可调度节点,然后根据一系列函数对这些可调度节点打分,然后选出其中得分最高的 Node 来运行 Pod。之后,调度器将这个调度决定通知给 kube-apiserver,这个过程叫做 _绑定_。 + + +在做调度决定时需要考虑的因素包括:单独和整体的资源请求、硬件/软件/策略限制、亲和以及反亲和要求、数据局域性、负载间的干扰等等。 + + +## kube-scheduler 调度流程 {#kube-scheduler-implementation} + + +kube-scheduler 给一个 pod 做调度选择包含两个步骤: + +1. 过滤 + +2. 打分 + + +过滤阶段会将所有满足 Pod 调度需求的 Node 选出来。例如,PodFitsResources 过滤函数会检查候选 Node 的可用资源能否满足 Pod 的资源请求。在过滤之后,得出一个 Node 列表,里面包含了所有可调度节点;通常情况下,这个 Node 列表包含不止一个 Node。如果这个列表是空的,代表这个 Pod 不可调度。 + + +在打分阶段,调度器会为 Pod 从所有可调度节点中选取一个最合适的 Node。根据当前启用的打分规则,调度器会给每一个可调度节点进行打分。 + + +最后,kube-scheduler 会将 Pod 调度到得分最高的 Node 上。如果存在多个得分最高的 Node,kube-scheduler 会从中随机选取一个。 + + +### 默认策略 + + +kube-scheduler 有一系列的默认调度策略。 + + +### 过滤策略 + +- `PodFitsHostPorts`:如果 Pod 中定义了 hostPort 属性,那么需要先检查这个指定端口是否 + 已经被 Node 上其他服务占用了。 + +- `PodFitsHost`:若 pod 对象拥有 hostname 属性,则检查 Node 名称字符串与此属性是否匹配。 + +- `PodFitsResources`:检查 Node 上是否有足够的资源(如,cpu 和内存)来满足 pod 的资源请求。 + +- `PodMatchNodeSelector`:检查 Node 的 {{< glossary_tooltip text="标签" term_id="label" >}} 是否能匹配 + Pod 属性上 Node 的 {{< glossary_tooltip text="标签" term_id="label" >}} 值。 + +- `NoVolumeZoneConflict`:检测 pod 请求的 {{< glossary_tooltip text="Volumes" term_id="volume" >}} 在 + Node 上是否可用,因为某些存储卷存在区域调度约束。 + +- `NoDiskConflict`:检查 Pod 对象请求的存储卷在 Node 上是否可用,若不存在冲突则通过检查。 + +- `MaxCSIVolumeCount`:检查 Node 上已经挂载的 {{< glossary_tooltip text="CSI" term_id="csi" >}} + 存储卷数量是否超过了指定的最大值。 + +- `CheckNodeMemoryPressure`:如果 Node 上报了内存资源压力过大,而且没有配置异常,那么 Pod 将不会被调度到这个 Node 上。 + +- `CheckNodePIDPressure`:如果 Node 上报了 PID 资源压力过大,而且没有配置异常,那么 Pod 将不会被调度到这个 Node 上。 + +- `CheckNodeDiskPressure`:如果 Node 上报了磁盘资源压力过大(文件系统满了或者将近满了), + 而且配置异常,那么 Pod 将不会被调度到这个 Node 上。 + +- `CheckNodeCondition`:Node 可以上报其自身的状态,如磁盘、网络不可用,表明 kubelet 未准备好运行 pod。 + 如果 Node 被设置成这种状态,那么 pod 将不会被调度到这个 Node 上。 + +- `PodToleratesNodeTaints`:检查 pod 属性上的 {{< glossary_tooltip text="tolerations" term_id="toleration" >}} 能否容忍 + Node 的 {{< glossary_tooltip text="taints" term_id="taint" >}}。 + +- `CheckVolumeBinding`:检查 Node 上已经绑定的和未绑定的 {{< glossary_tooltip text="PVCs" term_id="persistent-volume-claim" >}} + 能否满足 Pod 对象的存储卷需求。 + + +### 打分策略 + +- `SelectorSpreadPriority`:尽量将归属于同一个 {{< glossary_tooltip text="Service" term_id="service" >}}、{{< glossary_tooltip term_id="statefulset" >}} 或 {{< glossary_tooltip term_id="replica-set" >}} 的 Pod 资源分散到不同的 Node 上。 + +- `InterPodAffinityPriority`:遍历 Pod 对象的亲和性条目,并将那些能够匹配到给定 Node 的条目的权重相加,结果值越大的 Node 得分越高。 + +- `LeastRequestedPriority`:空闲资源比例越高的 Node 得分越高。换句话说,Node 上的 Pod 越多,并且资源被占用的越多,那么这个 Node 的得分就会越少。 + +- `MostRequestedPriority`:空闲资源比例越低的 Node 得分越高。这个调度策略将会把你所有的工作负载(Pod)调度到尽量少的 Node 上。 + +- `RequestedToCapacityRatioPriority`:为 Node 上每个资源占用比例设定得分值,给资源打分函数在打分时使用。 + +- `BalancedResourceAllocation`:优选那些使得资源利用率更为均衡的节点。 + +- `NodePreferAvoidPodsPriority`:这个策略将根据 Node 的注解信息中是否含有 `scheduler.alpha.kubernetes.io/preferAvoidPods` 来 + 计算其优先级。使用这个策略可以将两个不同 Pod 运行在不同的 Node 上。 + +- `NodeAffinityPriority`:基于 Pod 属性中 PreferredDuringSchedulingIgnoredDuringExecution 来进行 Node 亲和性调度。你可以通过这篇文章 + [Pods 到 Nodes 的分派](https://kubernetes.io/docs/concepts/configuration/assign-pod-node/) 来了解到更详细的内容。 + +- `TaintTolerationPriority`:基于 Pod 中对每个 Node 上污点容忍程度进行优先级评估,这个策略能够调整待选 Node 的排名。 + +- `ImageLocalityPriority`:Node 上已经拥有 Pod 需要的 {{< glossary_tooltip text="容器镜像" term_id="image" >}} 的 Node 会有较高的优先级。 + +- `ServiceSpreadingPriority`:这个调度策略的主要目的是确保将归属于同一个 Service 的 Pod 调度到不同的 Node 上。如果 Node 上 + 没有归属于同一个 Service 的 Pod,这个策略更倾向于将 Pod 调度到这类 Node 上。最终的目的:即使在一个 Node 宕机之后 Service 也具有很强容灾能力。 + +- `CalculateAntiAffinityPriorityMap`:这个策略主要是用来实现[pod反亲和] + (https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity)。 + +- `EqualPriorityMap`:将所有的 Node 设置成相同的权重为 1。 + +{{% /capture %}} +{{% capture whatsnext %}} +* 阅读关于 [调度器性能调优](/docs/concepts/scheduling/scheduler-perf-tuning/) +* 阅读关于 [Pod 拓扑分布约束](/docs/concepts/workloads/pods/pod-topology-spread-constraints/) +* 阅读关于 kube-scheduler 的 [参考文档](/docs/reference/command-line-tools-reference/kube-scheduler/) +* 了解关于 [配置多个调度器](/docs/tasks/administer-cluster/configure-multiple-schedulers/) 的方式 +* 了解关于 [拓扑结构管理策略](/docs/tasks/administer-cluster/topology-manager/) +* 了解关于 [Pod 额外开销](/docs/concepts/configuration/pod-overhead/) +{{% /capture %}} diff --git a/content/zh/docs/concepts/scheduling/scheduler-perf-tuning.md b/content/zh/docs/concepts/scheduling/scheduler-perf-tuning.md new file mode 100644 index 0000000000..ccdb76fcc4 --- /dev/null +++ b/content/zh/docs/concepts/scheduling/scheduler-perf-tuning.md @@ -0,0 +1,185 @@ +--- +title: 调度器性能调优 +content_template: templates/concept +weight: 70 +--- + + +{{% capture overview %}} + +{{< feature-state for_k8s_version="1.14" state="beta" >}} + + +作为 kubernetes 集群的默认调度器,kube-scheduler 主要负责将 Pod 调度到集群的 Node 上。 + + +在一个集群中,满足一个 Pod 调度请求的所有 Node 称之为 _可调度_ Node。调度器先在集群中找到一个 Pod 的可调度 Node,然后根据一系列函数对这些可调度 Node打分,之后选出其中得分最高的 Node 来运行 Pod。最后,调度器将这个调度决定告知 kube-apiserver,这个过程叫做 _绑定_。 + + +这篇文章将会介绍一些在大规模 Kubernetes 集群下调度器性能优化的方式。 + +{{% /capture %}} + +{{% capture body %}} + + +## 设置打分阶段 Node 数量占集群总规模的百分比 + + +在 Kubernetes 1.12 版本之前,kube-scheduler 会检查集群中所有节点的可调度性,并且给可调度节点打分。Kubernetes 1.12 版本添加了一个新的功能,允许调度器在找到一定数量的可调度节点之后就停止继续寻找可调度节点。该功能能提高调度器在大规模集群下的调度性能。这个数值是集群规模的百分比。这个百分比通过 `percentageOfNodesToScore` 参数来进行配置。其值的范围在 1 到 100 之间,最大值就是 100%。如果设置为 0 就代表没有提供这个参数配置。Kubernetes 1.14 版本又加入了一个特性,在该参数没有被用户配置的情况下,调度器会根据集群的规模自动设置一个集群比例,然后通过这个比例筛选一定数量的可调度节点进入打分阶段。该特性使用线性公式计算出集群比例,如在 100-node 的集群下取 50%。在 5000-node 的集群下取 10%。这个自动设置的参数的最低值是 5%。换句话说,调度器至少会对集群中 5% 的节点进行打分,除非用户将该参数设置的低于 5。 + + +下面就是一个将 `percentageOfNodesToScore` 参数设置为 50% 的例子。 + +```yaml +apiVersion: kubescheduler.config.k8s.io/v1alpha1 +kind: KubeSchedulerConfiguration +algorithmSource: + provider: DefaultProvider + +... + +percentageOfNodesToScore: 50 +``` + + +{{< note >}} 当集群中的可调度节点少于 50 个时,调度器仍然会去检查所有的 Node,因为可调度节点太少,不足以停止调度器最初的过滤选择。{{< /note >}} + + +**如果想要关闭这个功能**,你可以将 `percentageOfNodesToScore` 值设置成 100。 + + +### 调节 percentageOfNodesToScore 参数 + + +`percentageOfNodesToScore` 的值必须在 1 到 100 之间,而且其默认值是通过集群的规模计算得来的。另外,还有一个 50 个 Node 的数值是硬编码在程序里面的。设置这个值的作用在于:当集群的规模是数百个 Node 并且 `percentageOfNodesToScore` 参数设置的过低的时候,调度器筛选到的可调度节点数目基本不会受到该参数影响。当集群规模较小时,这个设置将导致调度器性能提升并不明显。然而在一个超过 1000 个 Node 的集群中,将调优参数设置为一个较低的值可以很明显的提升调度器性能。 + + +值得注意的是,该参数设置后可能会导致只有集群中少数节点被选为可调度节点,很多 node 都没有进入到打分阶段。这样就会造成一种后果,一个本来可以在打分阶段得分很高的 Node 甚至都不能进入打分阶段。由于这个原因,这个参数不应该被设置成一个很低的值。通常的做法是不会将这个参数的值设置的低于 10。很低的参数值一般在调度器的吞吐量很高且对 node 的打分不重要的情况下才使用。换句话说,只有当你更倾向于在可调度节点中任意选择一个 Node 来运行这个 Pod 时,才使用很低的参数设置。 + + +如果你的集群规模只有数百个节点或者更少,我们并不推荐你将这个参数设置得比默认值更低。因为这种情况下不太可能有效的提高调度器性能。 + + +### 调度器做调度选择的时候如何覆盖所有的 Node + + +如果你想要理解这一个特性的内部细节,那么请仔细阅读这一章节。 + + +在将 Pod 调度到 Node 上时,为了让集群中所有 Node 都有公平的机会去运行这些 Pod,调度器将会以轮询的方式覆盖全部的 Node。你可以将 Node 列表想象成一个数组。调度器从数组的头部开始筛选可调度节点,依次向后直到可调度节点的数量达到 `percentageOfNodesToScore` 参数的要求。在对下一个 Pod 进行调度的时候,前一个 Pod 调度筛选停止的 Node 列表的位置,将会来作为这次调度筛选 Node 开始的位置。 + + +如果集群中的 Node 在多个区域,那么调度器将从不同的区域中轮询 Node,来确保不同区域的 Node 接受可调度性检查。如下例,考虑两个区域中的六个节点: + +``` +Zone 1: Node 1, Node 2, Node 3, Node 4 +Zone 2: Node 5, Node 6 +``` + + +调度器将会按照如下的顺序去评估 Node 的可调度性: + +``` +Node 1, Node 5, Node 2, Node 6, Node 3, Node 4 +``` + + +在评估完所有 Node 后,将会返回到 Node 1,从头开始。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/security/_index.md b/content/zh/docs/concepts/security/_index.md new file mode 100644 index 0000000000..4c79303ff3 --- /dev/null +++ b/content/zh/docs/concepts/security/_index.md @@ -0,0 +1,9 @@ +--- +title: "安全" +weight: 81 +--- + + diff --git a/content/zh/docs/concepts/services-networking/_index.md b/content/zh/docs/concepts/services-networking/_index.md index b8cc1a2f58..905f25af01 100644 --- a/content/zh/docs/concepts/services-networking/_index.md +++ b/content/zh/docs/concepts/services-networking/_index.md @@ -2,3 +2,10 @@ title: "服务、负载均衡和联网" weight: 80 --- + + diff --git a/content/zh/docs/concepts/services-networking/dual-stack.md b/content/zh/docs/concepts/services-networking/dual-stack.md new file mode 100644 index 0000000000..f8f359784c --- /dev/null +++ b/content/zh/docs/concepts/services-networking/dual-stack.md @@ -0,0 +1,215 @@ +--- +reviewers: +- lachie83 +- khenidak +- aramase +title: IPv4/IPv6 双协议栈 +feature: + title: IPv4/IPv6 双协议栈 + description: > + Allocation of IPv4 and IPv6 addresses to Pods and Services + +content_template: templates/concept +weight: 70 +--- + + +{{% capture overview %}} + +{{< feature-state for_k8s_version="v1.16" state="alpha" >}} + + +IPv4/IPv6 双协议栈能够将 IPv4 和 IPv6 地址分配给 {{< glossary_tooltip text="Pods" term_id="pod" >}} 和 {{< glossary_tooltip text="Services" term_id="service" >}}。 + + +如果你为 Kubernetes 集群启用了 IPv4/IPv6 双协议栈网络,则该集群将支持同时分配 IPv4 和 IPv6 地址。 + +{{% /capture %}} + +{{% capture body %}} + + +## 支持的功能 + + +在 Kubernetes 集群上启用 IPv4/IPv6 双协议栈可提供下面的功能: + + + * 双协议栈 pod 网络 (每个 pod 分配一个 IPv4 和 IPv6 地址) + * IPv4 和 IPv6 启用的服务 (每个服务必须是一个单独的地址族) + * Kubenet 多地址族支持(IPv4 和 IPv6) + * Pod 的集群外出口通过 IPv4 和 IPv6 路由 + + +## 先决条件 + + +为了使用 IPv4/IPv6 双栈的 Kubernetes 集群,需要满足以下先决条件: + + + * Kubernetes 1.16 版本及更高版本 + * 提供商支持双协议栈网络(云提供商或其他提供商必须能够为 Kubernetes 节点提供可路由的 IPv4/IPv6 网络接口) + * Kubenet 网络插件 + * Kube-proxy 运行在 IPVS 模式 + + +## 启用 IPv4/IPv6 双协议栈 + + +要启用 IPv4/IPv6 双协议栈,为集群的相关组件启用 `IPv6DualStack` [特性门控](/docs/reference/command-line-tools-reference/feature-gates/),并且设置双协议栈的集群网络分配: + + * kube-controller-manager: + * `--feature-gates="IPv6DualStack=true"` + * `--cluster-cidr=,` eg. `--cluster-cidr=10.244.0.0/16,fc00::/24` + * `--service-cluster-ip-range=,` + * kubelet: + * `--feature-gates="IPv6DualStack=true"` + * kube-proxy: + * `--proxy-mode=ipvs` + * `--cluster-cidrs=,` + * `--feature-gates="IPv6DualStack=true"` + +{{< caution >}} + +如果命令行的 `--cluster-cidr` 指定大于 /24 的 IPv6 地址块,地址分配将失败。 +{{< /caution >}} + + +## 服务 + + +如果你的集群启用了 IPv4/IPv6 双协议栈网络,则可以使用 IPv4 或 IPv6 地址来创建 {{< glossary_tooltip text="Services" term_id="service" >}}。你可以通过设置服务的 `.spec.ipFamily` 字段来选择服务的集群 IP 的地址族。你只能在创建新服务时设置该字段。`.spec.ipFamily` 字段的设置是可选的,并且仅当你计划在集群上启用 IPv4 和 IPv6 的 {{< glossary_tooltip text="Services" term_id="service" >}} 和 {{< glossary_tooltip text="Ingresses" term_id="ingress" >}}。对于[出口](#出口流量)流量,该字段的配置不是必须的。 + +{{< note >}} + +集群的默认地址族是第一个服务集群 IP 范围的地址族,该地址范围通过 kube-controller-manager 上的 `--service-cluster-ip-range` 标志设置。 +{{< /note >}} + + +你可以设置 `.spec.ipFamily` 为: + + + * `IPv4`:API 服务器将从 `service-cluster-ip-range` 中分配 `ipv4` 地址 + * `IPv6`:API 服务器将从 `service-cluster-ip-range` 中分配 `ipv6` 地址 + + +以下服务规约不包含 `ipFamily` 字段。Kubernetes 将从最初配置的 `service-cluster-ip-range` 范围内分配一个 IP 地址(也称作“集群 IP”)给该服务。 + +{{< codenew file="service/networking/dual-stack-default-svc.yaml" >}} + + +以下服务规约不包含 `ipFamily` 字段。Kubernetes 将从已配置的 `service-cluster-ip-range` 范围内分配一个 IPv6 地址(也称作“集群 IP”)给该服务。 + +{{< codenew file="service/networking/dual-stack-ipv6-svc.yaml" >}} + + +为了进行比较,将从已配置的 `service-cluster-ip-range` 向该服务分配以下 IPV4 地址(也称为“集群 IP”)。 + +{{< codenew file="service/networking/dual-stack-ipv4-svc.yaml" >}} + + +### 负载均衡器类型 + + +在支持启用了 IPv6 的外部服务均衡器的云驱动上,除了将 `ipFamily` 字段设置为 `IPv6`,将 `type` 字段设置为 `LoadBalancer`,为你的服务提供云负载均衡。 + + +## 出口流量 + + +公共路由和非公共路由的 IPv6 地址块的使用是可以的。提供底层 {{< glossary_tooltip text="CNI" term_id="cni" >}} 的提供程序可以实现这种传输。如果你拥有使用非公共路由 IPv6 地址的 Pod,并且希望该 Pod 到达集群外目的(比如,公共网络),你必须为出口流量和任何响应消息设置 IP 伪装。[ip-masq-agent](https://github.com/kubernetes-incubator/ip-masq-agent) 可以感知双栈,所以你可以在双栈集群中使用 ip-masq-agent 来进行 IP 伪装。 + + +## 已知问题 + + + * IPv6 网络块分配使用默认的 IPv4 CIDR 块大小(/24) + * Kubenet 强制 IPv4,IPv6 的 IPs 位置报告 (--cluster-cidr) + * 如果 `EndpointSlice` 特性门控启用,则双栈网络不起作用。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + +* [验证 IPv4/IPv6 双协议栈](/docs/tasks/network/validate-dual-stack)网络 + +{{% /capture %}} + diff --git a/content/zh/docs/concepts/services-networking/ingress-controllers.md b/content/zh/docs/concepts/services-networking/ingress-controllers.md index 925d697391..b427403eba 100644 --- a/content/zh/docs/concepts/services-networking/ingress-controllers.md +++ b/content/zh/docs/concepts/services-networking/ingress-controllers.md @@ -107,12 +107,10 @@ Make sure you review your ingress controller's documentation to understand the c {{% /capture %}} {{% capture whatsnext %}} - - * 了解更多关于 [Ingress](/docs/concepts/services-networking/ingress/)。 * [在 Minikube 上使用 NGINX 控制器安装 Ingress](/docs/tasks/access-application-cluster/ingress-minikube)。 {{% /capture %}} diff --git a/content/zh/docs/concepts/services-networking/ingress.md b/content/zh/docs/concepts/services-networking/ingress.md index 39be35721d..c31514a81a 100644 --- a/content/zh/docs/concepts/services-networking/ingress.md +++ b/content/zh/docs/concepts/services-networking/ingress.md @@ -3,6 +3,15 @@ title: Ingress content_template: templates/concept weight: 40 --- + {{% capture overview %}} {{< feature-state for_k8s_version="v1.1" state="beta" >}} @@ -13,57 +22,62 @@ weight: 40 - ## 专用术语 -为了避免歧义,本指南定义了以下术语: + +为了清楚起见,本指南定义了以下术语: -节点 -:Kubernetes 集群中的单个工作机器。 -集群 -:运行由Kubernetes管理的容器化应用程序的一组节点。 对于此示例,在大多数常见的Kubernetes部署中,群集中的节点不属于公共网络。 + +Node(节点) +: Kubernetes 中的一台工作者机器,是集群的一部分。 -边缘路由器 -:为集群强制执行防火墙策略的路由器。这可以是由云提供商管理的网关或物理硬件。 + +Cluster(集群) +: 运行由 Kubernetes 管理的容器化应用程序的一组节点。在大多数常见的 Kubernetes 部署中,集群中的节点不属于公共 Internet。 -集群网络 -:一组逻辑或物理的链接,根据 Kubernetes [网络模型](/docs/concepts/cluster-administration/networking/) 在集群内实现通信。 + +Edge router(边缘路由器) +: 强制对集群执行防火墙策略的路由器。这可能是由云提供商或物理硬件管理的网关。 -服务: -Kubernetes {{< glossary_tooltip term_id="service" >}} 使用 {{< glossary_tooltip text="标签" term_id="label" >}} 选择器标识一组 Pod。除非另有说明,否则假定服务只具有在集群网络中可路由的虚拟 IP。 + +Cluster network(集群网络) +: 一组逻辑或物理的链接,根据 Kubernetes [网络模型](/docs/concepts/cluster-administration/networking/) 在集群内实现通信。 + + +Service(服务) +: Kubernetes {{< glossary_tooltip term_id="service" >}} 使用 {{< glossary_tooltip text="label" term_id="label" >}} 选择器标识一组 Pod。除非另有说明,否则假定服务只具有在集群网络中可路由的虚拟 IP。 - ## Ingress 是什么? -Ingress公开了从群集外部到群集内 {{< link text="services" url="/docs/concepts/services-networking/service/" >}} 的HTTP和HTTPS路由。 -流量路由由Ingress资源上定义的规则控制。 + +Ingress 公开了从集群外部到集群内部 {{< link text="services" url="/docs/concepts/services-networking/service/" >}} 的 HTTP 和 HTTPS 路由。 +流量路由由 Ingress 资源上定义的规则控制。 ```none internet @@ -73,44 +87,34 @@ Ingress公开了从群集外部到群集内 {{< link text="services" url="/docs/ [ Services ] ``` - +可以将 Ingress 配置为提供服务外部可访问的 URL、负载均衡流量、终止 SSL / TLS 并提供基于名称的虚拟主机。[Ingress 控制器](/docs/concepts/services-networking/ingress-controllers)通常负责通过负载均衡器来实现 Ingress,尽管它也可以配置边缘路由器或其他前端来帮助处理流量。 + +Ingress 不会公开任意端口或协议。 +将 HTTP 和 HTTPS 以外的服务公开到 Internet 时,通常使用 [Service.Type=NodePort](/docs/concepts/services-networking/service/#nodeport) 或者 [Service.Type=LoadBalancer](/docs/concepts/services-networking/service/#loadbalancer) 类型的服务。 -可以将Ingress配置为提供服务外部可访问的URL,负载平衡流量,终止 SSL / TLS 并提供基于名称的虚拟主机。 [Ingress 控制器](/docs/concepts/services-networking/ingress-controllers)通常负责通过负载平衡器来实现入口,尽管它也可以配置边缘路由器或其他前端以帮助处理流量。 - -Ingress 不会公开任意端口或协议。 将 HTTP 和 HTTPS 以外的服务公开给 Internet 时,通常使用以下类型的服务 [Service.Type=NodePort](/docs/concepts/services-networking/service/#nodeport) 或者 [Service.Type=LoadBalancer](/docs/concepts/services-networking/service/#loadbalancer). - - - ## 环境准备 -您必须具有[ Ingress 控制器](/docs/concepts/services-networking/ingress-controllers)才能满足Ingress的要求。 仅创建Ingress资源无效。 + +您必须具有 [ingress 控制器](/docs/concepts/services-networking/ingress-controllers)才能满足 Ingress 的要求。仅创建 Ingress 资源无效。 -您可以部署一个 Ingress 控制器 - -GCE/Google Kubernetes Engine 是在主节点上部署 Ingress 控制器。 -您可以在 Pod 中部署任意数量的自定义 Ingress 控制器。 -您必须使用适当的类来注释每个 Ingress,如[这里](https://git.k8s.io/ingress-nginx/docs/user-guide/multiple-ingress.md#multiple-ingress-controllers) 和 [这里](https://git.k8s.io/ingress-gce/examples/PREREQUISITES.md#ingress-class) 所示。 - -一定要检查一下这个控制器的 [beta 限制](https://github.com/kubernetes/ingress-gce/blob/master/LIMITATIONS.md)。 -在 GCE/Google Kubernetes Engine 之外的环境中,需要将[控制器部署](https://git.k8s.io/ingress-nginx/README.md) 为 Pod。 + +您可能需要部署 Ingress 控制器,例如 [ingress-nginx](https://kubernetes.github.io/ingress-nginx/deploy/)。您可以从许多[ Ingress 控制器](/docs/concepts/services-networking/ingress-controllers)中进行选择。 {{< note >}} @@ -120,15 +124,25 @@ Make sure you review your Ingress controller's documentation to understand the c 确保您查看了 Ingress 控制器的文档,以了解选择它的注意事项。 {{< /note >}} +一定要检查一下这个控制器的 [beta 限制](https://github.com/kubernetes/ingress-gce/blob/master/LIMITATIONS.md)。 +在 GCE/Google Kubernetes Engine 之外的环境中,需要将[控制器部署](https://git.k8s.io/ingress-nginx/README.md) 为 Pod。 + +{{< note >}} + +确保您查看了 Ingress 控制器的文档,以了解选择它的注意事项。 +{{< /note >}} + - ## Ingress 资源 -最小的 Ingress 资源实例: + +一个最小的 Ingress 资源示例: ```yaml apiVersion: networking.k8s.io/v1beta1 @@ -147,34 +161,38 @@ spec: servicePort: 80 ``` - + 与所有其他 Kubernetes 资源一样,Ingress 需要使用 `apiVersion`、`kind` 和 `metadata` 字段。 + 有关使用配置文件的一般信息,请参见[部署应用](/docs/tasks/run-application/run-stateless-application-deployment/)、 [配置容器](/docs/tasks/configure-pod-container/configure-pod-configmap/)、[管理资源](/docs/concepts/cluster-administration/manage-deployment/)。 + Ingress 经常使用注解(annotations)来配置一些选项,具体取决于 Ingress 控制器,例如 [rewrite-target annotation](https://github.com/kubernetes/ingress-nginx/blob/master/docs/examples/rewrite/README.md)。 + 不同的 [Ingress 控制器](/docs/concepts/services-networking/ingress-controllers)支持不同的注解(annotations)。查看文档以供您选择 Ingress 控制器,以了解支持哪些注解(annotations)。 + +Ingress [规范](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status) 具有配置负载均衡器或者代理服务器所需的所有信息。最重要的是,它包含与所有传入请求匹配的规则列表。Ingress 资源仅支持用于定向 HTTP 流量的规则。 -与所有其他 Kubernetes 资源一样,Ingress 需要使用 `apiVersion`, `kind`, 和 `metadata`字段。 -有关使用配置文件的一般信息,请参阅[部署应用程序](/docs/tasks/run-application/run-stateless-application-deployment/),[配置容器](/docs/tasks/configure-pod-container/configure-pod-configmap/),[管理资源](/docs/concepts/cluster-administration/manage-deployment/)。 -Ingress 经常根据 Ingress 控制器使用注释来配置一些选项,例如 [rewrite-target注解](https://github.com/kubernetes/ingress-nginx/blob/master/docs/examples/rewrite/README.md) -不同的[Ingress控制器](/docs/concepts/services-networking/ingress-controllers)支持不同的注释。 -查看文档以供您选择 Ingress 控制器,以了解支持哪些注释。 - -Ingress [spec](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status) 具有配置负载平衡器或代理服务器所需的所有信息。 -最重要的是,它包含与所有传入请求匹配的规则列表。 Ingress 资源仅支持用于定向HTTP流量的规则。 + +### Ingress 规则 +每个 HTTP 规则都包含以下信息: + +* 可选主机。在此示例中,未指定主机,因此该规则适用于通过指定 IP 地址的所有入站 HTTP 通信。如果提供了主机(例如 foo.bar.com),则规则适用于该主机。 +* 路径列表(例如,`/testpath`),每个路径都有一个由 `serviceName` 和 `servicePort` 定义的关联后端。在负载均衡器将流量定向到引用的服务之前,主机和路径都必须匹配传入请求的内容。 +* 后端是[服务文档](/docs/concepts/services-networking/service/)中所述的服务和端口名称的组合。与规则的主机和路径匹配的对 Ingress 的HTTP(和HTTPS)请求将发送到列出的后端。 -### Ingress 规则 + +通常在 Ingress 控制器中配置默认后端,以服务任何不符合规范中路径的请求。 -每个HTTP规则都包含以下信息: -* host 选项。在此示例中,未指定主机,因此该规则适用于通过指定 IP 地址的所有入站 HTTP 通信。 如果提供了 host 地址(例如foo.bar.com),则规则适用于该主机。 -* 路径列表(例如,`/testpath` ),每个路径都有一个由 `serviceName` 和 `servicePort` 定义的关联后端。在负载均衡器将流量定向到引用的服务之前,主机和路径都必须匹配传入请求的内容。 -* 后端是 [服务文档](/docs/concepts/services-networking/service/) 中所述的服务和端口名称的组合。与规则的主机和路径匹配的对 Ingress 的 HTTP 和 HTTPS 请求将发送到列出的后端。 - - +### 默认后端 + +没有规则的 Ingress 将所有流量发送到单个默认后端。默认后端通常是 [Ingress 控制器](/docs/concepts/services-networking/ingress-controllers)的配置选项,并且未在 Ingress 资源中指定。 + - -### 默认后端 - -没有设定规则的 Ingress 将所有流量发送到单个默认后端。 -默认后端通常是 [Ingress控制器](/docs/concepts/services-networking/ingress-controllers) 的配置选项,并且未在Ingress资源中指定。 - 如果没有主机或路径与 Ingress 对象中的 HTTP 请求匹配,则流量将路由到您的默认后端。 +Ingress 类型 + +### 单服务 Ingress + - -## Ingress 的类型 - -### 单服务 Ingress - -现有的 Kubernetes 概念允许您暴露单个 Service (查看 [替代方案](#alternatives)), -同样您也可以使用 Ingress 来实现,具体方法是指定一个没有规则的 *默认后端(default backend)*。 - +现有的 Kubernetes 概念允许您暴露单个 Service (查看[替代方案](#alternatives)),您也可以通过指定无规则的 *默认后端* 来对 Ingress 进行此操作。 {{< codenew file="service/networking/ingress.yaml" >}} - - -如果使用 `kubectl apply -f` 创建它,则应该能够查看刚刚添加的Ingress的状态: - +如果使用 `kubectl apply -f` 创建它,则应该能够查看刚刚添加的 Ingress 的状态: ```shell kubectl get ingress test-ingress @@ -250,12 +264,20 @@ NAME HOSTS ADDRESS PORTS AGE test-ingress * 107.178.254.228 80 59s ``` - +其中 `107.178.254.228` 是由 Ingress 控制器分配以满足该 Ingress 的 IP。 -其中 `107.178.254.228` 是 Ingress 控制器为该 Ingress 分配的 IP 该。 +{{< note >}} + +Ingress 控制器和负载均衡器可能需要一两分钟才能分配 IP 地址。 +在此之前,您通常会看到地址为 ``。 +{{< /note >}} {{< note >}} @@ -268,16 +290,16 @@ Until that time, you often see the address listed as ``. +### 简单分列 + - -### 简单分列 - -分列配置根据请求的 HTTP URI 将流量从单个IP地址路由到多个服务。 -通过Ingress,您可以将负载均衡器的数量保持在最低水平。 例如,如下设置: +一个分列配置根据请求的 HTTP URI 将流量从单个 IP 地址路由到多个服务。 +Ingress 允许您将负载均衡器的数量降至最低。例如,这样的设置: ```none foo.bar.com -> 178.91.123.132 -> / foo service1:4200 @@ -287,8 +309,7 @@ foo.bar.com -> 178.91.123.132 -> / foo service1:4200 - -可能需要一个 Ingress 就像: +将需要一个 Ingress,例如: ```yaml apiVersion: networking.k8s.io/v1beta1 @@ -315,13 +336,8 @@ spec: - 当您使用 `kubectl apply -f` 创建 Ingress 时: -```shell -kubectl describe ingress test -``` - ```shell kubectl describe ingress simple-fanout-example ``` @@ -352,8 +368,8 @@ When it has done so, you can see the address of the load balancer at the Address field. --> -Ingress 控制器提供实现特定的负载均衡器来满足 Ingress,只要 Service (`service1`, `service2`) 存在。 -当它这样做了,你会在地址栏看到负载平衡器的地址。 +Ingress 控制器将提供实现特定的负载均衡器来满足 Ingress,只要 Service (`s1`,`s2`) 存在。 +当它这样做了,你会在地址栏看到负载均衡器的地址。 {{< note >}} @@ -362,20 +378,18 @@ Depending on the [Ingress controller](/docs/concepts/services-networking/ingress you are using, you may need to create a default-http-backend [Service](/docs/concepts/services-networking/service/). --> - -取决于你使用的 [Ingress 控制器](/docs/concepts/services-networking/ingress-controllers), -您可能需要创建一个默认的 http-backend [Service](/docs/concepts/services-networking/service/).。 +根据您使用的 [Ingress 控制器](/docs/concepts/services-networking/ingress-controllers),您可能需要创建默认 HTTP 后端 [Service](/docs/concepts/services-networking/service/)。 {{< /note >}} - ### 基于名称的虚拟托管 + 基于名称的虚拟主机支持将 HTTP 流量路由到同一 IP 地址上的多个主机名。 ```none @@ -389,8 +403,7 @@ bar.foo.com --| |-> bar.foo.com service2:80 The following Ingress tells the backing load balancer to route requests based on the [Host header](https://tools.ietf.org/html/rfc7230#section-5.4). --> - -下面的 Ingress 让后台的负载均衡器基于 [Host header](https://tools.ietf.org/html/rfc7230#section-5.4) 路由请求。 +以下 Ingress 让后台负载均衡器基于[主机 header](https://tools.ietf.org/html/rfc7230#section-5.4) 路由请求。 ```yaml apiVersion: networking.k8s.io/v1beta1 @@ -413,21 +426,20 @@ spec: servicePort: 80 ``` - +如果您创建的 Ingress 资源没有规则中定义的任何主机,则可以匹配到您 Ingress 控制器 IP 地址的任何网络流量,而无需基于名称的虚拟主机。 + - -如果您在规则中未定义任何主机的情况下创建 Ingress 资源,则可以匹配到 Ingress 控制器 IP 地址的任何网络流量,而无需基于名称的虚拟主机。 - -例如,以下Ingress资源会将 `first.bar.com` 请求的流量路由到 `service1`,将 `second.foo.com` 请求的流量路由到 `service2`, -而所有到IP地址但未在请求中定义主机名的流量 (也就是说,不向 `service3` 提供请求报文头)。 +例如,以下 Ingress 资源会将 `first.bar.com` 请求的流量路由到 `service1`,将 `second.foo.com` 请求的流量路由到 `service2`,而没有在请求中定义主机名的 IP 地址的流量路由(即,不提供请求标头)到 `service3`。 ```yaml apiVersion: networking.k8s.io/v1beta1 @@ -457,7 +469,11 @@ spec: +### TLS + + -### TLS +您可以通过指定包含 TLS 私钥和证书的 secret {{< glossary_tooltip term_id="secret" >}} 来加密 Ingress。 +目前,Ingress 只支持单个 TLS 端口 443,并假定 TLS 终止。 -您可以通过指定包含TLS私钥和证书的 {{< glossary_tooltip term_id="secret" >}} 来加密 Ingress。 -目前,Ingress 只支持单个 TLS 端口,443,并假定 TLS 终止。 如果 Ingress 中的 TLS 配置部分指定了不同的主机,那么它们将根据通过 SNI TLS 扩展指定的主机名(如果 Ingress 控制器支持 SNI)在同一端口上进行复用。 TLS Secret 必须包含名为 `tls.crt` 和 `tls.key` 的密钥,这些密钥包含用于 TLS 的证书和私钥,例如: @@ -494,8 +509,7 @@ sure the TLS secret you created came from a certificate that contains a CN for `sslexample.foo.com`. --> -在 Ingress 中引用此秘钥会告诉 Ingress 控制器使用 TLS 保护从客户端到负载均衡器的通道。 -您需要确保创建包含 `sslexample.foo.com` 的 TLS 秘钥的 CN 的证书。 +在 Ingress 中引用此 Secret 将会告诉 Ingress 控制器使用 TLS 加密从客户端到负载均衡器的通道。您需要确保创建的 TLS secret 来自包含 `sslexample.foo.com` 的 CN 的证书。 ```yaml apiVersion: networking.k8s.io/v1beta1 @@ -518,7 +532,9 @@ spec: ``` {{< note >}} - -各种 Ingress 控制器所支持的 TLS 功能之间存在间隙。请参阅有关文件 -[nginx](https://git.k8s.io/ingress-nginx/README.md#https), -[GCE](https://git.k8s.io/ingress-gce/README.md#frontend-https), -或任何其他平台特定的 Ingress 控制器,以了解 TLS 如何在您的环境中工作。 +各种 Ingress 控制器所支持的 TLS 功能之间存在差异。请参阅有关文件 +[nginx](https://git.k8s.io/ingress-nginx/README.md#https)、 +[GCE](https://git.k8s.io/ingress-gce/README.md#frontend-https) 或者任何其他平台特定的 Ingress 控制器,以了解 TLS 如何在您的环境中工作。 + {{< /note >}} +### 负载均衡 + -### 负载均衡 - -Ingress 控制器使用一些适用于所有 Ingress 的负载均衡策略设置进行自举,例如负载平衡算法、后端权重方案等。 -更高级的负载平衡概念(例如,持久会话、动态权重)尚未通过 Ingress 公开。 -您可以通过用于服务的负载平衡器来获取这些功能。 +Ingress 控制器使用一些适用于所有 Ingress 的负载均衡策略设置进行自举,例如负载均衡算法、后端权重方案和其他等。更高级的负载均衡概念(例如,持久会话、动态权重)尚未通过 Ingress 公开。您可以通过用于服务的负载均衡器来获取这些功能。 - 值得注意的是,即使健康检查不是通过 Ingress 直接暴露的,但是在 Kubernetes 中存在并行概念,比如 [就绪检查](/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/),它允许您实现相同的最终结果。 -请检查控制器说明文档,以了解他们是怎样实现健康检查的 ( +请检查控制器特殊说明文档,以了解他们是怎样处理健康检查的 ( [nginx](https://git.k8s.io/ingress-nginx/README.md), [GCE](https://git.k8s.io/ingress-gce/README.md#health-checks))。 - ## 更新 Ingress -假设您想向现有的 Ingress 中添加新主机,可以通过编辑资源来更新它: + +要更新现有的 Ingress 以添加新的 Host,可以通过编辑资源来对其进行更新: ```shell kubectl describe ingress test @@ -606,7 +620,8 @@ This pops up an editor with the existing configuration in YAML format. Modify it to include the new Host: --> -弹出一个编辑器用于编辑现有的 yaml,修改它来增加新的主机: +这将弹出具有 YAML 格式的现有配置的编辑器。 +修改它来增加新的主机: ```yaml spec: @@ -631,13 +646,13 @@ spec: +保存更改后,kubectl 将更新 API 服务器中的资源,该资源将告诉 Ingress 控制器重新配置负载均衡器。 + - -保存更改后,kubectl 将更新 API 服务器中的资源,该资源将告诉 Ingress 控制器重新配置负载平衡器。 - -验证一下: +验证: ```shell kubectl describe ingress test @@ -667,63 +682,59 @@ Events: - -您可以通过 `kubectl replace -f` 命令调用修改后的 Ingress YAML 文件来获得同样的结果。 +您可以通过 `kubectl replace -f` 命令调用修改后的 Ingress yaml 文件来获得同样的结果。 +## 跨可用区失败 + - -## 跨可用区失败 - -用于跨故障域传播流量的技术在云提供商之间是不同的。详情请查阅相关 Ingress 控制器的文档。 -请查看相关[Ingress控制器](/docs/concepts/services-networking/ingress-controllers)的文档以了解详细信息。 -您还可以参考[联合文档](/docs/concepts/cluster-administration/federation/),以获取有关在联合群集中部署Ingress的详细信息。 +云提供商之间跨故障域分配流量的技术有所不同。详情请查阅相关 [Ingress 控制器](/docs/concepts/services-networking/ingress-controllers)的文档。 +有关在联邦集群中部署 Ingress 的详细信息,请参阅[联邦文档](/docs/concepts/cluster-administration/federation/)。 +## 未来工作 + - -## 未来的工作 - -跟踪 [SIG网络](https://github.com/kubernetes/community/tree/master/sig-network) 详细了解Ingress和相关资源的发展。 -您也可以跟踪 [Ingress信息库](https://github.com/kubernetes/ingress/tree/master) 了解 Ingress 控制器进化的更多信息。 +跟踪 [SIG 网络](https://github.com/kubernetes/community/tree/master/sig-network)以获得有关 Ingress 和相关资源演变的更多细节。您还可以跟踪 [Ingress 仓库](https://github.com/kubernetes/ingress/tree/master)以获取有关各种 Ingress 控制器的更多细节。 +## 替代方案 + +不直接使用 Ingress 资源,也有多种方法暴露 Service: + - -## 替代方案 - -不直接使用 Ingress 资源,也有多种方法暴露 Service: - * 使用 [Service.Type=LoadBalancer](/docs/concepts/services-networking/service/#loadbalancer) * 使用 [Service.Type=NodePort](/docs/concepts/services-networking/service/#nodeport) {{% /capture %}} {{% capture whatsnext %}} - -* 了解 [ingress 控制器](/docs/concepts/services-networking/ingress-controllers/) -* [使用NGINX控制器在Minikube上设置Ingress](/docs/tasks/access-application-cluster/ingress-minikube) +* 了解更多 [ingress 控制器](/docs/concepts/services-networking/ingress-controllers/) +* [使用 NGINX 控制器在 Minikube 上安装 Ingress](/docs/tasks/access-application-cluster/ingress-minikube) {{% /capture %}} - diff --git a/content/zh/docs/concepts/services-networking/service.md b/content/zh/docs/concepts/services-networking/service.md index 0915c40d75..0b304d7b82 100644 --- a/content/zh/docs/concepts/services-networking/service.md +++ b/content/zh/docs/concepts/services-networking/service.md @@ -1,5 +1,7 @@ --- -title: Service +reviewers: +- bprashanth +title: Services feature: title: 服务发现与负载均衡 description: > @@ -9,6 +11,20 @@ content_template: templates/concept weight: 10 --- + {{% capture overview %}} @@ -350,9 +366,9 @@ There are a few reasons for using proxying for Services: 使用服务代理有以下几个原因: -  * DNS 实现的历史由来已久,它不遵守记录 TTL,并且在名称查找结果到期后对其进行缓存。 -  * 有些应用程序仅执行一次 DNS 查找,并无限期地缓存结果。 -  * 即使应用和库进行了适当的重新解析,DNS 记录上的 TTL 值低或为零也可能会给 DNS 带来高负载,从而使管理变得困难。 + * DNS 实现的历史由来已久,它不遵守记录 TTL,并且在名称查找结果到期后对其进行缓存。 + * 有些应用程序仅执行一次 DNS 查找,并无限期地缓存结果。 + * 即使应用和库进行了适当的重新解析,DNS 记录上的 TTL 值低或为零也可能会给 DNS 带来高负载,从而使管理变得困难。 diff --git a/content/zh/docs/concepts/storage/dynamic-provisioning.md b/content/zh/docs/concepts/storage/dynamic-provisioning.md index 12c808053a..acce335669 100644 --- a/content/zh/docs/concepts/storage/dynamic-provisioning.md +++ b/content/zh/docs/concepts/storage/dynamic-provisioning.md @@ -3,6 +3,18 @@ title: 动态卷供应 content_template: templates/concept weight: 40 --- + {{% capture overview %}} diff --git a/content/zh/docs/concepts/storage/storage-classes.md b/content/zh/docs/concepts/storage/storage-classes.md index cbff001739..f51e62160a 100644 --- a/content/zh/docs/concepts/storage/storage-classes.md +++ b/content/zh/docs/concepts/storage/storage-classes.md @@ -431,7 +431,6 @@ parameters: type: pd-standard replication-type: none ``` - - * `userSecretNamespace`:`userSecretName` 的命名空间。 * `fsType`:Kubernetes 支持的 fsType。默认:`"ext4"`。 * `imageFormat`:Ceph RBD 镜像格式,"1" 或者 "2"。默认值是 "1"。 @@ -836,7 +833,6 @@ parameters: * `adminSecretNamespace`: The namespace for `adminSecretName`. Default is "default". --> - * `quobyteAPIServer`:Quobyte API 服务器的格式是 `"http(s)://api-server:7860"` * `registry`:用于挂载卷的 Quobyte registry。你可以指定 registry 为 ``:`` @@ -868,7 +864,6 @@ parameters: --type="kubernetes.io/quobyte" --from-literal=key='opensesame' \ --namespace=kube-system ``` - + {{% capture overview %}} - - + 此页面描述了各个云供应商可关联至一个节点的最大卷数。 - +waiting for volumes to attach. --> -谷歌、亚马逊和微软等云供应商通常对可以关联到节点的卷数量进行限制。 +谷歌、亚马逊和微软等云供应商通常对可以关联到节点的卷数量进行限制。 Kubernetes 需要尊重这些限制。 否则,在节点上调度的 Pod 可能会卡住去等待卷的关联。 + + {{% /capture %}} {{% capture body %}} diff --git a/content/zh/docs/concepts/storage/volume-pvc-datasource.md b/content/zh/docs/concepts/storage/volume-pvc-datasource.md new file mode 100644 index 0000000000..d39e7128eb --- /dev/null +++ b/content/zh/docs/concepts/storage/volume-pvc-datasource.md @@ -0,0 +1,142 @@ +--- +title: CSI 卷克隆 +content_template: templates/concept +weight: 30 +--- + + + +{{% capture overview %}} + +{{< feature-state for_k8s_version="v1.16" state="beta" >}} + + +本文档描述 Kubernetes 中克隆现有 CSI 卷的概念。建议先熟悉[卷](/docs/concepts/storage/volumes)。 + + + +此功能需要启动 VolumePVCDataSource 功能门: + +``` +--feature-gates=VolumePVCDataSource=true +``` + + +{{% /capture %}} + + +{{% capture body %}} + + + +## 介绍 + + + +{{< glossary_tooltip text="CSI" term_id="csi" >}} 卷克隆功能增加了在 `dataSource` 字段指定现有的 {{< glossary_tooltip text="PVC" term_id="persistent-volume-claim" >}}s,来表示用户想要克隆的 {{< glossary_tooltip term_id="volume" >}}。 + + + +克隆定义为已有 Kubernetes 卷的副本,可以像任何标准卷一样被使用。唯一的区别就是配置后,后端设备将创建指定卷的精确副本,而不是创建一个“新的”空卷。 + + + +从 Kubernetes API 的角度看,克隆的实现只是在创建新的 PVC 时,增加了指定一个现有未绑定 PVC 作为数据源的能力。 + + + +用户在使用该功能时,需要注意以下事项: + + + +* 克隆支持(`VolumePVCDataSource`)仅适用于 CSI 驱动。 +* 克隆支持仅适用于 动态供应器。 +* CSI 驱动可能实现,也可能未实现卷克隆功能。 +* 仅当 PVC 与目标 PVC 存在于同一命名空间(源和目标 PVC 必须在相同的命名空间)时,才可以克隆 PVC。 +* 仅在同一存储类中支持克隆。 + - 目标卷必须和源卷具有相同的存储类 + - 可以使用默认的存储类并且 storageClassName 字段在规格中忽略了 + + + + +## 供应 + + + +克隆卷与其他任何 PVC 一样配置,除了需要增加 dataSource 来引用同一命名空间中现有的 PVC。 + +```yaml +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: clone-of-pvc-1 + namespace: myns +spec: + accessModes: + - ReadWriteOnce + storageClassName: cloning + resources: + requests: + storage: 5Gi + dataSource: + kind: PersistentVolumeClaim + name: pvc-1 +``` + + + +结果是一个名称为 `clone-of-pvc-1` 的新 PVC 与指定的源 `pvc-1` 拥有相同的内容。 + + + +## 用法 + + + +一旦新的 PVC 可用,被克隆的 PVC 项其他 PVC 一样被使用。可以预期的是,新创建的 PVC 是一个独立的对象。可以独立使用,克隆,快照或删除它,而不需要考虑它的原始数据源 PVC。这也意味着,源没有以任何方式链接到新创建的 PVC,它也可以被修改或删除,而不会影响到新创建的克隆。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/storage/volume-snapshot-classes.md b/content/zh/docs/concepts/storage/volume-snapshot-classes.md index 67b6e17fe4..eef44967da 100644 --- a/content/zh/docs/concepts/storage/volume-snapshot-classes.md +++ b/content/zh/docs/concepts/storage/volume-snapshot-classes.md @@ -1,7 +1,7 @@ --- title: 卷快照类 content_template: templates/concept -weight: 20 +weight: 30 --- {{% capture overview %}} diff --git a/content/zh/docs/concepts/storage/volume-snapshots.md b/content/zh/docs/concepts/storage/volume-snapshots.md new file mode 100644 index 0000000000..c629370213 --- /dev/null +++ b/content/zh/docs/concepts/storage/volume-snapshots.md @@ -0,0 +1,259 @@ +--- +title: 卷快照 +content_template: templates/concept +weight: 20 +--- + + + +{{% capture overview %}} + +{{< feature-state for_k8s_version="v1.12" state="alpha" >}} + + +本文档描述 Kubernetes 中 `VolumeSnapshots` 的当前状态。建议先熟悉[持久卷](/docs/concepts/storage/persistent-volumes/)。 + +{{% /capture %}} + + +{{% capture body %}} + + + +## 介绍 + + +与 `PersistentVolume` 和 `PersistentVolumeClaim` 两个 API 资源用于给用户和管理员提供卷类似,`VolumeSnapshotContent` 和 `VolumeSnapshot` 两个 API 资源用于给用户和管理员创建卷快照。 + + +`VolumeSnapshotContent` 是从管理员已提供的集群中的卷获取的快照。就像持久卷是集群的资源一样,它也是集群中的资源。 + + +`VolumeSnapshot` 是用户对于卷的快照的请求。它类似于持久卷声明。 + + +`VolumeSnapshots` 允许用户消费抽象的存储资源,集群管理员需要能够提供多种 `VolumeSnapshotContents`,又不会向用户暴露这些应该供应的卷快照的细节。为了实现这些需求,就需要 `VolumeSnapshotClass` 资源。 + + +当使用该功能时,用户需要注意以下几点: + + +* API 对象 `VolumeSnapshot`,`VolumeSnapshotContent` 和 `VolumeSnapshotClass` 是 CRD,不是核心 API 的部分。 +* `VolumeSnapshot` 支持仅可用于 CSI 驱动。 +* 作为部署过程的一部分,Kubernetes 团队为快照控制器提供了一个名为 `external-snapshotter` 的 sidecar 帮助容器。它监视 `VolumeSnapshot` 对象然后向 CSI 端点触发 `CreateSnapshot` 和 `DeleteSnapshot` 操作。 +* CSI 驱动可能实现,也可能没有实现卷快照功能。CSI 驱动可能会使用 `external-snapshotter` 来提供对卷快照的支持。 +* 支持卷快照的 CSI 驱动将自动安装 用于定义卷快照定义的 CRD。 + + +## 卷快照和卷快照内容的生命周期 + + +`VolumeSnapshotContents` 是集群中的资源。`VolumeSnapshots` 是对于这些资源的请求。`VolumeSnapshotContents` 和 `VolumeSnapshots` 之间的交互遵循以下生命周期: + + +### 供应卷快照 + + +快照可以通过两种方式进行供应:静态或动态。 + + +#### 静态的 + +集群管理员创建多个 `VolumeSnapshotContents`。它们带有实际存储的详细信息,可以供集群用户使用。它们存在于 Kubernetes API 中,并且能够被使用。 + + +#### 动态的 + +当管理员创建的静态 `VolumeSnapshotContents` 都不能匹配用户的 `VolumeSnapshot`,集群可能会尝试专门为 `VolumeSnapshot` 对象供应一个卷快照。此供应基于 `VolumeSnapshotClasses`:`VolumeSnapshot` 必须请求[卷快照类](/docs/concepts/storage/volume-snapshot-classes/)并且管理员必须已经创建并配置了该类,才能进行动态供应。 + + +### 绑定 + + +用户创建,或在动态供应场景下已经创建了的 `VolumeSnapshot` 具有特定数量的存储请求和特定的访问模式。一个控制循环监视新的 VolumeSnapshots,找到匹配的 VolumeSnapshotContent(如果可能),并把它们绑定到一起。如果 VolumeSnapshotContent 是给动态供应给一个新的VolumeSnapshot,循环将依然绑定 VolumeSnapshotContent 到 VolumeSnapshot。一旦绑定,无论是如何绑定的,`VolumeSnapshot` 绑定都是排他的。VolumeSnapshot 到 VolumeSnapshotContent 的绑定是一对一的映射。 + + +如果不存在匹配的 VolumeSnapshotContent,VolumeSnapshots 将永远保持未绑定状态。当匹配的 VolumeSnapshotContents 可用时,将绑定 VolumeSnapshots。 + + +### 使用保护的持久性卷声明 + + +使用保护的持久性卷声明功能的目的是确保使用中的 PVC API 对象不会从系统中被删除(因为这可能会导致数据丢失)。 + + +如果一个 PVC 正在被快照用来作为源进行快照创建,则该 PVC 是使用中的。如果用户删除正作为快照源的 PVC API 对象,则 PVC 对象不会立即被删除掉。相反,PVC 对象的删除将推迟到任何快照不在主动使用它为止。当快照的 `Status` 中的 `ReadyToUse`值为 `true` 时,PVC 将不再用作快照源。 + + +### 删除 + + +删除操作会从 Kubernetes API 中删除 `VolumeSnapshotContent` 对象,同时删除它在外部基础架构中关联存储资产。 + + +## 卷快照内容 + + +每个 VolumeSnapshotContent 包含一个 spec,用来表示卷快照的规格。 + +```yaml +apiVersion: snapshot.storage.k8s.io/v1alpha1 +kind: VolumeSnapshotContent +metadata: + name: new-snapshot-content-test +spec: + snapshotClassName: csi-hostpath-snapclass + source: + name: pvc-test + kind: PersistentVolumeClaim + volumeSnapshotSource: + csiVolumeSnapshotSource: + creationTime: 1535478900692119403 + driver: csi-hostpath + restoreSize: 10Gi + snapshotHandle: 7bdd0de3-aaeb-11e8-9aae-0242ac110002 +``` + + +### 类 + + +VolumeSnapshotContent 可以具有一个类,该类通过设置 `snapshotClassName` 属性为 [VolumeSnapshotClass](/docs/concepts/storage/volume-snapshot-classes/) 的名称来指定。一个特定类的 VolumeSnapshotContent 只能够绑定到请求该类的 VolumeSnapshots。没有 `snapshotClassName` 的 VolumeSnapshotContent 没有类,并且只能绑定到不要求特定类的 VolumeSnapshots。 + + +## VolumeSnapshots + + +每个 VolumeSnapshot 对象包含 spec 和 status,用来表示卷快照的规格和状态。 + +```yaml +apiVersion: snapshot.storage.k8s.io/v1alpha1 +kind: VolumeSnapshot +metadata: + name: new-snapshot-test +spec: + snapshotClassName: csi-hostpath-snapclass + source: + name: pvc-test + kind: PersistentVolumeClaim +``` + + +### 类 + + +通过使用 `snapshotClassName` 属性来指定 [VolumeSnapshotClass](/docs/concepts/storage/volume-snapshot-classes/) 的名称,卷快照可以请求特定的类。 +只有所请求类(与 VolumeSnapshot 有相同的 `snapshotClassName`)的 VolumeSnapshotContents 才可以绑定到 VolumeSnapshot。 + + +## 从快照供应卷 + + +你可以供应一个新卷,该卷预填充了快照中的数据,在 `持久卷声明` 对象中使用 *dataSource* 字段。 + + +更多详细信息,请参阅 [卷快照和从快照还原卷](/docs/concepts/storage/persistent-volumes/#volume-snapshot-and-restore-volume-from-snapshot-support)。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/storage/volumes.md b/content/zh/docs/concepts/storage/volumes.md index c438b11bb4..b99cd5545a 100644 --- a/content/zh/docs/concepts/storage/volumes.md +++ b/content/zh/docs/concepts/storage/volumes.md @@ -29,7 +29,7 @@ Kubernetes 抽象出 `Volume` 对象来解决这两个问题。 Familiarity with [Pods](/docs/user-guide/pods) is suggested. --> -阅读本文前建议您熟悉一下 [Pods](/docs/user-guide/pods)。 +阅读本文前建议您熟悉一下 [Pods](/docs/user-guide/pods)。 {{% /capture %}} @@ -728,7 +728,6 @@ spec: pdName: my-data-disk fsType: ext4 ``` - @@ -1322,7 +1321,6 @@ spec: path: my-group/my-password mode: 511 ``` - 或者,如果存在 `MountFlags=slave` 就删除掉。然后重启 Docker 守护进程: diff --git a/content/zh/docs/concepts/workloads/_index.md b/content/zh/docs/concepts/workloads/_index.md index 4e1e785585..850d6b64bd 100644 --- a/content/zh/docs/concepts/workloads/_index.md +++ b/content/zh/docs/concepts/workloads/_index.md @@ -8,4 +8,4 @@ weight: 50 title: "Workloads" weight: 50 --- ---> \ No newline at end of file +--> diff --git a/content/zh/docs/concepts/workloads/controllers/_index.md b/content/zh/docs/concepts/workloads/controllers/_index.md index 87407c0336..21c6b5b903 100644 --- a/content/zh/docs/concepts/workloads/controllers/_index.md +++ b/content/zh/docs/concepts/workloads/controllers/_index.md @@ -1,11 +1,11 @@ +--- +title: "控制器" +weight: 20 +--- + - ---- -title: "控制器" -weight: 20 ---- diff --git a/content/zh/docs/concepts/workloads/controllers/cron-jobs.md b/content/zh/docs/concepts/workloads/controllers/cron-jobs.md index 04a0c44172..7c503c5577 100644 --- a/content/zh/docs/concepts/workloads/controllers/cron-jobs.md +++ b/content/zh/docs/concepts/workloads/controllers/cron-jobs.md @@ -1,53 +1,105 @@ --- -approvers: +reviewers: - erictune - soltysh - janetkuo -title: Cron Job -redirect_from: -- "/docs/concepts/jobs/cron-jobs/" -- "/docs/concepts/jobs/cron-jobs.html" -- "/docs/user-guide/cron-jobs/" -- "/docs/user-guide/cron-jobs.html" +title: CronJob +content_template: templates/concept +weight: 80 --- -{{< toc >}} +{{% capture overview %}} + + + +_Cron Job_ 创建基于时间调度的 [Jobs](/docs/concepts/workloads/controllers/jobs-run-to-completion/)。 + +一个 CronJob 对象就像 _crontab_ (cron table) 文件中的一行。它用 [Cron](https://en.wikipedia.org/wiki/Cron) 格式进行编写,并周期性的在给定的调度时间执行 Job。 + +{{< note >}} + +所有 **CronJob** 的 `schedule:` 时间都是用 UTC 表示。 +{{< /note >}} + + + +有关创建和使用 CronJob 的说明及规范文件的示例,请参见 [使用 CronJob 运行自动任务](/docs/tasks/job/automated-tasks-with-cron-jobs)。 -## Cron Job 是什么? - -_Cron Job_ 管理基于时间的 [Job](/docs/concepts/jobs/run-to-completion-finite-workloads/),即: - -* 在给定时间点只运行一次 -* 在给定时间点周期性地运行 - -一个 CronJob 对象类似于 _crontab_ (cron table)文件中的一行。它根据指定的预定计划周期性地运行一个 Job,格式可以参考 [Cron](https://en.wikipedia.org/wiki/Cron) 。 +{{% /capture %}} +{{% capture body %}} -**注意:** 在预定计划中,问号(`?`)和星号(`*`)的意义是相同的,表示给定字段的取值是任意可用值。 + -典型的用法如下所示: +## CronJob 限制 +CronJob 创建 Job 对象,每个 Job 的执行次数大约为一次。 +我们之所以说 "大约",是因为在某些情况下,可能会创建两个 Job,或者不会创建任何 Job。 +我们试图使这些情况尽量少发生,但不能完全杜绝。因此,Job 应该是 _幂等的_。 + -* 在给定的时间点调度 Job 运行 -* 创建周期性运行的 Job,例如:数据库备份、发送邮件。 +如果 `startingDeadlineSeconds` 设置为很大的数值或未设置(默认),并且 `concurrencyPolicy` 设置为 `Allow`,则作业将始终至少运行一次。 -### 前提条件 + +对于每个 CronJob,CronJob 控制器检查从上一次调度的时间点到现在所错过了调度次数。如果错过的调度次数超过 100 次,那么它就不会启动这个任务,并记录这个错误: +```` +Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew. -当使用的 Kubernetes 集群,版本 >= 1.4(对 ScheduledJob),>= 1.5(对 CronJob),当启动 API Server(参考 [为集群开启或关闭 API 版本](/docs/admin/cluster-management/#turn-on-or-off-an-api-version-for-your-cluster) 获取更多信息)时,通过传递选项 `--runtime-config=batch/v2alpha1=true` 可以开启 batch/v2alpha1 API。 +```` -可选地,使用 `kubectl run` 创建一个 Cron Job,不需要写完整的配置: + -```shell -$ kubectl run hello --schedule="*/1 * * * *" --restart=OnFailure --image=busybox -- /bin/sh -c "date; echo Hello from the Kubernetes cluster" -cronjob "hello" created -``` +需要注意的是,如果设置 `startingDeadlineSeconds` 字段非空,则控制器会统计从 `startingDeadlineSeconds` 的值到现在而不是从上一个计划时间到现在错过了多少次 Job。例如,如果 `startingDeadlineSeconds` 是 `200`,则控制器会统计在过去 200 秒中错过了多少次 Job。 + + + +如果未能在调度时间内创建 CronJob,则计为错过。例如,如果 `concurrencyPolicy` 被设置为 `Forbid`,并且当前有一个调度仍在运行的情况下,试图调度的 CronJob 将被计算为错过。 + + + +例如,假设一个 CronJob 被设置为`08:30:00` 准时开始,它的 `startingDeadlineSeconds` 属性被设置为10,如果在`08:29:00` 时将 CronJob 控制器的时间改为 `08:42:00`,Job 将不会启动。 +如果觉得晚些开始比没有启动好,那请设置一个较长的 `startingDeadlineSeconds`。 + + + +CronJob 只负责创建与其时间表相匹配的 Job,相应的 Job 又会负责管理它所代表的Pod。 创建该 Cron Job 之后,通过如下命令获取它的状态信息: diff --git a/content/zh/docs/concepts/workloads/controllers/daemonset.md b/content/zh/docs/concepts/workloads/controllers/daemonset.md index 2d7a49c509..228d4713ea 100644 --- a/content/zh/docs/concepts/workloads/controllers/daemonset.md +++ b/content/zh/docs/concepts/workloads/controllers/daemonset.md @@ -1,163 +1,415 @@ --- -approvers: +reviewers: +- enisoc - erictune +- foxish +- janetkuo +- kow3ns title: DaemonSet -redirect_from: -- "/docs/admin/daemons/" -- "/docs/admin/daemons.html" +content_template: templates/concept +weight: 50 --- -{{< toc >}} + +{{% capture overview %}} + +_DaemonSet_ 确保全部(或者某些)节点上运行一个 Pod 的副本。当有节点加入集群时, +也会为他们新增一个 Pod 。当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。 -## 什么是 DaemonSet? + - 运行集群存储 daemon,例如在每个节点上运行 `glusterd`、`ceph`。 - 在每个节点上运行日志收集 daemon,例如`fluentd`、`logstash`。 -- 在每个节点上运行监控 daemon,例如 [Prometheus Node Exporter](https://github.com/prometheus/node_exporter)、`collectd`、Datadog 代理、New Relic 代理,或 Ganglia `gmond`。 +- 在每个节点上运行监控 daemon,例如 [Prometheus Node Exporter](https://github.com/prometheus/node_exporter)、[Sysdig 代理](https://sysdigdocs.atlassian.net/wiki/spaces/Platform)、`collectd`、[Dynatrace OneAgent](https://www.dynatrace.com/technologies/kubernetes-monitoring/)、[AppDynamics 代理](https://docs.appdynamics.com/display/CLOUD/Container+Visibility+with+Kubernetes)、[Datadog 代理](https://docs.datadoghq.com/agent/kubernetes/daemonset_setup/)、[New Relic 代理](https://docs.newrelic.com/docs/integrations/kubernetes-integration/installation/kubernetes-installation-configuration),Ganglia `gmond` 或 [Instana 代理](https://www.instana.com/supported-integrations/kubernetes-monitoring/)。 + 一个简单的用法是在所有的节点上都启动一个 DaemonSet,将被作为每种类型的 daemon 使用。 -一个稍微复杂的用法是单独对每种 daemon 类型使用多个 DaemonSet,但具有不同的标志,和/或对不同硬件类型具有不同的内存、CPU要求。 + +一个稍微复杂的用法是单独对每种 daemon 类型使用多个 DaemonSet,但具有不同的标志, +和/或对不同硬件类型具有不同的内存、CPU要求。 + +{{% /capture %}} +{{% capture body %}} -## 编写 DaemonSet 规约 + +## 编写 DaemonSet Spec + +### 创建 DaemonSet + + +您可以在 YAML 文件中描述 DaemonSet。例如,下面的 daemonset.yaml 文件描述了一个运行 fluentd-elasticsearch Docker 镜像的 DaemonSet: + +{{< codenew file="controllers/daemonset.yaml" >}} + +* 基于 YAML 文件创建 DaemonSet: +``` +kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml +``` + + ### 必需字段 - - - -和其它所有 Kubernetes 配置一样,DaemonSet 需要 `apiVersion`、`kind` 和 `metadata` 字段。 -有关配置文件的基本信息,详见文档 [deploying applications](/docs/user-guide/deploying-applications/)、[配置容器](/docs/user-guide/configuring-containers/) 和 [资源管理](/docs/concepts/tools/kubectl/object-management-overview/) 。 +和其它所有 Kubernetes 配置一样,DaemonSet 需要 `apiVersion`、`kind` 和 `metadata` 字段。有关配置文件的基本信息,详见文档 [部署应用](/docs/user-guide/deploying-applications/)、[配置容器](/docs/tasks/) 和 [使用kubectl进行对象管理](/docs/concepts/overview/object-management-kubectl/overview/)。 DaemonSet 也需要一个 [`.spec`](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status) 配置段。 + ### Pod 模板 `.spec` 唯一必需的字段是 `.spec.template`。 - - -`.spec.template` 是一个 [Pod 模板](/docs/user-guide/replication-controller/#pod-template)。 -它与 [Pod](/docs/user-guide/pods) 具有相同的 schema,除了它是嵌套的,而且不具有 `apiVersion` 或 `kind` 字段。 +`.spec.template` 是一个 [Pod 模板](/docs/concepts/workloads/pods/pod-overview/#pod-templates)。它与 [Pod](/docs/concepts/workloads/pods/pod/) 具有相同的 schema,除了它是嵌套的,而且不具有 `apiVersion` 或 `kind` 字段。 除了 Pod 必需字段外,在 DaemonSet 中的 Pod 模板必须指定合理的标签(查看 [Pod Selector](#pod-selector))。 在 DaemonSet 中的 Pod 模板必须具有一个值为 `Always` 的 [`RestartPolicy`](/docs/user-guide/pod-states),或者未指定它的值,默认是 `Always`。 - - + +### Pod Selector {#pod-selector} + +`.spec.selector` 字段表示 Pod Selector,它与 [Job](/docs/concepts/jobs/run-to-completion-finite-workloads/) 的 `.spec.selector` 的作用是相同的。 + +从 Kubernetes 1.8开始,您必须指定与 `.spec.template` 的标签匹配的 pod selector。当不配置时,pod selector 将不再有默认值。selector 默认与 `kubectl apply` 不兼容。 此外,一旦创建了 DaemonSet,它的 `.spec.selector` 就不能修改。修改 pod selector 可能导致成为 孤儿Pod,并且这对用户来说是困惑的。 + + `spec.selector` 表示一个对象,它由如下两个字段组成: * `matchLabels` - 与 [ReplicationController](/docs/concepts/workloads/controllers/replicationcontroller/) 的 `.spec.selector` 的作用相同。 -* `matchExpressions` - 允许构建更加复杂的 Selector,可以通过指定 key、value 列表,以及与 key 和 value 列表相关的操作符。 - - +* `matchExpressions` - 允许构建更加复杂的 Selector,可以通过指定 key、value 列表 +,以及与 key 和 value 列表相关的操作符。 当上述两个字段都指定时,结果表示的是 AND 关系。 -如果指定了 `.spec.selector`,必须与 `.spec.template.metadata.labels` 相匹配。如果没有指定,它们默认是等价的。如果与它们配置的不匹配,则会被 API 拒绝。 - -如果 Pod 的 label 与 selector 匹配,或者直接基于其它的 DaemonSet、或者 Controller(例如 ReplicationController),也不可以创建任何 Pod。 -否则 DaemonSet Controller 将认为那些 Pod 是它创建的。Kubernetes 不会阻止这样做。一个场景是,可能希望在一个具有不同值的、用来测试用的节点上手动创建 Pod。 +如果指定了 `.spec.selector`,必须与 `.spec.template.metadata.labels` 相匹配。如果与它们配置的不匹配,则会被 API 拒绝。 +此外,您通常不应该创建任何 pods,它们的 label 与 selector 匹配,或者直接创建,或者通过另一个 DaemonSet、或者其他控制器,比如 ReplicaSet。否则,DaemonSet 控制器会认为这些 Pod 是由它创建的。Kubernetes 不会阻止你这样做。 您可能希望这样做的一种情况是在节点上手动创建具有不同值的 Pod 以进行测试。 + ### 仅在某些节点上运行 Pod -如果指定了 `.spec.template.spec.nodeSelector`,DaemonSet Controller 将在能够与 [Node Selector](/docs/concepts/configuration/assign-pod-node/) 匹配的节点上创建 Pod。 -类似这种情况,可以指定 `.spec.template.spec.affinity`,然后 DaemonSet Controller 将在能够与 [Node Affinity](/docs/concepts/configuration/assign-pod-node/) 匹配的节点上创建 Pod。 +如果指定了 `.spec.template.spec.nodeSelector`,DaemonSet Controller 将在能够与 [Node Selector](/docs/concepts/configuration/assign-pod-node/) 匹配的节点上创建 Pod。类似这种情况,可以指定 `.spec.template.spec.affinity`,然后 DaemonSet Controller 将在能够与 [node Affinity](/docs/concepts/configuration/assign-pod-node/) 匹配>的节点上创建 Pod。 如果根本就没有指定,则 DaemonSet Controller 将在所有节点上创建 Pod。 + +## 如何调度 Daemon Pods + +### 由 DaemonSet 控制器调度(从v1.12 开始默认禁用) + +正常情况下,Pod 运行在哪个机器上是由 Kubernetes 调度器来选择的。然而,由 DaemonSet Controller 创建的 Pod 已经确定了在哪个机器上(Pod 创建时指定了 `.spec.nodeName`,调度器会忽略它),因此: - DaemonSet Controller 并不关心一个节点的 [`unschedulable`](/docs/admin/node/#manual-node-administration) 字段。 - DaemonSet Controller 可以创建 Pod,即使调度器还没有启动,这对集群启动是非常有帮助的。 + +### 由默认 scheduler 调度(从v1.12开始默认开启) + +{{< feature-state state="beta" for-kubernetes-version="1.12" >}} + +DaemonSet 确保所有符合条件的节点都运行一个 Pod 的副本。通常,运行 Pod 的节点由 Kubernetes scheduler 选择。然而,DaemonSet pods 由 DaemonSet controller 创建和调度。这将引入以下问题: + + * Pod 行为的不一致性:等待调度的正常 Pod 已被创建并处于 `Pending` 状态,但 DaemonSet pods 未在 `Pending` 状态下创建。 这使用户感到困惑。 + * [Pod preemption](/docs/concepts/configuration/pod-priority-preemption/)由默认 scheduler 处理。 启用抢占后,DaemonSet 控制器将在不考虑 pod 优先级和抢占的情况下制定调度决策。 + + +`ScheduleDaemonSetPods` 允许您使用默认 scheduler 而不是 DaemonSet 控制器来调度 DaemonSets,方法是将 `NodeAffinity` 添加到 DaemonSet pods,而不是 `.spec.nodeName`。 然后使用默认 scheduler 将 pod 绑定到目标主机。 如果 DaemonSet pod的亲和节点已存在,则替换它。 DaemonSet 控制器仅在创建或修改 DaemonSet pods 时执行这些操作,并且不对 DaemonSet的 `spec.template` 进行任何更改。 + +```yaml +nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchFields: + - key: metadata.name + operator: In + values: + - target-host-name +``` + + +此外,`node.kubernetes.io/unschedulable:NoSchedule` toleration 会自动添加到 DaemonSet Pods。 在调度DaemonSet Pod 时,默认调度器会忽略 `unschedulable`节点。 + + +### Taints and Tolerations + +尽管 Daemon Pods 尊重[taints and tolerations](/docs/concepts/configuration/taint-and-toleration),根据相关特性,会自动将以下 tolerations 添加到 DaemonSet Pods 中。 + +| Toleration Key | Effect | Version | Description | +| ---------------------------------------- | ---------- | ------- | ------------------------------------------------------------ | +| `node.kubernetes.io/not-ready` | NoExecute | 1.13+ | DaemonSet pods will not be evicted when there are node problems such as a network partition. | +| `node.kubernetes.io/unreachable` | NoExecute | 1.13+ | DaemonSet pods will not be evicted when there are node problems such as a network partition. | +| `node.kubernetes.io/disk-pressure` | NoSchedule | 1.8+ | | +| `node.kubernetes.io/memory-pressure` | NoSchedule | 1.8+ | | +| `node.kubernetes.io/unschedulable` | NoSchedule | 1.12+ | DaemonSet pods tolerate unschedulable attributes by default scheduler. | +| `node.kubernetes.io/network-unavailable` | NoSchedule | 1.12+ | DaemonSet pods, who uses host network, tolerate network-unavailable attributes by default scheduler. | -## 与 Daemon Pod 通信 + +## 与 Daemon Pods 通信 与 DaemonSet 中的 Pod 进行通信,几种可能的模式如下: - **Push**:配置 DaemonSet 中的 Pod 向其它 Service 发送更新,例如统计数据库。它们没有客户端。 -- **NodeIP 和已知端口**:DaemonSet 中的 Pod 可以使用 `hostPort`,从而可以通过节点 IP 访问到 Pod。客户端能通过某种方法知道节点 IP 列表,并且基于此也可以知道端口。 -- **DNS**:创建具有相同 Pod Selector 的 [Headless Service](/docs/user-guide/services/#headless-services),然后通过使用 `endpoints` 资源或从 DNS 检索到多个 A 记录来发现 DaemonSet。 +- **NodeIP 和已知端口**:DaemonSet 中的 Pod 可以使用 `hostPort`,从而可以通过节点 IP 访问到 Pod。客户端能通过某种方法知道节点 IP 列表,并且基于此也可以知道端口 +。 +- **DNS**:创建具有相同 Pod Selector 的 [Headless Service](/docs/concepts/services-networking/service/#headless-services),然后通过使用 `endpoints` 资源或从 DNS 检索到多个 A 记录来发现 DaemonSet。 - **Service**:创建具有相同 Pod Selector 的 Service,并使用该 Service 随机访问到某个节点上的 daemon(没有办法访问到特定节点)。 + ## 更新 DaemonSet -如果修改了节点标签(Label),DaemonSet 将立刻向新匹配上的节点添加 Pod,同时删除新近不能够匹配的节点上的 Pod。 +如果修改了节点标签(Label),DaemonSet 将立刻向新匹配上的节点添加 Pod,同时删除不能够匹配的节点上的 Pod。 -我们可以修改 DaemonSet 创建的 Pod。然而,不允许对 Pod 的所有字段进行更新。当下次节点(即使具有相同的名称)被创建时,DaemonSet Controller 还会使用最初的模板。 +您可以修改 DaemonSet 创建的 Pod。然而,不允许对 Pod 的所有字段进行更新。当下次 +节点(即使具有相同的名称)被创建时,DaemonSet Controller 还会使用最初的模板。 +您可以删除一个 DaemonSet。如果使用 `kubectl` 并指定 `--cascade=false` 选项,则 Pod 将被保留在节点上。然后可以创建具有不同模板的新 DaemonSet。具有不同模板的新 DaemonSet 将能够通过标签匹配并识别所有已经存在的 Pod。 +如果有任何 Pod 需要替换,则 DaemonSet 根据它的 `updateStrategy` 来替换。 + ## DaemonSet 的可替代选择 ### init 脚本 我们很可能希望直接在一个节点上启动 daemon 进程(例如,使用 `init`、`upstartd`、或 `systemd`)。这非常好,但基于 DaemonSet 来运行这些进程有如下一些好处: - - - 像对待应用程序一样,具备为 daemon 提供监控和管理日志的能力。 + - 为 daemon 和应用程序使用相同的配置语言和工具(如 Pod 模板、`kubectl`)。 -- Kubernetes 未来版本可能会支持对 DaemonSet 创建 Pod 与节点升级工作流进行集成。 + - 在资源受限的容器中运行 daemon,能够增加 daemon 和应用容器的隔离性。然而,这也实现了在容器中运行 daemon,但却不能在 Pod 中运行(例如,直接基于 Docker 启动)。 + ### 裸 Pod -可能要直接创建 Pod,同时指定其运行在特定的节点上。 -然而,DaemonSet 替换了由于任何原因被删除或终止的 Pod,例如节点失败、例行节点维护、内核升级。由于这个原因,我们应该使用 DaemonSet 而不是单独创建 Pod。 - +可能要直接创建 Pod,同时指定其运行在特定的节点上。然而,DaemonSet 替换了由于任何原因被删除或终止的 Pod,例如节点失败、例行节点维护、内核升级。由于这个原因,我们应该使用 DaemonSet 而不是单独创建 Pod。 + ### 静态 Pod 可能需要通过在一个指定目录下编写文件来创建 Pod,该目录受 Kubelet 所监视。这些 Pod 被称为 [静态 Pod](/docs/concepts/cluster-administration/static-pod/)。 -不像 DaemonSet,静态 Pod 不受 kubectl 和其它 Kubernetes API 客户端管理。静态 Pod 不依赖于 apiserver,这使得它们在集群启动的情况下非常有用。 -而且,未来静态 Pod 可能会被废弃掉。 +不像 DaemonSet,静态 Pod 不受 kubectl 和其它 Kubernetes API 客户端管理。静态 Pod 不依赖于 apiserver,这使得它们在集群启动的情况下非常有用。而且,未来静态 Pod 可能会被废弃掉。 + +### Deployments -DaemonSet 与 [Replication Controller](/docs/user-guide/replication-controller) 非常类似,它们都能创建 Pod,这些 Pod 对应的进程都不希望被终止掉(例如,Web 服务器、存储服务器)。 -为无状态的 Service 使用 Replication Controller,比如前端(Frontend)服务,实现对副本的数量进行扩缩容、平滑升级,比之于精确控制 Pod 运行在某个主机上要重要得多。 +DaemonSet 与 [Deployments](/docs/concepts/workloads/controllers/deployment/) 非常类似,它们都能创建 Pod,这些 Pod 对应的进程都不希望被终止掉(例如,Web 服务器、存储服务器)。 +为无状态的 Service 使用 Deployments,比如前端 Frontend 服务,实现对副本的数量进行扩缩容、平滑升级,比基于精确控制 Pod 运行在某个主机上要重要得多。 需要 Pod 副本总是运行在全部或特定主机上,并需要先于其他 Pod 启动,当这被认为非常重要时,应该使用 Daemon Controller。 +{{% /capture %}} diff --git a/content/zh/docs/concepts/workloads/controllers/deployment.md b/content/zh/docs/concepts/workloads/controllers/deployment.md index 102f4e73a8..832b94d620 100644 --- a/content/zh/docs/concepts/workloads/controllers/deployment.md +++ b/content/zh/docs/concepts/workloads/controllers/deployment.md @@ -25,13 +25,43 @@ You should not manage ReplicaSets owned by a Deployment. All the use cases shoul The following are typical use cases for Deployments: -* [Create a Deployment to rollout a ReplicaSet](#creating-a-deployment). The ReplicaSet creates Pods in the background. Check the status of the rollout to see if it succeeds or not. -* [Declare the new state of the Pods](#updating-a-deployment) by updating the PodTemplateSpec of the Deployment. A new ReplicaSet is created and the Deployment manages moving the Pods from the old ReplicaSet to the new one at a controlled rate. Each new ReplicaSet updates the revision of the Deployment. -* [Rollback to an earlier Deployment revision](#rolling-back-a-deployment) if the current state of the Deployment is not stable. Each rollback updates the revision of the Deployment. -* [Scale up the Deployment to facilitate more load.](#scaling-a-deployment) -* [Pause the Deployment](#pausing-and-resuming-a-deployment) to apply multiple fixes to its PodTemplateSpec and then resume it to start a new rollout. -* [Use the status of the Deployment](#deployment-status) as an indicator that a rollout has stuck -* [Clean up older ReplicaSets](#clean-up-policy) that you don't need anymore +- [Use Case](#use-case) +- [Creating a Deployment](#creating-a-deployment) + - [Pod-template-hash label](#pod-template-hash-label) +- [Updating a Deployment](#updating-a-deployment) + - [Rollover (aka multiple updates in-flight)](#rollover-aka-multiple-updates-in-flight) + - [Label selector updates](#label-selector-updates) +- [Rolling Back a Deployment](#rolling-back-a-deployment) + - [Checking Rollout History of a Deployment](#checking-rollout-history-of-a-deployment) + - [Rolling Back to a Previous Revision](#rolling-back-to-a-previous-revision) +- [Scaling a Deployment](#scaling-a-deployment) + - [Proportional scaling](#proportional-scaling) +- [Pausing and Resuming a Deployment](#pausing-and-resuming-a-deployment) +- [Deployment status](#deployment-status) + - [Progressing Deployment](#progressing-deployment) + - [Complete Deployment](#complete-deployment) + - [Failed Deployment](#failed-deployment) + - [Operating on a failed deployment](#operating-on-a-failed-deployment) +- [Clean up Policy](#clean-up-policy) +- [Use Cases](#use-cases) + - [Canary Deployment](#canary-deployment) +- [Writing a Deployment Spec](#writing-a-deployment-spec) + - [Pod Template](#pod-template) + - [Replicas](#replicas) + - [Selector](#selector) + - [Strategy](#strategy) + - [Recreate Deployment](#recreate-deployment) + - [Rolling Update Deployment](#rolling-update-deployment) + - [Max Unavailable](#max-unavailable) + - [Max Surge](#max-surge) + - [Progress Deadline Seconds](#progress-deadline-seconds) + - [Min Ready Seconds](#min-ready-seconds) + - [Rollback To](#rollback-to) + - [Revision](#revision) + - [Revision History Limit](#revision-history-limit) + - [Paused](#paused) +- [Alternative to Deployments](#alternative-to-deployments) + - [kubectl rolling update](#kubectl-rolling-update) ## Creating a Deployment diff --git a/content/zh/docs/concepts/workloads/controllers/garbage-collection.md b/content/zh/docs/concepts/workloads/controllers/garbage-collection.md index 4768cada66..e023a786be 100644 --- a/content/zh/docs/concepts/workloads/controllers/garbage-collection.md +++ b/content/zh/docs/concepts/workloads/controllers/garbage-collection.md @@ -5,52 +5,84 @@ redirect_from: - "/docs/concepts/abstractions/controllers/garbage-collection.html" - "/docs/user-guide/garbage-collection/" - "/docs/user-guide/garbage-collection.html" - content_template: templates/concept --- + + {{% capture overview %}} + - -Kubernetes 垃圾收集器的角色是删除指定的对象,这些对象曾经有但以后不再拥有 Owner 了。 - -**注意**:垃圾收集是 beta 特性,在 Kubernetes 1.4 及以上版本默认启用。 +Kubernetes 垃圾收集器的作用是删除某些曾经拥有所有者(owner)但现在不再拥有所有者的对象。 {{% /capture %}} {{% capture body %}} + + +## 所有者和附属 + +某些 Kubernetes 对象是其它一些对象的所有者。例如,一个 ReplicaSet 是一组 Pod 的所有者。 +具有所有者的对象被称为是所有者的*附属*。 +每个附属对象具有一个指向其所属对象的 `metadata.ownerReferences` 字段。 有时,Kubernetes 会自动设置 `ownerReference` 的值。 例如,当创建一个 ReplicaSet 时,Kubernetes 自动设置 ReplicaSet 中每个 Pod 的 `ownerReference` 字段值。 在 1.6 版本,Kubernetes 会自动为某些对象设置 `ownerReference` 的值,这些对象是由 ReplicationController、ReplicaSet、StatefulSet、DaemonSet 和 Deployment 所创建或管理。 - - - -也可以通过手动设置 `ownerReference` 的值,来指定 Owner 和 Dependent 之间的关系。 +也可以通过手动设置 `ownerReference` 的值,来指定所有者和附属之间的关系。 这里有一个配置文件,表示一个具有 3 个 Pod 的 ReplicaSet: {{< codenew file="controllers/replicaset.yaml" >}} + + 如果创建该 ReplicaSet,然后查看 Pod 的 metadata 字段,能够看到 OwnerReferences 字段: ```shell -kubectl create -f https://k8s.io/docs/concepts/controllers/my-repset.yaml +kubectl apply -f https://k8s.io/examples/controllers/replicaset.yaml kubectl get pods --output=yaml ``` + - -输出显示了 Pod 的 Owner 是名为 my-repset 的 ReplicaSet: +输出显示了 Pod 的所有者是名为 my-repset 的 ReplicaSet: ```shell apiVersion: v1 @@ -58,7 +90,7 @@ kind: Pod metadata: ... ownerReferences: - - apiVersion: extensions/v1beta1 + - apiVersion: apps/v1 controller: true blockOwnerDeletion: true kind: ReplicaSet @@ -67,101 +99,201 @@ metadata: ... ``` +{{< note >}} -## 控制垃圾收集器删除 Dependent + -当删除对象时,可以指定是否该对象的 Dependent 也自动删除掉。 +根据设计,kubernetes 不允许跨命名空间指定所有者。这意味着: + +1)命名空间范围的附属只能在相同的命名空间中指定所有者,并且只能指定集群范围的所有者。 + +2)集群范围的附属只能指定集群范围的所有者,不能指定命名空间范围的。 + +{{< /note >}} + + +## 控制垃圾收集器删除附属者 + +当删除对象时,可以指定是否该对象的附属者也自动删除掉。 自动删除 Dependent 也称为 *级联删除* 。 Kubernetes 中有两种 *级联删除* 的模式:*background* 模式和 *foreground* 模式。 -如果删除对象时,不自动删除它的 Dependent,这些 Dependent 被称作是原对象的 *孤儿* 。 +如果删除对象时,不自动删除它的附属者,这些附属者被称作是原对象的*孤儿* 。 + -在 *foreground 级联删除* 模式下,根对象首先进入 “删除中” 状态。在 “删除中” 状态会有如下的情况: +### 显式级联删除 + +在*显式级联删除*模式下,根对象首先进入 `deletion in progress` 状态。在 `deletion in progress` 状态会有如下的情况: * 对象仍然可以通过 REST API 可见。 * 会设置对象的 `deletionTimestamp` 字段。 - * 对象的 `metadata.finalizers` 字段包含了值 "foregroundDeletion"。 + * 对象的 `metadata.finalizers` 字段包含了值 `foregroundDeletion`。 - 一旦对象被设置为 “删除中” 状态,垃圾收集器会删除对象的所有 Dependent。 - 垃圾收集器在删除了所有 “Blocking” 状态的 Dependent(对象的 `ownerReference.blockOwnerDeletion=true`)之后,它会删除 Owner 对象。 +一旦对象被设置为 `deletion in progress` 状态,垃圾收集器会删除对象的所有附属。 + 垃圾收集器在删除了所有 `Blocking` 状态的附属(对象的 `ownerReference.blockOwnerDeletion=true`)之后,它会删除拥有者对象。 -注意,在 “foreground 删除” 模式下,只有设置了 `ownerReference.blockOwnerDeletion` 值的 Dependent 才能阻止删除 Owner 对象。 -在 Kubernetes 1.7 版本中将增加许可控制器(Admission Controller),基于 Owner 对象上的删除权限来控制用户去设置 `blockOwnerDeletion` 的值为 true,所以未授权的 Dependent 不能够延迟 Owner 对象的删除。 +注意,在 `foregroundDeletion` 模式下,只有设置了 `ownerReference.blockOwnerDeletion` 值的附属者才能阻止删除拥有者对象。 +在 Kubernetes 1.7 版本中将增加准入控制器(Admission Controller),基于拥有者对象上的删除权限来控制用户去设置 `blockOwnerDeletion` 的值为 true,所以未授权的附属者不能够延迟拥有者对象的删除。 如果一个对象的 `ownerReferences` 字段被一个 Controller(例如 Deployment 或 ReplicaSet)设置,`blockOwnerDeletion` 会被自动设置,不需要手动修改这个字段。 + +### 隐式级联删除 + +在 *隐式级联删除除* 模式下,Kubernetes 会立即删除拥有者对象,然后垃圾收集器会在后台删除这些附属。 + + ### 设置级联删除策略 -通过为 Owner 对象设置 `deleteOptions.propagationPolicy` 字段,可以控制级联删除策略。 -可能的取值包括:“orphan”、“Foreground” 或 “Background”。 +通过为拥有者对象设置 `deleteOptions.propagationPolicy` 字段,可以控制级联删除策略。 +可能的取值包括:`orphan`、`Foreground`或`Background`。 对很多 Controller 资源,包括 ReplicationController、ReplicaSet、StatefulSet、DaemonSet 和 Deployment,默认的垃圾收集策略是 `orphan`。 -因此,除非指定其它的垃圾收集策略,否则所有 Dependent 对象使用的都是 `orphan` 策略。 +因此,除非指定其它的垃圾收集策略,否则所有附属对象使用的都是 `orphan` 策略。 下面是一个在后台删除 Dependent 对象的例子: ```shell kubectl proxy --port=8080 -curl -X DELETE localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/my-repset \ --d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Background"}' \ --H "Content-Type: application/json" +curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \ + -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Background"}' \ + -H "Content-Type: application/json" ``` + - -下面是一个在前台删除 Dependent 对象的例子: +下面是一个在前台删除附属对象的例子: ```shell kubectl proxy --port=8080 -curl -X DELETE localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/my-repset \ --d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \ --H "Content-Type: application/json" +curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \ + -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \ + -H "Content-Type: application/json" ``` + -下面是一个孤儿 Dependent 的例子: +这里是一个孤儿附属的例子: ```shell kubectl proxy --port=8080 -curl -X DELETE localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/my-repset \ --d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \ --H "Content-Type: application/json" +curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \ + -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \ + -H "Content-Type: application/json" ``` + kubectl 也支持级联删除。 -通过设置 `--cascade` 为 true,可以使用 kubectl 自动删除 Dependent 对象。 -设置 `--cascade` 为 false,会使 Dependent 对象成为孤儿 Dependent 对象。 -`--cascade` 的默认值是 true。 - -下面是一个例子,使一个 ReplicaSet 的 Dependent 对象成为孤儿 Dependent: +通过设置 `--cascade` 为 `true`,可以使用 kubectl 自动删除附属对象。设置 `--cascade` 为 `false`,会使附属对象成为孤儿附属对象。`--cascade` 的默认值是 true。 +下面是一个例子,使一个 ReplicaSet 的附属对象成为孤儿附属: ```shell kubectl delete replicaset my-repset --cascade=false ``` + + +### Deployment 的其他说明 + +在 1.7 之前的版本中,当在 Deployment 中使用级联删除时,您必须*使用* `propagationPolicy:Foreground`。这样不仅删除所创建的 ReplicaSet,还删除其 Pod。如果不使用这种类型的 `propagationPolicy`,则将只删除 ReplicaSet,而 Pod 被孤立。 + +更多信息,请参考 [kubeadm/#149](https://github.com/kubernetes/kubeadm/issues/149#issuecomment-284766613)。 + + ## 已知的问题 -* 1.7 版本,垃圾收集不支持 [自定义资源](/docs/concepts/api-extension/custom-resources/),比如那些通过 CustomResourceDefinition 新增,或者通过 API server 聚集而成的资源对象。 -[其它已知的问题](https://github.com/kubernetes/kubernetes/issues/26120) +跟踪 [#26120](https://github.com/kubernetes/kubernetes/issues/26120) {{% /capture %}} @@ -169,9 +301,10 @@ kubectl delete replicaset my-repset --cascade=false {{% capture whatsnext %}} +## 控制垃圾收集器删除附属者 +[设计文档 1](https://git.k8s.io/community/contributors/design-proposals/api-machinery/garbage-collection.md) -[设计文档 1](https://git.k8s.io/community/contributors/design-proposals/garbage-collection.md) -[设计文档 2](https://git.k8s.io/community/contributors/design-proposals/synchronous-garbage-collection.md) +[设计文档 2](https://git.k8s.io/community/contributors/design-proposals/api-machinery/synchronous-garbage-collection.md) {{% /capture %}} diff --git a/content/zh/docs/concepts/workloads/controllers/jobs-run-completion.md b/content/zh/docs/concepts/workloads/controllers/jobs-run-completion.md new file mode 100644 index 0000000000..9a59b28fa9 --- /dev/null +++ b/content/zh/docs/concepts/workloads/controllers/jobs-run-completion.md @@ -0,0 +1,868 @@ +--- +title: Job 从运行到完成 +content_template: templates/concept +feature: + title: Batch execution + description: > + In addition to services, Kubernetes can manage your batch and CI workloads, replacing containers that fail, if desired. +weight: 70 +--- + + + +{{% capture overview %}} + + + +Job 创建一个或多个 pod,并且确保指定数量的 pod 成功终止。Pod 成功完成后,Job 将跟踪成功完成的情况。当达到指定的成功完成次数时,任务(即 Job)就完成了。删除 Job 将清除其创建的 pod。 + + + +一种简单的情况时创建一个 Job 对象,以便可靠地运行一个 Pod 来完成。如果第一个 pod 失败了或被删除了(例如,由于节点硬件故障或节点重启),则 Job 对象将启动一个新的 pod。 + + + +也可以使用 Job 去并行运行多个 pod。 + +{{% /capture %}} + + +{{% capture body %}} + + + +## 运行一个 Job 示例 + + + +下面是一个 Job 配置样例。它计算 π 到2000位并将其打印出来。大约需要 10 秒钟才能完成。 + +{{< codenew file="controllers/job.yaml" >}} + + + +可以使用以下命令运行示例: + +```shell +kubectl apply -f https://k8s.io/examples/controllers/job.yaml +``` +``` +job "pi" created +``` + + + +使用 `kubectl` 命令检查 Job 的状态: + +```shell +kubectl describe jobs/pi +``` +``` +Name: pi +Namespace: default +Selector: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495 +Labels: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495 + job-name=pi +Annotations: +Parallelism: 1 +Completions: 1 +Start Time: Tue, 07 Jun 2016 10:56:16 +0200 +Pods Statuses: 0 Running / 1 Succeeded / 0 Failed +Pod Template: + Labels: controller-uid=b1db589a-2c8d-11e6-b324-0209dc45a495 + job-name=pi + Containers: + pi: + Image: perl + Port: + Command: + perl + -Mbignum=bpi + -wle + print bpi(2000) + Environment: + Mounts: + Volumes: +Events: + FirstSeen LastSeen Count From SubobjectPath Type Reason Message + --------- -------- ----- ---- ------------- -------- ------ ------- + 1m 1m 1 {job-controller } Normal SuccessfulCreate Created pod: pi-dtn4q +``` + + + +要查看 Job 的已完成 pod,可以使用 `kubectl get pods` 命令。 + + + +要以机器可读的形式列出属于 Job 的所有 pod,可以使用以下命令: + +```shell +pods=$(kubectl get pods --selector=job-name=pi --output=jsonpath='{.items[*].metadata.name}') +echo $pods +``` +``` +pi-aiw0a +``` + + + +这里,选择器与 Job 的选择器相同。`--output=jsonpath` 选项指定一个表达式来从 pod 返回列表中获取每个 pod 的名称。 + + + +查看其中一个 pod 的标准输出: + +```shell +kubectl logs $pods +``` +The output is similar to this: +```shell +3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901 +``` + + + +## 编写 Job 规范 + + + +和其他 Kubernetes 配置一样,Job 需要 `apiVersion`,`kind` 和 `metadata` 字段。 + + + +Job 也需要 [`.spec` 部分](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status)。 + + + +### Pod 模板 + + + +`.spec.template` 是 `.spec` 中唯一必填字段。 + + + +`.spec.template` 是 [pod 模板](/docs/concepts/workloads/pods/pod-overview/#pod-templates)。它具有与 [pod](/docs/user-guide/pods) 完全相同的架构,只是它是嵌套的并且没有 `apiVersion` 或 `kind`。 + + + +除了 pod 的必填字段,Job 中的 pod 模板还必须指定合适的标签(参考 [pod 选择器](#pod-selector))和适当的重启策略。 + + + +[`RestartPolicy`](/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy) 只能等于 `Never` 或 `OnFailure`。 + + + +### Pod 选择器 + + + +`.spec.selector` 字段是可选的。在大多数场景下不必指定它。请参阅[指定自己的 pod 选择器](#specifying-your-own-pod-selector)。 + + + +### 并行 Job + + + +下面是适合作为 Job 运行的三种主要任务类型: + + + +1. 非并行 Job + - 通常,除非 pod 发生故障,否则仅启动一个 pod。 + - 一旦 pod 成功终止,Job 即完成。 +1. 配置了*固定完成计数*的并行 Job: + - 为 `.spec.completions` 指定一个非零正数值。 + - Job 代表整体任务,并且在 1 到 `.spec.completions` 范围内都有一个 pod 成功完成时,Job 才算完成。 + - **尚未实现:** 每个 pod 都会被传递一个从 1 到 `.spec.completions` 之间的索引值。 +1. 具有*工作队列*的并行 Job: + - 不指定 `.spec.completions` 的话, 默认为 `.spec.parallelism`。 + - Pod 必须在彼此之间或外部服务之间进行协调,来确定每个 pod 该处理什么任务。例如,一个 pod 可以从工作队列中获取一批任务(最多 N 个)。 + - 每个 pod 都可以独立确定其所有对端是否完成,从而确定整个 Job 完成。 + - 当 Job 中的_任何_ pod 成功结束后,不会再创建新的 pod。 + - 一旦至少一个 pod 成功终止并且所有的 pod 都终止了,则 Job 就成功完成了。 + - 一旦 任何 pod 成功退出,其他 pod 都不应该为此任务做任务工作或编写任何输出。它们都应该处在退出过程中。 + + + +对于_非并行_ Job,可以不设置 `.spec.completions` 和 `.spec.parallelism`。两者均未设置时,默认值为 1。 + + + +对于一个_固定完成计数_ Job,应该将 `.spec.completions` 设置为所需的完成数量。`.spec.parallelism` 可以设置,也可以不设置,默认值为 1。 + + + +对于一个_工作队列_ Job,不要设置 `.spec.completions`,并且将 `.spec.parallelism` 设置一个非负整数。 + + + +有关如何使用不同类型 Job 的更多信息,请参考 [Job 模式](#job-patterns)部分。 + + + + +#### 控制并行 + + + +请求的并发数(`.spec.parallelism`)可以设置为任何非负的整数。如果未指定,默认值为 1。如果指定为 0,则 Job 就被有效地暂停直到该配置值增加。 + + + +实际的并发数(在任何时刻运行着的 pod 数量)由于下面的一些原因,可能大于或小于请求的并发数: + + + +- 对于_固定完成计数_ Job,实际上并行运行的 pod 数量不会超过剩余的完成数。更高的 `.spec.parallelism` 值将被优先忽略。 +- 对于_工作队列_ Job,任何 pod 成功之后都不会启动新的 pod。然而,剩余的 pod 可以完成。 +- 如果控制器还没来得及反应。 +- 如果控制器由于任何原因(缺少 `ResourceQuota`,缺少权限等)未能创建 pod,则 pod 数量将少于请求数。 +- 控制器可能会因为同一 Job 中有过多之前失败的 pod,从而限制新的 pod 的创建。 +- 当 pod 优雅关闭时,需要花费一些时间才能停止。 + + + +## 处理 Pod 和容器失败 + + + +Pod 中的容器可能由于多种原因而失败,例如,由于容器中的进程以非零退出码退出,或者容器由于超过内存限制而被杀掉等。如果容器失败发生,并且 `.spec.template.spec.restartPolicy = "OnFailure"`,则 pod 停留在节点上,但是容器会重新运行。因此,你的程序需要处理本地重启的情况,或者指定 `.spec.template.spec.restartPolicy = "Never"`。参阅 [pod 生命周期](/docs/concepts/workloads/pods/pod-lifecycle/#example-states)获取更多关于 `restartPolicy` 的信息。 + + + +由于多种原因,整个 pod 也可能失败,比如,当 pod 从节点上被踢走(节点在升级,重启,被删除等),或者 pod 中的容器失败且设置了 `.spec.template.spec.restartPolicy = "Never"`。当 pod 失败后,Job 控制器将启动一个新的 pod。这意味着你的应用程序需要处理这种情况(应用程序在新的 pod 中重启)。特别是,它需要处理由先前运行引起的临时文件,锁,不完整输出等等。 + + + +请注意,即使你指定了 `.spec.parallelism = 1`,`.spec.completions = 1` 和 `.spec.template.spec.restartPolicy = "Never"`,统一程序有时也会启动两次。 + + + +如果你指定 `.spec.parallelism` 和 `.spec.completions` 配置都大于 1,则可能同时有多个 pod 运行。因此,你的 pod 必须容忍并发。 + + + +### Pod 的退避失败策略 + + + +在某些情况下(配置中的逻辑错误等),你需要在重试一定次数后才使 Job 失败。为此需要设置 `.spec.backoffLimit` 配置值为判断 Job 失败前的重试次数。 退避限制默认设置为 6。与 Job 相关的 pod在失败后,经过一个指数级退避延迟(10 秒,20 秒,40 秒,上限为 6 分钟),由 Job 控制器重新创建。 如果在 Job 的下一次状态检查之前未出现新的失败 pod,则会重置退避计数。 + +{{< note >}} + + +1.12 之前的 Kubernetes 版本仍然存在问题 [#54870](https://github.com/kubernetes/kubernetes/issues/54870) + +{{< /note >}} +{{< note >}} + + +如果你的 Job 外配置了 `restartPolicy = "OnFailure"`,请记住,一旦 Job 达到退避限制,运行在该 Job 的容器将被终止。这会使得调试 Job 的可执行将变得更加困难。我们建议在调试 Job 或使用日志系统时设置 `restartPolicy = "Never"`,以确保失败 Job 的输出不会在不经意间丢失。 +{{< /note >}} + + + +## Job 终止和清理 + + + +当 Job 完成后,不会再创建 pod,但是 pod 也不会被删除。将这些 pod 保留,使你仍然可以查看已完成 pod 的日志来检查错误,警告或其他诊断输出。Job 对象在完成后也同样保留下来,以便你可以查看它的状态。由用户来决定在查看完状态后删除旧的 Job。使用 `kubectl`(例如 `kubectl delete jobs/pi` 或 `kubectl delete -f ./job.yaml` )来删除 Job。当你使用 `kubectl` 删除 Job 后,它所创建的所有 pod 也会被删除。 + + + +默认情况下,除非 pod 失败(`restartPolicy=Never`)或容器错误退出(`restartPolicy=OnFailure`),否则 Job 将不会被中断运行。Job 中断将遵循上面介绍的 `.spec.backoffLimit`。一旦 `.spec.backoffLimit` 达到,Job 将被标记为失败,企鹅别所有正运行的 pod 将被终止。 + + + +终止 Job 的另一种方式是设置有限期限。通过设置 Job 对象的 `.spec.activeDeadlineSeconds` 字段为秒数来达到。`activeDeadlineSeconds` 适用于 Job 存在期间,不管有多少 pod 被创建。一旦 Job 达到 `activeDeadlineSeconds`,所有运行中的 pod将被终止,并且 Job 的状态将变成 `type: Failed` 与 `reason: DeadlineExceeded`。 + + + +请注意,Job 的 `.spec.activeDeadlineSeconds` 配置优先于 `.spec.backoffLimit` 配置。因此,重试一个或多个失败 pod 的 Job 在达到 `activeDeadlineSeconds` 指定的时间限制前,不会部署其他的 pod,即使 `backoffLimit` 尚未达到。 + + + +例子: + +```yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: pi-with-timeout +spec: + backoffLimit: 5 + activeDeadlineSeconds: 100 + template: + spec: + containers: + - name: pi + image: perl + command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] + restartPolicy: Never +``` + + + +请注意,Job 对象中的 Job 规范和 [Pod 模板规范](/docs/concepts/workloads/pods/init-containers/#detailed-behavior)都有 `activeDeadlineSeconds` 字段。确保将此字段设置在适当的层级。 + + + +## 自动清理已完成的 Job + + + +系统中已完成的 Job 通常不再需要。将它们保留在系统中将会给 API 服务器带来压力。如果 Job 由更高级别的控制器管理,比如 [CronJobs](/docs/concepts/workloads/controllers/cron-jobs/),则 Job 可以由 CronJobs 基于指定的基于容量的清理策略来进行清除。 + + + +### 已完成 Job 的 TTL 机制 + +{{< feature-state for_k8s_version="v1.12" state="alpha" >}} + + + +清理已完成 Job(`Complete` 或 `Failed`)的另一个方式是通过使用 [TTL 控制器](/docs/concepts/workloads/controllers/ttlafterfinished/)提供的 TTL 机制,TTL 通过指定 Job 的 `.spec.ttlSecondsAfterFinished` 字段来清理已完成资源。 + + + +当 TTL 控制器清理 Job 时,它将级联删除 Job,即删除它的依赖对象,比如 pod 将和 Job 一起被删除。请注意,当 Job 被删除后,它的生命周期保证,如终结者,将被触发。 + + + +例如: + +```yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: pi-with-ttl +spec: + ttlSecondsAfterFinished: 100 + template: + spec: + containers: + - name: pi + image: perl + command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] + restartPolicy: Never +``` + + + +`pi-with-ttl` Job 在完成后 100 秒就会自动删除掉。 + + + +如果该字段设为为 `0`,那么 Job 将在完成后立即被自动删除掉。如果该字段未设置,则 Job 在完成后将不会被 TTL 控制器清理掉。 + + + +请注意,此 TTL 机制处于 alpha 阶段,由 `TTLAfterFinished` 功能门控制是否启动。有关详细信息,请参阅 [TTL 控制器](/docs/concepts/workloads/controllers/ttlafterfinished/)中关于已完成资源的处理。 + + + +## Job 模式 + + + +Job 对象可用于支持 pod 的可靠并行执行。Job 对象并非设计为支持紧密通信的并行过程(常见于科学计算领域)。它被用于支持一组独立但相关的*工作项*的并行处理。这些可能是要发送的电子邮件,要渲染的帧,要编码转换的文件,要扫描的 NoSQL 数据库中一段范围内的键等等。 + + + +在复杂的系统中,可能会有多个不同的工作项集。这里我们只考虑用户想要一起管理一组工作项 — *批处理任务*。 + + + +并行计算有几种不同的模式,每种都有各自的优缺点。权衡点如下: + + + +- 一个 Job 对象处理一个工作项,还是一个 Job 对象处理所有的工作项。后者适用于有大量工作项的场景。前者在管理大量 Job 对象时会对用户和系统带来一些开销。 +- 创建和工作项数量一样多的 pod,还是一个 pod 处理多个工作项。前者通常对现有代码和容器进行较少的修改。后者更适用于处理大量工作项(理由和前一条的相似)。 +- 几种方法使用工作队列。这需要运行一个队列服务,并对现有的程序和容器进行修改以使其能够使用工作队列。其他方法更容易适应现有的容器化应用程序。 + + + + +权衡总结如下表,第 2 至 4 列对应上面的权衡点。模式名称也是样例和详细描述的链接。 + + + +| 模式 | 单个 Job 对象 | 比工作项更少的 pod? | 使用未修改的 app? | Kube 1.1 中生效? | +| -------------------------------------------------------------------- |:-----------------:|:---------------------------:|:-------------------:|:-------------------:| +| [Job 模板扩展](/docs/tasks/job/parallel-processing-expansion/) | | | ✓ | ✓ | +| [一个项对应一个 pod 的队列](/docs/tasks/job/coarse-parallel-processing-work-queue/) | ✓ | | 有时 | ✓ | +| [具有可变 pod 数量的队列](/docs/tasks/job/fine-parallel-processing-work-queue/) | ✓ | ✓ | | ✓ | +| 具有静态工作分配的单个 Job | ✓ | | ✓ | | + + + +当使用 `.spec.completions` 指定完成数时,由 Job 控制器创建的每个 pod 都有一个相同的 [`规范`](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status)。这意味着一个任务的所有 pod 将有相同的命令行和镜像,相同的卷以及(几乎)相同的环境变量。这些模式通过不同的方式安排 pod 去处理不同的任务。 + + + +下表列出了每种模式下对 `.spec.parallelism` 和 `.spec.completions` 需要做的设置。 + + + + +| 模式 | `.spec.completions` | `.spec.parallelism` | +| -------------------------------------------------------------------- |:-------------------:|:--------------------:| +| [Job 模板扩展](/docs/tasks/job/parallel-processing-expansion/) | 1 | 应该为 1 | +| [一个项对应一个 pod 的队列](/docs/tasks/job/coarse-parallel-processing-work-queue/) | W | 任意 | +| [具有可变 pod 数量的队列](/docs/tasks/job/fine-parallel-processing-work-queue/) | 1 | 任意 | +| 具有静态工作分配的单个 Job | W | 任意 | + + + +## 高级用法 + + + +### 指定你的 pod 选择器 + + + +通常,在创建 Job 对象时,不用指定 `.spec.selector`。系统的默认逻辑会在创建 Job 时添加这个字段。它会选择一个不会和其他 pod 重叠的选择器。 + + + +但是,在某些情况下,你可能需要去覆盖默认设置的选择器。为此,你需要指定 Job 的 `.spec.selector`。 + + + +当设置时需要特别小心。如果你指定的标签选择器不是 Job 的 pod 所独有的,并且匹配到了不相关的 pod,那么不相关 Job 的 pod 可能会被删除,或此 Job 可能将其他 pod 统计为已完成,或者其中一个或两个 Job 可能拒绝创建 pod 或运行完成。如果一个选择了非唯一的选择器,则其他的控制器(比如 ReplicationController)和它的 pod 的行为也将是不可预测的。当指定了 `.spec.selector`,Kubernetes将不会阻止你产生错误。 + + + +下面的例子描述了你想要使用该功能的场景。 + + + +假设 `old` Job 已经在运行了。你想要运行中的 pod 保持运行,但是你想 Job 创建的其他 pod 使用不同的 pod 模板,并使 Job 具有一个新的名称。你不能更新 Job 对象,因为这些字段是不可更新的。因此,你需要删除 `old` 但是_让它的 pod 运行_,可以使用 `kubectl delete jobs/old --cascade=false` 命令。在删除之前,你需要记下它所使用的选择器: + +``` +kubectl get job old -o yaml +``` +``` +kind: Job +metadata: + name: old + ... +spec: + selector: + matchLabels: + controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002 + ... +``` + + + +然后使用新名称 `new` 创建一个新的 Job ,并且显示指定相同的选择器。由于现有的 pod 具有 `controller-uid=a8f3d00d-c6d2-11e5-9f87-42010af00002` 标签,它们也受 `new` Job 的控制。 + + + +由于你不再使用系统通常为你自动生成的选择器,你需要在新的 Job 中指定 `manualSelector: true`。 + +``` +kind: Job +metadata: + name: new + ... +spec: + manualSelector: true + selector: + matchLabels: + controller-uid: a8f3d00d-c6d2-11e5-9f87-42010af00002 + ... +``` + + + +新的 Job 本身将具有一个与 `a8f3d00d-c6d2-11e5-9f87-42010af00002` 不通的 uid。设置 `manualSelector: true` 来告诉系统你知道自己在做什么,并使其允许这种不匹配。 + + + +## 备选方案 + + + +### 裸 pod + + + +当 pod 所在节点重启或发生故障时,pod 将终止并且不会重启。然后,Job 将创建新的 pod 替换终止的 pod。因此,即使你的应用仅需要一个 pod,我们还是推荐使用 Job 而不是裸 pod。 + + + +### 副本控制器 + + + +Job 是[副本控制器](/docs/user-guide/replication-controller)的补充。副本控制器管理预期不会终止的 pod(比如 web 服务器),而 Job 管理预期将会终止的 pod(比如批处理任务)。 + + + +正如在 [Pod 生命周期](/docs/concepts/workloads/pods/pod-lifecycle/)中所讨论的,`Job` *仅*适用于具有 `RestartPolicy` 值为 `OnFailure` 或 `Never` 的 pod。(注意:如果 `RestartPolicy` 未指定,默认值为 `Always`。) + + + +### 单 Job 启动控制 pod + + + +单个 Job 的另一种模式是创建一个创建其他 pod 的 pod,充当这些 pod 的一种自定义控制器。这提供了更大的灵活性,但是入门起来可能有点复杂,并且与 Kubernetes 的集成较少。 + + + +这种模式的一个样例是:一个 Job 启动一个 pod 来运行一个脚本,该脚本依次启动 Spark 主控制器(参阅 [spark 例子](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/spark/README.md)),并运行 spark 驱动,然后进行清理。 + + + +这种方法的优点是整个过程可以获取 Job 对象的完成保证,不是完全控制 pod 的创建以及如何将工作分配给 pod。 + +## Cron Jobs {#cron-jobs} + + + +你可以使用 [`CronJob`](/docs/concepts/workloads/controllers/cron-jobs/) 来创建一个会在指定的时间/日期执行的 Job,类似于 Unix 工具 `cron`。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/workloads/controllers/replicaset.md b/content/zh/docs/concepts/workloads/controllers/replicaset.md new file mode 100644 index 0000000000..8fc47968cb --- /dev/null +++ b/content/zh/docs/concepts/workloads/controllers/replicaset.md @@ -0,0 +1,416 @@ +--- +reviewers: +- Kashomon +- bprashanth +- madhusudancs +title: ReplicaSet +content_template: templates/concept +weight: 10 +--- + +{{% capture overview %}} + + + +ReplicaSet 是下一代的 Replication Controller。 _ReplicaSet_ 和 [_Replication Controller_](/docs/concepts/workloads/controllers/replicationcontroller/) 的唯一区别是选择器的支持。ReplicaSet 支持新的基于集合的选择器需求,这在[标签用户指南](/docs/concepts/overview/working-with-objects/labels/#label-selectors)中有描述。而 Replication Controller 仅支持基于相等选择器的需求。 + +{{% /capture %}} + +{{% capture body %}} + + + +## 怎样使用 ReplicaSet + +大多数支持 Replication Controllers 的[`kubectl`](/docs/user-guide/kubectl/)命令也支持 ReplicaSets。但[`rolling-update`](/docs/reference/generated/kubectl/kubectl-commands#rolling-update) 命令是个例外。如果您想要滚动更新功能请考虑使用 Deployment。[`rolling-update`](/docs/reference/generated/kubectl/kubectl-commands#rolling-update) 命令是必需的,而 Deployment 是声明性的,因此我们建议通过 [`rollout`](/docs/reference/generated/kubectl/kubectl-commands#rollout)命令使用 Deployment。 + +虽然 ReplicaSets 可以独立使用,但今天它主要被[Deployments](/docs/concepts/workloads/controllers/deployment/) 用作协调 Pod 创建、删除和更新的机制。 +当您使用 Deployment 时,您不必担心还要管理它们创建的 ReplicaSet。Deployment 会拥有并管理它们的 ReplicaSet。 + + + +## 什么时候使用 ReplicaSet + +ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。 +然而,Deployment 是一个更高级的概念,它管理 ReplicaSet,并向 Pod 提供声明式的更新以及许多其他有用的功能。 +因此,我们建议使用 Deployment 而不是直接使用 ReplicaSet,除非您需要自定义更新业务流程或根本不需要更新。 + +这实际上意味着,您可能永远不需要操作 ReplicaSet 对象:而是使用 Deployment,并在 spec 部分定义您的应用。 + + +## 示例 + +{{< codenew file="controllers/frontend.yaml" >}} + + + +将此清单保存到 `frontend.yaml` 中,并将其提交到 Kubernetes 集群,应该就能创建 yaml 文件所定义的 ReplicaSet 及其管理的 Pod。 + +```shell +$ kubectl create -f http://k8s.io/examples/controllers/frontend.yaml +replicaset.apps/frontend created +$ kubectl describe rs/frontend +Name: frontend +Namespace: default +Selector: tier=frontend,tier in (frontend) +Labels: app=guestbook + tier=frontend +Annotations: +Replicas: 3 current / 3 desired +Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed +Pod Template: + Labels: app=guestbook + tier=frontend + Containers: + php-redis: + Image: gcr.io/google_samples/gb-frontend:v3 + Port: 80/TCP + Requests: + cpu: 100m + memory: 100Mi + Environment: + GET_HOSTS_FROM: dns + Mounts: + Volumes: +Events: + FirstSeen LastSeen Count From SubobjectPath Type Reason Message + --------- -------- ----- ---- ------------- -------- ------ ------- + 1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-qhloh + 1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-dnjpy + 1m 1m 1 {replicaset-controller } Normal SuccessfulCreate Created pod: frontend-9si5l +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +frontend-9si5l 1/1 Running 0 1m +frontend-dnjpy 1/1 Running 0 1m +frontend-qhloh 1/1 Running 0 1m +``` + + + +## 编写 ReplicaSet Spec + +与所有其他 Kubernetes API 对象一样,ReplicaSet 也需要 `apiVersion`、`kind`、和 `metadata` 字段。有关使用清单的一般信息,请参见 [使用 kubectl 管理对象](/docs/concepts/overview/object-management-kubectl/overview/)。 + +ReplicaSet 也需要 [`.spec`](https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status) 部分。 + + + +### Pod 模版 + +`.spec.template` 是 `.spec` 唯一需要的字段。`.spec.template` 是 [Pod 模版](/docs/concepts/workloads/pods/pod-overview/#pod-templates)。它和 [Pod](/docs/concepts/workloads/pods/pod/) 的语法几乎完全一样,除了它是嵌套的并没有 `apiVersion` 和 `kind`。 + +除了所需的 Pod 字段之外,ReplicaSet 中的 Pod 模板必须指定适当的标签和适当的重启策略。 + +对于标签,请确保不要与其他控制器重叠。更多信息请参考 [Pod 选择器](#pod-selector)。 + +对于 [重启策略](/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy),`.spec.template.spec.restartPolicy` 唯一允许的取值是 `Always`,这也是默认值. + +对于本地容器重新启动,ReplicaSet 委托给了节点上的代理去执行,例如[Kubelet](/docs/admin/kubelet/) 或 Docker 去执行。 + + + +### Pod 选择器 + +`.spec.selector` 字段是[标签选择器](/docs/concepts/overview/working-with-objects/labels/)。ReplicaSet 管理所有标签匹配与标签选择器的 Pod。它不区分自己创建或删除的 Pod 和其他人或进程创建或删除的pod。这允许在不影响运行中的 Pod 的情况下替换副本集。 + +`.spec.template.metadata.labels` 必须匹配 `.spec.selector`,否则它将被 API 拒绝。 + +Kubernetes 1.9 版本中,API 版本 `apps/v1` 中的 ReplicaSet 类型的版本是当前版本并默认开启。API 版本 `apps/v1beta2` 被弃用。 + + + +另外,通常您不应该创建标签与此选择器匹配的任何 Pod,或者直接与另一个 ReplicaSet 或另一个控制器(如 Deployment)标签匹配的任何 Pod。 +如果你这样做,ReplicaSet 会认为它创造了其他 Pod。Kubernetes 并不会阻止您这样做。 + +如果您最终使用了多个具有重叠选择器的控制器,则必须自己负责删除。 + + + +### Replicas + +通过设置 `.spec.replicas` 您可以指定要同时运行多少个 Pod。 +在任何时间运行的 Pod 数量可能高于或低于 `.spec.replicas` 指定的数量,例如在副本刚刚被增加或减少后、或者 Pod 正在被优雅地关闭、以及替换提前开始。 + +如果您没有指定 `.spec.replicas`, 那么默认值为 1。 + + + +## 使用 ReplicaSets 的具体方法 + +### 删除 ReplicaSet 和它的 Pod + +要删除 ReplicaSet 和它的所有 Pod,使用[`kubectl delete`](/docs/reference/generated/kubectl/kubectl-commands#delete) 命令。 +默认情况下,[垃圾收集器](/docs/concepts/workloads/controllers/garbage-collection/) 自动删除所有依赖的 Pod。 + +当使用 REST API 或 `client-go` 库时,您必须在删除选项中将 `propagationPolicy` 设置为 `Background` 或 `Foreground`。例如: + +```shell +kubectl proxy --port=8080 +curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \ +> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \ +> -H "Content-Type: application/json" +``` + + + +### 只删除 ReplicaSet + +您可以只删除 ReplicaSet 而不影响它的 Pod,方法是使用[`kubectl delete`](/docs/reference/generated/kubectl/kubectl-commands#delete) 命令并设置 `--cascade=false` 选项。 + +当使用 REST API 或 `client-go` 库时,您必须将 `propagationPolicy` 设置为 `Orphan`。例如: + +```shell +kubectl proxy --port=8080 +curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \ +> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \ +> -H "Content-Type: application/json" +``` + + + +一旦删除了原来的 ReplicaSet,就可以创建一个新的来替换它。 +由于新旧 ReplicaSet 的 `.spec.selector` 是相同的,新的 ReplicaSet 将接管老的 Pod。 +但是,它不会努力使现有的 Pod 与新的、不同的 Pod 模板匹配。 +若想要以可控的方式将 Pod 更新到新的 spec,就要使用 [滚动更新](#rolling-updates)的方式。 + + + + +### 将 Pod 从 ReplicaSet 中隔离 + +可以通过改变标签来从 ReplicaSet 的目标集中移除 Pod。这种技术可以用来从服务中去除 Pod,以便进行排错、数据恢复等。 +以这种方式移除的 Pod 将被自动替换(假设副本的数量没有改变)。 + + + +### 缩放 RepliaSet + +通过更新 `.spec.replicas` 字段,ReplicaSet 可以被轻松的进行缩放。ReplicaSet 控制器能确保匹配标签选择器的数量的 Pod 是可用的和可操作的。 + + + +### ReplicaSet 作为水平的 Pod 自动缩放器目标 + +ReplicaSet 也可以作为 [水平的 Pod 缩放器 (HPA)](/docs/tasks/run-application/horizontal-pod-autoscale/) 的目标。也就是说,ReplicaSet 可以被 HPA 自动缩放。 +以下是 HPA 以我们在前一个示例中创建的副本集为目标的示例。 + + +{{< codenew file="controllers/hpa-rs.yaml" >}} + + + +将这个列表保存到 `hpa-rs.yaml` 并提交到 Kubernetes 集群,就能创建它所定义的 HPA,进而就能根据复制的 Pod 的 CPU 利用率对目标 ReplicaSet进行自动缩放。 + +```shell +kubectl create -f https://k8s.io/examples/controllers/hpa-rs.yaml +``` + + + +或者,可以使用 `kubectl autoscale` 命令完成相同的操作。 +(而且它更简单!) + +```shell +kubectl autoscale rs frontend +``` + + + +## ReplicaSet 的替代方案 + +### Deployment (推荐) + +[`Deployment`](/docs/concepts/workloads/controllers/deployment/) 是一个高级 API 对象,它以 `kubectl rolling-update` 的方式更新其底层副本集及其Pod。 +如果您需要滚动更新功能,建议使用 Deployment,因为 Deployment 与 `kubectl rolling-update` 不同的是:它是声明式的、服务器端的、并且具有其他特性。 +有关使用 Deployment 来运行无状态应用的更多信息,请参阅 [使用 Deployment 运行无状态应用](/docs/tasks/run-application/run-stateless-application-deployment/)。 + + + +### 裸 Pod + +与用户直接创建 Pod 的情况不同,ReplicaSet 会替换那些由于某些原因被删除或被终止的 Pod,例如在节点故障或破坏性的节点维护(如内核升级)的情况下。 +因为这个好处,我们建议您使用 ReplicaSet,即使应用程序只需要一个 Pod。 +想像一下,ReplicaSet 类似于进程监视器,只不过它在多个节点上监视多个 Pod,而不是在单个节点上监视单个进程。 +ReplicaSet 将本地容器重启的任务委托给了节点上的某个代理(例如,Kubelet 或 Docker)去完成。 + + + +### Job + +使用[`Job`](/docs/concepts/jobs/run-to-completion-finite-workloads/) 代替ReplicaSet,可以用于那些期望自行终止的 Pod。 + + + +### DaemonSet + +对于管理那些提供主机级别功能(如主机监控和主机日志)的容器,就要用[`DaemonSet`](/docs/concepts/workloads/controllers/daemonset/) 而不用 ReplicaSet。 +这些 Pod 的寿命与主机寿命有关:这些 Pod 需要先于主机上的其他 Pod 运行,并且在机器准备重新启动/关闭时安全地终止。 + +{{% /capture %}} + diff --git a/content/zh/docs/concepts/workloads/controllers/replicationcontroller.md b/content/zh/docs/concepts/workloads/controllers/replicationcontroller.md new file mode 100644 index 0000000000..94b125b690 --- /dev/null +++ b/content/zh/docs/concepts/workloads/controllers/replicationcontroller.md @@ -0,0 +1,546 @@ +--- +title: ReplicationController +feature: + title: 自我修复 + anchor: ReplicationController 如何工作 + description: > + 重新启动失败的容器,在节点死亡时替换并重新调度容器,杀死不响应用户定义的健康检查的容器,并且在它们准备好服务之前不会它们公布给客户端。 + +content_template: templates/concept +weight: 20 +--- + + +{{% capture overview %}} + +{{< note >}} + +现在推荐使用配置 [`ReplicaSet`](/docs/concepts/workloads/controllers/replicaset/) 的 [`Deployment`](/docs/concepts/workloads/controllers/deployment/) 来建立副本管理机制。 +{{< /note >}} + + +_ReplicationController_ 确保在任何时候都有特定数量的 pod 副本处于运行状态。 +换句话说,ReplicationController 确保一个 pod 或一组同类的 pod 总是可用的。 +{{% /capture %}} + + +{{% capture body %}} + + +## ReplicationController 如何工作 + +当 pods 数量过多时,ReplicationController 会终止多余的 pods。当 pods 数量太少时,ReplicationController 将会启动新的 pods。 +与手动创建的 pod 不同,由 ReplicationController 创建的 pods 在失败、被删除或被终止时会被自动替换。 +例如,在中断性维护(如内核升级)之后,您的 pod 会在节点上重新创建。 +因此,即使您的应用程序只需要一个 pod,您也应该使用一个 ReplicationController。 +ReplicationController 类似于进程管理器,但是 ReplicationController 不是监控单个节点上的单个进程,而是监控跨多个节点的多个 pods。 + +在讨论中,ReplicationController 通常缩写为 "rc" 或 "rcs",并作为 kubectl 命令的快捷方式。 + +一个简单的例子是创建一个 ReplicationController 对象来可靠地无限期地运行 Pod 的一个实例。 +更复杂的用例是运行一个多副本服务(如 web 服务器)的若干相同副本。 + + +## 运行一个示例 ReplicationController + +这个示例 ReplicationController 配置运行 nginx web 服务器的三个副本。 + +{{< codenew file="controllers/replication.yaml" >}} + + +通过下载示例文件并运行以下命令来运行示例任务: + +```shell +kubectl apply -f https://k8s.io/examples/controllers/replication.yaml +``` +``` +replicationcontroller/nginx created +``` + + +使用以下命令检查 ReplicationController 的状态: + +```shell +kubectl describe replicationcontrollers/nginx +``` +``` +Name: nginx +Namespace: default +Selector: app=nginx +Labels: app=nginx +Annotations: +Replicas: 3 current / 3 desired +Pods Status: 0 Running / 3 Waiting / 0 Succeeded / 0 Failed +Pod Template: + Labels: app=nginx + Containers: + nginx: + Image: nginx + Port: 80/TCP + Environment: + Mounts: + Volumes: +Events: + FirstSeen LastSeen Count From SubobjectPath Type Reason Message + --------- -------- ----- ---- ------------- ---- ------ ------- + 20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-qrm3m + 20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-3ntk0 + 20s 20s 1 {replication-controller } Normal SuccessfulCreate Created pod: nginx-4ok8v +``` + + +此时,创建了三个 pod,但是还没有运行,可能正在拉取镜像。 +稍后,相同的命令可能显示: + +```shell +Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed +``` + + +要以机器可读的形式列出属于 ReplicationController 的所有 pod,可以使用如下命令: + +```shell +pods=$(kubectl get pods --selector=app=nginx --output=jsonpath={.items..metadata.name}) +echo $pods +``` +``` +nginx-3ntk0 nginx-4ok8v nginx-qrm3m +``` + + +这里,选择器与 ReplicationController 的选择器相同(参见 `kubectl describe` 输出),并以不同的形式出现在 `replication.yaml` 中。 +`--output=jsonpath` 选项指定了一个表达式,只从返回列表中的每个 pod 中获取名称。 + + +## 编写一个 ReplicationController Spec + +与所有其它 Kubernetes 配置一样,ReplicationController 需要 `apiVersion` ,`kind` 和 `metadata` 字段。 +有关使用配置文件的常规信息,参考[对象管理](/docs/concepts/overview/working-with-objects/object-management/)。 + +ReplicationController 也需要一个 [`.spec` 部分](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status)。 + + +### Pod 模板 + +`.spec.template` 是 `.spec` 的唯一必需字段。 + +`.spec.template` 是一个 [pod 模板](/docs/concepts/workloads/pods/pod-overview/#pod-templates)。它的模式与 [pod](/docs/concepts/workloads/pods/pod/) 完全相同,只是它是嵌套的,并且没有 `apiVersion` 或 `kind`。 + +除了 Pod 所需的字段外,ReplicationController 中的 pod 模板必须指定适当的标签和适当的重新启动策略。 +对于标签,请确保不与其他控制器重叠。参考 [pod 选择器](#pod-选择器)。 + +只允许 [`.spec.template.spec.restartPolicy`](/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy) 等于 `Always`,如果没有指定,这是默认值。 + +对于本地容器重启,ReplicationController 委托给节点上的代理, +例如 [Kubelet](/docs/admin/kubelet/) 或 Docker。 + + +### ReplicationController 上的标签 + +ReplicationController 本身可以有标签 (`.metadata.labels`)。 +通常,您可以将这些设置为 `.spec.template.metadata.labels`; +如果没有指定 `.metadata.labels` 那么它默认为 `.spec.template.metadata.labels`。 +但是,Kubernetes 允许它们是不同的,`.metadata.labels` 不会影响 ReplicationController 的行为。 + + +### Pod 选择器 + +`.spec.selector` 字段是一个[标签选择器](/docs/concepts/overview/working-with-objects/labels/#label-selectors)。 +ReplicationController 管理标签与选择器匹配的所有 Pods。 +它不区分它创建或删除的 pod 以及另一个人或进程创建或删除的 pod。 +这允许在不影响正在运行的 pod 的情况下替换 ReplicationController。 + +如果指定了 `.spec.template.metadata.labels`,它必须和 `.spec.selector` 相同,否则它将被 API 拒绝。 +如果没有指定 `.spec.selector`,它将默认为 `.spec.template.metadata.labels`。 + +此外,用户通常不应创建标签与此选择器匹配的任何其他 Pods,无论是直接创建、使用另一个 ReplicationController 来创建或者别的控制器(如 Job )来创建,都是不允许的。 +如果这样做, ReplicationController 会认为这些 Pods 是由它自己创建的。 +Kubernetes 并没有阻止你这样做。 + +如果您的确创建了多个控制器并且其选择器之间存在重叠,那么您将不得不自己管理删除操作(参考[后文](#使用-replicationcontrollers))。 + + +### 多个副本 + +你可以通过设置 `.spec.replicas` 来指定应该同时运行多少个 Pods。 +在任何时候,处于运行状态的 Pods 个数都可能高于或者低于设定值。例如,副本个数刚刚被增加或减少时,或者一个 pod 处于体面终止过程中而其替代副本已经提前开始创建时。 + +如果你没有指定 `.spec.replicas` ,那么它默认是1。 + + +## 使用 ReplicationController + + +### 删除一个 ReplicationController 以及它的 Pod + +要删除一个 ReplicationController 以及它的 Pod,使用 [`kubectl delete`](/docs/reference/generated/kubectl/kubectl-commands#delete)。 +Kubectl 将 ReplicationController 缩放为0并等待以便在删除 ReplicationController 本身之前删除每个 pod。 +如果这个 kubectl 命令被中断,可以重新启动它。 + +当使用 REST API 或 go 客户端库时,您需要明确地执行这些步骤(缩放副本为0、 等待 Pod 删除,之后删除 ReplicationController 资源)。 + + +### 只删除 ReplicationController + +你可以删除一个 ReplicationController 而不影响它的任何 pod。 + +使用 kubectl ,为 [`kubectl delete`](/docs/reference/generated/kubectl/kubectl-commands#delete) 指定 `--cascade=false` 选项。 + +当使用 REST API 或 go 客户端库时, 只需删除 ReplicationController 对象。 + +一旦原始对象被删除,你可以创建一个新的 ReplicationController 来替换它。 +只要新的和旧的 `.spec.selector` 相同,那么新的控制器将领养旧的 Pods。 +但是,它不会做出任何努力使现有的 pod 匹配新的、不同的 pod 模板。 +如果希望以受控方式更新 Pods 以使用新的 spec,请执行[滚动更新](#滚动更新)操作。 + + +### 从 ReplicationController 中隔离 pod + +通过更改 Pod 的标签,可以从 ReplicationController 的目标中删除 pod。 +此技术可用于从服务中删除 pod 以进行调试、数据恢复等。以这种方式删除的 pod 将自动替换(假设复制副本的数量也没有更改)。 + + +## 常见的使用模式 + + +### 重新调度 + +如上所述,无论您想要继续运行1个 pod 还是1000个,一个 ReplicationController 都将确保存在指定数量的 pod,即使在节点故障或 pod 终止(例如,由于另一个控制代理的操作)的情况下也是如此。 + +### 扩缩容 + +通过简单地更新 `replicas` 字段,ReplicationController 可以方便地横向扩容或缩容副本的数量,或手动或通过自动缩放控制代理。 + + +### 滚动更新 + +ReplicationController 的设计目的是通过逐个替换 pod 以方便滚动更新服务。 + +如[#1353](http://issue.k8s.io/1353)所述,建议的方法是使用1个副本创建一个新的 ReplicationController,逐个缩放新的(+1)和旧的(-1)控制器,然后在旧的控制器达到0个副本后将其删除。这一方法能够实现可控的 Pods 集合更新,即使存在意外失效的状况。 + +理想情况下,滚动更新控制器将考虑应用程序的就绪情况,并确保在任何给定时间都有足够数量的 Pods 有效地提供服务。 + +这两个 ReplicationController 将需要创建至少具有一个不同标签的 pod,比如 pod 主要容器的镜像标签,因为通常是镜像更新触发滚动更新。 + +滚动更新是在客户端工具 +[`kubectl rolling-update`](/docs/reference/generated/kubectl/kubectl-commands#rolling-update)中实现的。 访问 [`kubectl rolling-update` 任务](/docs/tasks/run-application/rolling-update-replication-controller/)以获得更多的具体示例。 + + +### 多个版本跟踪 + +除了在滚动更新过程中运行应用程序的多个版本之外,通常还会使用多个版本跟踪来长时间,甚至持续运行多个版本。这些跟踪将根据标签加以区分。 + +例如,一个服务可能把具有 `tier in (frontend), environment in (prod)` 的所有 pod 作为目标。 +现在假设您有10个副本的 pod 组成了这个层。但是你希望能够'金丝雀部署'这个组件的新版本。 +您可以为大部分副本设置一个 ReplicationController,其中 `replicas` 设置为9,标签为 `tier=frontend, environment=prod, track=stable` 而为 canary 设置另一个 ReplicationController,其中 `replicas` 设置为1,标签为 `tier=frontend, environment=prod, track=canary`。 +现在这个服务覆盖了 canary 和非 canary pod。但您可以单独处理 ReplicationController,以测试、监控结果等。 + + +### 和服务一起使用 ReplicationController + +多个 ReplicationController 可以位于一个服务的后面,例如,一部分流量流向旧版本,一部分流量流向新版本。 + +一个 ReplicationController 永远不会自行终止,但它不会像服务那样长寿。 +服务可以由多个 ReplicationController 控制的 pod 组成,并且在服务的生命周期内(例如,为了执行 pod 更新而运行服务),可以创建和销毁许多 ReplicationController。 +服务本身和它们的客户端都应该忽略负责维护服务 Pod 的 ReplicationController 的存在。 + + +## 编写多副本的应用 + +由 ReplicationController 创建的 Pod 是可替换的,语义上是相同的,尽管随着时间的推移,它们的配置可能会变得异构。 +这显然适合于多副本的无状态服务器,但是 ReplicationController 也可以用于维护主选、分片和工作池应用程序的可用性。 +这样的应用程序应该使用动态的工作分配机制,例如 [RabbitMQ工作队列](https://www.rabbitmq.com/tutorials/tutorial-two-python.html),而不是静态的/一次性定制每个 pod 的配置,这被认为是一种反模式。 +执行的任何 pod 定制,例如资源的垂直自动调整大小(例如,cpu 或内存),都应该由另一个在线控制器进程执行,这与 ReplicationController 本身没什么不同。 + + +## ReplicationController 的职责 + +ReplicationController 只需确保所需的 pod 数量与其标签选择器匹配,并且是可操作的。 +目前,它的计数中只排除终止的 pod。 +未来,可能会考虑系统提供的[就绪状态](http://issue.k8s.io/620)和其他信息,我们可能会对替换策略添加更多控制,我们计划发出事件,这些事件可以被外部客户端用来实现任意复杂的替换和/或缩减策略。 + +ReplicationController 永远被限制在这个狭隘的职责范围内。 +它本身既不执行就绪态探测,也不执行活跃性探测。 +它不负责执行自动缩放,而是由外部自动缩放器控制(如[#492](http://issue.k8s.io/492)中所述),后者负责更改其 `replicas` 字段取值。 +我们不会向 ReplicationController 添加调度策略(例如,[spreading](http://issue.k8s.io/367#issuecomment-48428019))。 +它也不应该验证所控制的 pod 是否与当前指定的模板匹配,因为这会阻碍自动调整大小和其他自动化过程。 +类似地,完成期限、整理依赖关系、配置扩展和其他特性也属于其他地方。 +我们甚至计划考虑批量创建 pod 的机制([#170](http://issue.k8s.io/170))。 + +ReplicationController 旨在成为可组合的构建基元。 +我们希望在它和其他补充原语的基础上构建更高级别的 API 和/或工具,以便于将来的用户使用。 +Kubectl 目前支持的“宏”操作(运行、缩放、滚动更新)就是这方面的概念示例。 +例如,我们可以想象类似于 [Asgard](http://techblog.netflix.com/2012/06/asgaard-web-based-cloud-management-and.html) 的东西管理 ReplicationController、自动定标器、服务、调度策略、 canary 等。 + + +## API 对象 + +在 Kubernetes REST API 中 Replication controller 是顶级资源。 +更多关于 API 对象的详细信息可以在 +[ReplicationController API 对象](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#replicationcontroller-v1-core)找到。 + + +## ReplicationController 的替代方案 + + +### ReplicaSet + +[`ReplicaSet`](/docs/concepts/workloads/controllers/replicaset/) 是下一代 ReplicationController ,支持新的[基于集合的标签选择器](/docs/concepts/overview/working-with-objects/labels/#set-based-requirement)。 +它主要被 [`Deployment`](/docs/concepts/workloads/controllers/deployment/) 用来作为一种编排 pod 创建、删除及更新的机制。 +请注意,我们推荐使用 Deployment 而不是直接使用 ReplicaSet,除非您需要自定义更新编排或根本不需要更新。 + + +### Deployment (推荐) + +[`Deployment`](/docs/concepts/workloads/controllers/deployment/) 是一种更高级别的 API 对象,它以类似于 `kubectl rolling-update` 的方式更新其底层 ReplicaSet 及其 Pod。 +如果您想要这种滚动更新功能,那么推荐使用 Deployment,因为与 `kubectl rolling-update` 不同,它们是声明式的、服务端的,并且具有其它特性。 + + +### 裸 Pods + +与用户直接创建 pod 的情况不同,ReplicationController 能够替换因某些原因被删除或被终止的 pod ,例如在节点故障或中断节点维护的情况下,例如内核升级。 +因此,我们建议您使用 ReplicationController,即使您的应用程序只需要一个 pod。 +可以将其看作类似于进程管理器,它只管理跨多个节点的多个 pod ,而不是单个节点上的单个进程。 +ReplicationController 将本地容器重启委托给节点上的某个代理(例如,Kubelet 或 Docker)。 + + +### Job + +对于预期会自行终止的 pod (即批处理任务),使用 [`Job`](/docs/concepts/jobs/run-to-completion-finite-workloads/) 而不是 ReplicationController。 + + +### DaemonSet + +对于提供机器级功能(例如机器监控或机器日志记录)的 pod ,使用 [`DaemonSet`](/docs/concepts/workloads/controllers/daemonset/) 而不是 ReplicationController。 +这些 pod 的生命期与机器的生命期绑定:它们需要在其他 pod 启动之前在机器上运行,并且在机器准备重新启动/关闭时安全地终止。 + + +## 更多信息 + +请阅读[运行无状态的 Replication Controller](/docs/tutorials/stateless-application/run-stateless-ap-replication-controller/)。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/workloads/controllers/statefulset.md b/content/zh/docs/concepts/workloads/controllers/statefulset.md new file mode 100644 index 0000000000..6638f5cf3e --- /dev/null +++ b/content/zh/docs/concepts/workloads/controllers/statefulset.md @@ -0,0 +1,457 @@ +--- +reviewers: +- enisoc +- erictune +- foxish +- janetkuo +- kow3ns +- smarterclayton +title: StatefulSets +content_template: templates/concept +weight: 40 +--- + + + +{{% capture overview %}} + + + +StatefulSet 是用来管理有状态应用的工作负载 API 对象。 + +{{< note >}} + + +**注意** StatefulSets 是在 1.9 版本中正式发布的。 + +{{< /note >}} + +{{< glossary_definition term_id="statefulset" length="all" >}} +{{% /capture %}} + +{{% capture body %}} + + + +## 使用 StatefulSets + +StatefulSets 对于需要满足以下一个或多个需求的应用程序很有价值: + +* 稳定的、唯一的网络标识符。 +* 稳定的、持久的存储。 +* 有序的、优雅的部署和缩放。 +* 有序的、自动的滚动更新。 + +在上面,稳定意味着 Pod 调度或重调度的整个过程是有持久性的。如果应用程序不需要任何稳定的标识符或有序的部署、删除或伸缩,则应该使用由一组无状态的副本控制器提供的工作负载来部署应用程序,比如 [Deployment](/docs/concepts/workloads/controllers/deployment/) 或者 [ReplicaSet](/docs/concepts/workloads/controllers/replicaset/) 可能更适用于您的无状态需要。 + + + +## 限制 + +* 给定 Pod 的存储必须由 [PersistentVolume 驱动](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/persistent-volume-provisioning/README.md) 基于所请求的 `storage class` 来提供,或者由管理员预先提供。 +* 删除和/或收缩 StatefulSet 并*不会*删除它关联的存储卷。这样做是为了保证数据安全,它通常比自动清除 StatefulSet 所有相关的资源更有价值。 +* StatefulSet 当前需要 [headless 服务](/docs/concepts/services-networking/service/#headless-services) 来负责 Pod 的网络标识。您需要负责创建此服务。 +* 当删除 StatefulSets 时,StatefulSet 不提供任何终止 Pod 的保证。为了实现 StatefulSet 中的 Pod 可以有序和优雅的终止,可以在删除之前将 StatefulSet 缩放为 0。 +* 在默认 [Pod 管理策略](#pod-management-policies)(`OrderedReady`) 时使用 [滚动更新](#rolling-updates),可能进入需要 [人工干预](#forced-rollback) 才能修复的损坏状态。 + + + +## 组件 +下面的示例演示了 StatefulSet 的组件。 + +* 名为 nginx 的无头服务用来控制网络域。 +* 名为 web 的 StatefulSet 有一个 Spec,它表明将在单个 Pod 中启动 nginx 容器的 3 个副本。 +* volumeClaimTemplates 将通过 [PersistentVolumes](/docs/concepts/storage/persistent-volumes/) 驱动提供的 PersistentVolume 来提供稳定的存储。 + + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: nginx + labels: + app: nginx +spec: + ports: + - port: 80 + name: web + clusterIP: None + selector: + app: nginx +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: web +spec: + selector: + matchLabels: + app: nginx # has to match .spec.template.metadata.labels + serviceName: "nginx" + replicas: 3 # by default is 1 + template: + metadata: + labels: + app: nginx # has to match .spec.selector.matchLabels + spec: + terminationGracePeriodSeconds: 10 + containers: + - name: nginx + image: k8s.gcr.io/nginx-slim:0.8 + ports: + - containerPort: 80 + name: web + volumeMounts: + - name: www + mountPath: /usr/share/nginx/html + volumeClaimTemplates: + - metadata: + name: www + spec: + accessModes: [ "ReadWriteOnce" ] + storageClassName: "my-storage-class" + resources: + requests: + storage: 1Gi +``` + + + +## Pod 选择器 +您必须设置 StatefulSet 的 `.spec.selector` 字段来匹配它的`.spec.template.metadata.labels`标签。在 Kubernetes 1.8 版本之前,忽略`.spec.selector` 字段会提供默认设置。在 1.8 和以后的版本中,指定的 Pod 选择器匹配失败将在创建 StatefulSet 期间导致验证错误。 + + + +## Pod 的身份 + +StatefulSet Pod 具有唯一的标识,该标识包括顺序标识、稳定的网络标识和稳定的存储。该标识和 Pod 是绑定的,不管它被调度在哪个节点上。 + + + +### 有序索引 + +对于具有 N 个副本的 StatefulSet,StatefulSet 中的每个 Pod 将被分配一个整数序号,从 0 到 N-1,该序号在 StatefulSet 上是唯一的。 + + + +### 稳定的网络 ID + +StatefulSet 中的每个 Pod 根据 StatefulSet 的名称和 Pod 的序号派生出它的主机名。组合主机名的格式为`$(statefulset name)-$(ordinal)`。上例将会创建三个名称为`web-0,web-1,web-2`的三个 Pod。 +StatefulSet 可以使用 [headless 服务](/docs/concepts/services-networking/service/#headless-services) 控制它的 Pod 的网络域。管理域的这个服务的格式为: +`$(service name).$(namespace).svc.cluster.local`,其中`cluster.local`是集群域。 + 一旦每个 Pod 创建成功,就会得到一个匹配的 DNS 子域,格式为:`$(podname).$(governing service domain)`,其中管理服务由 StatefulSet 的 `serviceName` 域来定义。 + + + + +下面给出一些选择集群域、服务名、StatefulSet 名、及其怎样影响 StatefulSet 的 Pod 上的 DNS 名称的示例: + +Cluster Domain | Service (ns/name) | StatefulSet (ns/name) | StatefulSet Domain | Pod DNS | Pod Hostname | +-------------- | ----------------- | ----------------- | -------------- | ------- | ------------ | + cluster.local | default/nginx | default/web | nginx.default.svc.cluster.local | web-{0..N-1}.nginx.default.svc.cluster.local | web-{0..N-1} | + cluster.local | foo/nginx | foo/web | nginx.foo.svc.cluster.local | web-{0..N-1}.nginx.foo.svc.cluster.local | web-{0..N-1} | + kube.local | foo/nginx | foo/web | nginx.foo.svc.kube.local | web-{0..N-1}.nginx.foo.svc.kube.local | web-{0..N-1} | + +{{< note >}} + + +**注意** 集群域会被设置为 `cluster.local` 除非有[其他配置](/docs/concepts/services-networking/dns-pod-service/#how-it-works)。 + +{{< /note >}} + + + +### 稳定的存储 + +Kubernetes 为每个 VolumeClaimTemplate 创建一个 [PersistentVolume](/docs/concepts/storage/persistent-volumes/)。在上面的 nginx 示例中,每个 Pod 将会得到基于 StorageClass `my-storage-class` 提供的 1 Gib 的 PersistentVolume。如果没有声明 StorageClass,就会使用默认的 StorageClass。当一个 Pod 被安排到节点上时,它的 `volumeMounts` 挂载了与其 PersistentVolumeClaims 相关联的 PersistentVolume。请注意,当 Pod 或者 StatefulSet 被删除时,与 PersistentVolumeClaims 相关联的 PersistentVolume 并不会被删除。要删除它必须通过手动方式来完成。 + + + + +### Pod 名称标签 + +当 StatefulSet {{< glossary_tooltip term_id="controller" >}} 创建 Pod 时,它会添加一个标签 `statefulset.kubernetes.io/pod-name`,该标签设置为 Pod 名称。这个标签允许您给 StatefulSet 中的特定 Pod 绑定一个 Service。 + + + +## 部署和伸缩保证 + +* 对于包含 N 个 副本的 StatefulSet,当部署 Pod 时,它们是依次创建的,顺序为`0..N-1`。 +* 当删除 Pod 时,它们是逆序终止的,顺序为`N-1..0`。 +* 在将缩放操作应用到 Pod 之前,它前面的所有 Pod 必须是 Running 和 Ready 状态。 +* 在 Pod 终止之前,所有的继任者必须完全关闭。 + + + +StatefulSet 不应该声明 `pod.Spec.TerminationGracePeriodSeconds` 为 0。这种做法是不安全的,要强烈阻止。更多的解释请参考 [强制删除 StatefulSet Pods](/docs/tasks/run-application/force-delete-stateful-set-pod/)。 + + + +在上面的 nginx 示例被创建后,会按照 web-0、web-1、web-2 的顺序部署三个 Pod。在 web-0 进入 [Running 和 Ready](/docs/user-guide/pod-states/) 状态前不会部署 web-1。在 web-1 进入 Running 和 Ready 状态前不会部署 web-2。如果 web-1 已经处于 Running 和 Ready 状态,而 web-2 尚未部署,在此期间发生了 web-0 运行失败,那么 web-2 将不会被部署,要等到 web-0 部署完成并进入 Running 和 Ready 状态后,才会部署 web-2。 + + + + 如果用户想将示例中的 StatefulSet 收缩为 `replicas=1`,首先被终止的是 web-2。在 web-2 没有被完全停止和删除前,web-1 不会被终止。当 web-2 已被终止和删除、web-1 尚未被终止,如果在此期间发生 web-0 运行失败,那么就不会终止 web-1,必须等到 web-0 进入 Running 和 Ready 状态后才会终止 web-1。 + + + +### Pod 管理策略 {#pod-management-policies} +在 Kubernetes 1.7 及以后的版本中,StatefulSet 允许您放松其排序保证,同时通过它的 `.spec.podManagementPolicy` 域保持其唯一性和身份保证。 + +#### 有序的 Pod 管理 + +`有序的` Pod 管理是 StatefulSet 的默认功能。它实现了 [上面](#deployment-and-scaling-guarantees)描述的行为。 + +#### 并行的 Pod 管理 + +`并行` Pod 管理让 StatefulSet 控制器并行的启动或终止所有的 Pod,启动或者终止其他 Pod 前,无需等待 Pod 进入 Running 和 ready 或者完全停止状态。 + + + +## 更新策略 + +在 Kubernetes 1.7 及以后的版本中,StatefulSet 的 `.spec.updateStrategy` 字段让您可以配置和禁用掉自动滚动更新 Pod 的容器、标签、资源请求/限制、以及注解。 + + + + +### On Delete + +`OnDelete` 更新策略实现了 1.6 及以前版本的历史遗留行为。当 StatefulSet 的 `.spec.updateStrategy.type` 设置为 `OnDelete` 时,它的控制器将不会自动更新 StatefulSet 中的 Pod。用户必须手动删除 Pod 以便让控制器创建新的 Pod,以此来对 StatefulSet 的 `.spec.template` 的变动作出反应。 + + + + +### 滚动更新 {#rolling-updates} + +`RollingUpdate` 更新策略对 StatefulSet 中的 Pod 执行自动的滚动更新。在没有声明`.spec.updateStrategy`时,`RollingUpdate`是默认配置。 +当 StatefulSet 的 `.spec.updateStrategy.type` 被设置为 `RollingUpdate` 时,StatefulSet 控制器会删除和重建 StatefulSet 中的每个 Pod。 +它将按照与 Pod 终止相同的顺序(从最大序号到最小序号)进行,每次更新一个 Pod。它会等到被更新的 Pod 进入 Running 和 Ready 状态,然后再更新其前身。 + + + +#### 分区 + +通过声明 `.spec.updateStrategy.rollingUpdate.partition`的方式,`RollingUpdate`更新策略可以实现分区。如果声明了一个分区,当 StatefulSet 的`.spec.template` 被更新时,所有序号大于等于该分区序号的 Pod 都会被更新。所有序号小于该分区序号的 Pod 都不会被更新,并且,即使他们被删除也会依据之前的版本进行重建。如果 StatefulSet 的 `.spec.updateStrategy.rollingUpdate.partition` 大于它的 `.spec.replicas`,对它的 `.spec.template` 的更新将不会传递到它的 Pod。 +在大多数情况下,您不需要使用分区,但如果您希望进行阶段更新、执行金丝雀或执行分阶段展开,则这些分区会非常有用。 + + +#### 强制回滚 {#forced-rollback} + +在默认 [Pod 管理策略](#pod-management-policies)(`OrderedReady`) 时使用 [滚动更新](#rolling-updates) ,可能进入需要人工干预才能修复的损坏状态。 + +如果更新后 Pod 模板配置进入无法运行或就绪的状态(例如,由于错误的二进制文件或应用程序级配置错误),StatefulSet 将停止回滚并等待。 + +在这种状态下,仅将 Pod 模板还原为正确的配置是不够的。由于 [已知问题](https://github.com/kubernetes/kubernetes/issues/67250), +StatefulSet 将继续等待损坏状态的 Pod 准备就绪(永远不会发生),然后再尝试将其恢复为正常工作配置。 + +恢复模板后,还必须删除 StatefulSet 尝试使用错误的配置来运行的 Pod。这样,StatefulSet 才会开始使用被还原的模板来重新创建 Pod。 + +{{% /capture %}} +{{% capture whatsnext %}} + + + +* 示例一:[部署有状态应用](/docs/tutorials/stateful-application/basic-stateful-set/)。 +* 示例二:[使用 StatefulSet 部署 Cassandra](/docs/tutorials/stateful-application/cassandra/)。 + + +{{% /capture %}} + diff --git a/content/zh/docs/concepts/workloads/controllers/ttlafterfinished.md b/content/zh/docs/concepts/workloads/controllers/ttlafterfinished.md new file mode 100644 index 0000000000..f2aebc4ee8 --- /dev/null +++ b/content/zh/docs/concepts/workloads/controllers/ttlafterfinished.md @@ -0,0 +1,120 @@ +--- +reviewers: +- janetkuo +title: 已完成资源的 TTL 控制器 +content_template: templates/concept +weight: 65 +--- + + +{{% capture overview %}} + +{{< feature-state for_k8s_version="v1.12" state="alpha" >}} + + +TTL 控制器提供了一种 TTL 机制来限制已完成执行的资源对象的生命周期。TTL 控制器目前只处理[作业](/docs/concepts/workloads/controllers/jobs-run-to-completion/),可能以后会扩展以处理将完成执行的其他资源,例如 Pod 和自定义资源。 + + +Alpha 免责声明:此功能目前是 alpha 版,可以通过[feature gate](/docs/reference/command-line-tools-reference/feature-gates/) `TTLAfterFinished` 启用。 + + +{{% /capture %}} + + +{{% capture body %}} + + +## TTL 控制器 + + +TTL 控制器现在只支持 Jobs。集群操作员可以通过指定 Job 的 `.spec.ttlSecondsAfterFinished` 字段来自动清理已结束的作业(“完成”或“失败”),就像下边的[示例](/docs/concepts/workloads/controllers/jobs-run-to-completion/#clean-up-finished-jobs-automatically)。 + +TTL 控制器假设资源能在执行完成后的 TTL 秒内被清理,也就是当 TTL 过期后。当 TTL 控制器清理资源时,它将做级联删除,即删除资源对象的同时也删除其依赖对象。注意,当资源被删除时,由该资源的生命周期保证其终结器(finalizers)等被执行。 + + +可以随时设置 TTL 秒。以下是设置 Job 的 `.spec.ttlSecondsAfterFinished` 字段的一些示例: + + +* 在资源清单(manifest)中指定此字段,以便作业在完成后的某个时间被自动清除。 +* 将此字段设置为存在的、已完成的资源,以采用此新功能。 +* 在资源创建时使用 [mutating admission webhook](/docs/reference/access-authn-authz/extensible-admission-controllers/#admission-webhooks) 动态设置该字段。集群管理员可以使用它对完成的资源强制执行 TTL 策略。 +* 使用 [mutating admission webhook](/docs/reference/access-authn-authz/extensible-admission-controllers/#admission-webhooks) 在资源完成后动态设置该字段,并根据资源状态、标签等选择不同的 TTL 值。 + + +## 警告 + + +### 更新 TTL 秒 + + +请注意,在创建资源后或已经执行结束后,仍可以修改其 TTL 周期,例如作业的 `.spec.ttlSecondsAfterFinished` 字段。但是,一旦作业变为可被删除状态(当其 TTL 已过期时),即使您通过 API 扩展其 TTL 时长得到了成功的响应,系统也不保证作业将被保留。 + + +### 时间偏差 + + +由于 TTL 控制器使用存储在 Kubernetes 资源中的时间戳来确定 TTL 是否已过期,因此该功能对集群中的时间偏差很敏感,这可能导致 TTL 控制器在错误的时间清理资源对象。 + + +在 Kubernetes 中,需要在所有节点上运行 NTP(参见[#6159](https://github.com/kubernetes/kubernetes/issues/6159#issuecomment-93844058))以避免时间偏差。时钟并不总是如此正确,但差异应该很小。设置非零 TTL 时请注意这种风险。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + +[自动清理作业](/docs/concepts/workloads/controllers/jobs-run-to-completion/#clean-up-finished-jobs-automatically) + + +[设计文档](https://github.com/kubernetes/enhancements/blob/master/keps/sig-apps/0026-ttl-after-finish.md) + +{{% /capture %}} diff --git a/content/zh/docs/concepts/workloads/pods/_index.md b/content/zh/docs/concepts/workloads/pods/_index.md index 3b714c7ff5..1c35becca5 100644 --- a/content/zh/docs/concepts/workloads/pods/_index.md +++ b/content/zh/docs/concepts/workloads/pods/_index.md @@ -1,12 +1,11 @@ +--- +title: "Pods" +weight: 10 +--- + - ---- -title: "Pods" -weight: 10 ---- - diff --git a/content/zh/docs/concepts/workloads/pods/disruptions.md b/content/zh/docs/concepts/workloads/pods/disruptions.md new file mode 100644 index 0000000000..a82b9c11e6 --- /dev/null +++ b/content/zh/docs/concepts/workloads/pods/disruptions.md @@ -0,0 +1,533 @@ +--- +title: 干扰 +content_template: templates/concept +weight: 60 +--- + + + +{{% capture overview %}} + + +本指南针对的是希望构建高可用性应用程序的应用所有者,他们有必要了解可能发生在 pod 上的干扰类型。 + + + +文档同样适用于想要执行自动化集群操作(例如升级和自动扩展集群)的集群管理员。 + +{{% /capture %}} + + +{{% capture body %}} + + + +## 自愿干扰和非自愿干扰 + + + +Pod 不会消失,除非有人(用户或控制器)将其销毁,或者出现了不可避免的硬件或软件系统错误。 + + + +我们把这些不可避免的情况称为应用的*非自愿干扰*。例如: + + + +- 节点下层物理机的硬件故障 +- 集群管理员错误地删除虚拟机(实例) +- 云提供商或虚拟机管理程序中的故障导致的虚拟机消失 +- 内核错误 +- 节点由于集群网络隔离从集群中消失 +- 由于节点[资源不足](/docs/tasks/administer-cluster/out-of-resource/)导致 pod 被驱逐。 + + + +除了资源不足的情况,大多数用户应该都熟悉这些情况;它们不是特定于 Kubernetes 的。 + + + +我们称其他情况为*自愿干扰*。包括由应用程序所有者发起的操作和由集群管理员发起的操作。典型的应用程序所有者的 +作包括: + + + +- 删除 deployment 或其他管理 pod 的控制器 +- 更新了 deployment 的 pod 模板导致 pod 重启 +- 直接删除 pod(例如,因为误操作) + + + +集群管理员操作包括: + + + +- [排空(drain)节点](/docs/tasks/administer-cluster/safely-drain-node/)进行修复或升级。 +- 从集群中排空节点以缩小集群(了解[集群自动扩缩](/docs/tasks/administer-cluster/cluster-management/#cluster-autoscaler))。 +- 从节点中移除一个 pod,以允许其他 pod 使用该节点。 + + + +这些操作可能由集群管理员直接执行,也可能由集群管理员所使用的自动化工具执行,或者由集群托管提供商自动执行。 + + + +咨询集群管理员或联系云提供商,或者查询发布文档,以确定是否为集群启用了任何资源干扰源。如果没有启用,可以不用创建 Pod Disruption Budgets(Pod 干扰预算) + +{{< caution >}} + + + +并非所有的自愿干扰都会受到 pod 干扰预算的限制。例如,删除 deployment 或 pod 的删除操作就会跳过 pod 干扰预算检查。 + +{{< /caution >}} + + + +## 处理干扰 + + + +以下是减轻非自愿干扰的一些方法: + + + +- 确保 pod[请求所需资源](/docs/tasks/configure-pod-container/assign-cpu-ram-container)。 +- 如果需要更高的可用性,请复制应用程序。(了解有关运行多副本的[无状态](/docs/tasks/run-application/run-stateless-application-deployment/)和[有状态](/docs/tasks/run-application/run-replicated-stateful-application/)应用程序的信息。) +- 为了在运行复制应用程序时获得更高的可用性,请跨机架(使用[反亲和性](/docs/user-guide/node-selection/#inter-pod-affinity-and-anti-affinity-beta-feature))或跨区域(如果使用[多区域集群](/docs/setup/multiple-zones))扩展应用程序。 + + + +自愿干扰的频率各不相同。在一个基本的 Kubernetes 集群中,根本没有自愿干扰。然而,集群管理 +或托管提供商可能运行一些可能导致自愿干扰的额外服务。例如,节点软 +更新可能导致自愿干扰。另外,集群(节点)自动缩放的某些 +现可能导致碎片整理和紧缩节点的自愿干扰。集群 +理员或托管提供商应该已经记录了各级别的自愿干扰(如果有的话)。 + + + +Kubernetes 提供特性来满足在出现频繁自愿干扰的同时运行高可用的应用程序。我们称这些特性为*干扰预算* + + + +## 干扰预算工作原理 + + + +应用程序所有者可以为每个应用程序创建 `PodDisruptionBudget` 对象(PDB)。PDB 将限制在同一时间因自愿干扰导致的复制应用程序中宕机的 pod 数量。例如,基于定额的应用程序希望确保运行的副本数 +永远不会低于仲裁所需的数量。Web 前端可能希望确保提供负载的副本数量永远不会低于总数的某个百分比。 + + + +集群管理员和托管提供商应该使用遵循 Pod Disruption Budgets 的接口(通过调用[驱逐 API](/docs/tasks/administer-cluster/safely-drain-node/#the-eviction-api)),而不是直接删除 pod 或 deployment。示例包括 `kubectl drain` 命令和 Kubernetes-on-GCE 集群升级脚本(`cluster/gce/upgrade.sh`)。 + + + +当集群管理员想排空一个节点时,可以使用 `kubectl drain` 命令。该命令试图驱逐机器上的所有 pod。驱逐请求可能会暂时被拒绝,且该工具定时重试失败的请求直到所有的 pod 都被终止,或者达到配置的超时时间。 + + + +PDB 指定应用程序可以容忍的副本数量(相当于应该有多少副本)。例如,具有 `.spec.replicas: 5` 的 deployment 在任何时间都应该有 5 个 pod。如果 PDB 允许其在某一时刻有 4 个副本,那么驱逐 API 将允许同一时刻仅有一个而不是两个 pod 自愿干扰。 + + + +使用标签选择器来指定构成应用程序的一组 pod,这与应用程序的控制器(deployment,stateful-set 等)选择 pod 的逻辑一样。 + + + +Pod 控制器的 `.spec.replicas` 计算“预期的” pod 数量。根据 pod 对象的 `.metadata.ownerReferences` 字段来发现控制器。 + + + +PDB 不能阻止[非自愿干扰](#voluntary-and-involuntary-disruptions)的发生,但是确实会计入 +算。 + + + +由于应用程序的滚动升级而被删除或不可用的 pod 确实会计入干扰预算,但是控制器(如 deployment 和 stateful-set)在进行滚动升级时不受 PDB +的限制。应用程序更新期间的故障处理是在控制器的 spec 中配置的。(了解[更新 deployment](/docs/concepts/workloads/controllers/deployment/#updating-a-deployment)。) + + + +当使用驱逐 API 驱逐 pod 时,pod 会被优雅地终止(参考 [PodSpec](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#podspec-v1-core) 中的 `terminationGracePeriodSeconds`)。 + + + +## PDB 例子 + + + +假设集群有 3 个节点,`node-1` 到 `node-3`。集群上运行了一些应用。其中一个应用有 3 个副本,分别是 `pod-a`,`pod-b` 和 `pod-c`。另外,还有一个不带 PDB 的无关 pod `pod-x` 也同样显示。最初,所有的 pod 分布如下: + + +| node-1 | node-2 | node-3 | +|:--------------------:|:-------------------:|:------------------:| +| pod-a *available* | pod-b *available* | pod-c *available* | +| pod-x *available* | | | + + + +3 个 pod 都是 deployment 的一部分,并且共同拥有同一个 PDB,要求 3 个 pod 中至少有 2 个 pod 始终处于可用状态。 + + + +例如,假设集群管理员想要重启系统,升级内核版本来修复内核中的 bug。集群管理员首先使用 `kubectl drain` 命令尝试排空 `node-1` 节点。命令尝试驱逐 `pod-a` 和 `pod-x`。操作立即就成功了。两个 pod 同时进入 `terminating` 状态。这时的集群处于下面的状态: + +| node-1 *draining* | node-2 | node-3 | +|:--------------------:|:-------------------:|:------------------:| +| pod-a *terminating* | pod-b *available* | pod-c *available* | +| pod-x *terminating* | | | + + + +Deployment 控制器观察到其中一个 pod 正在终止,因此它创建了一个替代 pod `pod-d`。由于 `node-1` 被封锁(cordon),`pod-d` 落在另一个节点上。同样其他控制器也创建了 `pod-y` 作为 `pod-x` 的替代品。 + + + +(注意:对于 StatefulSet 来说,`pod-a`(也称为 `pod-0`)需要在替换 pod 创建之前完全终止,替代它的也称为 `pod-0`,但是具有不同的 UID。反之,样例也适用于 StatefulSet。) + + + +当前集群的状态如下: + +| node-1 *draining* | node-2 | node-3 | +|:--------------------:|:-------------------:|:------------------:| +| pod-a *terminating* | pod-b *available* | pod-c *available* | +| pod-x *terminating* | pod-d *starting* | pod-y | + + + +在某一时刻,pod 被终止,集群如下所示: + +| node-1 *drained* | node-2 | node-3 | +|:--------------------:|:-------------------:|:------------------:| +| | pod-b *available* | pod-c *available* | +| | pod-d *starting* | pod-y | + + + +此时,如果一个急躁的集群管理员试图排空(drain)`node-2` 或 `node-3`,drain 命令将被阻塞,因为对于 deployment 来说只有 2 个可用的 pod,并且它的 PDB 至少需要 2 个。经过一段时间,`pod-d` 变得可用。 + + + +集群状态如下所示: + +| node-1 *drained* | node-2 | node-3 | +|:--------------------:|:-------------------:|:------------------:| +| | pod-b *available* | pod-c *available* | +| | pod-d *available* | pod-y | + + + +现在,集群管理员试图排空(drain)`node-2`。drain 命令将尝试按照某种顺序驱逐两个 pod,假设先是 `pod-b`,然后是 `pod-d`。命令成功驱逐 `pod-b`,但是当它尝试驱逐 `pod-d`时将被拒绝,因为对于 deployment 来说只剩一个可用的 pod 了。 + + + +Deployment 创建 `pod-b` 的替代 pod `pod-e`。因为集群中没有足够的资源来调度 `pod-e`,drain 命令再次阻塞。集群最终将是下面这种状态: + +| node-1 *drained* | node-2 | node-3 | *no node* | +|:--------------------:|:-------------------:|:------------------:|:------------------:| +| | pod-b *available* | pod-c *available* | pod-e *pending* | +| | pod-d *available* | pod-y | | + + + +此时,集群管理员需要增加一个节点到集群中以继续升级操作。 + + + +可以看到 Kubernetes 如何改变干扰发生的速率,根据: + + + +- 应用程序需要多少个副本 +- 优雅关闭应用实例需要多长时间 +- 启动应用新实例需要多长时间 +- 控制器的类型 +- 集群的资源能力 + + + +## 分离集群所有者和应用所有者角色 + + + +通常,将集群管理者和应用所有者视为彼此了解有限的独立角色是很有用的。这种责任分离在下面这些场景下是有意义的: + + + +- 当有许多应用程序团队共用一个 Kubernetes 集群,并且有自然的专业角色 +- 当第三方工具或服务用于集群自动化管理 + + + +Pod 干扰预算通过在角色之间提供接口来支持这种分离。 + + + +如果你的组织中没有这样的责任分离,则可能不需要使用 Pod 干扰预算。 + + + +## 如何在集群上执行干扰操作 + + + +如果你是集群管理员,并且需要对集群中的所有节点执行干扰操作,例如节点或系统软件升级,则可以使用以下选项 + + + + +- 接受升级期间的停机时间。 +- 故障转移到另一个完整的副本集群。 + - 没有停机时间,但是对于重复的节点和人工协调成本可能是昂贵的。 +- 编写可容忍干扰的应用程序和使用 PDB。 + - 没有停机 + 间。 + - 最小的资源重复。 + - 允许更多的集群管理自动化。 + - 编写可容忍干扰的应用程序是棘手的,但对于支持容忍自愿干扰所做的工作,和支持自动扩缩和容忍非 + 愿干扰所做工作相比,有大量的重叠 + +{{% /capture %}} + + +{{% capture whatsnext %}} + + + +* 参考[配置 Pod 干扰预算](/docs/tasks/run-application/configure-pdb/)中的方法来保护你的 +用。 + + + +* 了解更多关于[排空节点](/docs/tasks/administer-cluster/safely-drain-node/)的信息。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/workloads/pods/ephemeral-containers.md b/content/zh/docs/concepts/workloads/pods/ephemeral-containers.md new file mode 100644 index 0000000000..3f20c0d6b4 --- /dev/null +++ b/content/zh/docs/concepts/workloads/pods/ephemeral-containers.md @@ -0,0 +1,313 @@ +--- +title: 临时容器 +content_template: templates/concept +weight: 80 +--- + + + +{{% capture overview %}} + +{{< feature-state state="alpha" >}} + + + +此页面概述了临时容器:一种特殊的容器,该容器在现有 {{< glossary_tooltip term_id="pod" >}} 中临时运行,为了完成用户启动的操作,例如故障排查。使用临时容器来检查服务,而不是构建应用程序。 + + + +{{< warning >}} +临时容器处于早期的 alpha 阶段,不适用于生成环境集群。应该预料到临时容器在某些情况下不起作用,例如在定位容器的名称命名空间。根据 [Kubernetes +弃用政策](/docs/reference/using-api/deprecation-policy/),该 alpha 功能将来可能发生重大变化或完全删除。 +{{< /warning >}} + +{{% /capture %}} + +{{% capture body %}} + + + +## 了解临时容器 + + + +{{< glossary_tooltip text="Pods" term_id="pod" >}} 是 Kubernetes 应用程序的基本构建块。由于 pod 是一次性且可替换的,因此一旦 Pod 创建,就无法将容器加入到 Pod 中。取而代之的是,通常使用 {{< glossary_tooltip text="deployments" term_id="deployment" >}} 以受控的方式来删除并替换 Pod。 + + + +有时有必要检查现有 Pod 的状态,例如,对于难以复现的故障进行排查。在这些场景中,可以在现有 Pod 中运行临时容器来检查其状态并运行任意命令。 + + + +### 什么是临时容器? + + + +临时容器与其他容器的不同之处在于,它们缺少对资源或执行的保证,并且永远不会自动重启,因此不适用于构建应用程序。临时容器使用与常规容器相同的 `ContainerSpec` 段进行描述,但许多字段是不相容且不允许的。 + + + +- 临时容器没有端口配置,因此像 `ports`,`livenessProbe`,`readinessProbe` 这样的字段是不允许的。 +- Pod 资源分配是不可变的,因此 `resources` 配置是不允许的。 +- 有关允许字段的完整列表,请参见[临时容器参考文档](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#ephemeralcontainer-v1-core)。 + + + +临时容器是使用 API 中的一种特殊的 `ephemeralcontainers` 处理器进行创建的,而不是直接添加到 `pod.spec` 段,因此无法使用 `kubectl edit` 来添加一个临时容器。 + + + +与常规容器一样,将临时容器添加到 Pod 后,将不能更改或删除临时容器。 + + + +## 临时容器的用途 + + + +当容器崩溃或容器镜像中不包含调试工具时,使用 `kubectl +exec` 命令进行故障排查不足,临时容器对于交互式故障处理很有用。 + + + +尤其是,[distroless 镜像](https://github.com/GoogleContainerTools/distroless)能够使得部署最小的容器镜像,从而减少攻击面并减少故障和漏洞的暴露。由于 distroless 镜像不包含 shell 或任何的调试工具,因此很难单独使用 `kubectl exec` 命令进行故障排查。 + + + +使用临时容器时,启用[进程命名空间共享](/docs/tasks/configure-pod-container/share-process-namespace/)很有帮助,可以查看其他容器中的进程。 + + + +### 例子 + + + +{{< note >}} +本节中的示例要求启用 `EphemeralContainers` [特性](/docs/reference/command-line-tools-reference/feature-gates/),并且 kubernetes 客户端和服务端版本要求为 v1.16 或更高版本。 +{{< /note >}} + + + +本节中的示例演示了临时容器如何在 API 中出现。用户通常会使用 `kubectl` 插件来进行故障排查,从而自动化执行这些步骤。 + + + +临时容器是使用 Pod 的 `ephemeralcontainers` 子资源创建的,可以使用 `kubectl --raw` 命令进行显示。首先描述临时容器被添加为一个 `EphemeralContainers` 列表: + +```json +{ + "apiVersion": "v1", + "kind": "EphemeralContainers", + "metadata": { + "name": "example-pod" + }, + "ephemeralContainers": [{ + "command": [ + "sh" + ], + "image": "busybox", + "imagePullPolicy": "IfNotPresent", + "name": "debugger", + "stdin": true, + "tty": true, + "terminationMessagePolicy": "File" + }] +} +``` + + + +使用如下命令更新已运行的临时容器 `example-pod`: + +```shell +kubectl replace --raw /api/v1/namespaces/default/pods/example-pod/ephemeralcontainers -f ec.json +``` + + + +这将返回临时容器的新列表: + +```json +{ + "kind":"EphemeralContainers", + "apiVersion":"v1", + "metadata":{ + "name":"example-pod", + "namespace":"default", + "selfLink":"/api/v1/namespaces/default/pods/example-pod/ephemeralcontainers", + "uid":"a14a6d9b-62f2-4119-9d8e-e2ed6bc3a47c", + "resourceVersion":"15886", + "creationTimestamp":"2019-08-29T06:41:42Z" + }, + "ephemeralContainers":[ + { + "name":"debugger", + "image":"busybox", + "command":[ + "sh" + ], + "resources":{ + + }, + "terminationMessagePolicy":"File", + "imagePullPolicy":"IfNotPresent", + "stdin":true, + "tty":true + } + ] +} +``` + + + +可以使用以下命令查看新创建的临时容器的状态: + +```shell +kubectl describe pod example-pod +``` + +``` +... +Ephemeral Containers: + debugger: + Container ID: docker://cf81908f149e7e9213d3c3644eda55c72efaff67652a2685c1146f0ce151e80f + Image: busybox + Image ID: docker-pullable://busybox@sha256:9f1003c480699be56815db0f8146ad2e22efea85129b5b5983d0e0fb52d9ab70 + Port: + Host Port: + Command: + sh + State: Running + Started: Thu, 29 Aug 2019 06:42:21 +0000 + Ready: False + Restart Count: 0 + Environment: + Mounts: +... +``` + + + +可以使用以下命令连接到新的临时容器: + +```shell +kubectl attach -it example-pod -c debugger +``` + + + +如果启用了进程命名空间共享,则可以从该 Pod 的所有容器中查看进程。如下所示: + +```shell +/ # ps auxww +PID USER TIME COMMAND + 1 root 0:00 /pause + 6 root 0:00 nginx: master process nginx -g daemon off; + 11 101 0:00 nginx: worker process + 12 101 0:00 nginx: worker process + 13 101 0:00 nginx: worker process + 14 101 0:00 nginx: worker process + 15 101 0:00 nginx: worker process + 16 101 0:00 nginx: worker process + 17 101 0:00 nginx: worker process + 18 101 0:00 nginx: worker process + 19 root 0:00 /pause + 24 root 0:00 sh + 29 root 0:00 ps auxww +``` + +{{% /capture %}} diff --git a/content/zh/docs/concepts/workloads/pods/init-containers.md b/content/zh/docs/concepts/workloads/pods/init-containers.md index 066c59470e..31ff8dd202 100644 --- a/content/zh/docs/concepts/workloads/pods/init-containers.md +++ b/content/zh/docs/concepts/workloads/pods/init-containers.md @@ -12,63 +12,119 @@ content_template: templates/concept {{% capture overview %}} -本页提供了 Init 容器的概览,它是一种专用的容器,在应用容器启动之前运行,并包括一些应用镜像中不存在的实用工具和安装脚本。 + + +本页提供了 Init 容器的概览,它是一种专用的容器,在{{< glossary_tooltip text="Pod" term_id="pod" >}}内的应用容器启动之前运行,并包括一些应用镜像中不存在的实用工具和安装脚本。 {{% /capture %}} -{{< toc >}} - - -这个特性在 1.6 版本已经退出 beta 版本。Init 容器可以在 PodSpec 中有效 QoS 层同应用的 `containers` 数组一起来指定。 -beta 注解的值将仍然需要保留,并覆盖 PodSpec 字段值。 + +你可以在Pod的规格信息中与containers数组同级的位置指定 Init 容器。 {{% capture body %}} + + ## 理解 Init 容器 -[Pod](/docs/concepts/abstractions/pod/) 能够具有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用容器启动的 Init 容器。 +{{< glossary_tooltip text="Pod" term_id="pod" >}} 可以包含多个容器,应用运行在这些容器里面,同时 Pod 也可以有一个或多个先于应用容器启动的 Init 容器。 + + Init 容器与普通的容器非常像,除了如下两点: - - * 它们总是运行到完成。 * 每个都必须在下一个启动之前成功完成。 - + 如果 Pod 的 Init 容器失败,Kubernetes 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的 `restartPolicy` 值为 Never,它不会重新启动。 -指定容器为 Init 容器,需要在 PodSpec 中添加 `initContainers` 字段,以 [Container](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#container-v1-core) 类型对象的 JSON 数组的形式,还有 app 的 `containers` 数组。 + + +指定容器为 Init 容器,需要在 Pod 的 spec 中添加 `initContainers` 字段, 该字段內以[Container](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#container-v1-core) 类型对象数组的形式组织,和应用的 `containers` 数组同级相邻。 Init 容器的状态在 `status.initContainerStatuses` 字段中以容器状态数组的格式返回(类似 `status.containerStatuses` 字段)。 + ### 与普通容器的不同之处 -Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。 -然而,Init 容器对资源请求和限制的处理稍有不同,在下面 [资源](#资源) 处有说明。 -而且 Init 容器不支持 Readiness Probe,因为它们必须在 Pod 就绪之前运行完成。 - -如果为一个 Pod 指定了多个 Init 容器,那些容器会按顺序一次运行一个。 -每个 Init 容器必须运行成功,下一个才能够运行。 -当所有的 Init 容器运行完成时,Kubernetes 初始化 Pod 并像平常一样运行应用容器。 +Init 容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置。 然而,Init 容器对资源请求和限制的处理稍有不同,在下面 [资源](#资源) 处有说明。 +同时 Init 容器不支持 Readiness Probe,因为它们必须在 Pod 就绪之前运行完成。 + +如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时,Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。 + ## Init 容器能做什么? -因为 Init 容器具有与应用容器分离的单独镜像,它们的启动相关代码具有如下优势: +因为 Init 容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势: -* 它们可以包含并运行实用工具,出于安全考虑,是不建议在应用容器镜像中包含这些实用工具的。 -* 它们可以包含用于安装的工具和定制化代码,这些都是在应用镜像中没有的。例如,创建镜像没必要 `FROM` 另一个镜像,只需要在安装过程中使用类似 `sed`、 `awk`、 `python` 或 `dig` 这样的工具。 -* 应用镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。 -* 它们使用 Linux Namespace,所以对应用容器具有不同的文件系统视图。因此,它们能够具有访问 Secret 的权限,而应用容器不能够访问。 -* 它们在应用容器启动之前运行完成,然而应用容器并行运行,所以 Init 容器提供了一种简单的方式来阻塞或延迟应用容器的启动,直到满足了一组先决条件。 +* Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。例如,没有必要仅为了在安装过程中使用类似 `sed`、 `awk`、 `python` 或 `dig` 这样的工具而去`FROM` 一个镜像来生成一个新的镜像。 +* Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。 +* 应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。 +* Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器可具有访问 {{< glossary_tooltip text="Secrets" term_id="secret" >}} 的权限,而应用容器不能够访问。 +* 由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。 + ### 示例 @@ -82,50 +138,38 @@ Init 容器支持应用容器的全部字段和特性,包括资源限制、数 curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$()&ip=$()' -* 在启动应用容器之前等一段时间,使用类似 `sleep 60` 的命令。 -* 克隆 Git 仓库到数据卷。 +* 在启动应用容器之前等一段时间,使用类似命令: + + `sleep 60` + +* 克隆 Git 仓库到 {{< glossary_tooltip text="Volume" term_id="volume" >}}。 * 将配置值放到配置文件中,运行模板工具为主应用容器动态地生成配置文件。例如,在配置文件中存放 POD_IP 值,并使用 Jinja 生成主应用配置文件。 -更多详细用法示例,可以在 [StatefulSet 文档](/docs/concepts/abstractions/controllers/statefulsets/) 和 [Pod 初始化](/docs/tasks/configure-pod-container/configure-pod-initialization) 中找到。 - - - -### 使用 Init 容器 - -下面是 Kubernetes 1.5 版本 yaml 文件,展示了一个具有 2 个 Init 容器的简单 Pod。 -第一个等待 `myservice` 启动,第二个等待 `mydb` 启动。 -一旦这两个 Service 都启动完成,Pod 将开始启动。 + +### 使用 Init 容器 + +下面的例子定义了一个具有 2 个 Init 容器的简单 Pod。 第一个等待 `myservice` 启动,第二个等待 `mydb` 启动。 一旦这两个 Init容器 都启动完成,Pod 将启动`spec`区域中的应用容器。 ```yaml apiVersion: v1 @@ -137,23 +181,17 @@ metadata: spec: containers: - name: myapp-container - image: busybox + image: busybox:1.28 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] initContainers: - name: init-myservice - image: busybox + image: busybox:1.28 command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;'] - name: init-mydb - image: busybox + image: busybox:1.28 command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;'] ``` - - -1.5 版本的语法在 1.6 版本仍然可以使用,但是我们推荐使用 1.6 版本的新语法。 -在 Kubernetes 1.6 版本中,Init 容器在 API 中新建了一个字段。 -虽然期望使用 beta 版本的 annotation,但在未来发行版将会被废弃掉。 - 下面的 yaml 文件展示了 `mydb` 和 `myservice` 两个 Service: ``` @@ -179,16 +217,35 @@ spec: ``` - -这个 Pod 可以使用下面的命令进行启动和调试: +要启动这个 Pod,可以执行如下命令: + +``` +kubectl apply -f myapp.yaml +``` + +``` +pod/myapp-pod created +``` + + + +要检查其状态: +``` +kubectl get -f myapp.yaml +``` ``` -$ kubectl create -f myapp.yaml -pod "myapp-pod" created -$ kubectl get -f myapp.yaml NAME READY STATUS RESTARTS AGE myapp-pod 0/1 Init:0/2 0 6m -$ kubectl describe -f myapp.yaml +``` + +如需更详细的信息: + +``` +kubectl describe -f myapp.yaml +``` + +``` Name: myapp-pod Namespace: default [...] @@ -221,111 +278,175 @@ Events: 13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulled Successfully pulled image "busybox" 13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Created Created container with docker id 5ced34a04634; Security:[seccomp=unconfined] 13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634 +``` + +如需查看Pod内 Init 容器的日志,请执行: + +``` $ kubectl logs myapp-pod -c init-myservice # Inspect the first init container $ kubectl logs myapp-pod -c init-mydb # Inspect the second init container ``` + -一旦我们启动了 `mydb` 和 `myservice` 这两个 Service,我们能够看到 Init 容器完成,并且 `myapp-pod` 被创建: +在这一刻,Init 容器将会等待至发现名称为`mydb`和`myservice`的 Service。 + +如下为创建这些 Service 的配置文件: ``` +--- +apiVersion: v1 +kind: Service +metadata: + name: myservice +spec: + ports: + - protocol: TCP + port: 80 + targetPort: 9376 +--- +apiVersion: v1 +kind: Service +metadata: + name: mydb +spec: + ports: + - protocol: TCP + port: 80 + targetPort: 9377 +``` + + +创建`mydb`和`myservice`的 service 命令: + +```shell $ kubectl create -f services.yaml +``` + +``` service "myservice" created service "mydb" created +``` + +这样你将能看到这些 Init容器 执行完毕,随后`my-app`的Pod转移进入 Running 状态: +```shell $ kubectl get -f myapp.yaml +``` +```shell NAME READY STATUS RESTARTS AGE myapp-pod 1/1 Running 0 9m ``` +一旦我们启动了 `mydb` 和 `myservice` 这两个 Service,我们能够看到 Init 容器完成,并且 `myapp-pod` 被创建: -这个例子非常简单,但是应该能够为创建自己的 Init 容器提供一些启发。 + +这个简单的例子应该能为你创建自己的 Init 容器提供一些启发。 [What's next](#what-s-next) 部分提供了更详细例子的链接。 + ## 具体行为 -在 Pod 启动过程中,Init 容器会按顺序在网络和数据卷初始化之后启动。 -每个容器必须在下一个容器启动之前成功退出。 -如果由于运行时或失败退出,导致容器启动失败,它会根据 Pod 的 `restartPolicy` 指定的策略进行重试。 -然而,如果 Pod 的 `restartPolicy` 设置为 Always,Init 容器失败时会使用 `RestartPolicy` 策略。 +在 Pod 启动过程中,每个Init 容器在网络和数据卷初始化之后会按顺序启动。每个 Init容器 成功退出后才会启动下一个 Init容器。 如果因为运行或退出时失败引发容器启动失败,它会根据 Pod 的 `restartPolicy` 策略进行重试。 +然而,如果 Pod 的 `restartPolicy` 设置为 Always,Init 容器失败时会使用 `restartPolicy` 的 OnFailure 策略。 - - -在所有的 Init 容器没有成功之前,Pod 将不会变成 `Ready` 状态。 -Init 容器的端口将不会在 Service 中进行聚集。 -正在初始化中的 Pod 处于 `Pending` 状态,但应该会将条件 `Initialized` 设置为 true。 +在所有的 Init 容器没有成功之前,Pod 将不会变成 `Ready` 状态。 Init 容器的端口将不会在 Service 中进行聚集。 正在初始化中的 Pod 处于 `Pending` 状态,但会将条件 `Initializing` 设置为 true。 如果 Pod [重启](#pod-restart-reasons),所有 Init 容器必须重新执行。 -对 Init 容器 spec 的修改,被限制在容器 image 字段中。 -更改 Init 容器的 image 字段,等价于重启该 Pod。 +对 Init 容器 spec 的修改仅限于容器的 image 字段。 更改 Init 容器的 image 字段,等同于重启该 Pod。 + +因为 Init 容器可能会被重启、重试或者重新执行,所以 Init 容器的代码应该是幂等的。 特别地,基于 `EmptyDirs` 写文件的代码,应该对输出文件可能已经存在做好准备。 + +Init 容器具有应用容器的所有字段。 然而 Kubernetes 禁止使用 `readinessProbe`,因为 Init 容器不能定义不同于完成(completion)的就绪(readiness)。 这一点会在校验时强制执行。 + +在 Pod 上使用 `activeDeadlineSeconds`和在容器上使用 `livenessProbe` 可以避免 Init 容器一直重复失败。 `activeDeadlineSeconds` 时间包含了 Init 容器启动的时间。 + +在 Pod 中的每个应用容器和 Init 容器的名称必须唯一;与任何其它容器共享同一个名称,会在校验时抛出错误。 + ### 资源 -为 Init 容器指定顺序和执行逻辑,下面对资源使用的规则将被应用: +给定Init 容器的执行顺序下,资源使用适用于如下规则: + +* 所有 Init 容器上定义的任何特定资源的 limit 或 request 的最大值,作为 Pod *有效初始 request/limit* +* Pod 对资源的 *有效 limit/request * 是如下两者的较大者: + * 所有应用容器对某个资源的 limit/request 之和 + * 对某个资源的有效初始 limit/request +* 基于有效 limit/request 完成调度,这意味着 Init 容器能够为初始化过程预留资源,这些资源在 Pod 生命周期过程中并没有被使用。 +* Pod 的 *有效 QoS 层* ,与 Init 容器和应用容器的一样。 + +配额和限制适用于有效 Pod的 limit/request。 +Pod 级别的 cgroups 是基于有效 Pod 的 limit/request,和调度器相同。 - -* 在所有 Init 容器上定义的,任何特殊资源请求或限制的最大值,是 *有效初始请求/限制* -* Pod 对资源的 *有效请求/限制* 要高于: - * 所有应用容器对某个资源的请求/限制之和 - * 对某个资源的有效初始请求/限制 -* 基于有效请求/限制完成调度,这意味着 Init 容器能够为初始化预留资源,这些资源在 Pod 生命周期过程中并没有被使用。 -* Pod 的 *有效 QoS 层* ,是 Init 容器和应用容器相同的 QoS 层。 - - - -基于有效 Pod 请求和限制来应用配额和限制。 -Pod 级别的 cgroups 是基于有效 Pod 请求和限制,和调度器相同。 - + ### Pod 重启的原因 -Pod 能够重启,会导致 Init 容器重新执行,主要有如下几个原因: +Pod重启导致 Init 容器重新执行,主要有如下几个原因: -* 用户更新 PodSpec 导致 Init 容器镜像发生改变。应用容器镜像的变更只会重启应用容器。 -* Pod 基础设施容器被重启。这不多见,但某些具有 root 权限可访问 Node 的人可能会这样做。 -* 当 `restartPolicy` 设置为 Always,Pod 中所有容器会终止,强制重启,由于垃圾收集导致 Init 容器完成的记录丢失。 +* 用户更新 Pod 的 Spec 导致 Init 容器镜像发生改变。Init 容器镜像的变更会引起 Pod 重启. 应用容器镜像的变更仅会重启应用容器。 +* Pod 的基础设施容器 (译者注:如 pause 容器) 被重启。 这种情况不多见,必须由具备 root 权限访问 Node 的人员来完成。 +* 当 `restartPolicy` 设置为 Always,Pod 中所有容器会终止而强制重启,由于垃圾收集导致 Init 容器的完成记录丢失。 - -## 支持与兼容性 - -Apiserver 版本为 1.6 或更高版本的集群,通过使用 `spec.initContainers` 字段来支持 Init 容器。 -之前的版本可以使用 alpha 和 beta 注解支持 Init 容器。 -`spec.initContainers` 字段也被加入到 alpha 和 beta 注解中,所以 Kubernetes 1.3.0 版本或更高版本可以执行 Init 容器,并且 1.6 版本的 apiserver 能够安全的回退到 1.5.x 版本,而不会使存在的已创建 Pod 失去 Init 容器的功能。 - {{% /capture %}} {{% capture whatsnext %}} + - -* [创建具有 Init 容器的 Pod](/docs/tasks/configure-pod-container/configure-pod-initialization/#creating-a-pod-that-has-an-init-container) - +* 阅读[创建包含 Init 容器的 Pod](/docs/tasks/configure-pod-container/configure-pod-initialization/#creating-a-pod-that-has-an-init-container) +* 学习如何[调测 Init 容器](/docs/tasks/debug-application-cluster/debug-init-containers/) {{% /capture %}} - - - diff --git a/content/zh/docs/concepts/workloads/pods/pod-overview.md b/content/zh/docs/concepts/workloads/pods/pod-overview.md new file mode 100644 index 0000000000..e589b39a2b --- /dev/null +++ b/content/zh/docs/concepts/workloads/pods/pod-overview.md @@ -0,0 +1,256 @@ +--- +reviewers: +- erictune +title: Pod 概览 +content_template: templates/concept +weight: 10 +--- + + + +{{% capture overview %}} + +本节提供了 `Pod` 的概览信息,`Pod` 是最小可部署的 Kubernetes 对象模型。 +{{% /capture %}} + + +{{% capture body %}} + + + +## 理解 Pod + +*Pod* 是 Kubernetes 的基本构建块,它是 Kubernetes 对象模型中创建或部署的最小和最简单的单元。 +Pod 表示集群上正在运行的进程。 + + + +Pod 封装了应用程序容器(或者在某些情况下封装多个容器)、存储资源、唯一网络 IP 以及控制容器应该如何运行的选项。 +Pod 表示部署单元:*Kubernetes 中应用程序的单个实例*,它可能由单个容器或少量紧密耦合并共享资源的容器组成。 + + +[Docker](https://www.docker.com) 是 Kubernetes Pod 中最常用的容器运行时,但 Pod 也能支持其他的[容器运行时](https://kubernetes.io/docs/setup/production-environment/container-runtimes/)。 + +Kubernetes 集群中的 Pod 可被用于以下两个主要用途: + + + +* **运行单个容器的 Pod**。"每个 Pod 一个容器"模型是最常见的 Kubernetes 用例;在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。 +* **运行多个协同工作的容器的 Pod**。 +Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 +这些位于同一位置的容器可能形成单个内聚的服务单元——一个容器将文件从共享卷提供给公众,而另一个单独的“挂斗”容器则刷新或更新这些文件。 +Pod 将这些容器和存储资源打包为一个可管理的实体。 + + + +[Kubernetes 博客](http://kubernetes.io/blog) 上有一些其他的 Pod 用例信息。更多信息请参考: + +* [分布式系统工具包:复合容器的模式](https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns) +* [容器设计模式](https://kubernetes.io/blog/2016/06/container-design-patterns) + + + +每个 Pod 表示运行给定应用程序的单个实例。如果希望横向扩展应用程序(例如,运行多个实例),则应该使用多个 Pod,每个实例使用一个。 +在 Kubernetes 中,这通常被称为 _副本_。 +通常使用一个称为控制器的抽象来创建和管理一组被复制的 Pod。 +更多信息请参见 [POD 和控制器](#pods-and-controllers)。 + + + +### Pod 怎样管理多个容器 + +Pod 被设计成支持形成内聚服务单元的多个协作过程(作为容器)。 +Pod 中的容器被自动的安排到集群中的同一物理或虚拟机上,并可以一起进行调度。 +容器可以共享资源和依赖、彼此通信、协调何时以及何种方式终止它们。 + + + +注意,在单个 Pod 中将多个并置和共同管理的容器分组是一个相对高级的使用方式。 +只在容器紧密耦合的特定实例中使用此模式。 +例如,您可能有个充当共享卷中文件的 Web 服务器的容器,以及从远程源更新这些文件的单独的"挂斗"容器,如下图所示: + + +{{< figure src="/images/docs/pod.svg" title="pod diagram" width="50%" >}} + + + +Pod 为其组成容器提供了两种共享资源:*网络* 和 *存储*。 + + + +#### 联网 + +每个 Pod 分配一个唯一的 IP 地址。 +Pod 中的每个容器共享网络命名空间,包括 IP 地址和网络端口。 +*Pod 内的容器* 可以使用 `localhost` 互相通信。 +当 Pod 中的容器与 *Pod 之外* 的实体通信时,它们必须协调如何使用共享的网络资源(例如端口)。 + + + +#### 存储 + +一个 Pod 可以指定一组共享存储 *卷*。 +Pod 中的所有容器都可以访问共享卷,允许这些容器共享数据。 +卷还允许 Pod 中的持久数据在重启 Pod 中的某个容器时存活。 +有关 Kubernetes 如何在 Pod 中实现共享存储的更多信息,请参考 [卷](/docs/concepts/storage/volumes/)。 + + + +## 使用 Pod + +你很少在 Kubernetes 中直接创建单独的 Pod,甚至是单个存在的 Pod。 +这是因为 Pod 被设计成了相对短暂的一次性的实体。 +当 Pod 由您创建或者间接地由控制器创建时,它被调度在集群中的节点上运行。 +Pod 会保持在该节点上运行,直到进程被终止、Pod 对象被删除、Pod 因资源不足而被 *驱逐* 或者节点失效为止。 +{{< note >}} + +重启 Pod 中的容器不应与重启 Pod 混淆。Pod 本身不运行,而是作为容器运行的环境,并且一直保持到被删除为止。 +{{< /note >}} + + + +Pod 本身并不能自愈。 +如果 Pod 被调度到失败的节点,或者如果调度操作本身失败,则删除该 Pod;同样,由于缺乏资源或进行节点维护,Pod 在被驱逐后将不再生存。 +Kubernetes 使用了一个更高级的称为 *控制器* 的抽象,由它处理相对可丢弃的 Pod 实例的管理工作。 +因此,虽然可以直接使用 Pod,但在 Kubernetes 中,更为常见的是使用控制器管理 Pod。 +有关 Kubernetes 如何使用控制器实现 Pod 伸缩和愈合的更多信息,请参考 [Pod 和控制器](#pods-and-controllers)。 + + + +### Pod 和控制器 + +控制器可以为您创建和管理多个 Pod,管理副本和上线,并在集群范围内提供自修复能力。 +例如,如果一个节点失败,控制器可以在不同的节点上调度一样的替身来自动替换 Pod。 + + + +包含一个或多个 Pod 的控制器一些示例包括: + +* [Deployment](/docs/concepts/workloads/controllers/deployment/) +* [StatefulSet](/docs/concepts/workloads/controllers/statefulset/) +* [DaemonSet](/docs/concepts/workloads/controllers/daemonset/) + +控制器通常使用您提供的 Pod 模板来创建它所负责的 Pod。 + + + +## Pod 模板 + +Pod 模板是包含在其他对象中的 Pod 规范,例如 +[Replication Controllers](/docs/concepts/workloads/controllers/replicationcontroller/)、 [Jobs](/docs/concepts/jobs/run-to-completion-finite-workloads/)、和 +[DaemonSets](/docs/concepts/workloads/controllers/daemonset/)。 +控制器使用 Pod 模板来制作实际使用的 Pod。 +下面的示例是一个简单的 Pod 清单,它包含一个打印消息的容器。 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: myapp-pod + labels: + app: myapp +spec: + containers: + - name: myapp-container + image: busybox + command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600'] +``` + + + +Pod 模板就像饼干切割器,而不是指定所有副本的当前期望状态。 +一旦饼干被切掉,饼干就与切割器没有关系。 +没有“量子纠缠”。 +随后对模板的更改或甚至切换到新的模板对已经创建的 Pod 没有直接影响。 +类似地,由副本控制器创建的 Pod 随后可以被直接更新。 +这与 Pod 形成有意的对比,Pod 指定了属于 Pod 的所有容器的当前期望状态。 +这种方法从根本上简化了系统语义,增加了原语的灵活性。 + +{{% /capture %}} + +{{% capture whatsnext %}} + +* 进一步了解 Pod 的行为: + * [Pod 的终止](/docs/concepts/workloads/pods/pod/#termination-of-pods) + * 其他 Pod 话题 +{{% /capture %}} diff --git a/content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md b/content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md new file mode 100644 index 0000000000..3501fac9c2 --- /dev/null +++ b/content/zh/docs/concepts/workloads/pods/pod-topology-spread-constraints.md @@ -0,0 +1,402 @@ +--- +title: Pod 拓扑扩展约束 +content_template: templates/concept +weight: 50 +--- + + + + +{{% capture overview %}} + +{{< feature-state for_k8s_version="v1.16" state="alpha" >}} + + + +可以使用_拓扑扩展约束_来控制 {{< glossary_tooltip text="Pods" term_id="Pod" >}} 在集群内故障域(例如地区,区域,节点和其他用户自定义拓扑域)之间的分布。这可以帮助实现高可用以及提升资源利用率。 + +{{% /capture %}} + +{{% capture body %}} + + + +## 先决条件 + + + +### 启用功能 + + + +确保 `EvenPodsSpread` 功能已开启(在 1.16 版本中该功能默认关闭)。阅读[功能选项](/docs/reference/command-line-tools-reference/feature-gates/)了解如何开启该功能。`EvenPodsSpread` 必须在 {{< glossary_tooltip text="API Server" term_id="kube-apiserver" >}} **和** {{< glossary_tooltip text="scheduler" term_id="kube-scheduler" >}} 中都要开启。 + + + +### 节点标签 + + + +拓扑扩展约束依赖于节点标签来标识每个节点所在的拓扑域。例如,一个节点可能具有标签:`node=node1,zone=us-east-1a,region=us-east-1` + + + +假设你拥有一个具有以下标签的 4 节点集群: + +``` +NAME STATUS ROLES AGE VERSION LABELS +node1 Ready 4m26s v1.16.0 node=node1,zone=zoneA +node2 Ready 3m58s v1.16.0 node=node2,zone=zoneA +node3 Ready 3m17s v1.16.0 node=node3,zone=zoneB +node4 Ready 2m43s v1.16.0 node=node4,zone=zoneB +``` + + + +然后从逻辑上看集群如下: + +``` ++---------------+---------------+ +| zoneA | zoneB | ++-------+-------+-------+-------+ +| node1 | node2 | node3 | node4 | ++-------+-------+-------+-------+ +``` + + + +可以复用在大多数集群上自动创建和填充的[知名标签](/docs/reference/kubernetes-api/labels-annotations-taints/),而不是手动添加标签。 + + + +## Pod 的拓扑约束 + +### API + + + +`pod.spec.topologySpreadConstraints` 字段定义如下所示: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: mypod +spec: + topologySpreadConstraints: + - maxSkew: + topologyKey: + whenUnsatisfiable: + labelSelector: +``` + + + +可以定义一个或多个 `topologySpreadConstraint` 来指示 kube-scheduler 如何将每个传入的 Pod 根据与现有的 Pod 的关联关系在集群中部署。字段包括: + + + +- **maxSkew** 描述 pod 分布不均的程度。这是给定拓扑类型中任意两个拓扑域中匹配的 pod 之间的最大允许差值。它必须大于零。 +- **topologyKey** 是节点标签的键。如果两个节点使用此键标记并且具有相同的标签值,则调度器会将这两个节点视为处于同一拓扑中。调度器试图在每个拓扑域中放置数量均衡的 pod。 +- **whenUnsatisfiable** 指示如果 pod 不满足扩展约束时如何处理: + - `DoNotSchedule`(默认)告诉调度器不用进行调度。 + - `ScheduleAnyway` 告诉调度器在对最小化倾斜的节点进行优先级排序时仍对其进行调度。 +- **labelSelector** 用于查找匹配的 pod。匹配此标签的 pod 将被统计,以确定相应拓扑域中 pod 的数量。有关详细信息,请参考[标签选择器](/docs/concepts/overview/working-with-objects/labels/#label-selectors)。 + + + +执行 `kubectl explain Pod.spec.topologySpreadConstraints` 命令了解更多关于 topologySpreadConstraints 的信息。 + + + +### 例子:单个拓扑扩展约束 + + + +假设你拥有一个 4 节点集群,其中标记为 `foo:bar` 的 3 个 pod 分别位于 node1,node2 和 node3 中(`P` 表示 pod): + +``` ++---------------+---------------+ +| zoneA | zoneB | ++-------+-------+-------+-------+ +| node1 | node2 | node3 | node4 | ++-------+-------+-------+-------+ +| P | P | P | | ++-------+-------+-------+-------+ +``` + + + +如果希望传入的 pod 均匀散布在现有的 pod 区域,则可以指定字段如下: + +{{< codenew file="pods/topology-spread-constraints/one-constraint.yaml" >}} + + + +`topologyKey: zone` 意味着均匀分布将只应用于存在标签对为 "zone:" 的节点上。`whenUnsatisfiable: DoNotSchedule` 告诉调度器,如果传入的 pod 不满足约束,则让它保持挂起状态。 + + + +如果调度器将传入的 pod 放入 "zoneA",pod 分布将变为 [3, 1],因此实际的倾斜为 2(3 - 1)。这违反了 `maxSkew: 1`。此示例中,传入的 pod 只能放置在 "zoneB" 上: + +``` ++---------------+---------------+ +---------------+---------------+ +| zoneA | zoneB | | zoneA | zoneB | ++-------+-------+-------+-------+ +-------+-------+-------+-------+ +| node1 | node2 | node3 | node4 | OR | node1 | node2 | node3 | node4 | ++-------+-------+-------+-------+ +-------+-------+-------+-------+ +| P | P | P | P | | P | P | P P | | ++-------+-------+-------+-------+ +-------+-------+-------+-------+ +``` + + + +可以调整 pod 规格以满足各种要求: + + + +- 将 `maxSkew` 更改为更大的值,比如 "2",这样传入的 pod 也可以放在 "zoneA" 上。 +- 将 `topologyKey` 更改为 "node",以便将 pod 均匀分布在节点上而不是区域中。在上面的例子中,如果 `maxSkew` 保持为 "1",那么传入的 pod 只能放在 "node4" 上。 +- 将 `whenUnsatisfiable: DoNotSchedule` 更改为 `whenUnsatisfiable: ScheduleAnyway`,以确保传入的 pod 始终可以调度(假设满足其他的调度 API)。但是,最好将其放置在具有较少匹配 pod 的拓扑域中。(请注意,此优先性与其他内部调度优先级(如资源使用率等)一起进行标准化。) + + + +### 例子:多个拓扑扩展约束 + + + +下面的例子建立在前面例子的基础上。假设你拥有一个 4 节点集群,其中 3 个标记为 `foo:bar` 的 pod 分别位于 node1,node2 和 node3 上(`P` 表示 pod): + +``` ++---------------+---------------+ +| zoneA | zoneB | ++-------+-------+-------+-------+ +| node1 | node2 | node3 | node4 | ++-------+-------+-------+-------+ +| P | P | P | | ++-------+-------+-------+-------+ +``` + + + +可以使用 2 个拓扑扩展约束来控制 pod 在 区域和节点两个维度上进行分布: + +{{< codenew file="pods/topology-spread-constraints/two-constraints.yaml" >}} + + + +在这种情况下,为了匹配第一个约束,传入的 pod 只能放置在 "zoneB" 中;而在第二个约束中,传入的 pod 只能放置在 "node4" 上。然后两个约束的结果加在一起,因此唯一可行的选择是放置在 "node4" 上。 + + + +多个约束可能导致冲突。假设有一个跨越 2 个区域的 3 节点集群: + +``` ++---------------+-------+ +| zoneA | zoneB | ++-------+-------+-------+ +| node1 | node2 | nod3 | ++-------+-------+-------+ +| P P | P | P P | ++-------+-------+-------+ +``` + + + +如果对集群应用 "two-constraints.yaml",会发现 "mypod" 处于 `Pending` 状态。这是因为:为了满足第一个约束,"mypod" 只能放在 "zoneB" 中,而第二个约束要求 "mypod" 只能放在 "node2" 上。pod 调度无法满足两种约束。 + + + +为了克服这种情况,可以增加 `maxSkew` 或修改其中一个约束,让其使用 `whenUnsatisfiable: ScheduleAnyway`。 + + + +### 约定 + + + +这里有一些值得注意的隐式约定: + + + +- 只有与传入 pod 具有相同命名空间的 pod 才能作为匹配候选者。 + + + +- 没有 `topologySpreadConstraints[*].topologyKey` 的节点将被忽略。这意味着: + 1. 位于这些节点上的 pod 不影响 `maxSkew` 的计算。在上面的例子中,假设 "node1" 没有标签 "zone",那么 2 个 pod 将被忽略,因此传入的 pod 将被调度到 "zoneA" 中。 + 2. 传入的 pod 没有机会被调度到这类节点上。在上面的例子中,假设一个带有标签 `{zone-typo: zoneC}` 的 "node5" 加入到集群,它将由于没有标签键 "zone" 而被忽略。 + + + +注意,如果传入 pod 的 `topologySpreadConstraints[*].labelSelector` 与自身的标签不匹配,将会发生什么。在上面的例子中,如果移除传入 pod 的标签,pod 仍然可以调度到 "zoneB",因为约束仍然满足。然而,在调度之后,集群的不平衡程度保持不变。zoneA 仍然有 2 个带有 {foo:bar} 标签的 pod,zoneB 有 1 个带有 {foo:bar} 标签的 pod。因此,如果这不是你所期望的,建议工作负载的 `topologySpreadConstraints[*].labelSelector` 与其自身的标签匹配。 + + + +- 如果传入的 pod 定义了 `spec.nodeSelector` 或 `spec.affinity.nodeAffinity`,则将忽略不匹配的节点。 + + + + 假设有一个从 zonea 到 zonec 的 5 节点集群: + + + ``` + +---------------+---------------+-------+ + | zoneA | zoneB | zoneC | + +-------+-------+-------+-------+-------+ + | node1 | node2 | node3 | node4 | node5 | + +-------+-------+-------+-------+-------+ + | P | P | P | | | + +-------+-------+-------+-------+-------+ + ``` + + + + 你知道 "zoneC" 必须被排除在外。在这种情况下,可以按如下方式编写 yaml,以便将 "mypod" 放置在 "zoneB" 上,而不是 "zoneC" 上。同样,`spec.nodeSelector` 也要一样处理。 + + {{< codenew file="pods/topology-spread-constraints/one-constraint-with-nodeaffinity.yaml" >}} + + + +## 与 PodAffinity/PodAntiAffinity 相比较 + + + +在 Kubernetes 中,与 "Affinity" 相关的指令控制 pod 的调度方式(更密集或更分散)。 + + + +- 对于 `PodAffinity`,可以尝试将任意数量的 pod 打包到符合条件的拓扑域中。 +- 对于 `PodAntiAffinity`,只能将一个 pod 调度到单个拓扑域中。 + + + +"EvenPodsSpread" 功能提供灵活的选项来将 pod 均匀分布到不同的拓扑域中,以实现高可用性或节省成本。这也有助于滚动更新工作负载和平滑扩展副本。有关详细信息,请参考[动机](https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/20190221-even-pods-spreading.md#motivation)。 + + + +## 已知局限性 + + + +1.16 版本(此功能为 alpha)存在下面的一些限制: + + + +- `Deployment` 的缩容可能导致 pod 分布不平衡。 +- pod 匹配到污点节点是允许的。参考 [Issue 80921](https://github.com/kubernetes/kubernetes/issues/80921)。 + +{{% /capture %}} diff --git a/content/zh/docs/concepts/workloads/pods/pod.md b/content/zh/docs/concepts/workloads/pods/pod.md new file mode 100644 index 0000000000..8ad79f817d --- /dev/null +++ b/content/zh/docs/concepts/workloads/pods/pod.md @@ -0,0 +1,399 @@ +--- +reviewers: +title: Pods +content_template: templates/concept +weight: 20 +--- + + + +{{% capture overview %}} + + + +_Pods_ 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。 + +{{% /capture %}} + + +{{% capture body %}} + + + +## Pod 是什么? + +_pod_ (就像在鲸鱼荚或者豌豆荚中)是一组(一个或多个)容器(例如 Docker 容器),这些容器有共享存储、网络、以及怎样运行这些容器的声明。Pod 的内容总是共同定位和共同调度,并且在共享的上下文中运行。 +Pod 以特定于应用的“逻辑主机”为模型,它包含一个或多个应用容器,这些容器是相对紧密的耦合在一起;在容器出现之前,在相同的物理机或虚拟机上运行意味着在相同的逻辑主机上运行。 + + + +虽然 Kubernetes 支持多种容器运行时,但 Docker 是最常见的一种运行时,它有助于描述 Docker 术语中的 Pod。 + +Pod 的共享上下文是一组 Linux 命名空间、cgroups、以及其他潜在的资源隔离相关的因素,这些相同的东西也隔离了 Docker 容器。在 Pod 的上下文中,单个应用程序可能还会应用进一步的子隔离。 + + + +Pod 中的所有容器共享一个 IP 地址和端口空间,并且可以通过 `localhost` 互相发现。他们也能通过标准的进程间通信(如 SystemV 信号量或 POSIX 共享内存)方式进行互相通信。不同 Pod 中的容器的 IP 地址互不相同,没有 [特殊配置](/docs/concepts/policy/pod-security-policy/) 就不能使用 IPC 进行通信。这些容器之间经常通过 Pod IP 地址进行通信。 + +Pod 中的应用也能访问共享卷,共享卷是 Pod 定义的一部分,可被用来挂载到每个应用的文件系统上。 + + + +在 [Docker](https://www.docker.com/) 体系的术语中,Pod 被建模为一组具有共享命名空间和共享 [卷](/docs/concepts/storage/volumes/) 的 Docker 容器。 + +与单个应用程序容器一样,Pod被认为是相对短暂的(而不是持久的)实体。如 [Pod 的生命](/docs/concepts/workloads/pods/pod-lifecycle/) 所讨论的那样:Pod 被创建、给它指定一个唯一 ID (UID)、被调度到节点、在节点上存续直到终止(取决于重启策略)或被删除。如果节点宕机,调度到该节点上的 Pod 会在一个超时周期后被安排删除。给定 Pod (由 UID 定义)不会重新调度到新节点;相反,它会被一个完全相同的 Pod 替换掉,如果需要甚至连 Pod 名称都可以一样,除了 UID 是新的(更多信息请查阅 [副本控制器(replication +controller)](/docs/concepts/workloads/controllers/replicationcontroller/))。 + + + +当某些东西被说成与 Pod(如卷)具有相同的生存期时,这意味着只要pod(具有该UID)存在,它就存在。如果那个 Pod 因为某种原因被删除了,即使创建了相同的 Pod 做替换,Pod 的相关的资源(如卷等)也会被销毁进行重新创建。 + +{{< figure src="/images/docs/pod.svg" title="pod diagram" width="50%" >}} + + + +包含多个容器的 Pod 包含文件拉取器和 web 服务器,使用了持久卷在容器之间进行存储共享。 + +{{< figure src="/images/docs/pod.svg" title="pod diagram" width="50%" >}} + + + + +## Pod 的动机 + +### 管理 + +Pod 是形成内聚服务单元的多个协作过程模式的模型。它们提供了一个比它们的应用组成集合更高级的抽象,从而简化了应用的部署和管理。Pod 可以用作部署单元、水平缩放和复制。在 Pod中,多个容器的共同定位(协同调度)、共享命运(例如,终止)、协调复制、资源共享和依赖项管理都是自动处理的。 + + + + +### 资源共享和通信 + +Pod 使它的组成容器间能够进行数据共享和通信。 + +Pod 中的应用都使用相同的网络命名空间(相同 IP 和 端口空间),而且能够互相“发现”并使用 `localhost` 进行通信。因此,在 Pod 中的应用必须协调它们的端口使用情况。每个 Pod 在扁平的共享网络空间中具有一个IP地址,该空间能与整个网络上的其他物理机或虚拟机进行完全通信。 + + + +主机名被设置为 Pod 内的应用程序容器的 Pod 名称。请参考[组网的更多信息](/docs/concepts/cluster-administration/networking/)。 + +Pod 除了定义了 Pod 中运行的应用程序容器之外,Pod 还指定了一组共享存储卷。该共享存储卷能使数据在容器重新启动后继续保留,并能在 Pod 内的应用程序之间共享。 + + + +## 使用 Pod + +Pod 可以用于托管垂直集成的应用程序栈(例如,LAMP),但最主要的动机是支持位于同一位置的、共同管理的帮助程序,例如: + +* 内容管理系统、文件和数据加载器、本地缓存管理器等。 +* 日志和检查点备份、压缩、旋转、快照等。 +* 数据更改监视器、日志跟踪器、日志和监视适配器、事件发布器等。 +* 代理、桥接器和适配器 +* 控制器、管理器、配置器和更新器 + + + + +通常,单个 Pod 并不打算运行同一应用程序的多个实例。 + +更多解释,请参考 [分布式系统工具包:复合容器的模式](https://kubernetes.io/blog/2015/06/the-distributed-system-toolkit-patterns) + + + +## 备选方案的思考 + +_为什么不在单个(Docker)容器中运行多个程序?_ + +1. 透明度。Pod 内的容器对基础设施可见,使得基础设施能够向这些容器提供服务,例如流程管理和资源监控。这为用户提供了许多便利。 +1. 解耦软件依赖关系。可以独立地对单个容器进行版本控制、重新构建和重新部署。Kubernetes 有一天甚至可能支持单个容器的实时更新。 +1. 易用性。用户不需要运行他们自己的进程管理器、也不用担心信号和退出代码传播等。 +1. 效率。因为基础结构承担了更多的责任,所以容器可以变得更加轻量化。 + + + +_为什么不支持基于亲和性的容器联合调度?_ + +这种处理方法尽管可以提供同址,但不能提供 Pod 的大部分好处,如资源共享、IPC、有保证的命运共享和简化的管理。 + + + +## Pod 的持久性(或稀缺性) + +Pod 并没想被视为持久的实体。它们无法在调度失败、节点故障或其他驱逐策略(例如由于缺乏资源或在节点维护的情况下)中生存。 + +一般来说,用户不需要直接创建 Pod。他们几乎都是使用控制器进行创建,即使对于单例的创建也一样使用控制器,例如 [Deployments](/docs/concepts/workloads/controllers/deployment/)。 +控制器提供集群范围的自修复以及复制和滚动管理。 +像 [StatefulSet](/docs/concepts/workloads/controllers/statefulset.md) 这样的控制器还可以提供支持有状态的 Pod。 + + + +在集群调度系统中,使用 API 合集作为面向用户的主要原语是比较常见的,包括 [Borg](https://research.google.com/pubs/pub43438.html)、[Marathon](https://mesosphere.github.io/marathon/docs/rest-api.html)、[Aurora](http://aurora.apache.org/documentation/latest/reference/configuration/#job-schema)、和 [Tupperware](https://www.slideshare.net/Docker/aravindnarayanan-facebook140613153626phpapp02-37588997)。 + + + +Pod 暴露为原语是为了便于: + +* 调度器和控制器可插拔性 +* 支持 Pod 级别的操作,而不需要通过控制器 API "代理" 它们 +* Pod 生命与控制器生命的解耦,如自举 +* 控制器和服务的解耦;端点控制器只监视 Pod +* Kubelet 级别的功能与集群级别功能的清晰组合;Kubelet 实际上是 "Pod 控制器" +* 高可用性应用程序期望在 Pod 终止之前并且肯定要在 Pod 被删除之前替换 Pod,例如在计划驱逐或镜像预先提取的情况下。 + + + +## Pod 的终止 + +因为 Pod 代表在集群中的节点上运行的进程,所以当不再需要这些进程时(与被 KILL 信号粗暴地杀死并且没有机会清理相比),允许这些进程优雅地终止是非常重要的。 +用户应该能够请求删除并且知道进程何时终止,但是也能够确保删除最终完成。当用户请求删除 Pod 时,系统会记录在允许强制删除 Pod 之前所期望的宽限期,并向每个容器中的主进程发送 TERM 信号。一旦过了宽限期,KILL 信号就发送到这些进程,然后就从 API 服务器上删除 Pod。如果 Kubelet 或容器管理器在等待进程终止时发生重启,则终止操作将以完整的宽限期进行重试。 + + + + +流程示例: + +1. 用户发送命令删除 Pod,使用的是默认的宽限期(30秒) +2. API 服务器中的 Pod 会随着宽限期规定的时间进行更新,过了这个时间 Pod 就会被认为已 "死亡"。 +3. 当使用客户端命令查询 Pod 状态时,Pod 显示为 "Terminating"。 +4. (和第3步同步进行)当 Kubelet 看到 Pod 由于步骤2中设置的时间而被标记为 terminating 状态时,它就开始执行关闭 Pod 流程。 + 1. 如果 Pod 定义了 [preStop 钩子](/docs/concepts/containers/container-lifecycle-hooks/#hook-details),就在 Pod 内部调用它。如果宽限期结束了 `preStop` 钩子还在运行,那么就用小的(2秒)扩展宽限期调用步骤2。 + + 2. 给 Pod 内的进程发送 TERM 信号。 +5. (和第3步同步进行)从服务的端点列表中删除 Pod,Pod也不再被视为副本控制器的运行状态的 Pod 集的一部分。当负载平衡器(如服务代理)将 Pod 从轮换中移除时,关闭迟缓的 Pod 将不能继续为流量服务。 +6. 当宽限期结束后,Pod 中运行的任何进程都将被用 SIGKILL 杀死。 +7. Kubelet 将通过设置宽限期为0(立即删除)来完成删除 API 服务器上的 Pod。Pod 从 API 中消失,从客户端也不再可见。 + + + + +默认情况下,所有删除在30秒内都是优雅的。`kubectl delete` 命令支持 `--grace-period=` 选项,允许用户覆盖默认值并声明他们自己的宽限期。设置为 ‘0’ 会[强制删除](/docs/concepts/workloads/pods/pod/#force-deletion-of-pods) Pod。在 kubectl 1.5以后的版本(含1.5版本)中,为了执行强制删除,您还必须为 `--grace-period=0` 声明一个额外的 `--force` 标志。 + + + +### Pod 的强制删除 + +强制删除pod定义为从集群状态和 etcd 中立即删除 Pod。当执行强制删除时,apiserver 并不会等待 kubelet 的确认信息,该 Pod 已在所运行的节点上被终止了。强制删除操作从 API 中立即清除了 Pod, 因此可以用相同的名称创建一个新的 Pod。在节点上,设置为立即终止的 Pod 还是会在被强制删除前设置一个小的宽限期。 + +强制删除对某些 Pod 可能具有潜在危险,因此应该谨慎地执行。对于 StatefulSet 管理的 Pod,请参考 [从 StatefulSet 中删除 Pod](/docs/tasks/run-application/force-delete-stateful-set-pod/)的任务文档。 + + + +## Pod 容器的特权模式 + +从 Kubernetes v1.1 开始,Pod 内的任何容器都可以开启特权模式,开启的方法是在容器声明中的 `SecurityContext` 域使用 `privileged` 标志。这对于希望使用linux功能(如操作网络堆栈和访问设备)的容器非常有用。容器内的进程获得的特权与容器外的进程几乎相同。使用特权模式,将网络和卷插件编写为不需要编译到 kubelet 中的独立的 Pod 应该更容易。 + +如果主节点的 Kubernetes 版本是 v1.1 或更高,而工作节点的版本低于 v1.1,新的特权 Pod 将被 API 服务器接受,但不会被启动。它们将处于 pending 状态。如果用户使用命令 `kubectl describe pod FooPodName`,就可以看到 Pod 处于 pending 状态的原因。`describe` 命令的输出事件列表将显示: +`Error validating pod "FooPodName"."FooPodNamespace" from api, ignoring: spec.containers[0].securityContext.privileged: forbidden '<*>(0xc2089d3248)true'` + + + +如果主节点的版本低于 v1.1,那么特权 Pod 就不能被创建。如果用户尝试创建有特权容器的 Pod,将会得到下面的错误信息: +`The Pod "FooPodName" is invalid. +spec.containers[0].securityContext.privileged: forbidden '<*>(0xc20b222db0)true'` + + + +## API 对象 + +Pod 是 Kubernetes REST API 中的顶级资源。关于该 API 对象的更详细信息请参考 [Pod API 对象](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#pod-v1-core)。 diff --git a/content/zh/docs/concepts/workloads/pods/podpreset.md b/content/zh/docs/concepts/workloads/pods/podpreset.md index cce548b0a3..114231a587 100644 --- a/content/zh/docs/concepts/workloads/pods/podpreset.md +++ b/content/zh/docs/concepts/workloads/pods/podpreset.md @@ -1,72 +1,151 @@ --- -approvers: +reviewers: - jessfraz title: Pod Preset content_template: templates/concept +weight: 50 --- {{% capture overview %}} -本文提供了 PodPreset 的概述。 在 pod 创建时,用户可以使用 `podpreset` 对象将特定信息注入 -pod 中,这些信息可以包括 secret、 卷、卷挂载和环境变量。 + +本文提供了 PodPreset 的概述。 在 Pod 创建时,用户可以使用 PodPreset 对象将特定信息注入 Pod 中,这些信息可以包括 secret、 卷、卷挂载和环境变量。 {{% /capture %}} -{{< toc >}} {{% capture body %}} + + + ## 理解 Pod Preset -`Pod Preset` 是一种 API 资源,在 pod 创建时,用户可以用它将额外的运行时需求信息注入 pod。 -使用[标签选择器(label selector)](/docs/concepts/overview/working-with-objects/labels/#label-selectors)来指定 Pod Preset 所适用的 pod。 +`Pod Preset` 是一种 API 资源,在 Pod 创建时,用户可以用它将额外的运行时需求信息注入 Pod。 +使用[标签选择器(label selector)](/docs/concepts/overview/working-with-objects/labels/#label-selectors)来指定 Pod Preset 所适用的 Pod。 -使用 Pod Preset 使得 pod 模板编写者不必显式地为每个 pod 设置信息。 -这样,使用特定服务的 pod 模板编写者不需要了解该服务的所有细节。 + + +使用 Pod Preset 使得 Pod 模板编写者不必显式地为每个 Pod 设置信息。 +这样,使用特定服务的 Pod 模板编写者不需要了解该服务的所有细节。 + + 了解更多的相关背景信息,请参考 [ PodPreset 设计提案](https://git.k8s.io/community/contributors/design-proposals/service-catalog/pod-preset.md)。 + + ## PodPreset 如何工作 -Kubernetes 提供了准入控制器 (`PodPreset`),该控制器被启用时,会将 Pod Preset -应用于接收到的 pod 创建请求中。 -当出现 pod 创建请求时,系统会执行以下操作: +Kubernetes 提供了准入控制器 (`PodPreset`),该控制器被启用时,会将 Pod Preset +应用于接收到的 Pod 创建请求中。 +当出现 Pod 创建请求时,系统会执行以下操作: + + 1. 检索所有可用 `PodPresets` 。 -1. 检查 `PodPreset` 的标签选择器与要创建的 pod 的标签是否匹配。 -1. 尝试合并 `PodPreset` 中定义的各种资源,并注入要创建的 pod。 -1. 发生错误时抛出事件,该事件记录了 pod 信息合并错误,同时在 _不注入_ `PodPreset` 信息的情况下创建 pod。 -1. 为改动的 pod spec 添加注解,来表明它被 `PodPreset` 所修改。 注解形如: +1. 检查 `PodPreset` 的标签选择器与要创建的 Pod 的标签是否匹配。 +1. 尝试合并 `PodPreset` 中定义的各种资源,并注入要创建的 Pod。 +1. 发生错误时抛出事件,该事件记录了 pod 信息合并错误,同时在 _不注入_ `PodPreset` 信息的情况下创建 Pod。 +1. 为改动的 Pod spec 添加注解,来表明它被 `PodPreset` 所修改。 注解形如: `podpreset.admission.kubernetes.io/podpreset-": ""`。 -一个 Pod 可能不与任何 Pod Preset 匹配,也可能匹配多个 Pod Preset。 同时,一个 `PodPreset` + + +一个 Pod 可能不与任何 Pod Preset 匹配,也可能匹配多个 Pod Preset。 同时,一个 `PodPreset` 可能不应用于任何 Pod,也可能应用于多个 Pod。 当 `PodPreset` 应用于一个或多个 Pod 时,Kubernetes 修改 pod spec。 对于 `Env`、 `EnvFrom` 和 `VolumeMounts` 的改动, Kubernetes 修改 pod 中所有容器的规格,对于卷的改动,Kubernetes 修改 Pod spec。 + {{< note >}} -**注意:** Pod Preset 能够在适当的时候修改 Pod spec 的 `spec.containers` 字段, -但是不会应用于 `initContainers` 字段。 + + +Pod Preset 能够在适当的时候修改 Pod spec 的 `spec.containers` 字段,但是不会应用于 `initContainers` 字段。 {{< /note >}} + + ### 为特定 Pod 禁用 Pod Preset -在一些情况下,用户不希望 pod 被 pod preset 所改动,这时,用户可以在 pod spec 中添加形如 - `podpreset.admission.kubernetes.io/exclude: "true"` 的注解。 +在一些情况下,用户不希望 Pod 被 Pod Preset 所改动,这时,用户可以在 Pod spec 中添加形如 `podpreset.admission.kubernetes.io/exclude: "true"` 的注解。 + + ## 启用 Pod Preset 为了在集群中使用 Pod Preset,必须确保以下几点: -1. 已启用 api 类型 `settings.k8s.io/v1alpha1/podpreset`。 这可以通过在 API 服务器的 - `--runtime-config` 配置项中包含 `settings.k8s.io/v1alpha1=true` 来实现。 -1. 已启用准入控制器 `PodPreset`。 启用的一种方式是在 API 服务器的 `--admission-control` - 配置项中包含 `PodPreset` 。 -1. 已经通过在相应的名字空间中创建 `PodPreset` 对象,定义了 Pod preset。 + + +1. 已启用 API 类型 `settings.k8s.io/v1alpha1/podpreset`。 这可以通过在 API 服务器的 `--runtime-config` 配置项中包含 `settings.k8s.io/v1alpha1=true` 来实现。 +1. 已启用准入控制器 `PodPreset`。 启用的一种方式是在 API 服务器的 `--admission-control` 配置项中包含 `PodPreset` 。 +1. 已经通过在相应的命名空间中创建 `PodPreset` 对象,定义了 Pod Preset。 + {{% /capture %}} {{% capture whatsnext %}} - -* [使用 PodPreset 将信息注入 Pods](/docs/tasks/inject-data-application/podpreset/) - + +* [使用 PodPreset 将信息注入 Pod](/docs/tasks/inject-data-application/podpreset/) {{% /capture %}} - - diff --git a/content/zh/docs/contribute/_index.md b/content/zh/docs/contribute/_index.md new file mode 100644 index 0000000000..a3ec22713b --- /dev/null +++ b/content/zh/docs/contribute/_index.md @@ -0,0 +1,173 @@ +--- +content_template: templates/concept +title: 为 Kubernetes 文档做贡献 +linktitle: 贡献 +main_menu: true +weight: 80 +--- + + + +{{% capture overview %}} + + + +如果你想帮助对 Kubernetes 文档或网站做出贡献,我们很高兴得到你的帮助! +任何人都可以做出贡献,无论你刚参与项目还是参与了很长时间,无论你是开发人员还是用户,或是无法忍受看到拼写错误的人。 + + + +更多途径参与 Kubernetes 社区或了解我们,请访问 [Kubernetes 社区网站](/community/)。 + + + +查找 [样式指南](/docs/contribute/style/style-guide/) 或者 [Kubernetes 社区网站](/community/)? + +{{% /capture %}} + +{{% capture body %}} + + + +## 贡献者类型 + + + +- [签署了 CLA](/docs/contribute/start#sign-the-cla)并为项目贡献了时间和精力的 Kubernetes 组织的_成员_。 + 参见 [社区成员](https://github.com/kubernetes/community/blob/master/community-membership.md) 中对于成员资格的具体标准。 + + + +- SIG Docs 的_评审者_是对评审文档 PR 感兴趣,并被 SIG Docs 审批者添加到 Github 群组并在 Github 仓库中 `OWNERS` 文件的 Kubernetes 组织的成员。 + + + +- SIG Docs 的_审批者_是对项目持续贡献,并被授予合并 PR 权限和代表 Kubernetes 组织发布内容的成员。 + 批准人也可以在更广泛的 Kubernetes 社区中代表 SIG Docs 团队。 + SIG Docs审批者的一些职责,如协调发布版本,需要大量的时间投入。 + + + +## 贡献途径 + + + +以下列表将工作分成了:任何人都可以做的工作、Kubernetes 组织成员可以做的工作,和熟悉 SIG Docs 流程并且有更高访问权限才能做的工作。 +持续的贡献可以帮助你理解已有的工具和组织决策。 + + + +你对 Kubernetes 文档可以做出的贡献不仅限于列表列出的条目,但它可以帮助你开动起来。 + + + +- [任何人](/docs/contribute/start/) + - 登记记录可修正的错误 + + + +- [成员](/docs/contribute/start/) + - 完善已有文档 + - 在 Slack 或 SIG Docs 邮件列表中提出改进意见 + - 提升文档的易用性 + - 对 PR 提出无约束的反馈 + - 编写博文和案例分析 + + + +- [评审者](/docs/contribute/intermediate/) + - 为新功能特性编写文档 + - 对 issue 进行筛选和分类 + - 评审 PR + - 创建图表、图形分析和嵌入式的屏幕/视频 + - 本地化 + - 作为 docs 小组的代表为其他项目仓库做贡献 + - 在代码中编辑面向用户的字符串 + - 改进代码注释和 Godoc + + + +- [审批者](/docs/contribute/advanced/) + - 通过批准和合并 PR 发布贡献成果 + - 作为 docs 团队的代表参与 Kubernetes 发布团队 + - 对样式指南提出改进建议 + - 对文档测试提出改进建议 + - 对 Kubernetes 网站或其他工具提出改进建议 + +{{% /capture %}} diff --git a/content/zh/docs/contribute/advanced.md b/content/zh/docs/contribute/advanced.md new file mode 100644 index 0000000000..743e07171c --- /dev/null +++ b/content/zh/docs/contribute/advanced.md @@ -0,0 +1,473 @@ +--- +title: 高级贡献 +slug: advanced +content_template: templates/concept +weight: 30 +--- + + +{{% capture overview %}} + + +如果你已经阅读并掌握[开始贡献](/docs/contribute/start/)和[中级贡献](/docs/contribute/intermediate/),并准备了解更多贡献的途径,请阅读此文。您需要使用 Git 命令行工具和其他工具做这些工作。 + +{{% /capture %}} + +{{% capture body %}} + + +## 做一周的 PR 管理者 + + +SIG Docs 的 [approvers](/docs/contribute/participating/#approvers) 可以成为 PR 管理者。SIG Docs approvers 会每周轮换地加入到 [PR 管理者轮换日程](https://github.com/kubernetes/website/wiki/PR-Wranglers#2019-schedule-q1q2)中。 + + +PR 管理者的工作职责包括: + + +- 每天检查[悬决的 PR](https://github.com/kubernetes/website/pulls) 的质量并确保它们遵守[风格指南]](/docs/contribute/style/style-guide/)。 + - 首先查看最小的 PR(`size/XS`),然后逐渐扩展到最大的 PR(`size/XXL`)。 + - 尽可能多地审阅 PR。 +- 确保每个贡献者完成 CLA 签署。 + - 指导新的贡献者签署 [CLA](https://github.com/kubernetes/community/blob/master/CLA.md)。 + - 使用[此脚本](https://github.com/zparnold/k8s-docs-pr-botherer)自动提醒尚未签署 CLA 的贡献者签署 CLA。 +- 针对所建议的更改提供反馈,并帮助协调其他 SIG 成员进行技术审核。 + - 为 PR 所建议的内容更改提供在线反馈。 + - 如果您需要验证内容,请在 PR 上发表评论并要求贡献者提供更多细节。 + - 设置相关的 `sig/` 标签。 + - 如果需要,请从文件开头的 `reviewers:` 块中指定审阅者。 + - 设置 `Docs Review` 和 `Tech Review` 标签以标示 PR 的审阅状态。 + - 为尚未审阅的 PR 设置 `Needs Doc Review` 或者 `Needs Tech Review` 标签。 + - 为已审阅的但在合并前需要更多信息的或采取措施的 PR 设置 `Doc Review: Open Issues` 或者 `Tech Review: Open Issues` 标签。 + - 为可以合并的 PR 添加 `/lgtm` 和 `/approve` 标签。 +- 合并已经就绪的,或关闭不应该接受的 PR。 +- 每天对新增的 issues 进行分类和标记。有关 SIG 文档如何使用 metadata 的准则,请参见[中级贡献](/docs/contribute/intermediate/)。 + + +### 对于负责人有用的 GitHub 查询 + +执行管理操作时,以下查询很有用。完成以下三个查询后,剩余的要审阅的 PR 列表通常很小。 + + +- [没有签署 CLA, 不能 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): + 提醒贡献者签署 CLA。如果机器人和审阅者都已经提醒他们,请关闭 PR,并提醒他们在签署 CLA 后可以重新提交。 + **在作者没有签署 CLA 之前,不要审阅他们的 PR!** +- [需要 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+): + 如果需要技术审查,请告知机器人所建议的审阅者。如果 PR 需要文档审查或复制编辑,提交更改建议或向 PR 提交一个 copyedit 以使之进入下一步。 +- [有 LGTM ,需要批准](https://github.com/kubernetes/website/pulls?q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+label%3Algtm): + 确定 PR 是否需要进行其他更改或更新才能合并。如果您认为 PR 已准备好合并,请输入 `/approve`。 +- [非 master 分支的 PR](https://github.com/kubernetes/website/pulls?utf8=%E2%9C%93&q=is%3Aopen+is%3Apr+-label%3Ado-not-merge+label%3Alanguage%2Fen+-base%3Amaster): + 如果 PR 针对 `dev-` 分支,则表示它适用于即将发布的版本。请添加带有 `/assign @<负责人的 github 账号>` 的注释,确保[发行版本负责人](https://github.com/kubernetes/sig-release/tree/master/release-team)注意到该 PR。如果 PR 是针对旧分支,请帮助 PR 作者确定是否所针对的是最合适的分支。 + + +### 什么时候关闭 PR + +审查和批准是缩短和更新我们的 PR 队列的一种方式;另一种方式是关闭 PR。 + + +- 关闭两个星期未签署 CLA 的 PR。 +PR 作者可以在签署 CLA 后重新打开 PR,因此这是确保未签署 CLA 的 PR 不会被合并的一种风险较低的方法。 + +- 如果作者在两周或更长时间内未回复评论或反馈,请关闭 PR。 + +不要害怕关闭 PR。贡献者可以轻松地重新打开并继续工作。通常,关闭通知会激励作者继续完成其贡献。 + +要关闭 PR,请在 PR 上输入 `/close`。 + +{{< note >}} + + +一项名为 [`fejta-bot`](https://github.com/fejta-bot) 的自动服务会在 issues 停滞 90 天后会自动将其标记为过期;然后再等 30 天,如果仍然无人过问,则将其关闭。PR 管理者应该在 issues 处于无人过问状态 14-30 天后关闭它们。 + +{{< /note >}} + + +## 提出改进建议 + +SIG Docs 的 [成员](/docs/contribute/participating/#members) 可以提出改进建议。 + + +在对 Kubernetes 文档贡献了一段时间后,你可能会对样式指南、用于构建文档的工具链、网页样式、评审和合入 PR 的流程,或者文档的其他方面产生改进的想法。为了尽可能透明化,这些提议都需要在 SIG Docs 会议或 [kubernetes-sig-docs 邮件列表](https://groups.google.com/forum/#!forum/kubernetes-sig-docs)上讨论。此外,在提出全面的改进之前,它能真正帮助我们了解有关“当前工作如何运作”和“以往的决定是为何做出”的背景。想了解文档的当前运作方式,最快的途径是咨询 [kubernetes.slack.com](https://kubernetes.slack.com) 中的 `#sig-docs` 聊天群组。 + + +在进行了讨论并且 SIG 就期望的结果达成一致之后,你就能以最合理的方式处理改进建议了。例如,样式指南或网站功能的更新可能涉及 PR 的新增,而与文档测试相关的更改可能涉及 sig-testing。 + + +## 为 Kubernetes 版本发布协调文档 + + +SIG Docs 的[批准者(approvers)](/docs/contribute/participating/#approvers) 可以为 Kubernetes 版本发布协调文档。 + + +每一个 Kubernetes 版本都是由参与 sig-release 的 SIG(特别兴趣小组)的一个团队协调的。指定版本的发布团队中还包括总体发布牵头人,以及来自 sig-pm、sig-testing 的代表等。了解更多关于 Kubernetes 版本发布的流程,请参考 [https://github.com/kubernetes/sig-release](https://github.com/kubernetes/sig-release)。 + + +SIG Docs 团队的代表需要为一个指定的版本协调以下工作: + + +- 通过特性跟踪表来监视新功能特性或现有功能特性的修改。如果版本的某个功能特性的文档没有为发布做好准备,那么该功能特性不允许进入发布版本。 +- 定期参加 sig-release 会议并汇报文档的发布状态。 +- 评审和修改由负责实现某功能特性的 SIG 起草的功能特性文档。 +- 合入版本发布相关的 PR,并为对应发布版本维护 Git 特性分支。 +- 指导那些想学习并有意愿担当该角色的 SIG Docs 贡献者。这就是我们常说的“实习”。 +- 发布版本的组件发布时,相关的文档更新也需要发布。 + + +协调一个版本发布通常需要 3-4 个月的时间投入,该任务由 SIG Docs approvers 轮流承担。 + + +## 担任新的贡献者大使 + + +SIG Docs [approvers](/docs/contribute/participating/#approvers) 可以担任新的贡献者大使。 + +新的贡献者大使共同努力欢迎 SIG-Docs 的新贡献者,对新贡献者的 PR 提出建议,以及在前几份 PR 提交中指导新贡献者。 + +新的贡献者大使的职责包括: + + +- 可在 [Kubernetes #sig-docs 频道](https://kubernetes.slack.com) 上回答新贡献者的问题。 +- 与 PR 管理者合作为新参与者寻找合适的第一个 issues。 +- 通过前几个 PR 指导新贡献者到文档存储库。 +- 帮助新的贡献者创建成为 Kubernetes 成员所需的更复杂的 PR。 +- [为贡献者提供担保](/docs/contribute/advanced/#sponsor-a-new-contributor),使其成为 Kubernetes 成员。 + + +当前新贡献者大使将在每次 SIG 文档会议上以及 [Kubernetes #sig-docs 频道](https://kubernetes.slack.com)中宣布。 + + +## 为新的贡献者提供担保 + + +SIG Docs 的 [reviewers](/docs/contribute/participating/#reviewers) 可以为新的贡献者提供担保。 + + +新的贡献者针对一个或多个 Kubernetes 项目仓库成功提交了 5 个实质性 PR 之后,就有资格申请 Kubernetes 组织 [成员身份](/docs/contribute/participating#members)。贡献者的成员资格需要同时得到两位 reviewers 的保荐。 + + +新的文档贡献者可以通过咨询 [Kubernetes Slack 实例](https://kubernetes.slack.com) 上的 #sig-docs 频道或者 [SIG Docs 邮件列表](https://groups.google.com/forum/#!forum/kubernetes-sig-docs)来请求评审者保荐。如果你对申请人的工作充满信心,你自愿保荐他们。当他们提交成员资格申请时,回复 “+1” 并详细说明为什么你认为申请人适合加入 Kubernetes 组织。 + + +## 担任 SIG 联合主席 + +SIG Docs [approvers](/docs/contribute/participating/#approvers) 可以担任 SIG Docs 的联合主席。 + +### 前提条件 + + +Approvers 必须满足以下要求才能成为联合主席: + +- 已维持 SIG Docs approver 身份至少 6 个月 +- [曾领导 Kubernetes 文档发布](/docs/contribute/advanced/#coordinate-docs-for-a-kubernetes-release) 或者在两个版本发布中有实习经历 +- 理解 SIG Docs 工作流程和工具:git、Hugo、本地化、博客子项目 +- 理解其他 Kubernetes SIG 和仓库会如何影响 SIG Docs 工作流程,包括:[k/org 中的团队](https://github.com/kubernetes/org/blob/master/config/kubernetes/sig-docs/teams.yaml)、[k/community 中的流程](https://github.com/kubernetes/community/tree/master/sig-docs)、[k/test-infra](https://github.com/kubernetes/test-infra/) 中的插件、[SIG Architecture](https://github.com/kubernetes/community/tree/master/sig-architecture) 中的角色。 +- 在至少 6 个月的时段内,确保每周至少投入 5 个小时(通常更多) + + +### 职责范围 + +联合主席主要提供以下服务: +联合主席负责处理流程和政策、时间安排和召开会议、安排 PR 管理员、以及一些其他人不想做的事情,目的是增长贡献者团队。 + +职责范围包括: + + +- 保持 SIG Docs 专注于通过出色的文档最大限度地提高开发人员的满意度 +- 以身作则,践行[社区行为准则](https://github.com/cncf/foundation/blob/master/code-of-conduct.md) 并要求 SIG 成员对自身行为负责 +- 通过更新贡献准则,为 SIG 学习并设置最佳实践 +- 安排和举行 SIG 会议:每周状态更新,每季度回顾/计划会议以及其他需要的会议 +- 在 KubeCon 活动和其他会议上安排和负责文档工作 +- 与 {{< glossary_tooltip text="CNCF" term_id="cncf" >}} 及其尊贵合作伙伴(包括 Google、Oracle、Azure、IBM 和华为)一起以 SIG Docs 的身份招募和宣传 +- 负责 SIG 正常运行 + + +### 召开高效的会议 + +为了安排和召开高效的会议,这些准则说明了如何做、怎样做以及原因。 + +**坚持[社区行为准则](https://github.com/cncf/foundation/blob/master/code-of-conduct.md)**: + +- 相互尊重地、包容地进行讨论。 + + +**设定明确的议程**: + +- 设定清晰的主题议程 +- 提前发布议程 + +对于每周一次的会议,请将前一周的笔记复制并粘贴到笔记的“过去的会议”部分中 + + +**通过协作,完成准确的记录**: + +- 记录会议讨论 +- 考虑委派笔记记录员的角色 + +**清晰准确地分配执行项目**: + +- 记录操作项,分配给它的人员以及预期的完成日期 + + +**根据需要来进行协调**: + +- 如果讨论偏离议程,请让参与者重新关注当前主题 +- 为不同的讨论风格留出空间,同时保持讨论重点并尊重人们的时间 + +**尊重大家的时间**: + +- 准时开始和结束会议 + + +**有效利用 Zoom**: + +- 熟悉 [ Kubernetes Zoom 指南](https://github.com/kubernetes/community/blob/master/communication/zoom-guidelines.md) +- 输入主持人密钥登录时声明主持人角色 + +声明 Zoom 角色 + + +### 录制 Zoom 会议 + +准备开始录制时,请单击“录制到云”。 + +准备停止录制时,请单击“停止”。 + +视频会自动上传到 YouTube。 + +{{% /capture %}} diff --git a/content/zh/docs/contribute/generate-ref-docs/_index.md b/content/zh/docs/contribute/generate-ref-docs/_index.md new file mode 100644 index 0000000000..ac5f61a40f --- /dev/null +++ b/content/zh/docs/contribute/generate-ref-docs/_index.md @@ -0,0 +1,21 @@ +--- +title: 参考文档概述 +main_menu: true +weight: 80 +--- + + + + + +许多 Kubernetes 参考文档都是使用脚本从 Kubernetes 源代码生成的。本节的主题是如何生成这种类型的文档。 diff --git a/content/zh/docs/contribute/generate-ref-docs/contribute-upstream.md b/content/zh/docs/contribute/generate-ref-docs/contribute-upstream.md new file mode 100644 index 0000000000..0e4863e31b --- /dev/null +++ b/content/zh/docs/contribute/generate-ref-docs/contribute-upstream.md @@ -0,0 +1,405 @@ +--- +title: 为上游 Kubernetes 代码库做出贡献 +content_template: templates/task +--- + + +{{% capture overview %}} + + +此页面描述如何为上游 kubernetes/kubernetes 项目做出贡献,如修复 Kubernetes API 文档或 `kube-*` 组件(例如 kube-apiserver、kube-controller-manager 等)中发现的错误。 + + +相反,如果您想从上游代码重新生成 Kubernetes API 或 `kube-*` 组件的参考文档。请参考以下说明: + + +- [生成 Kubernetes API 的参考文档](/docs/contribute/generate-ref-docs/kubernetes-api/) +- [生成 Kubernetes 组件和工具的参考文档](/docs/contribute/generate-ref-docs/kubernetes-components/) + +{{% /capture %}} + + +{{% capture prerequisites %}} + + +您需要安装以下工具: + + +* [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 环境变量中。 + + +您需要知道如何创建对 GitHub 代码仓库的拉取请求(Pull Request)。 +通常,这涉及创建代码仓库的分支。要获取更多的信息请参考[创建 PR](https://help.github.com/articles/creating-a-pull-request/) 和 +[GitHub 标准 Fork 和 PR 工作流程](https://gist.github.com/Chaser324/ce0505fbed06b947d962)。 + + +{{% /capture %}} + + +{{% capture steps %}} + + +## 基本原则 + + +Kubernetes API 和 `kube-*` 组件(例如 `kube-apiserver`、`kube-controller-manager`)的参考文档是根据[上游 Kubernetes](https://github.com/kubernetes/kubernetes/) 中的源代码自动生成的。 + + +当您在生成的文档中看到错误时,您可能需要考虑创建一个 PR 用来在上游项目中对其进行修复。 + + +## 克隆 Kubernetes 代码仓库 + + +如果您还没有 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`。 +接下来其余步骤将您的基本目录称为 ``。 + +确定您的 [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 源代码中的一个或多个注释。 + + +`kube-*` 组件的文档也是从上游源代码生成的。您必须更改与要修复的组件相关的代码,才能修复生成的文档。 + + +### 更改上游 Kubernetes 源代码 + + +{{< note >}} +以下步骤仅作为示例,不是一般步骤,具体情况因您而异。 +{{< /note >}} + + +以下在 Kubernetes 源代码中编辑注释的示例。 + + +在您本地的 kubernetes/kubernetes 代码仓库中,切换出本地 master 分支,并确保它是最新的: + +```shell +cd +git checkout master +git pull https://github.com/kubernetes/kubernetes master +``` + + +假设 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"。 + + +以下命令查看您已更改的文件: + +```shell +git status +``` + + +输出显示您在 master 分支上,`types.go` 源文件已被修改: + +```shell +On branch master +... + modified: staging/src/k8s.io/api/apps/v1/types.go +``` + + +### 提交已编辑的文件 + + +运行 `git add` 和 `git commit` 命令提交到目前为止所做的更改。在下一步中,您将进行第二次提交,将更改分成两个提交很重要。 + + +### 生成 OpenAPI 规范和相关文件 + + +进入 `` 目录并运行以下脚本: + +```shell +hack/update-generated-swagger-docs.sh +hack/update-openapi-spec.sh +hack/update-generated-protobuf.sh +hack/update-api-reference-docs.sh +``` + + +运行 `git status` 命令查看生成的东西。 + +```shell +On branch master +... + modified: api/openapi-spec/swagger.json + modified: api/swagger-spec/apps_v1.json + modified: docs/api-reference/apps/v1/definitions.html + modified: staging/src/k8s.io/api/apps/v1/generated.proto + modified: staging/src/k8s.io/api/apps/v1/types.go + modified: staging/src/k8s.io/api/apps/v1/types_swagger_doc_generated.go +``` + + +查看 `api/openapi-spec/swagger.json` 的内容,以确保 typo 已经被修正。例如,您可以运行 `git diff -a api/openapi-spec/swagger.json` 命令。这很重要,因为 `swagger.json` 是文档生成过程中第二阶段的输入。 + + +运行 `git add` 和 `git commit` 命令来提交您的更改。现在您有两个提交: +一种包含编辑的 `types.go` 文件,另一种包含生成的 OpenAPI 规范和相关文件。 +将这两个提交分开独立。也就是说,不要 squash 您的提交。 + + +将您的更改作为 [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 源代码中的拼写错误的拉取请求的示例。 + + +{{< 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` 文件。 +{{< /note >}} + + +### Cherry Pick 将您的提交纳入发布分支 + + +在上一节中,您在 master 分支中编辑了一个文件,然后运行了脚本用来生成 OpenAPI 规范和相关文件。然后将您的更改提交到 kubernetes/kubernetes 代码仓库的 master 分支的 pull request 中。 现在,需要将您的更改反向移植到已经 release 的分支。例如,假设使用 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)。 + + +{{< note >}} +提出 cherry pick 要求您有权在 pull request 中设置标签和里程碑。如果您没有这些权限,则需要与可以为您设置标签和里程碑的人员合作。 +{{< /note >}} + + +当您提出一个 pull request,希望将您的一个提交 cherry pick 到 release-1.9 分支中时,下一步是在本地环境的 release-1.9 分支中运行这些脚本。 + +```shell +hack/update-generated-swagger-docs.sh +hack/update-openapi-spec.sh +hack/update-generated-protobuf.sh +hack/update-api-reference-docs.sh +``` + + +现在将提交添加到您的 Cherry-pick pull request 中,该请求具有最近生成的 OpenAPI 规范和相关文件。关注您的 pull request 请求,直到其合并到 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 元素。 + + + +## 生成已发布的参考文档 + + +上一节显示了如何编辑源文件然后生成多个文件,包括在 `kubernetes/kubernetes` 代码仓库中的 `api/openapi-spec/swagger.json`。 +`swagger.json` 文件是 OpenAPI 定义文件,可用于生成 API 参考文档。 + + +现在,您可以按照[生成 Kubernetes API 的参考文档](/docs/contribute/generate-ref-docs/kubernetes-api/)指南来生成 +[已发布的 Kubernetes API 参考文档](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/)。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + +* [生成 Kubernetes API 的参考文档](/docs/contribute/generate-ref-docs/kubernetes-api/) +* [为 Kubernetes 组件和工具生成参考文档](/docs/home/contribute/generated-reference/kubernetes-components/) +* [生成 kubectl 命令的参考文档](/docs/home/contribute/generated-reference/kubectl/) + +{{% /capture %}} + diff --git a/content/zh/docs/contribute/generate-ref-docs/kubectl.md b/content/zh/docs/contribute/generate-ref-docs/kubectl.md new file mode 100644 index 0000000000..897a301d37 --- /dev/null +++ b/content/zh/docs/contribute/generate-ref-docs/kubectl.md @@ -0,0 +1,487 @@ +--- +title: 为 kubectl 命令集生成参考文档 +content_template: templates/task +--- + + + +{{% capture overview %}} + + + +该页面显示了如何自动生成 `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 >}} + +{{% /capture %}} + + +{{% capture 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)。 + +{{% /capture %}} + + +{{% capture steps %}} + + +## 设置本地仓库 + + +创建本地工作区并设置您的 `GOPATH`。 + +```shell +mkdir -p $HOME/ + +export GOPATH=$HOME/ +``` + + +获取以下仓库的本地克隆: + +```shell +go get -u github.com/spf13/pflag +go get -u github.com/spf13/cobra +go get -u gopkg.in/yaml.v2 +go get -u kubernetes-incubator/reference-docs +``` + + +如果您还没有下载过 `kubernetes/website` 仓库,现在下载: + +```shell +git clone https://github.com//website $GOPATH/src/github.com//website +``` + + +克隆下载 kubernetes/kubernetes 仓库,并作为 k8s.io/kubernetes: + +```shell +git clone https://github.com/kubernetes/kubernetes $GOPATH/src/k8s.io/kubernetes +``` + + +从 `$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/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`。下文将该目录称为 ``。 + + +在您当地的 k8s.io/kubernetes 仓库中,检查感兴趣的分支并确保它是最新的。例如,如果您想要生成 Kubernetes 1.15 的文档,您可以使用以下命令: + +```shell +cd +git checkout release-1.15 +git pull https://github.com/kubernetes/kubernetes release-1.15 +``` + + +如果不需要编辑 kubectl 源码,请按照说明[编辑 Makefile](#editing-makefile)。 + + + +## 编辑 kubectl 源码 + + + +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 分支中。 + + + +## 以 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)。 + + + +跟踪你的 cherry-pick PR,直到它合入到已发布分支中。 + +{{< note >}} + + +提议一个 cherry-pick 合入,需要你有在 PR 中设置标签和里程碑的权限。如果你没有,你需要与有权限为你设置标签和里程碑的人合作完成。 +{{< /note >}} + + + +## 编辑 Makefile + + + +进入 `` 目录, 打开 `Makefile` 进行编辑: + + +* 设置 `K8SROOT` 为 ``。 +* 设置 `WEBROOT` 为 ``。 +* 设置 `MINOR_VERSION` 为要构建的文档的次要版本。例如,如果您想为 Kubernetes 1.15 构建文档,请将 `MINOR_VERSION` 设置为 15。保存并关闭 `Makefile` 文件。 + + +例如,更新以下变量: + +``` +WEBROOT=$(GOPATH)/src/github.com//website +K8SROOT=$(GOPATH)/src/k8s.io/kubernetes +MINOR_VERSION=15 +``` + + +## 创建版本目录 + + +版本目录是 kubectl 命令集构建的临时区域。该目录中的 YAML 文件用于创建 kubectl 命令集参考的结构和导航。 + + + +在 `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 +``` + + + +## 从 kubernetes/kubernetes 检出一个分支 + + + +在本地 仓库中,检出你想要生成文档的、包含 Kubernetes 版本的分支。例如,如果希望为 Kubernetes 1.15 版本生成文档,请检出 1.15 分支。确保本地分支是最新的。 + +```shell +cd +git checkout release-1.15 +git pull https://github.com/kubernetes/kubernetes release-1.15 +``` + + + +## 运行文档生成代码 + + + +在 kubernetes-incubator/reference-docs 仓库的本地目录中,构建并运行 kubectl 命令集参数生成代码。你可能需要以 root 用户运行命令: + +```shell +cd +make copycli +``` + + +`copycli` 命令将清理暂存目录,生成 kubectl 命令集文件,并将整理后的 kubectl 参考 HTML 页面和文件复制到 ``。 + + +## 找到生成的文件 + + +验证是否已生成以下两个文件: + +```shell +[ -e "/gen-kubectldocs/generators/build/index.html" ] && echo "index.html built" || echo "no index.html" +[ -e "/gen-kubectldocs/generators/build/navData.js" ] && echo "navData.js built" || echo "no navData.js" +``` + + +## 找到复制的文件 + + +确认所有生成的文件都已复制到您的 ``: + +```shell +cd +git status +``` + + +输出应包括修改后的文件: + +``` +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/node_modules/font-awesome/css/font-awesome.min.css +``` + + +## 在本地测试文档 + + +在本地 `` 中构建 Kubernetes 文档。 + +```shell +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 合入的几分钟后,你更新的参考主题将出现在[已发布文档](/docs/home/)中。 + + +{{% /capture %}} + +{{% capture 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/) + +{{% /capture %}} \ No newline at end of file diff --git a/content/zh/docs/contribute/generate-ref-docs/kubernetes-api.md b/content/zh/docs/contribute/generate-ref-docs/kubernetes-api.md new file mode 100644 index 0000000000..f8b05a6aca --- /dev/null +++ b/content/zh/docs/contribute/generate-ref-docs/kubernetes-api.md @@ -0,0 +1,364 @@ +--- +title: 为 Kubernetes API 生成参考文档 +content_template: templates/task +--- + + +{{% capture overview %}} + + +本页面展示了如何为 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) 规范中重新生成参考文档,请继续阅读此页面。 + +{{% /capture %}} + + +{{% capture 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)。 + +{{% /capture %}} + + +{{% capture steps %}} + + +## 设置本地仓库 + + +创建本地工作区并设置您的 `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` 仓库,现在下载: + +```shell +git clone https://github.com//website $GOPATH/src/github.com//website +``` + + +克隆下载 kubernetes/kubernetes 仓库,并作为 k8s.io/kubernetes: + +```shell +git clone 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-incubator/reference-docs](https://github.com/kubernetes-incubator/reference-docs) 仓库克隆后的基本目录为 `$GOPATH/src/github.com/kubernetes-incubator/reference-docs`。 +其余后续步骤将您的基本目录称为 ``。 + + +## 生成 API 参考文档 + + +本节说明如何生成[已发布的 Kubernetes API 参考文档](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/)。 + + +### 修改 Makefile 文件 + + +进入 `` 目录,然后编辑 `Makefile` 文件: + + +* 设置 `K8SROOT` 为 ``. +* 设置 `WEBROOT` 为 ``. +* 设置 `MINOR_VERSION` 为要构建的文档的次要版本。例如,如果您想为 Kubernetes 1.15 构建文档,请将 `MINOR_VERSION` 设置为 15。保存并关闭 `Makefile` 文件。 + + +例如,更新以下变量: + +``` +WEBROOT=$(GOPATH)/src/github.com//website +K8SROOT=$(GOPATH)/src/k8s.io/kubernetes +MINOR_VERSION=15 +``` + + +### 复制 OpenAPI 规范 + + +在 `` 目录中运行以下命令: + +```shell +make updateapispec +``` + + +输出显示文件已被复制: + +```shell +cp ~/src/k8s.io/kubernetes/api/openapi-spec/swagger.json gen-apidocs/generators/openapi-spec/swagger.json +``` + + +### 构建 API 参考文档 + + +在 `` 目录中运行以下命令: + +```shell +make api +``` + + +验证是否已生成这两个文件: + +```shell +[ -e "/gen-apidocs/generators/build/index.html" ] && echo "index.html built" || echo "no index.html" +[ -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 +``` + + +## 更新 API 参考索引页面 + + + +* 打开 `/content/en/docs/reference/kubernetes-api/index.md` 文件进行编辑,并且更新 API 参考版本号。例如: + + ``` + --- + title: v1.15 + --- + + [Kubernetes API v1.15](/docs/reference/generated/kubernetes-api/v1.15/) + ``` + + +* 打开 `/content/en/docs/reference/_index.md` 文件进行编辑,并添加新链接以获取最新的 API 参考。移除最旧的 API 参考版本。应该有五个指向最新 API 参考的链接。 + + + +## 在本地测试 API 参考 + + +发布 API 参考的本地版本。 +验证 [本地预览](http://localhost:1313/docs/reference/generated/kubernetes-api/v1.15/)。 + +```shell +cd +make docker-serve +``` + + +## 提交更改 + + +在 `` 中运行 `git add` 和 `git commit` 来提交更改。 + + +将您的更改[创建 PR](/docs/contribute/start/) 提交到 [kubernetes/website](https://github.com/kubernetes/website) 仓库。监视您提交的 PR,并根据需要回复 reviewer 的评论。继续监视您的 PR,直到合并为止。 + +{{% /capture %}} + +{{% capture 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/) + +{{% /capture %}} \ No newline at end of file diff --git a/content/zh/docs/contribute/generate-ref-docs/kubernetes-components.md b/content/zh/docs/contribute/generate-ref-docs/kubernetes-components.md new file mode 100644 index 0000000000..8df429632c --- /dev/null +++ b/content/zh/docs/contribute/generate-ref-docs/kubernetes-components.md @@ -0,0 +1,412 @@ +--- +title: 为 Kubernetes 组件和工具生成参考页面 +content_template: templates/task +--- + + + +{{% capture overview %}} + + + +本页面展示了如何使用 `update-imported-docs` 工具来为 [Kubernetes](https://github.com/kubernetes/kubernetes) 和 [Federation](https://github.com/kubernetes/federation) 仓库中的工具和组件生成参考文档。 + +{{% /capture %}} + +{{% capture 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/)。 + +{{% /capture %}} + +{{% capture steps %}} + + + +## 下载两个仓库 + + + +如果你还没有下载过 `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`。 + + + +## 自定义配置文件 + + + +打开 `/update-imported-docs/reference.yml` 进行编辑。不要修改 `generate-command` 条目的内容,除非你了解它的作用,并且需要修改指定的已发布分支。 + +```shell +repos: +- name: reference-docs + remote: https://github.com/kubernetes-incubator/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.11 + make generated_files + cp -L -R vendor $GOPATH/src + rm -r vendor + cd $GOPATH + go get -v github.com/kubernetes-incubator/reference-docs/gen-compdocs + cd src/github.com/kubernetes-incubator/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/)中。 + +{{% /capture %}} + +{{% capture 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/) + +{{% /capture %}} \ No newline at end of file diff --git a/content/zh/docs/contribute/intermediate.md b/content/zh/docs/contribute/intermediate.md new file mode 100644 index 0000000000..7b122f4293 --- /dev/null +++ b/content/zh/docs/contribute/intermediate.md @@ -0,0 +1,1449 @@ +--- +title: 中级贡献 +slug: intermediate +content_template: templates/concept +weight: 20 +card: + name: contribute + weight: 50 +--- + + +{{% capture overview %}} + + +本文假定你已经阅读并掌握了[开始贡献](/docs/contribute/start/)中介绍的内容,想要了解更多关于贡献的内容。 + + +{{< note >}} + +有些任务需要使用 Git 命令行客户端和其他工具。 +{{< /note >}} + +{{% /capture %}} + +{{% capture body %}} + + +现在,您已经熟悉了 Kubernetes 文档,并按照[开始贡献](/docs/contribute/start/)文章中介绍的方式进行了贡献,您可能已经准备好做更多的工作。这些任务假设您已经或愿意获得以下主题领域的更深入的知识: + + +- Kubernetes 概念 +- Kubernetes 文档工作流程 +- 在哪里和如何找到即将推出的 Kubernetes 功能的信息 +- 较强的研究能力 + + +这些任务不像初学者的任务那样是顺序的。没有人期望一个人会一直做所有的事情。 + +## 评审 pull request + + +通常,每周都会有一个特定的文档审核志愿者对 [pull requests 和 issues](#triage-and-categorize-issues) 进行分类和审核。这个人就是本周的 “PR 轮流负责人”。排班计划在 [PR 轮流负责人排班](https://github.com/kubernetes/website/wiki/PR-Wranglers) 中维护。 +如果想要加入排班计划,需要参加每周的 SIG Docs 会议并志愿申请。 +尽管你不在本周的排班计划中,你也可以审核那些还未开始检视的 PR。 + + +除了轮换之外,自动化系统(机器人)会根据修改的文件自动推荐相应的 approver 和 reviewer。 +PR 作者应该遵循机器人的指导,这也有助于 PR 得到快速审查。 + + +我们希望尽快合并和发布 pull requests。 +为了确保文档是准确的和最新的,每个 PR 都需要由理解内容的人以及具有编写优秀文档经验的人来评审。 + + +评审人员和批准人员需要提供可操作的和建设性的反馈,以保持贡献者的参与并帮助他们改进。 +有时候,帮助一个新的贡献者把他们的 PR 准备好合并比你自己重写它需要更多的时间, +但是从长远来看,当我们有不同的积极参与者时,这个项目会更好。 + + +在开始评审 PR 之前,请确保熟悉[文档内容指南](/docs/contribute/style/content-guide/)、[文档风格指南](/docs/contribute/style/style-guide/)、[行为准则](/community/code-of-conduct/)。 + + +### 找一个 PR 来评审 + + +要查看所有打开的 PR,请转到 GitHub 仓库中的**Pull Requests**选项卡。 +当符合以下所有条件时,PR 才有资格进行评审: + + +- 拥有 `cncf-cla:yes` 标签 +- 描述中没有 WIP +- 没有包含 `do-not-merge` 字样的标签 +- 没有合并冲突 +- 基于正确的分支(通常为 “master”,除非 PR 与某个未发布的功能相关) +- 没有被其他文档人员(或其他技术领域的评审人)评审,除非你被显式的请求参与评审。 + 需要说明的是,如果其他评审已经结束的情况下,你再留下很多新的意见,会让人感到沮丧,这适得其反。 + + +如果 PR 不符合合并的条件,请留下评论,让作者知道问题所在,并帮助他们解决问题。 +如果他们被告知并在几周或几个月内没有解决问题,最终他们的 PR 将被关闭而不会合并。 + + +如果您是新手,或者您没有太多的带宽,请寻找具有 `size/XS` 或 `size/S` 标记集的 PR。 +大小由 PR 更改的行数自动设置。 + +#### Reviewers and approvers + + +Kubernetes 网站仓库与 Kubernetes 的一些代码仓库在涉及审核者和审批者角色时的操作方式不同。 +有关评审人员和批准人员职责的更多信息,请参见[参与](/docs/contribute/participating/)。 +这里只做一个概述。 + + +- 当评审人员以评审 PR 的技术准确性时,评审人员发表一个 `/lgtm` 评论表示技术上是无误的。 + + {{< note >}}如果你对技术准确性不确信,不要在涉及文档修改的 PR 中回复 `/lgtm`。 {{< /note >}} + +- 批准者审核有关文档修改的内容时,注重质量和相关规范(比如[风格规范](/docs/contribute/style/style-guide))。 + 只有在 [`OWNERS`](https://github.com/kubernetes/website/blob/master/OWNERS) 文件中列出的 + 人才可以批准 PR。批准 PR 时,需要回复一个 `/approve` 评论。 + + +如果 PR 拥有来自 Kubernetes 社区的任何人的 `/lgtm` 评论和来自 `sig-docs-maintainers` 组的 `/approve` 评论,只要它没有被 hold 并且作者已签署了 CLA,PR 就会被合并。 + +{{< note >}} + +["参与"](/docs/contribute/participating/#approvers)部分包含有关 reviewers 和 approvers 的更多信息,包括 approvers 的具体职责。 +{{< /note >}} + + +### 审核 PR + + + + +1. 阅读 PR 描述,并阅读任何附加的 issues 或链接,如果有的话。 + “快速评审”有时弊大于利,所以确保你有正确的知识来提供有意义的评审。 + +2. 如果其他人是审核这个 PR 的最佳人选,请通过添加 `/assign @` 的评论让他们知道。 + 如果你要求一个非文档人员进行技术评审,但仍然想从文档的角度来评审 PR,那就继续吧。 + +3. 转到 **Files changed** 选项卡。查看所有的修改行。删除的内容具有红色背景,这些行也以 `-` 符号开头。 + 添加的内容具有绿色背景,这些行也以 `+` 符号开始。在一行中,实际修改的内容的背景颜色比该行的其余部分略深一些。 + + - 特别是如果 PR 使用复杂的格式或更改 CSS、Javascript 或其他站点范围内的元素,您可以使用 PR 预览网站。 + 转到 **Conversation** 选项卡,单击页面底部附近的 `deploy/netlify` 测试的 **Details** 链接。 + 默认情况下,它会在同一个浏览器窗口中打开,所以在一个新窗口中打开它,这样你就不会丢失你的部分评论。 + 切换回 **Files changed** 选项卡以继续您的审阅。 + - 确保 PR 符合文档[风格指南](/docs/contribute/style/style-guide/), + 如果不符合,请将作者链接到风格指南的相关部分。 + - 如果您对给定的更改有疑问、评论或其他反馈,请将鼠标悬停在一行上,然后单击出现的蓝白相间的 `+` 号。 + 键入您的评论并单击 **Start a review**。 + + - 如果你有更多的评论,请以同样的方式留下评论。 + - 按照惯例,如果您看到一个与 PR 的主要目的无关的小问题,比如一个打印错误或空格错误, + 您可以将它指出来,并在注释前加上 nit: 以便作者知道您认为它是无关紧要的。 + 他们仍然应该解决这个问题。 + - 当您查看完所有内容,或者没有任何评论时,回到页面顶部并单击 **Review changes**。 + 选择**Comment** 或**Request Changes**。添加评审摘要, + 并在评审摘要字段中另起一行添加适当的 [Prow 命令](https://prow.k8s.io/command-help)。 + SIG Docs 遵循 [Kubernetes 代码审查流程](https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md#the-code-review-process)。 + 您所有的意见将在一个单一的评论中发送给 PR 作者。 + + - 如果您认为 PR 已经准备好合并,请将文本 `/approve` 添加到摘要中。 + - 如果 PR 不需要额外的技术审查,也可以同时添加文本 `/lgtm` 。 + - 如果 PR *确实* 需要额外的技术审查,使用 `/assign` + GitHub 用户名添加需要提供技术审查的人。 + 查看上面出现的 Markdown 文件中的`reviewers`字段,看看谁可以提供技术审阅。 + - 如果需要阻止 PR 被合并,加上 `/hold` ,就会设置 `do-not-merge/hold` 标签。 + - 如果 PR 没有冲突、有 `lgtm` 和 `approve` 标签且没有 `hold` 标签,它就会自动合并。 + - 如果 PR 拥有 `lgtm` 和 `approve` 后再有新的变更,那么这些标签会自动清除。 + + PR 中可能用到的命令,参阅 + [斜线命令列表](https://prow.k8s.io/command-help)。 + + - 如果您以前选择了**Request changes** ,并且 PR 作者已经处理了您的关注点, + 那么您可以在**Files changed** 选项卡或 **Conversation** 选项卡底部更改您的审阅状态。 + 确保添加 `/approve` 标签,并在必要时指派技术审阅人员,以便合并 PR。 + + +### 提交到别人的 PR + + +留下评论是有帮助的,但有时你需要把自己的想法融入到其他人的 PR 中,而不仅仅是留下评论。 + + +除非对方明确要求你“接手”,或者你想重新建立一个长期被抛弃的 PR,否则不要急于“接手”。 +虽然短期内这样做可能更快,但会剥夺这个人做出贡献的机会。 + + +您的做法(接手)取决于您是需要编辑已经在 PR 范围内的文件,还是 PR 尚未触及的文件。 + + +如果以下任何一件事是符合的,你就不能提交到某人的 PR: + + +- 如果 PR 作者将他们的分支直接推入 [https://github.com/kubernetes/website/](https://github.com/kubernetes/website/) 仓库,那么只有具有 push 访问权限的审阅者才能提交到他们的 PR 中。 +- 如果 PR 作者明确禁止审批者进行编辑,那么除非他们更改此设置,否则您无法提交到他们的 PR 中。 + + +#### 文件已在 PR 中修改 + + +这个方法使用 GitHub UI。如果您愿意,您可以使用命令行,即使您想更改的文件是 PR 的一部分,如果您更愿意这样工作的话。 + + + +1. 点击 **Files changed** 选项卡。 +2. 向下找到你想要编辑的文件,点击铅笔图标。 +3. 修改并在下面添加提交记录,点击 **Commit changes**。 + + +您的提交现在被推送到 PR 对应的分支(可能在作者的分支上), +在 PR 中,您的更改反映在 **Files changed** 选项卡中。 +留下评论,让 PR 作者知道你修改了 PR。 + + +如果作者使用命令行而不是 GitHub UI 来处理这个 PR,那么在处理 PR 之前, +他们需要获取 fork 的更改并将本地分支重新建立在 fork 中的分支上。 + +#### 如果文件没有被 PR 修改 + + +如果需要更改尚未包含在 PR 中的文件,则需要使用命令行。 +如果您喜欢使用这个方法而不喜欢使用 GitHub UI,那么您总是可以使用这个方法。 + + +1. + 获取作者的 fork 的 URL。你可以在**Conversation** 标签的底部找到它。 + 查找文本 **Add more commits by pushing to** 。 + 这个短语后面的第一个链接是到分支的,第二个链接是到 fork 的。 + 复制第二个链接。稍后会用到分支的名称。 + +2. + 要给远程设置一个名称(比如作者的 GitHub 用户名),然后使用以下语法添加远程: + + ``` + git remote add + ``` + +3. + 获取远程。这不会更改任何本地文件,但会更新克隆的远程对象的概念(如分支和标记)及其当前状态。 + + ``` + git remote fetch + ``` + +4. + 拉取远程分支。如果已经有同名的本地分支,则此命令将失败。 + + ``` + git checkout + ``` + +5. + 进行更改,使用 `git add` 添加更改,然后提交更改。 + +6. + 将您的更改推到作者的远程。 + + ``` + git push + ``` + +7. + 回到 GitHub UI 并刷新 PR。给 PR 作者留言,让他们知道你修改了 PR。 + + +如果作者使用命令行而不是 GitHub UI 来处理这个 PR,那么在处理 PR 之前, +他们需要获取 fork 的更改并将本地分支重新建立在 fork 中的分支上。 + + +## 使用本地克隆 + + +对于需要多个文件的更改,或者涉及创建新文件或移动文件的更改, +使用本地 Git 克隆比依赖 GitHub UI 更有意义。 +这些指令使用 git 命令,并假设您已经在本地安装了它。 +您可以将它们调整为使用本地图形化 Git 客户机。 + + +### 克隆仓库 + + +对于处理 Kubernetes 文档的每个物理机,只需要克隆存储库一次。 + + + +1. 在终端中使用 `git clone` 来克隆仓库。你不需要指定任何证书。 + + ``` + git clone https://github.com/kubernetes/website + ``` + 新目录 `website` 会在当前目录中创建并包含该仓库的内容。 + +2. 进入 `website` 目录,将默认的 `origin` 重命名为远端 `upstream`。 + + ``` + cd website + + git remote rename origin upstream + ``` + +3. 如果还没有这样做,请在 GitHub 上创建存储库的分支。 + 在您的 web 浏览器中,访问 [https://github.com/kubernetes/website](https://github.com/kubernetes/website) + 并单击 Fork 按钮。几秒钟后,您将被重定向到您的 fork 的 URL,它通常类似于 `https://github.com//website`,除非您已经有一个名为 `website` 的存储库。复制这个网址。 + +4. 在你的 fork 中增加另一个远端 `origin`: + + ``` + git remote add origin + ``` + + +### 使用本地仓库 + + +在本地存储库上启动新的工作单元之前,您需要确定将工作基于哪个分支。 +答案取决于你在做什么,但是下面的指导方针是适用的: + + +- 对于现有内容的一般改进,可以从 `master` 开始。 +- 对于关于 Kubernetes 发布版本中已经存在的特性的新内容,请从 `master` 开始。 +- 对于多个 SIG Docs 贡献者将协作的长期工作,例如内容重组,使用为该工作创建的特定功能分支。 +- 对于与即将发布但尚未发布的 Kubernetes 版本相关的新内容,请使用为该 Kubernetes 版本创建的预发布特性分支。 + + +更多指导,请参考[选择分支](/docs/contribute/start/#choose-which-git-branch-to-use)。 + + +在您决定要使用哪个分支之后(或者用 Git 术语来说,基于它), +使用以下工作流来确保您的工作基于该分支的最新版本。 + + +1. + 拉取 `upstream` 和 `origin` 远端。 + 这将更新您对这些分支所包含内容的本地概念,但不会更改您的本地分支。 + + ``` + git fetch upstream + git fetch origin + ``` + +2. + 基于你选择的分支创建一个新的跟踪分支。以你使用 master 为例: + + ``` + git checkout -b upstream/master + ``` + + + 新分支基于 `upstream/master`, 而不是你本地的 `master`。它跟踪 `upstream/master`。 + +3. + 在检出的分支上使用编辑器修改。 + 你可以随时使用 `git status` 命令来查看你的更改。 + + +4. + 当您准备提交 pull request 时,提交您的更改。 + 首先使用 git status 查看需要向变更集中添加哪些更改。 + 有两个重要的部分:`Changes staged for commit` 和 `Changes not staged for commit`。 + 如果您希望将后一节中显示的 `modified` 或 `untracked` 文件添加到提交中,你需要使用 `git add`。 + + ``` + git add example-file.md + ``` + + + 当所有文件准备好时,使用 `git commit` 命令提交: + + ``` + git commit -m "Your commit message" + ``` + + {{< note >}} + 不要在提交消息中引用 GitHub issue 或 PR(通过 ID 或 URL)。如果您这样做了,那么每当提交出现在新的Git 分支中时,就会导致该 issue 或 PR 获得通知。稍后,您可以在 GitHub UI 中链接 issues 并将请求拉到一起。 + {{< /note >}} + +5. + 您还可以选择使用 hugo 命令在本地暂存站点来测试您的更改。[本地查看更改](#view-your-changes-locally)。您还可以在提交 PR 后查看更改。 + +6. + 在创建包含本地提交的 PR 之前,需要将分支推到 fork,也就是 `origin` 端点。 + + ``` + git push origin + ``` + + 从技术上讲,您可以从 push 命令中省略分支名称,但是这种情况下的行为取决于您使用的 Git 版本。 + 如果包含分支名称,结果将更加可重复。 + + +7. + 此时,如果您在 web 浏览器中访问 https://github.com/kubernetes/website, GitHub 会检测到您将一个新的分支推送到您的 fork,并提供创建一个 pull 请求。填写 pull request 模板。 + + - 标题不应超过 50 个字符,并总结更改的意图。 + - + 长表单描述应该包含关于修复的更多信息,如果 PR 修复了 GitHub issue, + 则应该包含类似 `Fixes #12345` 这样的行。 + 这将导致在合并 PR 时自动关闭该 issue。 + - + 您可以添加标签或其他元数据并分配审阅人员。有关语法,请参见[分类 issues](#triage-and-categorize-issues)。 + + 点击 **Create pull request** + +8. + 几个自动化测试将运行与您所应用的更改的网站状态。 + 如果任何测试失败,请单击**Details**链接获取更多信息。 + 如果 Netlify 测试成功完成,它的**Details**链接将转到 Kubernetes 网站的阶段性版本, + 其中应用了您的更改。 + 这是审阅人员检查更改的方式。 + +9. + 如果您注意到需要进行更多的更改,或者评审人员给了您反馈,请在本地处理反馈, + 然后再次重复步骤 4 - 6,创建一个新的提交。新的提交被添加到您的 pull 请求中, + 测试再次运行,包括 Netlify。 + +10. + 如果审查员将更改添加到您的 pull 请求中,您需要从 fork 获取这些更改,然后才能添加更多的更改。 + 假设您的分支当前已签出,请使用以下命令来完成此操作。 + + ``` + git fetch origin + git rebase origin/ + ``` + + 在 rebasing 之后,您需要添加 `-f` 标志来强制推送分支。 + + ``` + git push -f origin + ``` + +11. + 如果其他人的更改合并到您工作所基于的分支中,并且您对相同文件的相同部分进行了更改, + 则可能会发生冲突。如果 pull 请求显示有需要解决的冲突,您可以使用 GitHub UI 解决它们, + 或者在本地解决它们。 + + 首先执行第 10 步,确保你的 fork 仓库与你本地分支一致。 + + + 接着,拉取 `upstream` 并 rebase 你的分支。 + + ``` + git fetch upstream + git rebase upstream/master + ``` + + + 如果存在 Git 无法自动解决的冲突,可以使用 `git status` 命令查看冲突文件。 + 对于每个冲突文件,编辑它并查找冲突标记 `>>>`,`<<<`,and `===`。 + 解决冲突并删除冲突标记。然后使用 `git add `, + 并使用 `git rebase --continue` 继续将更改添加到更改集中。 + 当所有提交都已应用,并且没有更多冲突时,`git status` 将显示您不在 rebase 中, + 并且不需要提交任何更改。此时,强制将分支推到 fork, pull 请求应该不再显示任何冲突。 + + +如果您在解决冲突方面遇到困难,或者您被与 pull 请求相关的任何其他事情卡住, +请在 `#sig-docs` Slack 通道或 [kubernet-sig-docs 邮件列表](https://groups.google.com/forum/#!forum/kubernetes-sig-docs) 中寻求帮助。 + + +### 本地查看更改 + + +如果您还没有准备好创建一个 pull 请求, +但是您希望看到您的更改是什么样子的, +那么您可以构建并运行一个 docker 映像来生成所有文档并在本地提供它。 + + +1. 本地构建镜像: + + ``` + make docker-image + ``` + +2. `kubernetes-hugo` 镜像构建完成后,可以构建并启动网站: + + ``` + make docker-serve + ``` + +3. 在浏览器地址栏输入 `localhost:1313`。Hugo 将监视文件系统的更改,并根据需要重新构建站点。 + +4. 如果想停掉本地 Hugo 实例,只需要在命令行中输入 `Ctrl+C` 来关闭命令行窗口。 + + +或者,您可以在您的开发机器上安装并使用 hugo 命令: + +1. + [安装 Hugo](https://gohugo.io/getting-started/installing/) 版本 {{< hugoVersion >}} 或更新版本. + +2. + 在终端中,转到您克隆的 Kubernetes 文档的根目录,并输入以下命令: + + ``` + hugo server + ``` + +3. + 在浏览器地址栏中输入 `localhost:1313`。 + +4. + 如果想停掉本地 Hugo 实例,只需要在命令行中输入 `Ctrl+C` 来关闭命令行窗口。 + + +## issues 归类 + + +在任何给定的一周内,一个特定的文档审批者会自愿对 pull 请求和 issues 进行初步分类和审查。 +要进入这个名单,参加每周的团体文档会议和志愿者。 +即使你不在这周的时间表上,你仍然可以审核 PR。 + + +SIG 文档人员只负责对文档 issues 进行分类和分类。一般的网站 issues 也归档在 `kubernetes/website` 资源库中。 + + +当你对一个 issue 进行分类时: + + +- 评估这个 issue 是否有价值。有些 issues 可以通过回答问题或向作者指出资源来迅速解决。 +- 如果 issue 没有足够的细节可以采取行动,或者模板没有填好,询问作者更多的信息。 +- 向 issue 添加标签(有时称为标签)、项目或者里程碑。SIG 文档团队并没有大量使用项目和里程碑。 +- 根据您的判断,对某个 issue 拥有所有权并为其提交 PR (特别是如果它是快速的或与您已经在做的工作相关的)。 + + +如果你针对 issue 分类有疑问,请在 Slack `#sig-docs` 频道或 [kubernetes-sig-docs 邮件列表](https://groups.google.com/forum/#!forum/kubernetes-sig-docs) 中询问。 + + +### 有关标签的更多信息 + + +这些准则并非一成不变,可能会发生变化。 + + +- 一个 issue 可以有多个标签。 +- 一些标签使用斜杠符号进行分组,可以将其视为“子标签”。例如,`sig/` 存在许多标签,例如 `sig/cli` 和 `sig/api-machinery`。 +- 系统会根据 issue 所涉及文件中的元数据,issue 注释中使用的斜杠命令或 issue 文本中的信息,自动添加一些标签。 +- 由负责 issue 分类的人员(或报告 issue 的人员,如果他们是 SIG 文档批准者)手动添加一些标签。 + - `Actionable`:似乎有足够的信息可以解决或解决此 issue。 + - `good first issue`: Kubernetes 或 SIG Docs 经验有限的人也有可能可以解决此 issue。 + - `kind/bug`、`kind/feature`、`kind/documentation`: + 如果提出 issue 的人未正确填写模板,则可能不会自动分配这些标签。 + 错误是现有内容或功能的 issue,功能是对新内容或功能的请求。`kind/documentation` 标签当前未使用。 + - 优先级标签:定义 issue 的相对严重性。 + 如 [Kubernetes 贡献者指导](https://github.com/kubernetes/community/blob/master/contributors/guide/issue-triage.md#define-priority) 中所述。 +- 要添加标签,添加 `/label `。标签必须已经存在。 + 如果您尝试添加不存在的标签,该命令将被默认忽略。 + + +### 处理特殊 issue 类型 + + +我们经常遇到以下类型的 issues,足以记录如何处理它们。 + + +#### 重复的 issues + + +如果单个问题可以解决一个或多个 issues,则应将该问题合并为一个 issue。 +您应该决定哪个 issue 保持打开状态(或打开一个新 issue),移植所有相关信息,链接相关 issues, +并关闭描述同一 issue 的所有其他 issues。只处理一个 issue 将有助于减少混乱并避免重复处理同一问题。 + + +#### 无效链接 issues + + +根据报告无效链接的位置,需要采取不同的措施来解决此 issue。 +API 和 Kubectl 文档中的无效链接是自动化 issues,应分配为 `/priority critical-urgent`, +直到可以完全解决该问题为止。所有其他无效链接都是需要手动修复的 issues, +可以将其分配为 `/priority important-longterm`。 + + +#### 博客 issues + + +随着时间的流逝,Kubernetes 博客条目预计会过时, +因此我们仅保留不到一年的博客条目。 +如果某个 issue 与存在超过一年的博客条目有关,则应将其关闭而不进行修复。 + + +#### 支持请求或代码错误报告 + + +相反,为文档带来的一些 issues 是底层代码的 issues, +或者在某些内容(例如教程)不起作用时请求帮助。 +对于与文档无关的 issues,请关闭 issue 并指示请求者正确的支持场所(Slack,Stack Overflow), +并在适当的地方针对具有功能缺陷的问题提出 issue(可以从 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. +``` + + +示例代码错误报告响应: + +```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. +``` + + +## 记录新功能 + + +每个主要的 Kubernetes 版本都包含新功能,其中许多功能至少需要少量文档才能向人们展示如何使用它们。 + + +通常,负责功能的 SIG 负责对 `kubernetes/website` 存储库的相应 release 分支发起 PR, +提交该功能的文档草稿,并且由 SIG Docs 团队中的某人提供编辑反馈或直接编辑草稿。 + + +### 了解即将推出的功能 + + +要了解即将发布的功能,请参加每周一次的 sig-release 会议 +(请参阅[社区](https://kubernetes.io/community/)页面以获取即将举行的会议, +并在 [kubernetes/sig-release](https://github.com/kubernetes/sig-release/) 存储库中留意特定于发行版的文档。 +每个发行版在 [/sig-release/tree/master/releases/](https://github.com/kubernetes/sig-release/tree/master/releases) + 目录下都有一个子目录。每个子目录包含一个发布计划,一个发布说明草稿以及一个列出发布团队中每个人的文档。 + + +- 发布时间表包含与发布有关的所有其他文档、会议、会议记录和里程碑的链接。 + 它还包含有关该发行版的目标和时间表的信息,以及此发行版的任何特殊流程。 + 在文档底部附近,定义了几个与发布相关的术语。 + + 本文档还包含**Feature tracking sheet**的链接,这是查找排定要发布的所有新功能的正式方法。 + +- 发布团队文档列出了负责每个发布角色的人员。 + 如果不清楚要与谁谈论某个特定功能或问题,请参加发布会议询问您的问题, + 或者与发布负责人联系,以便他们可以重定向您。 +- 发行说明草稿是了解更多有关特定功能、更改、不推荐使用以及更多有关发行版本的好地方。 + 该内容要到发布周期的后期才能最终确定,因此请谨慎使用。 + + +#### 功能跟踪表 + + +给定 Kubernetes 版本的功能跟踪表列出了计划发布的每个功能。 +每个订单项都包含功能名称,功能主要 GitHub issue 的链接,其稳定性级别(Alpha,Beta 或 Stable), +SIG 和负责实施此功能的人员,是否需要文档,发布说明草稿功能,以及是否已合并。请记住以下几点: + + +- Beta 和稳定功能通常比 Alpha 功能具有更高的文档优先级。 +- 很难测试(因此要文档记录)尚未合并的功能,或者至少在其 PR 中被认为功能完整的功能。 +- 确定某个功能是否需要文档是一个手动过程,并且仅仅因为某个功能未标记为需要文档并不意味着它就不需要它们。 + + +### 记录功能 + + +如上所述,新功能的草案内容通常由负责实施新功能的 SIG 提交。 +这意味着您的角色可能更像是给定功能的牧羊人角色。 + + +选择要记录/跟踪的功能后,请在 `#sig-docs` Slack 频道, +每周一次的 sig-docs 会议中或直接在功能 SIG 提交的 PR 上询问有关功能。 +如果得到批准,则可以使用[提交到别人的 PR](#commit-into-another-persons-pr) 中介绍的技术来编辑 PR。 + + +如果您需要编写新主题,则以下链接很有用: + + +- [撰写新主题](/docs/contribute/style/write-new-topic/) +- [使用页面模板](/docs/contribute/style/page-templates/) +- [文档样式指南](/docs/contribute/style/style-guide/) + + +SIG 成员记录了新功能 + + +如果您是 Kubernetes 开发新功能的 SIG 成员,则需要一并更新 SIG 文档, +以确保在发布该功能时及时记录了您的功能。 +查看[功能跟踪电子表格](https://github.com/kubernetes/sig-release/tree/master/releases), + 或在 #sig-release Slack 频道中查看验证计划详细信息和截止日期。 + 与文档相关的一些截止日期是: + + +- **文档截止期限 - 打开占位 PR** :针对 `kubernetes/website` 仓库中的 `release-X.Y` 分支提交一个 PR, + 稍作修改(占位),稍后您将继续修改。使用 Prow 命令 `/milestone X.Y` 将 PR 分配给相关的里程碑。 + 这会提醒管理此版本的文档人员功能文档即将发布。 + 如果您的功能不需要任何文档更改,请在 #sig-release Slack 频道中说一下, + 以确保 sig-release 团队知道这一点。 + 如果该功能确实需要文档,但未创建 PR,则该功能可能已从里程碑中删除。 +- **文档截止日期 - PR 审核**:您的 PR 现在需要包含功能文档的初稿。不必担心格式或修饰。 + 只需描述该功能的用途以及使用方法即可。管理发行版的文档人员将与您合作,使内容成形以进行发布。 + 如果您的功能需要文档且未收到第一稿内容,则该功能可能已从里程碑中删除。 +- **文档完成 - PR 已审核,准备合并**:如果您的 PR 尚未在 `release-X.Y` 此期限之前合并到分支中, + 请与管理发行版的文档人员一起合作帮助它合入。 + 如果您的功能需要文档且文档尚未准备好,该功能可能会从里程碑中删除。 + + +如果您的功能是 Alpha 功能并且由[功能开关](/docs/reference/command-line-tools-reference/feature-gates/) 控制, +请确保将其作为 PR 的一部分添加到功能开关。 +如果您的功能要移出 Alpha,请确保将其从该文件中删除。 + + +## 贡献其他仓库 + + +该 Kubernetes 项目包含超过 50 个仓库。 +这些存储库中许多都包含可以视为文档的代码或内容,例如面向用户的帮助文本,错误消息, +API 参考中的面向用户的文本,甚至是代码注释。 + + +如果您看到文本并且不确定其来源,则可以在 Kubernetes 组织级别使用 GitHub 的搜索工具在所有存储库中搜索该文本。 +这可以帮助您确定将 issue 或 PR 提交到哪里。 + + +每个存储库可能都有自己的流程和过程。 +在您提交的 issue 或提交 PR,查看存储库的 `README.md`、`CONTRIBUTING.md` 以及 `code-of-conduct.md`。 + + +大多数存储库使用 issue 和 PR 模板。 +浏览一些未解决的 issues 和 PR,以了解该团队的流程。 +提交 issues 或 PR 时,​​请确保尽可能详细地填写模板。 + + +## 本地化内容 + + +Kubernetes 文档首先是用英语编写的,但是我们希望人们能够使用他们选择的语言来阅读它。 +如果您愿意用另一种语言编写,尤其是在软件领域,则可以帮助本地化 Kubernetes 文档 +或提供有关现有本地化内容的反馈。 +请参阅[本地化](/docs/contribute/localization/), +并在 [kubernetes-sig-docs 邮件列表][kubernetes-sig-docs mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-docs) #sig-docs 上询问,或者在 Slack 上询问是否有帮助的兴趣。 + + +### 参与本地化工作 + + +请遵循以下准则来使用本地化内容: + + +- 将 PR 限制为一种语言。 + + 每种语言都有其自己的审阅者和批准者。 + +- 审阅者,请验证 PR 是否仅对一种语言进行了更改。 + + 如果 PR 包含对一种以上源语言的更改,请 PR 贡献者为每种语言打开单独的 PR。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + +如果您熟悉本主题中讨论的所有任务,并且想与 Kubernetes 文档小组进行更深入的接触, +请阅读[文档高级贡献者](/docs/contribute/advanced/)主题。 +{{% /capture %}} diff --git a/content/zh/docs/contribute/localization.md b/content/zh/docs/contribute/localization.md new file mode 100644 index 0000000000..dcf2c8f968 --- /dev/null +++ b/content/zh/docs/contribute/localization.md @@ -0,0 +1,559 @@ +--- +title: 本地化 Kubernetes 文档 +content_template: templates/concept +card: + name: contribute + weight: 30 + title: 翻译文档 +--- + + +{{% capture overview %}} + + +此页面显示了如何为其他语言的文档提供[本地化](https://blog.mozilla.org/l10n/2011/12/14/i18n-vs-l10n-whats-the-diff/)。 + +{{% /capture %}} + +{{% capture body %}} + + +## 入门 + +由于贡献者无法批准他们自己的请求,因此您至少需要两个贡献者才能开始本地化。 + +所有本地化团队必须使用自身的资源独立工作。我们很高兴支持你的工作,但无法为你翻译。 + + +### 找到两个字母的语言代码 + +首先,有关本地化的两个字母的国家代码,请参考 [ISO 639-1 标准](https://www.loc.gov/standards/iso639-2/php/code_list.php)。例如,韩国的两个字母代码是 `ko`。 + +### fork 并且克隆仓库 {#fork-and-clone-the-repo} + +首先,在 [kubernetes/website](https://github.com/kubernetes/website) 仓库中的 [fork 你自己的分支](/docs/contribute/start/#improve-existing-content)。 + + +然后,克隆 website 仓库并通过 `cd` 命令进入 website 目录: + +```shell +git clone https://github.com//website +cd website +``` + + +### 发起 pr + +接下来,[提交 PR 请求](https://kubernetes.io/docs/contribute/start/#submit-a-pull-request),将本地化添加到 `kubernetes/website` 仓库。 + +PR 必须包含所有[最低要求的内容](#minimum-required-content),然后才能被批准。 + +有关添加新本地化的示例,请参见添加[法语文档](https://github.com/kubernetes/website/pull/12548) 的 PR。 + +### Join the Kubernetes GitHub organization + + +提交本地化 PR 后,您可以成为 Kubernetes GitHub 组织的成员。团队中的每个人都需要在 `kubernetes/org` 仓库中创建自己的[组织成员资格申请](https://github.com/kubernetes/org/issues/new/choose)。 + + +### 在 GitHub 中添加您的本地化团队 + +接下来,将您的 Kubernetes 本地化团队添加到[`sig-docs/teams.yaml`](https://github.com/kubernetes/org/blob/master/config/kubernetes/sig-docs/teams.yaml)。有关添加本地化团队的示例,请参见添加[西班牙本地化团队](https://github.com/kubernetes/org/pull/685) 的 PR。 + +`sig-docs-**-owners` 成员可以批准更改对应本地化目录 `/content/**/` 中内容的 PR,并仅限这类 PR。 + +`sig-docs-**-reviews` 团队自动分派新 PR 的审阅任务。 + + +`sig-docs-l10n-admins` 成员可以创建新的开发分支来协调翻译工作。 + +`website-milestone-maintainers` 成员可以使用 `/milestone` [Prow 命令](https://prow.k8s.io/command-help) 为 issues 或 PR 设定里程碑。 + + +### 配置工作流程 + +接下来,在 `kubernetes/test-infra` 仓库中为您的本地化添加一个 GitHub 标签。标签可让您过滤 issues 并提出针对特定语言的 pr。 + +有关添加标签的示例,请参见添加[意大利语标签](https://github.com/kubernetes/test-infra/pull/11316)的 PR。 + + +### 寻找社区 + +让 Kubernetes SIG Docs 知道您对创建本地化感兴趣! 加入[SIG Docs Slack 频道](https://kubernetes.slack.com/messages/C1J0BPD2M/)。其他本地化团队很乐意帮助您入门并回答您的任何问题。 + +您还可以在 `kubernetes/community` 存储库中为本地化创建一个 Slack 频道。有关添加 Slack 频道的示例,请参见[为印尼语和葡萄牙语添加频道](https://github.com/kubernetes/community/pull/3605)的 PR。 + + +## 最低要求内容 {#minimum-required-content} + +### 修改站点配置 + +Kubernetes 网站使用 Hugo 作为其 Web 框架。网站的 Hugo 配置位于[`config.toml`](https://github.com/kubernetes/website/tree/master/config.toml)文件中。为了支持新的本地化,您需要修改 `config.toml`。 + +在现有的 `[languages]` 下,将新语言的配置添加到 `config.toml` 中。例如,下面是德语的配置示例: + +```toml +[languages.de] +title = "Kubernetes" +description = "Produktionsreife Container-Verwaltung" +languageName = "Deutsch" +contentDir = "content/de" +weight = 3 +``` + + +为您的块分配一个 `weight` 参数时,找到权重最高的语言块并将其加 1。 + +有关 Hugo 多语言支持的更多信息,请参阅"[多语言模式](https://gohugo.io/content-management/multilingual/)"。 + + +### 添加一个新的本地化目录 + +将特定语言的子目录添加到仓库中的 [`content`](https://github.com/kubernetes/website/tree/master/content) 文件夹下。例如,德语的两个字母的代码是 `de`: + +```shell +mkdir content/de +``` + + +### 本地化社区行为准则 + +针对 [`cncf/foundation`](https://github.com/cncf/foundation/tree/master/code-of-conduct-languages) 仓库提交 PR,添加您所用语言版本的行为准则。 + +### 添加本地化的 README 文件 + + +为了指导其他本地化贡献者,请在 k/website 的根目录添加一个新的 [`README-**.md`](https://help.github.com/articles/about-readmes/),其中 `**` 是两个字母的语言代码。例如,德语 README 文件为 `README-de.md`。 + +在本地化的 `README-**.md` 文件中为本地化贡献者提供指导。包含 `README.md` 中包含的相同信息,以及: + +- 本地化项目的联系人 +- 任何有关本地化的信息 + + +创建本地化的 README 文件后,请在英语版文件 `README.md` 中添加指向该文件的链接,并给出英文形式的联系信息。您可以提供 GitHub ID、电子邮件地址、[Slack 频道](https://slack.com/)或其他联系方式。您还必须提供指向本地化的社区行为准则的链接。 + + +### 设置 OWNERS 文件 + +要设置每个对本地化做出贡献用户的角色,请在特定于语言的子目录内创建一个 `OWNERS` 文件,其中: + +- **reviewers**: 具有 reviewer 角色的 kubernetes 团队的列表,在本例中为在[在 GitHub 中添加您的本地化团队](#add-your-localization-team-in-github) 中创建的 `sig-docs-**-reviews` 团队。 +- **approvers**: 具有 approver 角色的 kubernetes 团队的列表,在本例中为在[在 GitHub 中添加您的本地化团队](#add-your-localization-team-in-github) 中创建的 `sig-docs-**-owners` 团队。 +- **labels**: 可以自动应用于 PR 的 GitHub 标签列表,在本例中为[配置工作流程](#configure-the-workflow)中创建的语言标签。 + + +有关 `OWNERS` 文件的更多信息,请访问[go.k8s.io/owners](https://go.k8s.io/owners)。 + +带有语言代码 `es` 的[西班牙 OWNERS 文件](https://git.k8s.io/website/content/es/OWNERS)看起来像: + + +```yaml +# 在 https://go.k8s.io/owners 地址查看 OWNERS 文档 + +# 这是西班牙语的本地化项目。 +# 团队和成员位于 https://github.com/orgs/kubernetes/teams。 + +reviewers: +- sig-docs-es-reviews + +approvers: +- sig-docs-es-owners + +labels: +- language/es +``` + + +添加了特定语言的 OWNERS 文件之后,使用新的 Kubernetes 团队更新 [根目录下的 OWNERS_ALIAES](https://git.k8s.io/website/OWNERS_ALIASES) 文件进行本地化,即 `sig-docs-**-owners` 和 `sig-docs-**-reviews`。 + +对于每个团队,请按字母顺序添加[在 GitHub 中添加您的本地化团队](#add-your-localization-team-in-github) 中请求的 GitHub 用户列表。 + +```diff +--- a/OWNERS_ALIASES ++++ b/OWNERS_ALIASES +@@ -48,6 +48,14 @@ aliases: + - stewart-yu + - xiangpengzhao + - zhangxiaoyu-zidif ++ sig-docs-es-owners: # Admins for Spanish content ++ - alexbrand ++ - raelga ++ sig-docs-es-reviews: # PR reviews for Spanish content ++ - alexbrand ++ - electrocucaracha ++ - glo-pena ++ - raelga + sig-docs-fr-owners: # Admins for French content + - perriea + - remyleone +``` + + +## 翻译文档 + +本地化*所有* Kubernetes 文档是一项艰巨的任务。从小做起,循序渐进。 + +所有本地化至少必须包括: + + +描述 | 网址 +-----|----- +主页 | [所有标题和副标题网址](/docs/home/) +安装 | [所有标题和副标题网址](/docs/setup/) +教程 | [Kubernetes 基础](/docs/tutorials/kubernetes-basics/), [Hello Minikube](/docs/tutorials/stateless-application/hello-minikube/) +网站字符串 | [新的本地化 TOML 文件中的所有网站字符串](https://github.com/kubernetes/website/tree/master/i18n) + + +翻译后的文档必须保存在自己的 `content/**/` 子目录中,否则将遵循与英文源相同的 URL 路径。例如,要准备将 [Kubernetes 基础](/docs/tutorials/kubernetes-basics/) 教程翻译为德语,请在 `content/de/` 文件夹下创建一个子文件夹并复制英文源: + +```shell +mkdir -p content/de/docs/tutorials +cp content/en/docs/tutorials/kubernetes-basics.md content/de/docs/tutorials/kubernetes-basics.md +``` + + +翻译工具可以加快翻译过程。例如,某些编辑器提供了用于快速翻译文本的插件。 + + +{{< caution >}} +机器生成的翻译不能达到最低质量标准,需要进行大量人工审查才能达到该标准。 +{{< /caution >}} + + +为了确保语法和含义的准确性,本地化团队的成员应在发布之前仔细检查所有由机器生成的翻译。 + + +### 源文件 + +本地化必须基于最新版本 {{< latest-version >}} 中的英文文件。 + +要查找最新版本的源文件: + +1. 导航到 Kubernetes website 仓库,网址为 https://github.com/kubernetes/website。 +2. 选择最新版本的 `release-1.X` 分支。 + +最新版本是 {{< latest-version >}},所以最新的发行分支是 [`{{< release-branch >}}`](https://github.com/kubernetes/website/tree/{{< release-branch >}})。 + + +### i18n/ 中的网站字符串 + + +本地化必须在新的语言特定文件中包含 [`i18n/en.toml`](https://github.com/kubernetes/website/blob/master/i18n/en.toml) 的内容。以德语为例:`i18n/de.toml`。 + + +将新的本地化文件添加到 `i18n/`。例如德语 (`de`): + +```shell +cp i18n/en.toml i18n/de.toml +``` + + +然后翻译每个字符串的值: + +```TOML +[docs_label_i_am] +other = "ICH BIN..." +``` + + +本地化网站字符串允许你自定义网站范围的文本和特性:例如,每个页面页脚中的合法版权文本。 + + +### 特定语言的样式指南和词汇表 + +一些语言团队有自己的特定语言风格指南和词汇表。例如,请参见[韩语本地化指南](/ko/docs/contribute/localization_ko/)。 + + +### 分支策略 + + +因为本地化项目是高度协同的工作,所以我们鼓励团队基于共享的开发分支工作。 + + +在开发分支上协作: + + +1. [@kubernetes/sig-docs-l10n-admins](https://github.com/orgs/kubernetes/teams/sig-docs-l10n-admins) 中的团队成员从 https://github.com/kubernetes/website 原有分支新建一个开发分支。 + 当您给 `kubernetes/org` 存储库[添加您的本地化团队](#add-your-localization-team-in-github)时,您的团队 approvers 便加入了 `sig-docs-l10n-admins`。 + + 我们推荐以下分支命名方案: + + `dev--.` + + 例如,一个德语本地化团队的 approvers 基于 Kubernetes v1.12 版本的源分支直接新建了 k/website 仓库的开发分支 `dev-1.12-de.1`。 + + +2. 个人贡献者基于开发分支新建特性分支。 + + 例如,一个德国贡献者新建了一个拉取请求,并将 `username:local-branch-name` 更改为 `kubernetes:dev-1.12-de.1`。 + +3. Approvers 审查功能分支并将其合并到开发分支中。 + +4. approver 会定期打开并批准新的 pr,将开发分支合并到其源分支。在批准 pr 之前,请确保先 squash 提交。 + + +根据需要重复步骤 1-4,直到完成本地化工作。例如,随后的德语开发分支将是:`dev-1.12-de.2`、`dev-1.12-de.3`,等等。 + + +团队必须将本地化内容合入到发布分支中,该发布分支也正是内容的来源。例如,源于 {{< release-branch >}} 的开发分支必须基于 {{< release-branch >}}。 + + +approver 必须通过使开发分支与源分支保持最新并解决合并冲突来维护开发分支。开发分支的存在时间越长,通常需要的维护工作就越多。考虑定期合并开发分支并新建分支,而不是维护一个持续时间很长的开发分支。 + + +在每个团队里程碑的起点,打开一个 issue 来比较先前的开发分支和当前的开发分支之间的上游变化很有帮助。 + + + 虽然只有 approver 才能开启新的开发分支并合并 pr,但任何人都可以为新的开发分支提交一个拉取请求(PR)。不需要特殊权限。 + + +有关基于 fork 或直接从仓库开展工作的更多信息,请参见 ["fork 和克隆"](#fork-and-clone-the-repo)。 + + +### 上游贡献 + + +Sig Docs 欢迎[上游贡献和修正](/docs/contribute/intermediate#localize-content) 到英文原文。 + + +## 帮助现有的本地化 + + +您还可以向现有本地化添加或改进内容提供帮助。加入 [Slack 频道](https://kubernetes.slack.com/messages/C1J0BPD2M/)进行本地化,然后开始新建 PR 来提供帮助。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + +本地化满足工作流程和最低输出要求后,SIG 文档将: + + +- 在网站上启用语言选择 +- 通过[Cloud Native Computing Foundation](https://www.cncf.io/about/) (CNCF) 频道, 包括[ Kubernetes 博客](https://kubernetes.io/blog/)公开本地化的可用性。 + +{{% /capture %}} diff --git a/content/zh/docs/contribute/participating.md b/content/zh/docs/contribute/participating.md new file mode 100644 index 0000000000..3d0fed1229 --- /dev/null +++ b/content/zh/docs/contribute/participating.md @@ -0,0 +1,532 @@ +--- +title: 参与 SIG Docs +content_template: templates/concept +card: + name: contribute + weight: 40 +--- + +{{% capture overview %}} + + +SIG Docs 是 Kubernetes 项目中的一个 [special interest groups](https://github.com/kubernetes/community/blob/master/sig-list.md), +总的来说,它负责编写、更新和维护 Kubernetes 文档。 + + +SIG Docs 欢迎所有贡献者提供内容和检视。任何人可以提交拉取请求(PR), +欢迎对文档内容提交 issue 和 对正在进行中的 PR 进行评论。 + + +在 SIG Docs,你可以成为 [member](#members)、[reviewer](#reviewers) 或者 [approver](#approvers)。 +这些角色拥有更高的权限,并且需要承担批准和提交更改的责任。 +有关 Kubernetes 社区中的成员如何工作的更多信息,请参见 [community-membership](https://github.com/kubernetes/community/blob/master/community-membership.md)。 +本文档的其余部分概述了这些角色在 SIG Docs 中发挥作用的一些独特方式, +SIG Docs 负责维护 Kubernetes 最面向公众的方面之一 —— Kubernetes 网站和文档。 +{{% /capture %}} + +{{% capture body %}} + + +## 角色和责任 + + + +当一个 pull 请求被合并到用于发布内容的分支(当前为“master”),该内容将发布并向全世界开放。 +为了确保发布内容的质量较高,每个 pull 请求需要 SIG Docs 的 approver 审批。 +它是这样工作的。 + + +- 当某个 pull request 拥有 `lgtm` 和 `approve` 标签, 并且没有 `hold` 标签时,这个 pull request 会自动合入。 +- Kubernetes 组织成员 和 SIG Docs 的 approvers 可以通过评论的方式阻止某个 pull request 自动合入(评论中包含 `/hold` 或 取消 `/lgtm` 的内容)。 +- 任何 Kubernetes 成员都可以通过在评论回复 `/lgtm` 来增加 `/lgtm` 标签。 +- 只有 SIG Docs 的 approver 可以在评论中回复 `/approve` 并触发合并。 + 某些 approver 还兼具其他角色,比如 [PR Wrangler](#pr-wrangler) 或 [SIG Docs chairperson](#sig-docs-chairperson)。 + + +关于 Kubernetes 组织成员和 SIG Docs approver 的区别,请参考 [Types of contributor](/docs/contribute#types-of-contributor)。 +以下部分将详细介绍这些角色及其内部的工作方式。 + +### Anyone + + +任何人可以针对 Kubernetes 的任何内容(包括文档)提交 issue。 + + +任何人想到提交 pull request,必须要签署 CLA。 否则 Kubernetes 项目则不能接受你的贡献。 + +### Members + + +任何 [Kubernetes 组织成员](https://github.com/kubernetes) 都可以检视 pull request。 +SIG Docs 组成员经常需要检视来自其他 SIG 的 pull request,以确保技术上的准确性。 + + +作何 Kubernetes 组织成员都可以在评论中增加 `/hold` 标签来阻止 PR 被合入。 +任何 Kubernetes 组织成员都可以移除 `/hold` 标签来让PR 合入(必须此前已有 `/lgtm` 和 `/approve` 标签)。 + + +#### 成为一个 member + + +在你成功的提交至少 5 个PR后,你就可以向 Kubernetes 组织提交申请 [membership](https://github.com/kubernetes/community/blob/master/community-membership.md#member)。 +按照如下流程: + + +1. 找到两个 reviewer 或 approver 为你提名。 + + 通过 [#sig-docs channel on the Kubernetes Slack instance](https://kubernetes.slack.com) 或者 + [SIG Docs mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-docs) + 来寻找为你提名的人。 + {{< note >}} + 不要单独发送邮件给某个人或在 Slack 中私聊。 + {{< /note >}} + +2. 在 `kubernetes/org` 仓库中提交一个 issue 发起请求。 + 按照[指导模板](https://github.com/kubernetes/community/blob/master/community-membership.md)填写请求。 + +3. 告知你的提名人,可以通过在 issue 中 `@` 或者直接发送给他们 issue 链接, + 这样他们可以过来投票(`+1`)。 + +4. 当请求被批准后,github 管理员团队成员会告诉你批准加入并且关闭 issue:"Congratulations, you are now a member!"。 + + +如果因为某些原因你的申请没有被批准,会员委员会成员会告诉你原因并指导你如何继续申请。 + +### Reviewers + + +Reviewers 是 [@kubernetes/sig-docs-pr-reviews](https://github.com/orgs/kubernetes/teams/sig-docs-pr-reviews) 成员。 + + +Reviewers 负责检视文档的 PR 并提供反馈。 + + +每个 PR 都会自动分配 reviewer,任何贡献者都可以在评论中回复 `/assign [@_github_handle]` + 来请求某个 reviewer 来检视。 +如果 reviewer 觉得没有问题且不需要进一步更改时,reviewer 会在评论中回复 `/lgtm` 。 + + +如果自动分配的 reviewer 未能及时检视,其他的 reviewer 也会参与。 +此外,你可以指定某个 reviewer 或者等他们回复 `/lgtm`。 + + +对于不重要的更改或者非技术性的检视,SIG Docs 的 [approver](#approvers) 也可以提供 `/lgtm` 标签。 + + +如果一个 reviewer 在评论中回复 `/approve` 会被自动忽略。 + + +关于如何成为 SIG Docs reviewer 以及其责任、时间承诺等更多内容,请参照 +[Becoming a reviewer or approver](#becoming-an-approver-or-reviewer)。 + + +#### 成为 reviewer + + +当你满足[需求](https://github.com/kubernetes/community/blob/master/community-membership.md#reviewer)时, +你就可以成为 SIG Docs 的 reviewer。 +其他 SIG 的 reviewer 也需要单独向 SIG Docs 申请。 + + +通过提交一个 PR 并把自己加到位于 `kubernetes/website` 仓库顶层的 [top-level OWNERS file](https://github.com/kubernetes/website/blob/master/OWNERS) 文件中的 `reviewers` 部分,指定一个或多个当前 SIG Docs 的 approver。 + + +如果你的 PR 被批准,你就成为了 SIG Docs reviewer 了。 +[K8s-ci-robot](https://github.com/kubernetes/test-infra/tree/master/prow#bots-home) 会在接下来的 PR 中请求你检视。 + + +如果您的 PR 被批准,你就会加入 [@kubernetes/sig-docs-pr-reviews](https://github.com/orgs/kubernetes/teams/sig-docs-pr-reviews) 组。只有 `kubernetes-website-admins` 组的成员才可以加入新成员。 + +### Approvers + + +approver 是 GitHub [@kubernetes/sig-docs-maintainers](https://github.com/orgs/kubernetes/teams/sig-docs-maintainers) 组织成员。 +参考 [Teams and groups within SIG Docs](#teams-and-groups-within-sig-docs)。 + + +approver 有权限合入 PR,这意味着他们可以发布内容到 Kubernetes 网站。 +如果一个 approver 留下 `/approve` 评论,则代表他批准了 PR。 +如果非 approver 成员尝试批准,则会被自动忽略。 + + +如果某个 PR 已有 `/lgtm` 标签,approver 再回复一个 `/lgtm` ,则这个 PR 会自动合入。 +SIG Docs approver 应该只在不需要额外的技术检视的情况下才可以标记 `/lgtm`。 + + +关于如何成为 SIG Docs 的 approver 及其责任和时间承诺等信息,请参考 [Becoming a reviewer or approver](#becoming-an-approver-or-reviewer)。 + + +#### 成为 approver + + +当满足[要求](https://github.com/kubernetes/community/blob/master/community-membership.md#approver) 时,你可以成为 SIG Docs 的 approver。其他的 SIG 的 approver 要想成为 SIG Docs 的 approver 需要单独申请。 + + +通过提交一个 PR 并把自己加到位于 `kubernetes/website` 仓库顶层的 [top-level OWNERS file](https://github.com/kubernetes/website/blob/master/OWNERS) 文件中的 `approvers` 部分,指定一个或多个当前 SIG Docs 的 approver。 + + +一旦你的 PR 被批准,你就是一个 SIG Docs 的 approver 了。 + + +如果您的 PR 被批准,你就会加入[@kubernetes/sig-docs-maintainers](https://github.com/orgs/kubernetes/teams/sig-docs-maintainers) 组。只有 `kubernetes-website-admins` 组的成员才可以加入新成员。 + + +#### Approver 职责 + + +Approvers 通过查看拉取请求(pr)并将其合并到网站仓库中来完善文档。因为此角色具有其他特权,所以 approvers 还具有其他职责: + + +- Approvers 可以使用 `/approve` 命令将 PR 合并到仓库中。 + + 粗心的合并会破坏站点,因此请确保在合并某些内容时,您是清楚的。 + +- 确保建议的更改符合贡献准则。 + + 如果您有任何疑问,或者不确定某个问题,请随时联系他人进行审核。 + +- 在 `/approve` PR 之前,请验证 netlify 测试是否通过。 + + 批准之前必须确保 Netlify 测试通过 + +- 请访问 netlify 页面预览 PR,确保批准前一切正常。 + + +#### PR 协调者 + + +每个 SIG Docs approver 都会参与 [PR Wrangler rotation scheduler](https://github.com/kubernetes/website/wiki/PR-Wranglers)。 +所有 SIG Docs approver 都会参与轮值。 +更多信息,请参考[做一周的PR协调者](/docs/contribute/advanced#be-the-pr-wrangler-for-a-week)。 + + +#### SIG Docs 主席 + + +每个 SIG,包括 SIG Docs,都会选出 1 位或多位成员作为主席。 +主席会成为 SIG Docs 和其他 Kubernetes 组织的联络接口人。 +他们需要了解整个 Kubernetes 项目,并明白 SIG Docs 如何运作。 +如需查询当前的主席,请查阅 [Leadership](https://github.com/kubernetes/community/tree/master/sig-docs#leadership)。 + + +## SIG Docs 团队和自动化 + + +SIG 文档中的自动化依赖于两种不同的自动化机制: +GitHub 组和 OWNERS 文件。 + +### GitHub groups + + +SIG Docs 组定义了两个 GitHub 组: + + - [@kubernetes/sig-docs-maintainers](https://github.com/orgs/kubernetes/teams/sig-docs-maintainers) + - [@kubernetes/sig-docs-pr-reviews](https://github.com/orgs/kubernetes/teams/sig-docs-pr-reviews) + + +可以在 GitHub 的评论中 `@name` 他们来与他们沟通。 + + +这些团队与自动化工具使用的组有所重叠,但并不完全匹配。 +对于分配 issue、拉请求和批准 PR,自动化使用来自 OWNERS 文件的信息。 + + +### OWNERS 文件和扉页 + + +Kubernetes 项目使用名为 prow 的自动化工具来处理 GitHub issue 和 PR。 +[Kubernetes website repository](https://github.com/kubernetes/website) 使用了两个 +[prow 插件](https://github.com/kubernetes/test-infra/blob/master/prow/plugins.yaml#L210): + +- blunderbuss +- approve + + +这两个插件使用位于 `kubernetes/website` 仓库顶层的 +[OWNERS](https://github.com/kubernetes/website/blob/master/OWNERS) 和 +[OWNERS_ALIASES](https://github.com/kubernetes/website/blob/master/OWNERS_ALIASES) 来控制工作流程。 + + +OWNERS 文件包含 SIG Docs reviewer 和 approver 的列表。 +OWNERS 文件也可以存在于子目录中中,可以重写 reviewer 和 approver,并且它自动继承上级。 +关于 OWNERS 的更多信息,请参考 [OWNERS](https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md)。 + + +此外,一个单独的 Markdown 格式的文件将会列出 reviewer 和 approver(扉页),或者列出 +其 GitHub 用户名 或者列出其组名。 + + +结合 OWNERS 文件及扉页可以给 PR 作者提供向谁请求检视的建议。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + +关于贡献 Kubernetes 的更多文档,请参考: + +- [Start contributing](/docs/contribute/start/) +- [Documentation style](/docs/contribute/style/) + +{{% /capture %}} + + diff --git a/content/zh/docs/contribute/start.md b/content/zh/docs/contribute/start.md new file mode 100644 index 0000000000..5f83541256 --- /dev/null +++ b/content/zh/docs/contribute/start.md @@ -0,0 +1,634 @@ +--- +title: 开始贡献 +slug: start +content_template: templates/concept +weight: 10 +card: + name: contribute + weight: 10 +--- + + +{{% capture overview %}} + + +如果您想要为 Kubernetes 文档做贡献,本页面的内容和链接的主题能够给您帮助。您不必是一位开发者或者技术作者,也同样可以为 Kubernetes 文档及其用户体验带来巨大的影响!您只需要有一个 [Github 账号](https://github.com/join) 和一个浏览器。 + +如果您在寻找有关如何开始向 Kubernetes 仓库贡献代码的信息,请参考 [Kubernetes 社区指南](https://github.com/kubernetes/community/blob/master/governance.md)。 + +{{% /capture %}} + + +{{% capture body %}} + + +## 关于我们文档的基础知识 + + +Kubernetes 文档是以 Markdown 形式编写的,使用 Hugo 进行部署。源码位于 Github 的 [https://github.com/kubernetes/website](https://github.com/kubernetes/website)。大部分文档源码位于 `/content/en/docs/`。有些参考文档是由 `update-imported-docs/` 目录内的脚本自动生产的。 + +您可以提交 issue、编辑内容或者对其他人的提交内容进行复审,这些都可以在 Github 网站上完成。您也可以使用 Github 内置的历史功能和查询工具。 + + +并非所有的任务都可以通过 Github UI 完成,这些任务会在[中级](/docs/contribute/intermediate/)和[高级](/docs/contribute/advanced/)文档贡献指南中讨论 + +### 参与文档特别兴趣小组(SIG Docs) + + +Kubernetes 文档是由 {{< glossary_tooltip text="特别兴趣小组" term_id="sig" >}} (SIG) 维护的,该小组名为 SIG Docs。我们通过 Slack 频道、邮件列表和网络视频周会进行[交流](#participate-in-sig-docs-discussions)。欢迎新的参与者加入。更多信息,请参考[参与 SIG Docs](/docs/contribute/participating/)。 + + +### 内容指南 + +SIG Docs 社区创建了有关 Kubernetes 文档中允许哪种内容的指南。查看[文档内容指南](/docs/contribute/style/content-guide/)确定是否允许您要进行的内容贡献。您可以在 [#sig-docs]((#participate-in-sig-docs-discussions)) 频道中询问有关允许内容的问题。 + + +### 风格指南 + +我们维护了一个[风格指南](/docs/contribute/style/style-guide/)页面,上面有关于 SIG Docs 社区对于语法、句法、源格式和排版的约定。在您做首次贡献前或者在有疑问的时候请先查阅风格指南。 + + +风格的变化是由 SIG Docs 组共同决定的。如您想提交变更或增加内容,请将内容[添加到议题](https://docs.google.com/document/d/1zg6By77SGg90EVUrhDIhopjZlSDg2jCebU-Ks9cYx0w/edit#)并参与会议讨论。更多信息,参见[进阶贡献](/docs/contribute/advanced/)主题。 + + +### 页面模板 + +我们使用页面模板来控制文档页面。需要确保您理解这些模版是如何工作的,请阅读[使用页面模板](/docs/contribute/style/page-templates/)。 + +### Hugo 短代码 + + +Kubernetes 文档使用 Hugo 将 Markdown 转换成 HTML。我们使用标准的 Hugo 短代码,同时也会有部分为 Kubernetes 定制化的代码。有关如何使用短代码的信息,请参见[自定义 Hugo 短代码](/docs/contribute/style/hugo-shortcodes/)。 + +### 多语言 + + +在 `/content/` 目录中有文档源码的多语言版本。每个语言拥有其自己的目录,采用 [ISO 639-1 标准](https://www.loc.gov/standards/iso639-2/php/code_list.php) 的两位编码命名。例如,英文文档源码位于 `/content/en/docs/` 目录。 + +更多关于对多语言文档做贡献的信息,请参考中级贡献指南中的["本地化内容"](/docs/contribute/intermediate#localize-content)。 + + +如果您有兴趣开始一个新的本地化语言项目,请参考["本地化"](/docs/contribute/localization/)。 + +## 提出可操作的 issues + + +任何拥有 Github 账号的人都能对于 Kubernetes 提出可行的 issue(或者 bug report)。如果发现问题,即便您不知道如何修复它,请[提出 issue](#how-to-file-an-issue)。除非您发现微小的错误的情况,例如发现了一个拼写错误,您想自己进行修复。在这种情况下,您可以[修复它](#improve-existing-content),而不用先提出一个 bug。 + +### 如何提出 issue + + +- **对于已有页面** + + 如果您在已有的 [Kubernetes 文档](/docs/)页面,在页面底部直接点击 **创建 Issue** 按钮。如果您当前未登录 Github,那么请登录。Github 文档表单会带着预填的信息出现。 + + 使用 Markdown 格式,填写尽可能多的详细信息。在方括号 (`[ ]`) 中,使用 `x` 代码选择了该选项。如果您提交了修复 issue 的方法,也填在里面。 + + +- **请求创建一个新页面** + + 如果认为有些内容应该存在,但您不知道应该将这些内容存放在哪里,或者任何不适合放在现有页面中,那么也可以提出一个 issue。您可以选择通过内容相近的页面创建 issue,或者直接在 [https://github.com/kubernetes/website/issues/new/](https://github.com/kubernetes/website/issues/new/)中记录 issue。 + + +### 如何记录好的 issues + +要确保我们能理解您的 issue,并能付诸行动,请谨记如下指南: + + +- 使用 issue 模板,尽可能填写详细的信息。 +- 清楚地描述该 issue 对用户造成的具体影响。 +- 限制 issue 的范围,以提交给合理的工作组。如果问题范围很大,将其拆分成若干个 issues。 + + 例如,“修复安全文档”就是一个不可执行的 issue,但 “为'限制网络访问'主题添加详细信息”就是可执行的。 +- 如果 issue 与另一个 issue 或者拉取请求(PR)有关,您可以通过 issue 的完整 URL 或者 PR 的序号(以 `#` 为前缀)进行关联。例如 `如 #987654`。 +- 保持尊重,避免发泄。例如,“关于 X 的文档很差”就是无用且不可执行的反馈。[行为准测](/community/code-of-conduct/) 也适用于 Kubernetes Github 仓库的交互。 + + +## 参与 SIG Docs 讨论 + +SIG Docs 团队交流采用如下机制: + +- [加入 Kubernetes 的 Slack 工作组](http://slack.k8s.io/),然后加入 `#sig-docs` 频道,在那里我会实时讨论文档的 issues。一定要做自我介绍! +- [加入 `kubernetes-sig-docs` 邮件列表](https://groups.google.com/forum/#!forum/kubernetes-sig-docs),在这里会有广泛的讨论以及官方决策的记录。 +- 参与 [SIG Docs 视频周例会](https://github.com/kubernetes/community/tree/master/sig-docs),会通过 Slack 频道和邮件列表通知。 + 目前通过 Zoom 进行会议,所以您需要下载 [Zoom 客户端](https://zoom.us/download),或者通过手机拨入。 + +{{< note >}} +您也可以查看 [Kubernetes 社区会议日历](https://calendar.google.com/calendar/embed?src=cgnt364vd8s86hr2phapfjc6uk%40group.calendar.google.com&ctz=America/Los_Angeles)。 +{{< /note >}} + + +## 改进现有内容 + +要改进现有的内容,您可以在创建 _fork_ 之后起草一个 _拉取请求(PR)_ 。这两个术语是 [Github 专用的](https://help.github.com/categories/collaborating-with-issues-and-pull-requests/)。 +出于本主题的目的,您无需了解有关它们的所有信息,因为您可以通过浏览器做所有的事情。当您继续阅读[贡献者中级指南](/docs/contribute/intermediate/),您会需要更多 Git 术语的背景知识。 + +{{< note >}} +**Kubernetes 代码开发者**:如果您在撰写 Kubernetes 新版本的新功能文档,流程会稍有不同。 +关于流程指南和最后期限的信息,请参阅[编写功能文档](/docs/contribute/intermediate/#sig-members-documenting-new-features)。 +{{< /note >}} + + +## 签署 CNCF CLA {#sign-the-cla} + +在贡献 Kubernetes 的代码或文档前,您 **必须** 阅读[贡献者指南](https://github.com/kubernetes/community/blob/master/contributors/guide/README.md),并[签署贡献者许可协议(CLA)](https://github.com/kubernetes/community/blob/master/CLA.md)。 +别担心 -- 不需要太多时间! + +### 开始贡献 + + +如果您发现了一些想要马上修复的问题,只需要遵循如下指南。您不需要[提出一个 issue](#file-actionable-issues)(尽管你当然可以这么做)。 + +如果您想从处理现有的 issue 开始,前往 [https://github.com/kubernetes/website/issues](https://github.com/kubernetes/website/issues) 找一些有 `good first issue` 标签的 issue (您可以使用[这个](https://github.com/kubernetes/website/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) 快捷方式)。阅读评论,确保针对此 issue 没有打开的 PR,并且没有人留言说他们最近正在解决这个 issue (3 天是个很好的规则)。留言说您会去解决这个 issue。 + + +### 选择使用的 Git 分支 + +提交 PR 最重要的方面就是选择您工作所基于的基础分支。使用如下指南来做决定: + + +- 用 `master` 来解决以及发布的内容中的问题,或者对于已经存在的内容进行改进。 +- 使用 release 分支(比如 `dev-{{< release-branch >}}` 用于 {{< release-branch >}} 发布)来撰写新的特性或者下个版本还未发布的变更说明。 +- 使用 SIG Docs 已经同意的 feature 分支来协作对现有文档进行重大改进或更改,包括内容重组或网站外观的更改。 + +如果您还不确定应该使用哪个分支,在 Slack 上询问 `#sig-docs` 或者参与 SIG Docs 周例会来确认。 + + +### 提交 PR + + + +按照如下步骤提交 PR 来改善 Kubernetes 文档。 + +1. 在您提交 issue 的页面上,点击右上角的铅笔图标。新的页面就会出现,上面会有一些帮助信息。 +2. 如果您从未创建过 Kubernetes 文档仓库的 fork,会提示您需要创建。请在您的 Github 账号下创建 fork,而不是在您所在的组织下创建。fork URL 通常是这样的 `https://github.com//website`,除非您已经有一个同名的仓库,那样会造成冲突。 + 您创建 fork 的原因是您无权直接将分支推送到确定的 Kubernetes 仓库。 + +3. Github Markdown 编辑器会载入着文档源码一起出现。根据实际情况撰写变化内容。在编辑器下方填写 **Propose file change(建议修改文件)** 表格。第一个区域需要填写提交说明消息,不能超过 50 个字符。第二个区域是可选的,也能够填写更多详细信息。 + + {{< note >}} +不要把 Github issues 或者 PR 的关联信息放在您的提交说明消息中。您可以之后把这些内容添加到 PR 的描述中。 +{{< /note >}} + + + 点击 **建议修改文件(Propose file change)** 按钮。变更会保存为您 fork 新分支(通常会自动命名为 `patch-1`)中的一个提交内容。 + + +4. 接下来屏幕会总结您的变更,将您的新分支(**head fork** 和 **compare** 选择框)与 **base fork** + 和 **base** 分支(默认是 `kubernetes/website` 的 `master` 分支)进行比较。您可以更改选择框,但现在请不要这么做。看一下屏幕底部显示的变化内容,如果看起来没问题,点击 **创建 PR(Create pull request)** 按钮。 + + {{< note >}} +如果您现在还不想创建 PR,也可以稍后再做,通过浏览 Kubernetes 网站代码仓库或者您 fork 仓库的网站主页 URL。Github 网站会检查到您推送了一个新分支到 fork,并提示创建 PR。 +{{< /note >}} + + +5. **Open a pull request(打开一个 PR)** 屏幕出现了。PR 的主题和提交说明的内容一致, + 如有需要您也可以修改。主体内容会自动填充您的扩展提交消息(如果存在)和一些模板文本。 + 阅读模板文本并填写要求的详细信息,然后删除额外的模板文本。 + 如果在描述中添加 `fixes #<000000>` 或者 `closes #<000000>`,其中 `#<000000>` 是相关问题的编号,则当PR合并时,GitHub 将自动关闭该问题。 + 保留选中 **Allow edits from maintainers(允许维护者编辑)** 复选框。 + 单击 **Create pull request(创建拉取请求)** 按钮。 + + + 祝贺您!您的 PR 就出现在了[拉取请求](https://github.com/kubernetes/website/pulls) 中。 + + 几分钟后,您可以预览 PR 所带来的变化。前往您 PR 的 **Conversation(对话)** 标签页, + 点击 `deploy/netlify` 测试的 **Details(详细信息)** 链接,它在页面底部附件。 + 默认会在同一个浏览器窗口中打开。 + + {{< note >}} + 请将 PR 请求限制为每种 PR 只能使用一种语言。例如,如果您需要对多种语言的同一代码示例进行相同的更改,请为每种语言打开一个单独的 PR。 + {{< /note >}} + + +6. 等待复审。通常,复审人员会由 `k8s-ci-robot` 建议指定。如果复审人员建议您修改,您可以 + 前往 **Files changed(改变的文件内容)** 标签页,点击任意 PR 中改变的文件页面上的铅笔图标。 + 保存更改的文件时,将在 PR 监视的分支中创建新的提交。如果您正在等待复审者审核更改, + 请每 7 天主动与复审者联系一次。您也可以进入 #sig-docs Slack 频道,这是寻求有关 PR 审查的帮助的好地方。 + +7. 如果修改被接受,复审人员会合并您的 PR,修改就会在几分钟后在 Kubernetes 网站上生效。 + + +这是提交 PR 的唯一方式。如果您已经是一名 Git 和 Github 的高级用户,您也可以使用本地 GUI 或者 +Git 命令行。关于使用 Git 客户端的基础会在[中级](/docs/contribute/intermediate/) 贡献者指南中讨论。 + + +## 复审文档 PR + +就算不是批注者或者复审者,也同样可以复审 PR。复审人员并不是"固定"的,意味着您单独的评审并不会让 PR 合并。然而,这依然对我们是很有帮助的。即使您没有留下任何评审意见,您可以了解 PR 的规范和礼仪,并习惯工作流程。 + + +1. 前往 [https://github.com/kubernetes/website/pulls](https://github.com/kubernetes/website/pulls)。 + 请会看到一个列表,里面包含了所有对于 Kubernetes 网站和文档提的 PR。 + + +2. 默认情况下,使用的筛选器是 `open`,所以您不会看见已经关闭或合并的 PR。 + 最好使用 `cncf-cla: yes` 筛选器,并且对于第一次复审来说,最好加上 `size/S` + 或者 `size/XS`。`size` 标签会根据 PR 修改的代码行数自动生成。 + 您可以通过页面顶端的选择框应用筛选器,或者使用 + [快捷方式](https://github.com/kubernetes/website/pulls?q=is%3Aopen+is%3Apr+label%3A%22cncf-cla%3A+yes%22+label%3Asize%2FS) + 来查找所有小型 PR。所有筛选条件都是 `与` 的,所以您不能在一次查询中同时查找 `size/XS` 和 `size/S` 的结果。 + + +3. 前往 **Files changed(文件修改)** 标签页。查看 PR 中的变化部分,如果适用,也看一下关联的问题。如果您发现问题或者可以改进的空间, + 将鼠标悬浮在那一行并点击前面出现的 `+` 加号。 + + 你可以留下评论,选择 **Add single comment(仅添加评论)** 或者也可以 **Start a review(开始复审)**。典型来说,开始复审更好,因为这样您就可以在多行下留下评论,并且只有在完成复审后统一提交并通知 PR 的作者,而不是每一条评论都发送通知。 + + +4. 完成后,点击页面顶端但 **Review changes(复审修改)** 按钮。您可以总结复审,并且可以选择comment(评论),approve(批准),或者 request changes(请求变更)。新的贡献者应该选择 **Comment(评论)**。 + + +感谢您对于 PR 的复审工作!当您对于项目还是新人时,最好在拉取请求评论中征求反馈意见。Slack 的 `#sig-docs` 频道就是一个征求意见好去处。 + +## 撰写博客文章 + + +任何人都可以撰写博客并提交复审。博客文章不应具有商业性质,而应包含广泛适用于 Kubernetes 社区的内容。 + +要提交博客文章,您可以选择使用 [Kubernetes 博客提交表单](https://docs.google.com/forms/d/e/1FAIpQLSdMpMoSIrhte5omZbTE7nB84qcGBy8XnnXhDFoW0h7p2zwXrw/viewform)或者按如下步骤进行: + + +1. 如果您还未签署 CLA,请[签署 CLA](#sign-the-cla)。 +2. 查看现有博客文章的 Markdown 格式,位于[网站代码仓库](https://github.com/kubernetes/website/tree/master/content/en/blog/_posts)。 +3. 在您选择的文本编辑器中写下您的博客文章。 +4. 在步骤 2 的相同链接中,点击 **Create new file(创建新文件)** 按钮。 + 将您的内容粘贴到编辑器中。将文件命名为与博客文章的标题的名称, + 但不要将日期放在文件名中。博客复审人员将与您一起确定最终文件名和博客发布日期。 +5. 保存文件时,Github 将引导您完成 PR 过程。 +6. 博客复审人员会对您的提交对内容进行复审,并与您一起完成反馈意见和最终的详细信息。 + 博客文章获得批准后,博客将会安排时间进行发布。 + + +## 提交案例研究 + +案例研究强调组织如何使用 Kubernetes 解决实际问题。它们是由 Kubernetes 市场团队共同撰写的,由 {{< glossary_tooltip text="CNCF" term_id="cncf" >}} 进行处理。 + +看一下[现有案例研究](https://github.com/kubernetes/website/tree/master/content/en/case-studies)的源码。 +使用 [Kubernetes 案例研究提交表](https://www.cncf.io/people/end-user-community/)提交您的提案。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + +当您对本主题中讨论的所有任务感到满意,并且您希望以更深入的方式与 Kubernetes 文档团队合作,请阅读[中级贡献者指南](/docs/contribute/intermediate/)。 + +{{% /capture %}} diff --git a/content/zh/docs/contribute/style/_index.md b/content/zh/docs/contribute/style/_index.md new file mode 100644 index 0000000000..aacaf26575 --- /dev/null +++ b/content/zh/docs/contribute/style/_index.md @@ -0,0 +1,21 @@ +--- +title: 文档风格概述 +main_menu: true +weight: 80 +--- + + + + + +本节的主题是提供有关编写风格、内容格式和组织以及使用 Hugo 定制生成 Kubernetes 文档的指导。 diff --git a/content/zh/docs/contribute/style/content-organization.md b/content/zh/docs/contribute/style/content-organization.md new file mode 100644 index 0000000000..3ce7964655 --- /dev/null +++ b/content/zh/docs/contribute/style/content-organization.md @@ -0,0 +1,270 @@ +--- +title: 内容组织 +content_template: templates/concept +weight: 40 +--- + + + + +{{% capture overview %}} + + + +本网站使用了 Hugo。在 Hugo 中,[内容组织](https://gohugo.io/content-management/organization/) 是一个核心概念。 + +{{% /capture %}} + +{{% capture body %}} + +{{% note %}} + + +**Hugo 提示:** 用 `hugo server --navigateToChanged` 命令启动 Hugo 以进行内容编辑会话。 +{{% /note %}} + + + +## 页面列表 + + + +### 页面顺序 + + + +文档侧方菜单、文档页面浏览器等以 Hugo 的默认排序顺序列出,它按照权重(从1开始)、日期(最新的排第一个)排序,最后按链接标题排序。 + + + +如果你想提升一个页面或一个章节,请在页面头部设置一个较高的权重: + +```yaml +title: My Page +weight: 10 +``` + + +{{% note %}} + + +对于页面的权重,不建议使用连续的数值,比如1、2、3...,而是采用间隔的数值,比如10、20、30...,这样你可以将后续的页面插入到想要的位置。 +{{% /note %}} + + + + +### 文档主菜单 + + + +`Documentation` 主菜单是从 `docs/` 下面的章节构建的,它在 `_index.md` 章节内容文件的头部设置了 `main_menu` 标志: + + +```yaml +main_menu: true +``` + + + + +注意,链接标题是从页面的 `linkTitle` 中提取的,因此如果希望它与标题不同,请在内容文件中更改它: + + +```yaml +main_menu: true +title: Page Title +linkTitle: Title used in links +``` + + +{{% note %}} + + +以上每种语言都需要完成。如果在菜单中没有看到你的章节,这可能是因为它没有被 Hugo 标识为一个章节。请在章节对应的目录下创建 `_index.md` 内容文件。 +{{% /note %}} + + + +### 文档侧方菜单 + + + +文档侧方菜单是从 `docs/` 下面的 _current 章节的 tree_ 开始构建的。 + + + +它将显示所有的章节和它们的页面。 + + + +如果你不想列出某个章节或页面,请在页面头部将 `toc_hide` 标志设置为 `true`。 + +```yaml +toc_hide: true +``` + + + +当导航到具有内容的章节时,将显示出指定的章节或页面(例如 `_index.md`)。否则,将显示该章节里的第一个页面。 + + + +### 文档浏览器 + + + +文档主页上的页面浏览器是用 `docs section` 下一层的所有章节和页面构建的。 + + + +如果你不想列出某个章节或页面,请在页面头部将 `toc_hide` 标志设置为 `true`。 + +```yaml +toc_hide: true +``` + + + +### 主菜单 + + + +右上菜单中的网站链接(也在页脚中)是通过页面查找构建的。这是为了确保页面实际存在。因此,如果 `case-studies` 章节在网站中不存在(按语言),则它将链接不到。 + + + + +## 页面包 + + + +除了独立的内容页面(Markdown文件),Hugo 还支持 [页面包](https://gohugo.io/content-management/page-bundles/)。 + + + +一个例子是 [定制 Hugo 短代码](/docs/contribute/style/hugo-shortcodes/)。它被认为是 `leaf bundle`。目录下的所有内容,包括 `index.md`,都是包的一部分。这还包括页面相关的链接、可被处理的图像等: + +```bash +en/docs/home/contribute/includes +├── example1.md +├── example2.md +├── index.md +└── podtemplate.json +``` + + + +另一个广泛使用的例子是 `includes` 包。它在页面头部设置 `headless: true`,这意味着它没有得到自己的 URL。它只用于其他页面。 + +```bash +en/includes +├── default-storage-class-prereqs.md +├── federated-task-tutorial-prereqs.md +├── federation-content-moved.md +├── index.md +├── partner-script.js +├── partner-style.css +├── task-tutorial-prereqs.md +├── user-guide-content-moved.md +└── user-guide-migration-notice.md +``` + + + +包中文件的一些重要说明: + + + +* 对于已翻译的包,任何丢失的非内容文件将从上面的语言继承。这避免了重复。 +* 包中的所有文件都是 Hugo 所指的 `Resources`,你可以为每种语言提供元数据,例如参数和标题,即使它不支持头部设置(YAML 文件等)。参见[页面资源元数据](https://gohugo.io/content-management/page-resources/#page-resources-metadata)。 +* 从 `Resource` 的 `.RelPermalink` 中获得的值是页面相关的。参见 [Permalinks](https://gohugo.io/content-management/urls/#permalinks)。 + + + + +## 样式 + + + +本网站的样式表的 `SASS` 源存储在 `src/sass` 下面,可以用 `make sass` 构建(Hugo很快就会得到 `SASS` 的支持,参见https://github.com/gohugoio/hugo/issues/4243)。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + + +* [定制 Hugo 短代码](/docs/contribute/style/hugo-shortcodes/) +* [样式指南](/docs/contribute/style/style-guide) + +{{% /capture %}} diff --git a/content/zh/docs/contribute/style/hugo-shortcodes/example1.md b/content/zh/docs/contribute/style/hugo-shortcodes/example1.md new file mode 100644 index 0000000000..0656ce4883 --- /dev/null +++ b/content/zh/docs/contribute/style/hugo-shortcodes/example1.md @@ -0,0 +1,23 @@ +--- +title: 例子 #1 +--- + + + + + +这是一个内容文件**示例**,位于一个**includes**叶子包中。 + +{{< note >}} + + +包含的内容文件也可以包含短代码。 +{{< /note >}} \ No newline at end of file diff --git a/content/zh/docs/contribute/style/hugo-shortcodes/example2.md b/content/zh/docs/contribute/style/hugo-shortcodes/example2.md new file mode 100644 index 0000000000..356983f3c0 --- /dev/null +++ b/content/zh/docs/contribute/style/hugo-shortcodes/example2.md @@ -0,0 +1,17 @@ +--- +title: 例子 #1 +--- + + + + + +这是另一个内容文件**示例**,位于一个**includes**叶子包中。 + + diff --git a/content/zh/docs/contribute/style/hugo-shortcodes/index.md b/content/zh/docs/contribute/style/hugo-shortcodes/index.md new file mode 100644 index 0000000000..b9523c7217 --- /dev/null +++ b/content/zh/docs/contribute/style/hugo-shortcodes/index.md @@ -0,0 +1,272 @@ +--- +approvers: +- chenopis +title: 定制 Hugo 短代码 +content_template: templates/concept +--- + + + +{{% capture overview %}} + +本页面将介绍定制 Hugo 短代码,可以用于 Kubernetes markdown 文档书写。 + + +更多关于短代码参见 [Hugo 文档](https://gohugo.io/content-management/shortcodes)。 +{{% /capture %}} + +{{% capture body %}} + +## 功能状态 + + +本站上面的 markdown 页面,你可以加入短代码来展示已经文档介绍的功能的版本和状态(state)。 + + +### 功能状态演示 + + +下面是一个功能状态代码段的演示,表明这个功能已经在 Kubernetes v1.10时就已经稳定了。 + +``` +{{}} +``` + + +会转换为: + +{{< feature-state for_k8s_version="v1.10" state="stable" >}} + + +`state`的可选值如下: + +* alpha +* beta +* deprecated +* stable + + +### 功能状态代码 + + +下面是为每个现有的功能状态的模板代码。 + + + +显示的 Kubernetes 默认为该页或站点版本。 +这个可以通过修改 for_k8s_version 短代码参数来调整。 + +``` +{{}} +``` + + +会转换为: + +{{< feature-state for_k8s_version="v1.10" state="stable" >}} + + +#### Alpha 功能 + +``` +{{}} +``` + + +会转换为: + +{{< feature-state state="alpha" >}} + + + +#### Beta 功能 + +``` +{{}} +``` + + +会转换为: + +{{< feature-state state="beta" >}} + + +#### 稳定功能 + +``` +{{}} +``` + + +会转换为: + +{{< feature-state state="stable" >}} + + +#### 废弃功能 + +``` +{{}} +``` + + +会转换为: + +{{< feature-state state="deprecated" >}} + + +## 词汇 + + + +你可以通过加入术语词汇的短代码,来自动更新和替换相应链接中的内容([我们的词汇库](/docs/reference/glossary/)) +这样,在浏览在线文档,鼠标移到术语上时,术语解释就会显示在提示框中。 + + + +词汇术语的原始数据保存在 [https://github.com/kubernetes/website/tree/master/content/en/docs/reference/glossary](https://github.com/kubernetes/website/tree/master/content/en/docs/reference/glossary),每个内容文件对应相应的术语解释。 + + +### 词汇演示 + + + +例如,下面的代码在 markdown 中将会转换为 `{{< glossary_tooltip text="cluster" term_id="cluster" >}}`,然后在提示框中显示。 + +````liquid +{{}} +```` + + +## 标签页 + + +在本站的 markdown 页面(`.md` 文件)中,你可以加入一个标签页集来显示不同形式的解决方案。 + + +标签页的短代码包含以下参数: + + + +* `name`: 标签页上的名字。 +* `codelang`: 如果要在`tab`短代码中加入内部内容,需要告知 Hugo 使用的是什么代码语言,方便代码高亮。 +* `include`: 标签页中所要包含的文件。如果标签页是在 Hugo 的页面包([leaf bundle](https://gohugo.io/content-management/page-bundles/#leaf-bundles))中,文件(可以是 Hugo 所支持的 MIME 类型文件)将会在包中查找。如果不是,所要包含的内容页面将会在当前路径的相关路径下查找。注意,在`include`属性部分,不能加入短代码内部内容,必须要使用自结束(self-closing)的语法。 +非内容文件将会被代码高亮。如果没有在`codelang`进行声明的话,所用的代码语言将会来自文件名。 + + + +* 如果内部内容是 markdown, 你必须要使用 `%` 分隔符来包装标签页,例如,`{{%/* tab name="Tab 1" %}}This is **markdown**{{% /tab */%}}` +* 可以在标签页集中混合使用上面的各种变形。 + + +下面是演示标签页短代码。 + +{{< note >}} +The tab **name** in a `tabs` definition must be unique within a content page. +一个内容页面下的,标签页定义中的标签页 **名** 必须是唯一的。 +{{< /note >}} + + +### 标签页演示:代码高亮 + +```go-text-template +{{}} +{{{< tab name="Tab 1" codelang="bash" >}} +echo "This is tab 1." +{{< /tab >}} +{{< tab name="Tab 2" codelang="go" >}} +println "This is tab 2." +{{< /tab >}}} +{{< /tabs */>}} +``` + + +会转换为: + +{{< tabs name="tab_with_code" >}} +{{< tab name="Tab 1" codelang="bash" >}} +echo "This is tab 1." +{{< /tab >}} +{{< tab name="Tab 2" codelang="go" >}} +println "This is tab 2." +{{< /tab >}} +{{< /tabs >}} + +### Tabs demo: Inline Markdown and HTML + +```go-html-template +{{}} +{{% tab name="Markdown" %}} +This is **some markdown.** +{{< note >}}**Note:** It can even contain shortcodes.{{< /note >}} +{{% /tab %}} +{{< tab name="HTML" >}} +
+

Plain HTML

+

This is some plain HTML.

+
+{{< /tab >}} +{{< /tabs */>}} +``` + + +会转换为: + +{{< tabs name="tab_with_md" >}} +{{% tab name="Markdown" %}} +This is **some markdown.** +{{< note >}}**Note:** It can even contain shortcodes.{{< /note >}} +{{% /tab %}} +{{< tab name="HTML" >}} +
+

Plain HTML

+

This is some plain HTML.

+
+{{< /tab >}} +{{< /tabs >}} + + +### 标签页演示:文件嵌套 + +```go-text-template +{{}} +{{< tab name="Content File #1" include="example1" />}} +{{< tab name="Content File #2" include="example2" />}} +{{< tab name="JSON File" include="podtemplate" />}} +{{< /tabs */>}} +``` + + +会转换为: + +{{< tabs name="tab_with_file_include" >}} +{{< tab name="Content File #1" include="example1" />}} +{{< tab name="Content File #2" include="example2" />}} +{{< tab name="JSON File" include="podtemplate" />}} +{{< /tabs >}} + + +{{% /capture %}} + +{{% capture whatsnext %}} + + +* 了解 [Hugo](https://gohugo.io/)。 +* 了解 [撰写新的话题](/docs/home/contribute/write-new-topic/)。 +* 了解 [使用页面模板](/docs/home/contribute/page-templates/)。 +* 了解 [暂存修改](/docs/home/contribute/stage-documentation-changes/)。 +* 了解 [创建 pull request](/docs/home/contribute/create-pull-request/)。 +{{% /capture %}} diff --git a/content/zh/docs/contribute/style/hugo-shortcodes/podtemplate.json b/content/zh/docs/contribute/style/hugo-shortcodes/podtemplate.json new file mode 100644 index 0000000000..bd4327414a --- /dev/null +++ b/content/zh/docs/contribute/style/hugo-shortcodes/podtemplate.json @@ -0,0 +1,22 @@ + { + "apiVersion": "v1", + "kind": "PodTemplate", + "metadata": { + "name": "nginx" + }, + "template": { + "metadata": { + "labels": { + "name": "nginx" + }, + "generateName": "nginx-" + }, + "spec": { + "containers": [{ + "name": "nginx", + "image": "dockerfile/nginx", + "ports": [{"containerPort": 80}] + }] + } + } + } diff --git a/content/zh/docs/contribute/style/page-templates.md b/content/zh/docs/contribute/style/page-templates.md new file mode 100644 index 0000000000..f1afdff427 --- /dev/null +++ b/content/zh/docs/contribute/style/page-templates.md @@ -0,0 +1,352 @@ +--- +title: 使用页面模板 +content_template: templates/concept +weight: 30 +--- + + + +{{% capture overview %}} + + + +当贡献新主题时,选择下列模板中的一种。 +这使指定页面的用户体验标准化。 + + + +页面模板在 [`kubernetes/website`](https://github.com/kubernetes/website) 仓库的 [`layouts/partials/templates`](https://git.k8s.io/website/layouts/partials/templates) 目录中。 + +{{< note >}} + + +每个新主题都需要使用模板。如果你不确定新主题要使用哪个模板,请从[概念模板](#concept-template)开始。 +{{< /note >}} + + +{{% /capture %}} + + +{{% capture body %}} + + + +## 概念模板 + + + +每个概念页面负责解释 Kubernetes 的某方面。例如,概念页面可以描述 Kubernetes Deployment 对象,并解释当部署、扩展和更新时,它作为应用程序所扮演的角色。一般来说,概念页面不包括步骤序列,而是提供任务或教程的链接。 + + + + +要编写新的概念页面,请在 `/content/en/docs/concepts` 目录的子目录中创建一个 Markdown 文件,其特点如下: + + + +- 在页面的 YAML 头部,设置 `content_template: templates/concept`。 +- 在页面的 body 中,设置所需的 `capture` 变量和所有想要包含的变量: + + | 变量 | 必需? | + |---------------|-----------| + | overview | 是 | + | body | 是 | + | whatsnext | 否 | + + + + 页面的 body 看起来像这样(移除所有不想要的可选 `capture` 变量): + + ``` + {{%/* capture overview */%}} + + {{%/* /capture */%}} + + {{%/* capture body */%}} + + {{%/* /capture */%}} + + {{%/* capture whatsnext */%}} + + {{%/* /capture */%}} + ``` + + + +- 在每个章节中写下你的内容。请遵从以下规则: + - 使用不低于 H2 级别的标题(避免使用 H1 的标题,但 H3、H4 的标题是可以的)(以两个 `#` 字符开头)。这些章节本身是由模板自动命名的。 + - 在 `overview` 节,用一个段落的篇幅来为当前话题设定语境。 + - 在 `body` 节,使用自由形式的 Markdown 文件来解释概念。 + - 在 `whatsnext` 节,列出读者接下来可能感兴趣的最多 5 个主题。 + + + +使用概念模板的已发布主题的一个示例是[注解](/docs/concepts/overview/working-with-objects/annotations/)。你当前正在阅读的页面也使用概念模板。 + + + +## 任务模板 + + + +任务页面展示了如何完成单个任务,通常是通过给出一个简短的步骤序列。任务页面中解释性质的文字极少,但是通常会给出提供相关背景和知识的概念主题的链接。 + + + +要编写新的任务页面,请在 `/content/en/docs/tasks` 目录的子目录中创建一个 Markdown 文件,其特点如下: + + + +- 在页面的 YAML 头部,设置 `content_template: templates/task`。 +- 在页面的 body 中,设置所需的 `capture` 变量和所有想要包含的变量: + + | 变量 | 必需? | + |---------------|-----------| + | overview | 是 | + | prerequisites | 是 | + | steps | 否 | + | discussion | 否 | + | whatsnext | 否 | + + + + 页面的 body 看起来像这样(移除所有不想要的可选 `capture` 变量): + + ``` + {{%/* capture overview */%}} + + {{%/* /capture */%}} + + {{%/* capture prerequisites */%}} + + {{}} {{}} + + {{%/* /capture */%}} + + {{%/* capture steps */%}} + + {{%/* /capture */%}} + + {{%/* capture discussion */%}} + + {{%/* /capture */%}} + + {{%/* capture whatsnext */%}} + + {{%/* /capture */%}} + ``` + + + +- 在每个章节中写下你的内容。请遵从以下规则: + - 使用不低于 H2 级别的标题(避免使用 H1 的标题,但 H3、H4 的标题是可以的)(以两个 `#` 字符开头)。这些章节本身是由模板自动命名的。 + - 在 `overview` 节,用一个段落的篇幅来为当前话题设定语境。 + - 在 `prerequisites 节`,如果有可能,请使用列表。在 `include` 下开始添加额外的先决条件。默认的先决条件包括运行中的 Kubernetes 集群。 + - 在 `steps` 节,使用编号列表。 + - 在讨论部分,使用通常的内容来扩展 `steps` 中包含的信息。 + - 在 `whatsnext` 节,列出读者接下来可能感兴趣的最多 5 个主题。 + + + +使用任务模板的已发布主题的一个示例是[使用 HTTP 代理访问 Kubernetes API](/docs/tasks/access-kubernetes-api/http-proxy-access-api)。 + + + +## 教程模板 + + + +教程页面展示了如何完成比单个任务更大的目标。通常教程页有几个章节,每个章节都有步骤说明。例如,教程可以提供说明 Kubernetes 的特定特性的代码示例的演练。教程可以包括表层解释,但是应该链接到相关的概念主题以进行深入解释。 + + + +要编写新的教程页面,请在 `/content/en/docs/tutorials` 目录的子目录中创建一个 Markdown 文件,其特点如下: + + + +- 在页面的 YAML 头部,设置 `content_template: templates/tutorial`。 +- 在页面的 body 中,设置所需的 `capture` 变量和所有想要包含的变量: + + | 变量 | 必需? | + |---------------|-----------| + | overview | 是 | + | prerequisites | 是 | + | objectives | 是 | + | lessoncontent | 是 | + | cleanup | 否 | + | whatsnext | 否 | + + + + 页面的 body 看起来像这样(移除所有不想要的可选 `capture` 变量): + + ``` + {{%/* capture overview */%}} + + {{%/* /capture */%}} + + {{%/* capture prerequisites */%}} + + {{}} {{}} + + {{%/* /capture */%}} + + {{%/* capture objectives */%}} + + {{%/* /capture */%}} + + {{%/* capture lessoncontent */%}} + + {{%/* /capture */%}} + + {{%/* capture cleanup */%}} + + {{%/* /capture */%}} + + {{%/* capture whatsnext */%}} + + {{%/* /capture */%}} + ``` + + + +- 在每个章节中写下你的内容。请遵从以下规则: + - 使用不低于 H2 级别的标题(避免使用 H1 的标题,但 H3、H4 的标题是可以的)(以两个 `#` 字符开头)。这些章节本身是由模板自动命名的。 + - 在 `overview` 节,用一个段落的篇幅来为当前话题设定语境。 + - 在 `prerequisites` 节,如果有可能,请使用列表。在默认情况下添加额外的先决条件。 + - 在 `objectives` 节,使用列表。 + - 在 `lessoncontent` 节,适当地使用编号列表和叙述内容的组合。 + - 在 `cleanup` 节,使用编号列表描述完成任务后清理集群状态的步骤。 + - 在 `whatsnext` 节,列出读者接下来可能感兴趣的最多 5 个主题。 + + + +使用教程模板的已发布主题的一个示例是[使用部署运行无状态应用程序](/docs/tutorials/stateless-application/run-stateless-application-deployment/)。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + + +- 学习[样式指南](/docs/contribute/style/style-guide/) +- 学习[内容组织](/docs/contribute/style/content-organization/) + +{{% /capture %}} diff --git a/content/zh/docs/contribute/style/write-new-topic.md b/content/zh/docs/contribute/style/write-new-topic.md new file mode 100644 index 0000000000..82378bf1be --- /dev/null +++ b/content/zh/docs/contribute/style/write-new-topic.md @@ -0,0 +1,346 @@ +--- +title: 撰写新主题 +content_template: templates/task +weight: 20 +--- + + + +{{% capture overview %}} + + +本页面展示如何为 Kubernetes 文档库创建新主题。 +{{% /capture %}} + +{{% capture prerequisites %}} + + +创建 Kubernetes 文档仓库的一个分支,如[开始贡献](/docs/contribute/start/)中所述。 +{{% /capture %}} + +{{% capture steps %}} + + + +## 选择页面类型 + + + +当你准备写一个新的主题时,考虑一下最适合你的内容的页面类型: + + + + + + + + + + + + + + + + + + + + +
概念每个概念页面负责解释 Kubernetes 的某方面。例如,概念页面可以描述 Kubernetes Deployment 对象,并解释当部署、扩展和更新时,它作为应用程序所扮演的角色。一般来说,概念页面不包括步骤序列,而是提供任务或教程的链接。一个概念主题的示例,请参见 节点.
任务任务页面展示了如何完成单个任务。这样做的目的是给读者一系列步骤,让他们在阅读时能够真正做到这一点。任务页面可长可短,前提是它始终聚焦在一个区域。在任务页面中,可以将简短的解释与要执行的步骤混合在一起,但如果需要提供冗长的解释,则应在概念主题中进行。相关联的任务和概念主题可以相互链接。一个简短的任务页面的实例,请参见 配置一个使用卷进行存储的 Pod. 一个较长的任务页面的实例,请参见 配置活动性和就绪性探测器
教程教程页面展示了如何实现将几个 Kubernetes 特性联系在一起的目标。教程可能提供一些步骤序列,读者可以在阅读页面时实际执行这些步骤。或者它可以提供相关代码片段的解释。例如,教程可以提供代码示例的演练。教程可以包括对 Kubernetes 几个关联特性的简要解释,但应该链接到相关概念主题,以便深入解释各个特性。
+ + + +为每个新页面使用模板。每种页面类型都有一个[模板](/docs/contribute/style/page-templates/)可以在编写主题时使用。使用模板有助于确保给定类型主题之间的一致性。 + + + +## 选择标题和文件名 + + + +选择一个标题,标题中包含了要通过搜索引擎要查找的关键字。创建一个文件名,使用标题中由连字符分隔的单词。例如,标题为[使用 HTTP 代理访问 Kubernetes API](/docs/tasks/access-kubernetes-api/http-proxy-access-api/) 的主题的文件名为 `http-proxy-access-api.md`。你不需要在文件名中加上 "kubernetes",因为 "kubernetes" 已经在主题的 URL 中了,例如: + + /docs/tasks/access-kubernetes-api/http-proxy-access-api/ + + + +## 在页面头部添加主题标题 + + + +在你的主题中,在[页面头部](https://jekyllrb.com/docs/frontmatter/)设置一个 `title` 字段。页面头部是位于页面顶部三条虚线之间的 YAML 块。下面是一个例子: + + + + --- + title: 使用 HTTP 代理访问 Kubernetes API + --- + + + +## 选择目录 + + + +根据页面类型,将新文件放入其中一个子目录中: + +* /content/en/docs/tasks/ +* /content/en/docs/tutorials/ +* /content/en/docs/concepts/ + + + +你可以将文件放在现有的子目录中,也可以创建一个新的子目录。 + + + +## 将主题放在目录中 + + + +目录是使用文档源的目录结构动态构建的。`/content/en/docs/` 下的顶层目录创建顶层导航,它和子目录在目录中都有条目。 + + + +每个子目录都有一个 `_index.md` 文件,它表示指定子目录内容的主页面。`_index.md` 文件不需要模板。它可以包含有关子目录中主题的概述内容。 + + + +默认情况下,目录中的其他文件按字母顺序排序。这几乎不是最好的顺序。要控制子目录中主题的相对排序,请将页面头部的键 `weight:` 设置为整数。通常我们使用10的倍数,添加后续主题时权重值递增。例如,权重为 `10` 的主题将位于权重为 `20` 的主题之前。 + + + +## 在主题中嵌入代码 + + + +如果你想在主题中包含一些代码,可以直接使用标记代码块语法将代码嵌入到文件中。建议用于以下情况(并非详尽列表): + + + +- 代码显示来自命令的输出,例如 `kubectl get deploy mydeployment -o json | jq '.status'`。 +- 代码不够通用,用户无法验证。例如,你可以嵌入 YAML 文件来创建一个依赖于特定 [Flexvolume](/docs/concepts/storage/volumes#flexvolume)实现的 Pod。 +- 该代码是一个不完整的示例,因为它的目的是高亮显示大文件的部分内容。例如,在描述自定义 [PodSecurityPolicy](/docs/tasks/administer-cluster/sysctl-cluster/#podsecuritypolicy)的方法时,出于某些原因,你可以直接在主题文件中提供一个简短的片段。 +- 由于其他原因,该代码不适合用户验证。例如,当使用 `kubectl edit` 命令描述如何将新属性添加到资源时,你可以提供一个仅包含要添加的属性的简短示例。 + + + +## 引用来自其他文件的代码 + + + +在主题中引用代码的另一种方法是创建一个新的、完整的示例文件(或示例文件组),然后从主题中引用这些示例。当示例是通用的和可重用的,并且你希望读者自己验证时,使用此方法引用示例 YAML 文件。 + + + +添加新的独立示例文件(如 YAML 文件)时,将代码放在 `/examples/` 的某个子目录中,其中 `` 是该主题的语言。在主题文件中使用 `codenew` 短代码: + +
{{< codenew file="<RELPATH>/my-example-yaml>" >}}
+ + + +`` 是要引用的文件的路径,相对于 `examples` 目录。以下 Hugo 短代码引用了位于 `/content/en/examples/pods/storage/gce-volume.yaml` 的 YAML 文件。 + +```none +{{}} +``` + +{{< note >}} + + +要展示上述示例中的原始 Hugo 短代码并避免 Hugo 对其进行解释,请直接在 `<` 字符之后和 `>` 字符之前使用 C 样式注释。请查看此页面的代码。 +{{< /note >}} + + + +## 显示如何从配置文件创建 API 对象 + + + +如果需要演示如何基于配置文件创建 API 对象,请将配置文件放在 `/examples` 下的某个子目录中。 + + + +在主题中展示以下命令: + +``` +kubectl create -f https://k8s.io/examples/pods/storage/gce-volume.yaml +``` + +{{< note >}} + + +将新的 YAML 文件添加到 `/examples` 目录时,请确保该文件也在 `/examples_test.go` 文件中被引用。当提交拉取请求时,网站的 Travis CI 会自动运行此测试用例,以确保所有示例都通过测试。 +{{< /note >}} + + + +有关使用此技术的主题的示例,请参见[运行单实例有状态的应用](/docs/tutorials/stateful-application/run-stateful-application/)。 + + + +## 向主题添加镜像 + + + +将镜像文件放入 `/images` 目录。首选的镜像格式是 SVG。 + +{{% /capture %}} + +{{% capture whatsnext %}} + + +* 学习[使用页面模板](/docs/home/contribute/page-templates/)。 +* 学习[展示你的修改](/docs/home/contribute/stage-documentation-changes/)。 +* 学习[创建一个拉取请求](/docs/home/contribute/create-pull-request/)。 +{{% /capture %}} diff --git a/content/zh/docs/doc-contributor-tools/README.md b/content/zh/docs/doc-contributor-tools/README.md new file mode 100644 index 0000000000..fe0e37a2c7 --- /dev/null +++ b/content/zh/docs/doc-contributor-tools/README.md @@ -0,0 +1,7 @@ +Kubernetes 文档贡献者的工具。 查看子目录内的 `README.md` 文件以获取更多信息。 + + + diff --git a/content/zh/docs/doc-contributor-tools/snippets/README.md b/content/zh/docs/doc-contributor-tools/snippets/README.md new file mode 100644 index 0000000000..4058cbd4b6 --- /dev/null +++ b/content/zh/docs/doc-contributor-tools/snippets/README.md @@ -0,0 +1,84 @@ + +# Atom 的代码段 + + + +代码段就是可以插入到编辑器中的一段文本,可以节省键入时间,减少语法错误。 +`atom-snippets.cson` 文件中所提供的代码段只用于在 Atom 中的 Markdown 文件。 + + +## 安装 + + + +将 `atom-snippets.cson` 文件中的内容复制到现有的`~/.atom/snippets.cson` 之中。 +**不要替换现有的文件。** + + +不需要重启 Atom。 + + +## 使用 + + + +浏览一遍 `atom-snippets.cson` 文件,记下代码段的标题和 `prefix`。 + + + +你可以使用以下任意一种方式来触发相应的代码段: +- 键入代码段的`prefix`,按下 `` 键 +- 在 **Packages / Snippets / Available** 中搜索代码段的标题 + + + +例如,打开一个 Markdown 文件,键入 `anote`,按下 ``。 +就会插入一段带有正确的 Hugo 短代码的空注释。 + + + +代码段可以插入一行或多行文本。一些代码行都设有预留值。想要切换到下一个预留值,再按一次`` 键即可。 + + + +一些代码段只会插入部分格式的 Markdown 或 Hugo 语法。 +例如,`coverview` 只会插入一个概念概览的开始标签,而`cclose`则会插入一个结束标签。 +这是因为每类 capture 都需要一个 capture-close 标签。 + + +## 使用代码段创建新的话题 + + +从空白文件中,创建一个新的概念,任务或者教程,使用以下的代码段: + +- `newconcept` +- `newtask` +- `newtutorial` + + +预设文本包含其中。 + + +## 提交新的代码段 + + + +1. 本地开发代码段,验证是否有效。 +2. 将代码单复制到 Github 的 `atom-snippets.cson` 文件中。 +提交 pull request,邀请 Kubernetes Slack `#sig-docs` 中的另外一名 Atom 用户进行审查。 diff --git a/content/zh/docs/doc-contributor-tools/snippets/atom-snippets.cson b/content/zh/docs/doc-contributor-tools/snippets/atom-snippets.cson new file mode 100644 index 0000000000..878ccc4ed7 --- /dev/null +++ b/content/zh/docs/doc-contributor-tools/snippets/atom-snippets.cson @@ -0,0 +1,226 @@ +# Your snippets +# +# Atom snippets allow you to enter a simple prefix in the editor and hit tab to +# expand the prefix into a larger code block with templated values. +# +# You can create a new snippet in this file by typing "snip" and then hitting +# tab. +# +# An example CoffeeScript snippet to expand log to console.log: +# +# '.source.coffee': +# 'Console log': +# 'prefix': 'log' +# 'body': 'console.log $1' +# +# Each scope (e.g. '.source.coffee' above) can only be declared once. +# +# This file uses CoffeeScript Object Notation (CSON). +# If you are unfamiliar with CSON, you can read more about it in the +# Atom Flight Manual: +# http://flight-manual.atom.io/using-atom/sections/basic-customization/#_cson + +'.source.gfm': + + # Capture variables for concept template + # For full concept template see 'newconcept' below + 'Insert concept template': + 'prefix': 'ctemplate' + 'body': 'content_template: templates/concept' + 'Insert concept overview': + 'prefix': 'coverview' + 'body': '{{% capture overview %}}' + 'Insert concept body': + 'prefix': 'cbody' + 'body': '{{% capture body %}}' + 'Insert concept whatsnext': + 'prefix': 'cnext' + 'body': '{{% capture whatsnext %}}' + + + # Capture variables for task template + # For full task template see 'newtask' below + 'Insert task template': + 'prefix': 'ttemplate' + 'body': 'content_template: templates/task' + 'Insert task overview': + 'prefix': 'toverview' + 'body': '{{% capture overview %}}' + 'Insert task prerequisites': + 'prefix': 'tprereq' + 'body': """ + {{% capture prerequisites %}} + + {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} + + {{% /capture %}} + """ + 'Insert task steps': + 'prefix': 'tsteps' + 'body': '{{% capture steps %}}' + 'Insert task discussion': + 'prefix': 'tdiscuss' + 'body': '{{% capture discussion %}}' + + + # Capture variables for tutorial template + # For full tutorial template see 'newtutorial' below + 'Insert tutorial template': + 'prefix': 'tutemplate' + 'body': 'content_template: templates/tutorial' + 'Insert tutorial overview': + 'prefix': 'tuoverview' + 'body': '{{% capture overview %}}' + 'Insert tutorial prerequisites': + 'prefix': 'tuprereq' + 'body': '{{% capture prerequisites %}}' + 'Insert tutorial objectives': + 'prefix': 'tuobjectives' + 'body': '{{% capture objectives %}}' + 'Insert tutorial lesson content': + 'prefix': 'tulesson' + 'body': '{{% capture lessoncontent %}}' + 'Insert tutorial whatsnext': + 'prefix': 'tunext' + 'body': '{{% capture whatsnext %}}' + 'Close capture': + 'prefix': 'ccapture' + 'body': '{{% /capture %}}' + 'Insert note': + 'prefix': 'anote' + 'body': """ + {{< note >}} + $1 + {{< /note >}} + """ + + # Admonitions + 'Insert caution': + 'prefix': 'acaution' + 'body': """ + {{< caution >}} + $1 + {{< /caution >}} + """ + 'Insert warning': + 'prefix': 'awarning' + 'body': """ + {{< warning >}} + $1 + {{< /warning >}} + """ + + # Misc one-liners + 'Insert TOC': + 'prefix': 'toc' + 'body': '{{< toc >}}' + 'Insert code from file': + 'prefix': 'codefile' + 'body': '{{< codenew file="$1" >}}' + 'Insert feature state': + 'prefix': 'fstate' + 'body': '{{< feature-state for_k8s_version="$1" state="$2" >}}' + 'Insert figure': + 'prefix': 'fig' + 'body': '{{< figure src="$1" title="$2" alt="$3" caption="$4" >}}' + 'Insert Youtube link': + 'prefix': 'yt' + 'body': '{{< youtube $1 >}}' + + + # Full concept template + 'Create new concept': + 'prefix': 'newconcept' + 'body': """ + --- + reviewers: + - ${1:"github-id-or-group"} + title: ${2:"topic-title"} + content_template: templates/concept + --- + {{% capture overview %}} + ${3:"overview-content"} + {{% /capture %}} + + {{< toc >}} + + {{% capture body %}} + ${4:"h2-heading-per-subtopic"} + {{% /capture %}} + + {{% capture whatsnext %}} + ${5:"next-steps-or-delete"} + {{% /capture %}} + """ + + + # Full task template + 'Create new task': + 'prefix': 'newtask' + 'body': """ + --- + reviewers: + - ${1:"github-id-or-group"} + title: ${2:"topic-title"} + content_template: templates/task + --- + {{% capture overview %}} + ${3:"overview-content"} + {{% /capture %}} + + {{< toc >}} + + {{% capture prerequisites %}} + + {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} + + ${4:"additional-prereqs-or-delete"} + + {{% /capture %}} + + {{% capture steps %}} + ${5:"h2-heading-per-step"} + {{% /capture %}} + + {{% capture discussion %}} + ${6:"task-discussion-or-delete"} + {{% /capture %}} + """ + + # Full tutorial template + 'Create new tutorial': + 'prefix': 'newtutorial' + 'body': """ + --- + reviewers: + - ${1:"github-id-or-group"} + title: ${2:"topic-title"} + content_template: templates/tutorial + --- + {{% capture overview %}} + ${3:"overview-content"} + {{% /capture %}} + + {{< toc >}} + + {{% capture prerequisites %}} + + {{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} + + ${4:"additional-prereqs-or-delete"} + + {{% /capture %}} + + {{% capture objectives %}} + ${5:"tutorial-objectives"} + {{% /capture %}} + + {{% capture lessoncontent %}} + ${6:"lesson-content"} + {{% /capture %}} + + {{% capture whatsnext %}} + ${7:"next-steps-or-delete"} + {{% /capture %}} + """ + diff --git a/content/zh/docs/getting-started-guides/ubuntu/security.md b/content/zh/docs/getting-started-guides/ubuntu/security.md deleted file mode 100644 index 74ac9b9dfd..0000000000 --- a/content/zh/docs/getting-started-guides/ubuntu/security.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -title: 安全考虑 -content_template: templates/task ---- - - -{{% capture overview %}} - -默认情况下,所有提供的节点之间的所有连接(包括 etcd 集群)都通过 easyrsa 的 TLS 进行保护。 - -本文介绍已部署集群的安全注意事项和生产环境建议。 -{{% /capture %}} -{{% capture prerequisites %}} - -本文假定您拥有一个使用 Juju 部署的正在运行的集群。 -{{% /capture %}} - - -{{% capture steps %}} - -## 实现 - -TLS 和 easyrsa 的实现使用以下 [layers](https://old-docs.jujucharms.com/2.5/en/developer-layers)。 - -[layer-tls-client](https://github.com/juju-solutions/layer-tls-client) -[layer-easyrsa](https://github.com/juju-solutions/layer-easyrsa) - - -## 限制 ssh 访问 - -默认情况下,管理员可以 ssh 到集群中的任意已部署节点。您可以通过以下命令来批量禁用集群节点的 ssh 访问权限。 - - juju model-config proxy-ssh=true - -注意:Juju 控制器节点在您的云中仍然有开放的 ssh 访问权限,并且在这种情况下将被用作跳板机。 - -有关如何管理 ssh 密钥的说明,请参阅 Juju 文档中的 [模型管理](https://old-docs.jujucharms.com/2.5/en/models) 页面。 -{{% /capture %}} - - diff --git a/content/zh/docs/home/supported-doc-versions.md b/content/zh/docs/home/supported-doc-versions.md index eae8ac97b1..986155dc0f 100644 --- a/content/zh/docs/home/supported-doc-versions.md +++ b/content/zh/docs/home/supported-doc-versions.md @@ -9,13 +9,13 @@ card: {{% capture overview %}} -本网站包含了当前最新版本和之前四个版本的 Kubernetes。 +本网站包含当前版本和之前四个版本的 Kubernetes 文档。 {{% /capture %}} {{% capture body %}} -## 当前最新版本 +## 当前版本 当前版本是 [{{< param "version" >}}](/)。 diff --git a/content/zh/docs/reference/_index.md b/content/zh/docs/reference/_index.md index 5e9d6dca2d..e89d629c5b 100644 --- a/content/zh/docs/reference/_index.md +++ b/content/zh/docs/reference/_index.md @@ -1,7 +1,5 @@ --- title: 参考 -approvers: -- chenopis linkTitle: "参考" main_menu: true weight: 70 @@ -35,29 +33,28 @@ This section of the Kubernetes documentation contains references. * [Kubernetes API 概述](/docs/reference/using-api/api-overview/) - Kubernetes API 概述。 * Kubernetes API 版本 + * [1.16](/docs/reference/generated/kubernetes-api/v1.16/) * [1.15](/docs/reference/generated/kubernetes-api/v1.15/) * [1.14](/docs/reference/generated/kubernetes-api/v1.14/) * [1.13](/docs/reference/generated/kubernetes-api/v1.13/) * [1.12](/docs/reference/generated/kubernetes-api/v1.12/) - * [1.11](/docs/reference/generated/kubernetes-api/v1.11/) ## API 客户端库 如果您需要通过编程语言调用 Kubernetes API,您可以使用 -[客户端库](/docs/reference/using-api/client-libraries/)。以下是官方支持的 -客户端库: +[客户端库](/docs/reference/using-api/client-libraries/)。以下是官方支持的客户端库: - [Kubernetes Go 语言客户端库](https://github.com/kubernetes/client-go/) - [Kubernetes Python 语言客户端库](https://github.com/kubernetes-client/python) diff --git a/content/zh/docs/reference/access-authn-authz/_index.md b/content/zh/docs/reference/access-authn-authz/_index.md index 1e1d30cfb1..aa4d8d2730 100644 --- a/content/zh/docs/reference/access-authn-authz/_index.md +++ b/content/zh/docs/reference/access-authn-authz/_index.md @@ -2,4 +2,4 @@ title: 访问 API weight: 20 toc-hide: true ---- \ No newline at end of file +--- diff --git a/content/zh/docs/reference/access-authn-authz/abac.md b/content/zh/docs/reference/access-authn-authz/abac.md index 4c3715e495..b39aa418f3 100644 --- a/content/zh/docs/reference/access-authn-authz/abac.md +++ b/content/zh/docs/reference/access-authn-authz/abac.md @@ -4,139 +4,312 @@ approvers: - lavalamp - deads2k - liggitt -title: ABAC 模式 +title: 使用 ABAC 鉴权 content_template: templates/concept --- + + {{% capture overview %}} + 基于属性的访问控制(Attribute-based access control - ABAC)定义了访问控制范例,其中通过使用将属性组合在一起的策略来向用户授予访问权限。 {{% /capture %}} {{% capture body %}} + + ## 策略文件格式 基于 `ABAC` 模式,可以这样指定策略文件 `--authorization-policy-file=SOME_FILENAME`。 -此文件是 JSON 格式[每行都是一个JSON对象](http://jsonlines.org/),不应存在封闭的列表或映射,每行只有一个映射。 +此文件格式是 [JSON Lines](http://jsonlines.org/),不应存在封闭的列表或映射,每行一个映射。 -每一行都是一个 "策略对象",策略对象是具有以下映射的属性: +每一行都是一个策略对象,策略对象是具有以下属性的映射: - - 版本控制属性: - - `apiVersion`,字符串类型: 有效值为"abac.authorization.kubernetes.io/v1beta1",允许版本控制和转换策略格式。 - - `kind`,字符串类型: 有效值为 "Policy",允许版本控制和转换策略格式。 - - `spec` 配置为具有以下映射的属性: - - 匹配属性: - - `user`,字符串类型; 来自 `--token-auth-file` 的用户字符串,如果你指定`user`,它必须与验证用户的用户名匹配。 - - `group`,字符串类型; 如果指定`group`,它必须与经过身份验证的用户的一个组匹配,`system:authenticated`匹配所有经过身份验证的请求。`system:unauthenticated`匹配所有未经过身份验证的请求。 - - 资源匹配属性: - - `apiGroup`,字符串类型; 一个 API 组。 - - 例: `extensions` - - 通配符: `*`匹配所有 API 组。 - - `namespace`,字符串类型; 一个命名空间。 - - 例如: `kube-system` - - 通配符: `*` 匹配所有资源请求。 - - `resource`,字符串类型; 资源类型。 - - 例:`pods` - - 通配符: `*`匹配所有资源请求。 - - 非资源匹配属性: - - `nonResourcePath`,字符串类型; 非资源请求路径。 - - 例如:`/version`或`/apis` - - 通配符: + - 版本控制属性: + - `apiVersion`,字符串类型:有效值为`abac.authorization.kubernetes.io/v1beta1`,允许对策略格式进行版本控制和转换。 + - `kind`,字符串类型:有效值为 `Policy`,允许对策略格式进行版本控制和转换。 + - `spec` 配置为具有以下映射的属性: + - 主体匹配属性: + - `user`,字符串类型;来自 `--token-auth-file` 的用户字符串,如果你指定 `user`,它必须与验证用户的用户名匹配。 + - `group`,字符串类型;如果指定 `group`,它必须与经过身份验证的用户的一个组匹配,`system:authenticated`匹配所有经过身份验证的请求。`system:unauthenticated`匹配所有未经过身份验证的请求。 + - 资源匹配属性: + - `apiGroup`,字符串类型;一个 API 组。 + - 例: `extensions` + - 通配符:`*`匹配所有 API 组。 + - `namespace`,字符串类型;一个命名空间。 + - 例如:`kube-system` + - 通配符:`*`匹配所有资源请求。 + - `resource`,字符串类型;资源类型。 + - 例:`pods` + - 通配符:`*`匹配所有资源请求。 + - 非资源匹配属性: + - `nonResourcePath`,字符串类型;非资源请求路径。 + - 例如:`/version`或 `/apis` + - 通配符: - `*` 匹配所有非资源请求。 - - `/foo/*` 匹配`/foo/`的所有子路径。 - - `readonly`,键入 boolean,如果为 true,则表示该策略仅适用于 get,list 和 watch 操作。 + - `/foo/*` 匹配 `/foo/` 的所有子路径。 + - `readonly`,键入布尔值,如果为 true,则表示该策略仅适用于 get、list 和 watch 操作。 -**注意:** 未设置的属性与类型设置为零值的属性相同(例如空字符串,0、false),然而未知的应该可读性优先。 +{{< note >}} + + +属性未设置等效于属性被设置为对应类型的零值( 例如空字符串、0、false),然而,出于可读性考虑,应尽量选择不设置这类属性。 在将来,策略可能以 JSON 格式表示,并通过 REST 界面进行管理。 -## 授权算法 +{{< /note >}} + + + +## 鉴权算法 请求具有与策略对象的属性对应的属性。 -当接收到请求时,确定属性。 未知属性设置为其类型的零值(例如: 空字符串,0,false)。 +当接收到请求时,确定属性。未知属性设置为其类型的零值(例如:空字符串,0,false)。 -设置为`“*"`的属性将匹配相应属性的任何值。 +设置为 `"*"` 的属性将匹配相应属性的任何值。 -检查属性的元组,以匹配策略文件中的每个策略。 如果至少有一行匹配请求属性,则请求被授权(但可能会在稍后验证失败)。 +检查属性的元组,以匹配策略文件中的每个策略。如果至少有一行匹配请求属性,则请求被鉴权(但仍可能无法通过稍后的合法性检查)。 -要允许任何经过身份验证的用户执行某些操作,请将策略组属性设置为 `"system:authenticated“`。 +要允许任何经过身份验证的用户执行某些操作,请将策略组属性设置为 `"system:authenticated"`。 -要允许任何未经身份验证的用户执行某些操作,请将策略组属性设置为`"system:authentication“`。 +要允许任何未经身份验证的用户执行某些操作,请将策略组属性设置为 `"system:authentication"`。 要允许用户执行任何操作,请使用 apiGroup,命名空间, -资源和 nonResourcePath 属性设置为 `“*"`的策略. +资源和 nonResourcePath 属性设置为 `"*"` 的策略。 -要允许用户执行任何操作,请使用设置为`“*”` 的 apiGroup,namespace,resource 和 nonResourcePath 属性编写策略。 +要允许用户执行任何操作,请使用设置为 `"*"` 的 apiGroup,namespace,resource 和 nonResourcePath 属性编写策略。 + + ## Kubectl -Kubectl 使用 api-server 的 `/api` 和 `/apis` 端点进行协商客户端/服务器版本。 通过创建/更新来验证发送到API的对象操作,kubectl 查询某些 swagger 资源。 对于API版本"v1", 那就是`/swaggerapi/api/v1` & `/swaggerapi/ experimental/v1`。 +Kubectl 使用 api-server 的 `/api` 和 `/apis` 端点来发现服务资源类型,并使用位于 `/openapi/v2` 的模式信息来验证通过创建/更新操作发送到 API 的对象。 -当使用 ABAC 授权时,这些特殊资源必须明确通过策略中的 `nonResourcePath` 属性暴露出来(参见下面的[例子](#examples)): +当使用 ABAC 鉴权时,这些特殊资源必须显式地通过策略中的 `nonResourcePath` 属性暴露出来(参见下面的 [示例](#examples)): -* `/api`,`/api/*`,`/apis`和`/apis/*` 用于 API 版本协商. -* `/version` 通过 `kubectl version` 检索服务器版本. -* `/swaggerapi/*` 用于创建/更新操作. - -要检查涉及到特定kubectl操作的HTTP调用,您可以调整详细程度: +* `/api`,`/api/*`,`/apis`和 `/apis/*` 用于 API 版本协商。 +* `/version` 通过 `kubectl version` 检索服务器版本。 +* `/swaggerapi/*` 用于创建 / 更新操作。 +要检查涉及到特定 kubectl 操作的 HTTP 调用,您可以调整详细程度: kubectl --v=8 version -## 例子 + + +## 例子 {#examples} + +1. Alice 可以对所有资源做任何事情: + + ```json + {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "alice", "namespace": "*", "resource": "*", "apiGroup": "*"}} + ``` +2. Kubelet 可以读取任何 pod: + + ```json + {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "kubelet", "namespace": "*", "resource": "pods", "readonly": true}} + ``` +3. Kubelet 可以读写事件: + + ```json + {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "kubelet", "namespace": "*", "resource": "events"}} + ``` + + + +4. Bob 可以在命名空间 `projectCaribou` 中读取 pod: + ```json + {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "bob", "namespace": "projectCaribou", "resource": "pods", "readonly": true}} + ``` +5. 任何人都可以对所有非资源路径进行只读请求: ```json {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group": "system:authenticated", "readonly": true, "nonResourcePath": "*"}} {"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"group": "system:unauthenticated", "readonly": true, "nonResourcePath": "*"}} ``` -[完整文件示例](http://releases.k8s.io/{{< param "githubbranch" >}}/pkg/auth/authorizer/abac/example_policy_file.jsonl) + + +[完整文件示例](http://releases.k8s.io/{{< param "githubbranch" >}}/pkg/auth/authorizer/abac/example_policy_file.jsonl) + +## 服务帐户的快速说明 + +服务帐户自动生成用户。用户名是根据命名约定生成的: + +```shell +system:serviceaccount:: +``` + + + 创建新的命名空间也会导致创建一个新的服务帐户: ```shell system:serviceaccount::default ``` -例如,如果要将 API 的 kube-system 完整权限中的默认服务帐户授予,则可以将此行添加到策略文件中: +例如,如果要将 API 的 kube-system 完整权限中的默认服务帐户授予,则可以将此行添加到策略文件中: ```json {"apiVersion":"abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user":"system:serviceaccount:kube-system:default","namespace":"*","resource":"*","apiGroup":"*"}} ``` -需要重新启动 apiserver 以获取新的策略行. +需要重新启动 apiserver 以获取新的策略行。 {{% /capture %}} diff --git a/content/zh/docs/reference/access-authn-authz/authorization.md b/content/zh/docs/reference/access-authn-authz/authorization.md index c953e33cc3..a7366e92d5 100644 --- a/content/zh/docs/reference/access-authn-authz/authorization.md +++ b/content/zh/docs/reference/access-authn-authz/authorization.md @@ -28,12 +28,12 @@ that Kubernetes authorization works with existing organization-wide or cloud-provider-wide access control systems which may handle other APIs besides the Kubernetes API. --> -在Kubernetes中,您必须在授权(授予访问权限)之前进行身份验证(登录),有关身份验证的信息, +在 Kubernetes 中,您必须在授权(授予访问权限)之前进行身份验证(登录),有关身份验证的信息, 请参阅 [访问控制概述](/docs/reference/access-authn-authz/controlling-access/). -Kubernetes期望REST API请求中常见的属性。 -这意味着Kubernetes授权适用于现有的组织范围或云提供商范围的访问控制系统, -除了Kubernetes API之外,它还可以处理其他API。 +Kubernetes 期望 REST API 请求中常见的属性。 +这意味着 Kubernetes 授权适用于现有的组织范围或云提供商范围的访问控制系统, +除了 Kubernetes API 之外,它还可以处理其他 API。 ## 审查您的请求属性 -Kubernetes仅审查以下API请求属性: +Kubernetes 仅审查以下 API 请求属性: - * **user** - 身份验证期间提供的`user`字符串。 + * **user** - 身份验证期间提供的 `user` 字符串。 * **group** - 经过身份验证的用户所属的组名列表。 * **extra** - 由身份验证层提供的任意字符串键到字符串值的映射。 * **API** - 指示请求是否针对 API 资源。 - * **Request path** - 各种非资源端点的路径,如`/api`或`/healthz`。 - * **API request verb** - API 动词`get`,`list`,`create`,`update`,`patch`,`watch`,`proxy`,`redirect`,`delete`和`deletecollection`用于资源请求。要确定资源API端点的请求动词,请参阅[确定请求动词](/docs/reference/access-authn-authz/authorization/#determine-whether-a-request-is-allowed-or-denied)。 - * **HTTP request verb** - HTTP 动词`get`,`post`,`put`和`delete`用于非资源请求。 - * **Resource** - 正在访问的资源的 ID 或名称(仅限资源请求) - 对于使用`get`,`update`,`patch`和`delete`动词的资源请求,您必须提供资源名称。 + * **Request path** - 各种非资源端点的路径,如 `/api` 或 `/healthz`。 + * **API request verb** - API 动词 `get`,`list`,`create`,`update`,`patch`,`watch`,`proxy`,`redirect`,`delete` 和 `deletecollection` 用于资源请求。要确定资源 API 端点的请求动词,请参阅[确定请求动词](/docs/reference/access-authn-authz/authorization/#determine-whether-a-request-is-allowed-or-denied)。 + * **HTTP request verb** - HTTP 动词 `get`,`post`,`put` 和 `delete` 用于非资源请求。 + * **Resource** - 正在访问的资源的 ID 或名称(仅限资源请求) - 对于使用 `get`,`update`,`patch` 和 `delete` 动词的资源请求,您必须提供资源名称。 * **Subresource** - 正在访问的子资源(仅限资源请求)。 * **Namespace** - 正在访问的对象的名称空间(仅适用于命名空间资源请求)。 - * **API group** - 正在访问的 API 组(仅限资源请求)。空字符串表示[核心API组](/docs/concepts/overview/kubernetes-api/)。 + * **API group** - 正在访问的 API 组(仅限资源请求)。空字符串表示[核心 API 组](/docs/concepts/overview/kubernetes-api/)。 -#### 检查API访问 +#### 检查 API 访问 -`kubectl`提供`auth can-i`子命令,用于快速查询 API 授权层。 -该命令使用`SelfSubjectAccessReview` API来确定当前用户是否可以执行给定操作,并且无论使用何种授权模式都可以工作。 +`kubectl` 提供 `auth can-i` 子命令,用于快速查询 API 授权层。 +该命令使用 `SelfSubjectAccessReview` API 来确定当前用户是否可以执行给定操作,并且无论使用何种授权模式都可以工作。 ```bash $ kubectl auth can-i create deployments --namespace dev @@ -192,14 +192,14 @@ These APIs can be queried by creating normal Kubernetes resources, where the res field of the returned object is the result of the query. --> -`SelfSubjectAccessReview`是`authorization.k8s.io` API组的一部分,它将 API 服务器授权公开给外部服务。 +`SelfSubjectAccessReview` 是 `authorization.k8s.io` API 组的一部分,它将 API 服务器授权公开给外部服务。 该组中的其他资源包括: -* `SubjectAccessReview` - 访问任何用户的 Review ,而不仅仅是当前用户。用于将授权决策委派给API服务器。例如,kubelet 和扩展 API 服务器使用它来确定用户对自己的API的访问权限。 -* `LocalSubjectAccessReview` - 与`SubjectAccessReview`类似,但仅限于特定的命名空间。 -* `SelfSubjectRulesReview` - 返回用户可在命名空间内执行的操作集的审阅。用户可以快速汇总自己的访问权限,或者用于隐藏/显示操作的UI。 +* `SubjectAccessReview` - 访问任何用户的 Review ,而不仅仅是当前用户。用于将授权决策委派给 API 服务器。例如,kubelet 和扩展 API 服务器使用它来确定用户对自己的 API 的访问权限。 +* `LocalSubjectAccessReview` - 与 `SubjectAccessReview` 类似,但仅限于特定的命名空间。 +* `SelfSubjectRulesReview` - 返回用户可在命名空间内执行的操作集的审阅。用户可以快速汇总自己的访问权限,或者用于 UI 中的隐藏/显示动作。 -可以通过创建普通 Kubernetes 资源来查询这些 API ,其中返回对象的响应“status”字段是查询的结果。 +可以通过创建普通 Kubernetes 资源来查询这些 API ,其中返回对象的响应 “status” 字段是查询的结果。 ```bash $ kubectl create -f - -o yaml << EOF @@ -247,20 +247,20 @@ You can choose more than one authorization module. Modules are checked in order so an earlier module has higher priority to allow or deny a request. --> -## 为您的授权模块使用标志 +## 为您的授权模块应用参数 -您必须在策略中包含一个标志,以指明您的策略包含哪个授权模块: +您必须在策略中包含一个参数标志,以指明您的策略包含哪个授权模块: -可以使用以下标志: +可以使用以下参数: * `--authorization-mode=ABAC` 基于属性的访问控制(ABAC)模式允许您使用本地文件配置策略。 * `--authorization-mode=RBAC` 基于角色的访问控制(RBAC)模式允许您使用 Kubernetes API 创建和存储策略。 - * `--authorization-mode=Webhook` WebHook 是一种 HTTP 回调模式,允许您使用远程REST端点管理授权。 - * `--authorization-mode=Node` 节点授权是一种特殊用途的授权模式,专门授权由 kubelet 发出的API请求。 + * `--authorization-mode=Webhook` WebHook 是一种 HTTP 回调模式,允许您使用远程 REST 端点管理授权。 + * `--authorization-mode=Node` 节点授权是一种特殊用途的授权模式,专门授权由 kubelet 发出的 API 请求。 * `--authorization-mode=AlwaysDeny` 该标志阻止所有请求。仅将此标志用于测试。 * `--authorization-mode=AlwaysAllow` 此标志允许所有请求。仅在您不需要 API 请求的授权时才使用此标志。 -您可以选择多个授权模块。按顺序检查模块,以便较早的模块具有更高的优先级来允许或拒绝请求。 +您可以选择多个授权模块。模块按顺序检查,以便较早的模块具有更高的优先级来允许或拒绝请求。 -## 通过pod创建权限升级 +## 通过 Pod 创建升级权限 -能够在命名空间中创建 pod 的用户可能会升级其在该命名空间内的权限。 -他们可以创建在该命名空间内访问其权限的 pod 。 -他们可以创建用户无法自己读取 secret 的 pod ,或者在具有不同/更高权限的服务帐户下运行的 pod 。 +能够在命名空间中创建 Pod 的用户可能会升级其在该命名空间内的权限。 +他们可以创建在该命名空间内访问其权限的 Pod 。 +他们可以创建用户无法自己读取 secret 的 Pod ,或者在具有不同/更高权限的服务帐户下运行的 Pod 。 {{< caution >}} -**注意:** 系统管理员在授予对 pod 创建的访问权限时要小心。 -授予在命名空间中创建 pod(或创建pod的控制器)的权限的用户可以: -读取命名空间中的所有秘密;读取命名空间中的所有配置映射; +**注意:** 系统管理员在授予对 Pod 创建的访问权限时要小心。 +授予在命名空间中创建 Pod(或创建 Pod 的控制器)的权限的用户可以: +读取命名空间中的所有 secret;读取命名空间中的所有 ConfigMap; 并模拟命名空间中的任何服务帐户并执行帐户可以执行的任何操作。 无论采用何种授权方式,这都适用。 {{< /caution >}} @@ -299,6 +299,6 @@ mode. * To learn more about Authentication, see **Authentication** in [Controlling Access to the Kubernetes API](/docs/reference/access-authn-authz/controlling-access/). * To learn more about Admission Control, see [Using Admission Controllers](/docs/reference/access-authn-authz/admission-controllers/). --> -* 要了解有关身份验证的更多信息,请参阅 **身份验证** [控制对Kubernetes API的访问](/docs/reference/access-authn-authz/controlling-access/). -* 要了解有关准入控制的更多信息,请参阅 [使用准入控制器](/docs/reference/access-authn-authz/admission-controllers/). +* 要了解有关身份验证的更多信息,请参阅 **身份验证** [控制对 Kubernetes API 的访问](/docs/reference/access-authn-authz/controlling-access/)。 +* 要了解有关准入控制的更多信息,请参阅 [使用准入控制器](/docs/reference/access-authn-authz/admission-controllers/)。 {{% /capture %}} \ No newline at end of file diff --git a/content/zh/docs/reference/access-authn-authz/bootstrap-tokens.md b/content/zh/docs/reference/access-authn-authz/bootstrap-tokens.md index ced000932d..77ca6f32d5 100644 --- a/content/zh/docs/reference/access-authn-authz/bootstrap-tokens.md +++ b/content/zh/docs/reference/access-authn-authz/bootstrap-tokens.md @@ -15,8 +15,8 @@ Bootstrapping](/docs/admin/kubelet-tls-bootstrapping/) 系统进行工作。 启动引导令牌被定义成一个特定类型的 secrets(`bootstrap.kubernetes.io/token`),并存在于 `kube-system` 命名空间中。然后这些 secrets 会被 API 服务器上的启动引导的认证器读取。 -控制器管理器中的控制器TokenCleaner能够删除过期的令牌。在节点发现的过程中Kubernetes会使用特殊的ConfigMap对象。 -控制器管理器中的BootstrapSigner控制器也会使用启动引导令牌为这类对象生成签名信息。 +控制器管理器中的控制器 TokenCleaner 能够删除过期的令牌。在节点发现的过程中 Kubernetes 会使用特殊的 ConfigMap 对象。 +控制器管理器中的 BootstrapSigner 控制器也会使用启动引导令牌为这类对象生成签名信息。 目前,启动引导令牌处于 **alpha** 阶段,但是预期也不会有大的突破性变化。 @@ -26,7 +26,7 @@ Bootstrapping](/docs/admin/kubelet-tls-bootstrapping/) 系统进行工作。 更加规范地说,它们必须符合正则表达式 `[a-z0-9]{6}\.[a-z0-9]{16}`。 令牌的第一部分是 "Token ID" ,它是公共信息。用于引用某个令牌,并确保不会泄露认证所使用的秘密信息。 -第二部分是 "令牌秘密(Token Secret)",它应该被共享给收信的第三方。 +第二部分是“令牌秘密(Token Secret)”,它应该被共享给收信的第三方。 ## 启用启动引导令牌 @@ -82,19 +82,19 @@ TokenCleaner 控制器会删除过期的令牌。 ## 使用 `kubeadm` 管理令牌 -你可以使用 `kubeadm` 工具管理正在运行集群的令牌。它会从 `kubeadm` 创建的集群(`/etc/kubernetes/admin.conf`) +你可以使用 `kubeadm` 工具管理正在运行集群的令牌。它会从 `kubeadm` 创建的集群(`/etc/kubernetes/admin.conf`) 自动抓取默认管理员密码。你可以通过参数 `--kubeconfig` 对下面命令指定一个另外的 kubeconfig 文件抓取密码。 * `kubeadm token list` 列举了令牌,同时显示了它们的过期时间和用途。 * `kubeadm token create` 创建一个新令牌。 * `--description` 设置新令牌的描述。 - * `--ttl duration` 设置令牌从 "现在" 起到过期时间的差值。 + * `--ttl duration` 设置令牌从“现在”起到过期时间的差值。 默认是 0 ,也就是不过期。 * `--usages` 设置令牌被使用的方式。默认是 `signing,authentication`。用途在上面已经描述。 * `kubeadm token delete |.` 删除令牌。 令牌可以只用 ID 来确认,也可以用整个令牌的值。如果只用 ID 的情况下,密文不匹配的令牌也会被删除。 -### ConfigMap签名 +### ConfigMap 签名 除了认证之外,令牌可以用于签名 ConfigMap。这在集群启动过程的早期,在客户端信任 API 服务器之前被使用。 被签名的 ConfigMap 可以通过共享令牌被认证。 @@ -131,6 +131,6 @@ ConfigMap 的 `kubeconfig` 成员是一个填好了集群信息的配置文件 这里主要交换的信息是 `certificate-authority-data`。在将来可能会有扩展。 签名是一个 JWS 签名,使用了 "detached" 模式。为了检验签名,用户应该按照 JWS 规则 -(base64 编码而忽略结尾的 `=`)对 `kubeconfig` 的载荷进行编码。完成编码的载荷会被通过插入 JWS 并存在于两个点的中间 +(base64 编码而忽略结尾的 `=`)对 `kubeconfig` 的载荷进行编码。完成编码的载荷会被通过插入 JWS 并存在于两个点的中间 ,用于形成一个完整的 JWS。可以使用令牌的完整信息(比如 `07401b.f395accd246ae52d`)作为共享密钥, 通过 `HS256` 方式 (HMAC-SHA256) 对 JWS 进行校验。 用户 _必须_ 确保使用了 HS256。 diff --git a/content/zh/docs/reference/access-authn-authz/controlling-access.md b/content/zh/docs/reference/access-authn-authz/controlling-access.md index 19831ea749..e181571a5d 100644 --- a/content/zh/docs/reference/access-authn-authz/controlling-access.md +++ b/content/zh/docs/reference/access-authn-authz/controlling-access.md @@ -2,40 +2,40 @@ approvers: - erictune - lavalamp -title: Kubernetes API访问控制 +title: Kubernetes API 访问控制 --- -用户通过 `kubectl`、客户端库或者通过发送REST请求[访问API](/docs/user-guide/accessing-the-cluster)。 用户(自然人)和[Kubernetes服务账户](/docs/tasks/configure-pod-container/configure-service-account/) 都可以被授权进行API访问。 -请求到达API服务器后会经过几个阶段,具体说明如图: +用户通过 `kubectl`、客户端库或者通过发送 REST 请求[访问 API](/docs/user-guide/accessing-the-cluster)。 用户(自然人)和 [Kubernetes 服务账户](/docs/tasks/configure-pod-container/configure-service-account/) 都可以被授权进行 API 访问。 +请求到达 API 服务器后会经过几个阶段,具体说明如图: ![Diagram of request handling steps for Kubernetes API request](/images/docs/admin/access-control-overview.svg) ## 传输层安全 -在典型的Kubernetes集群中,API通过443端口提供服务。 -API服务器会提供一份证书。 该证书一般是自签名的, 所以用户机器上的 `$USER/.kube/config` 目录通常 -包含该API服务器证书的根证书,用来代替系统默认根证书。 当用户使用 `kube-up.sh` 创建集群时,该证书通常会被自动写入用户的`$USER/.kube/config`。 如果集群中存在多个用户,则创建者需要与其他用户共享证书。 +在典型的 Kubernetes 集群中,API 通过 443 端口提供服务。 +API 服务器会提供一份证书。 该证书一般是自签名的, 所以用户机器上的 `$USER/.kube/config` 目录通常 +包含该 API 服务器证书的根证书,用来代替系统默认根证书。 当用户使用 `kube-up.sh` 创建集群时,该证书通常会被自动写入用户的 `$USER/.kube/config`。 如果集群中存在多个用户,则创建者需要与其他用户共享证书。 ## 认证 -一旦 TLS 连接建立,HTTP请求就进入到了认证的步骤。即图中的步骤 **1** 。 -集群创建脚本或集群管理员会为API服务器配置一个或多个认证模块。 -更具体的认证相关的描述详见 [这里](/docs/admin/authentication/)。 +一旦 TLS 连接建立,HTTP 请求就进入到了认证的步骤。即图中的步骤 **1** 。 +集群创建脚本或集群管理员会为 API 服务器配置一个或多个认证模块。 +更具体的认证相关的描述详见[这里](/docs/admin/authentication/)。 -认证步骤的输入是整个HTTP请求,但这里通常只是检查请求头和/或客户端证书。 +认证步骤的输入是整个 HTTP 请求,但这里通常只是检查请求头和 / 或客户端证书。 -认证模块支持客户端证书,密码和Plain Tokens, -Bootstrap Tokens,以及JWT Tokens (用于服务账户)。 +认证模块支持客户端证书,密码和 Plain Tokens, +Bootstrap Tokens,以及 JWT Tokens(用于服务账户)。 (管理员)可以同时设置多种认证模块,在设置了多个认证模块的情况下,每个模块会依次尝试认证, 直到其中一个认证成功。 -在 GCE 平台中,客户端证书,密码和Plain Tokens,Bootstrap Tokens,以及JWT Tokens同时被启用。 +在 GCE 平台中,客户端证书,密码和 Plain Tokens,Bootstrap Tokens,以及 JWT Tokens 同时被启用。 -如果请求认证失败,则请求被拒绝,返回401状态码。 +如果请求认证失败,则请求被拒绝,返回 401 状态码。 如果认证成功,则被认证为具体的 `username`,该用户名可供随后的步骤中使用。一些认证模块还提供了用户的组成员关系,另一些则没有。 -尽管Kubernetes使用 "用户名" 来进行访问控制和请求记录,但它实际上并没有 `user` 对象,也不存储用户名称或其他相关信息。 +尽管 Kubernetes 使用“用户名”来进行访问控制和请求记录,但它实际上并没有 `user` 对象,也不存储用户名称或其他相关信息。 ## 授权 @@ -43,7 +43,7 @@ Bootstrap Tokens,以及JWT Tokens (用于服务账户)。 请求须包含请求者的用户名,请求动作,以及该动作影响的对象。 如果存在相应策略,声明该用户具有进行相应操作的权限,则该请求会被授权。 -例如,如果Bob有如下策略,那么他只能够读取`projectCaribou`命名空间下的pod资源: +例如,如果 Bob 有如下策略,那么他只能够读取 `projectCaribou` 命名空间下的 pod 资源: ```json { @@ -57,7 +57,7 @@ Bootstrap Tokens,以及JWT Tokens (用于服务账户)。 } } ``` -如果Bob发起以下请求,那么请求能够通过授权,因为Bob被允许访问 `projectCaribou` 命名空间下的对象: +如果 Bob 发起以下请求,那么请求能够通过授权,因为 Bob 被允许访问 `projectCaribou` 命名空间下的对象: ```json { @@ -73,20 +73,20 @@ Bootstrap Tokens,以及JWT Tokens (用于服务账户)。 } } ``` -如果Bob对 `projectCaribou` 命名空间下的对象发起一个写(`create` 或者 `update`)请求,那么它的授权会被拒绝。 如果Bob请求读取(`get`) 其他命名空间,例如 `projectFish`下的对象,其授权也会被拒绝。 +如果 Bob 对 `projectCaribou` 命名空间下的对象发起一个写(`create` 或者 `update`)请求,那么它的授权会被拒绝。 如果 Bob 请求读取 (`get`)其他命名空间,例如 `projectFish` 下的对象,其授权也会被拒绝。 -Kubernetes的授权要求使用通用的REST属性与现有的组织或云服务提供商的访问控制系统进行交互。 采用REST格式是必要的,因为除Kubernetes外,这些访问控制系统还可能与其他的API进行交互。 +Kubernetes 的授权要求使用通用的 REST 属性与现有的组织或云服务提供商的访问控制系统进行交互。 采用 REST 格式是必要的,因为除 Kubernetes 外,这些访问控制系统还可能与其他的 API 进行交互。 -Kubernetes 支持多种授权模块,例如ABAC模式,RBAC模式和 Webhook模式。 管理员创建集群时,会配置API服务器应用的授权模块。 如果多种授权模式同时被启用,Kubernetes将检查所有模块,如果其中一种通过授权,则请求授权通过。 如果所有的模块全部拒绝,则请求被拒绝(HTTP状态码403)。 +Kubernetes 支持多种授权模块,例如 ABAC 模式,RBAC 模式和 Webhook 模式。 管理员创建集群时,会配置 API 服务器应用的授权模块。 如果多种授权模式同时被启用,Kubernetes 将检查所有模块,如果其中一种通过授权,则请求授权通过。 如果所有的模块全部拒绝,则请求被拒绝(HTTP 状态码 403)。 -要了解更多的Kubernetes授权相关信息,包括使用授权模块创建策略的具体说明等,可参考[授权概述](/docs/admin/authorization)。 +要了解更多的 Kubernetes 授权相关信息,包括使用授权模块创建策略的具体说明等,可参考[授权概述](/docs/admin/authorization)。 ## 准入控制 准入控制模块是能够修改或拒绝请求的软件模块。 作为授权模块的补充,准入控制模块会访问被创建或更新的对象的内容。 -它们作用于对象的创建,删除,更新和连接 (proxy)阶段,但不包括对象的读取。 +它们作用于对象的创建,删除,更新和连接(proxy)阶段,但不包括对象的读取。 可以同时配置多个准入控制器,它们会按顺序依次被调用。 @@ -98,23 +98,23 @@ Kubernetes 支持多种授权模块,例如ABAC模式,RBAC模式和 Webhook 可用的准入控制模块描述 [如下](/docs/admin/admission-controllers/)。 -一旦请求通过所有准入控制器,将使用对应API对象的验证流程对其进行验证,然后写入对象存储 (如步骤 **4**)。 +一旦请求通过所有准入控制器,将使用对应 API 对象的验证流程对其进行验证,然后写入对象存储 (如步骤 **4**)。 -## API的端口和IP +## API 的端口和 IP -上述讨论适用于发送请求到API服务器的安全端口(典型情况)。 -实际上API服务器可以通过两个端口提供服务: +上述讨论适用于发送请求到 API 服务器的安全端口(典型情况)。 +实际上 API 服务器可以通过两个端口提供服务: -默认情况下,API服务器在2个端口上提供HTTP服务: +默认情况下,API 服务器在 2 个端口上提供 HTTP 服务: 1. `Localhost Port`: - 用于测试和启动,以及管理节点的其他组件 - (scheduler, controller-manager)与API的交互 - - 没有TLS - - 默认值为8080,可以通过 `--insecure-port` 标记来修改。 - - 默认的IP地址为localhost, 可以通过 `--insecure-bind-address`标记来修改。 + (scheduler, controller-manager)与 API 的交互 + - 没有 TLS + - 默认值为 8080,可以通过 `--insecure-port` 标记来修改。 + - 默认的 IP 地址为 localhost, 可以通过 `--insecure-bind-address` 标记来修改。 - 请求会 **绕过** 认证和鉴权模块。 - 请求会被准入控制模块处理。 - 其访问需要主机访问的权限。 @@ -123,12 +123,12 @@ Kubernetes 支持多种授权模块,例如ABAC模式,RBAC模式和 Webhook - 尽可能使用该端口访问 - 应用 TLS。 可以通过 `--tls-cert-file` 设置证书, 通过 `--tls-private-key-file` 设置私钥。 - - 默认值为6443,可以通过 `--secure-port` 标记来修改。 - - 默认IP是首个非本地的网络接口地址,可以通过 `--bind-address` 标记来修改。 + - 默认值为 6443,可以通过 `--secure-port` 标记来修改。 + - 默认 IP 是首个非本地的网络接口地址,可以通过 `--bind-address` 标记来修改。 - 请求会经过认证和鉴权模块处理。 - 请求会被准入控制模块处理。 - 要求认证和授权模块正常运行。 -通过 `kube-up.sh`创建集群时, 对 Google Compute Engine (GCE) -和一些其他的云供应商来说, API通过443端口提供服务。 对 -GCE而言,项目上配置了防火墙规则,允许外部的HTTPS请求访问API,其他(厂商的)集群设置方法各不相同。 +通过 `kube-up.sh` 创建集群时, 对 Google Compute Engine(GCE) +和一些其他的云供应商来说, API 通过 443 端口提供服务。 对 +GCE 而言,项目上配置了防火墙规则,允许外部的 HTTPS 请求访问 API,其他(厂商的)集群设置方法各不相同。 diff --git a/content/zh/docs/reference/access-authn-authz/extensible-admission-controllers.md b/content/zh/docs/reference/access-authn-authz/extensible-admission-controllers.md new file mode 100644 index 0000000000..341d2d91d1 --- /dev/null +++ b/content/zh/docs/reference/access-authn-authz/extensible-admission-controllers.md @@ -0,0 +1,2090 @@ +--- +reviewers: +- smarterclayton +- lavalamp +- caesarxuchao +- deads2k +- liggitt +- jpbetz + +title: 动态准入控制 +content_template: templates/concept +weight: 40 +--- +{{% capture overview %}} + + +[admission 控制器文档](/docs/reference/access-authn-authz/admission-controllers/) +介绍如何使用标准的插件式 admission 控制器。然而, +由于以下原因插件 admission 控制器对于所有用例来说都不够灵活: + +* 他们需要编译到 kube-apiserver 里面。 +* 它们仅在 apiserver 启动时可配置。 + +*Admission Webhooks*(1.9 版中的 beta)解决了这些限制。 +它允许 admission 控制器能被独立开发以及在运行时配置。 + +本页介绍如何使用 Admission Webhooks。 +{{% /capture %}} + +{{% capture body %}} + +### 什么是 admission webhook? + + +Admission webhooks 是 HTTP 回调,它接收 admission 请求并对它们做一些事情。 +您可以定义两种类型的 admission webhook, +[validating admission Webhook](/docs/reference/access-authn-authz/admission-controllers/#validatingadmissionwebhook) +和 +[mutating admission webhook](/docs/reference/access-authn-authz/admission-controllers/#mutatingadmissionwebhook)。 +通过 validating admission Webhook,您可以拒绝请求以执行自定义的 admission 策略。 +通过 mutating admission webhook,您可以更改请求以执行自定义的默认值。 + + +### 尝试 admission webhook + +admission webhook 本质上是集群控制平面的一部分。 您应该非常谨慎地编写和部署它们。 +如果您打算编写/部署生产级 admission webhook,请阅读[用户指南](/docs/reference/access-authn-authz/extensible-admission-controllers/#write-an-admission-webhook-server)以获取相关说明。 +在下文中,我们将介绍如何快速试验 admission webhook。 + + +### 先决条件 + +* 确保 Kubernetes 集群版本至少为 v1.9。 + +* 确保启用 MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook 控制器。 + [这里](/docs/reference/access-authn-authz/admission-controllers/#is-there-a-recommended-set-of-admission-controllers-to-use) + 是一组推荐的 admission 控制器,通常可以启用。 + +* 确保启用了`admissionregistration.k8s.io/v1beta1` API。 + + +### 编写一个admission webhook 服务器 + +请参阅 Kubernetes e2e 测试中的 +[admission webhook 服务器](https://github.com/kubernetes/kubernetes/blob/v1.13.0/test/images/webhook/main.go)实现。 + webhook 处理由 apiservers 发送的 `admissionReview` 请求,并将其决定包含在 `admissionResponse` 中发回。 + +`admissionReview` 请求可以有不同的版本(例如,`v1beta1` 或未来版本中的 `v1`)。 +webhook 可以使用 `admissionReviewVersions` 字段定义它们接受的版本。 +apiserver 将尝试在其支持的列表中使用第一个版本。 +如果 apiserver 不支持此列表中指定的任何版本,则此对象的验证将失败。 +如果 webhook 配置依然如此,则对 webhook 的调用将失败并受到失败策略的控制。 + +示例 admission webhook 服务器置 `ClientAuth` 字段为 +[空](https://github.com/kubernetes/kubernetes/blob/v1.13.0/test/images/webhook/config.go#L47-L48), +默认为 `NoClientCert` 。这意味着 webhook 服务器不会验证客户端的身份,认为其是 apiservers。 +如果您需要双向 TLS 或其他方式来验证客户端,请参阅如何 [验证-apiservers](#验证-apiservers)。 + + +### 部署 admission webhook 服务 + +e2e 测试中的 webhook 服务器部署在 Kubernetes 集群中,通过 [deployment API](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#deployment-v1-apps)。 +该测试还创建了 [service](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#service-v1-core) 作为 webhook 服务器的前端。 +参见 [code](https://github.com/kubernetes/kubernetes/blob/v1.15.0/test/e2e/apimachinery/webhook.go#L301)。 + +您还可以在集群外部署 Webhook, +这需要相应地更新 [webhook 客户端配置](https://github.com/kubernetes/kubernetes/blob/v1.13.0/staging/src/k8s.io/api/admissionregistration/v1beta1/types.go#L247)。 + + +### 即时配置 admission webhook + +您可以动态配置哪些资源需要接受什么许可通过webhooks [ValidatingWebhookConfiguration](/docs/reference/produced/kubernetes-api/{{}}/#validatingwebhookconfiguration-v1-admissionregistration-k8s-io) 要么 +[MutatingWebhookConfiguration](/docs/reference/Generated/kubernetes-api/{{}}/#mutatingwebhookconfiguration-v1-admissionregistration-k8s-io)。 + +以下是一个示例`ValidatingWebhookConfiguration`,一个变异的 webhook 配置与此类似。有关每个配置字段的详细信息,请参见 [webhook 配置](#webhook-配置)部分。 + +{{< tabs name="ValidatingWebhookConfiguration_example_1" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: "pod-policy.example.com" +webhooks: +- name: "pod-policy.example.com" + rules: + - apiGroups: [""] + apiVersions: ["v1"] + operations: ["CREATE"] + resources: ["pods"] + scope: "Namespaced" + clientConfig: + service: + namespace: "example-namespace" + name: "example-service" + caBundle: "Ci0tLS0tQk......tLS0K" + admissionReviewVersions: ["v1", "v1beta1"] + sideEffects: None + timeoutSeconds: 5 +``` +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +metadata: + name: "pod-policy.example.com" +webhooks: +- name: "pod-policy.example.com" + rules: + - apiGroups: [""] + apiVersions: ["v1"] + operations: ["CREATE"] + resources: ["pods"] + scope: "Namespaced" + clientConfig: + service: + namespace: "example-namespace" + name: "example-service" + caBundle: "Ci0tLS0tQk......tLS0K" + admissionReviewVersions: ["v1beta1"] + timeoutSeconds: 5 +``` +{{% /tab %}} +{{< /tabs >}} + + +范围字段指定是仅集群范围的资源(Cluster)还是命名空间范围的资源资源(Namespaced)将与此规则匹配。`*`表示没有范围限制。 + +{{< note >}} + +当使用`clientConfig.service`时,服务器证书必须对`. .svc`有效。 + +{{< /note >}} + +{{< note >}} + +Webhook 呼叫的默认超时为 30 秒,但从 kubernetes 1.14 开始,可以设置超时,因此建议对 Webhooks 使用非常小的超时。 +如果 webhook 呼叫超时,则根据 webhook 的请求处理请求失败政策。 +{{< /note >}} + + + +当 apiserver 收到与`rules`匹配的请求时,apiserver 根据`clientConfig`配置定向给 webhook 发送`admissionReview`请求。 + +创建 webhook 配置后,系统将花费几秒钟来完成新配置的生效。 + + + +### 验证-apiservers + +如果您的 webhooks 需要身份验证,您可以将 apiservers 配置为使用基本身份验证,不记名令牌或证书来对 webhook 进行身份验证。 +完成配置有三个步骤。 + +* 启动apiserver时,通过 `--admission-control-config-file` 参数指定许可控制配置文件的位置。 + +* 在准入控制配置文件中,指定 MutatingAdmissionWebhook 控制器和 ValidatingAdmissionWebhook 控制器应该读取凭据的位置。 +凭证存储在 kubeConfig 文件中(是​​的,与 kubectl 使用的模式相同),因此字段名称为`kubeConfigFile`。 +以下是一个示例准入控制配置文件: + +```yaml +apiVersion: apiserver.k8s.io/v1alpha1 +kind: AdmissionConfiguration +plugins: +- name: ValidatingAdmissionWebhook + configuration: + apiVersion: apiserver.config.k8s.io/v1alpha1 + kind: WebhookAdmission + kubeConfigFile: "" +- name: MutatingAdmissionWebhook + configuration: + apiVersion: apiserver.config.k8s.io/v1alpha1 + kind: WebhookAdmission + kubeConfigFile: "" +``` + + +`admissionConfiguration`的 shcema 定义在 [这里](https://github.com/kubernetes/kubernetes/blob/v1.13.0/staging/src/k8s.io/apiserver/pkg/apis/apiserver/v1alpha1/types.go#L27). +有关每个配置字段的详细信息,请参见 [webhook配置](#webhook-配置)部分。 + +* 在 kubeConfig 文件中,提供证书凭据: + +```yaml +apiVersion: v1 +kind: Config +users: +# name should be set to the DNS name of the service or the host (including port) of the URL the webhook is configured to speak to. +# If a non-443 port is used for services, it must be included in the name when configuring 1.16+ API servers. +# +# For a webhook configured to speak to a service on the default port (443), specify the DNS name of the service: +# - name: webhook1.ns1.svc +# user: ... +# +# For a webhook configured to speak to a service on non-default port (e.g. 8443), specify the DNS name and port of the service in 1.16+: +# - name: webhook1.ns1.svc:8443 +# user: ... +# and optionally create a second stanza using only the DNS name of the service for compatibility with 1.15 API servers: +# - name: webhook1.ns1.svc +# user: ... +# +# For webhooks configured to speak to a URL, match the host (and port) specified in the webhook's URL. Examples: +# A webhook with `url: https://www.example.com`: +# - name: www.example.com +# user: ... +# +# A webhook with `url: https://www.example.com:443`: +# - name: www.example.com:443 +# user: ... +# +# A webhook with `url: https://www.example.com:8443`: +# - name: www.example.com:8443 +# user: ... +# +- name: 'webhook1.ns1.svc' + user: + client-certificate-data: "" + client-key-data: "" +# The `name` supports using * to wildcard-match prefixing segments. +- name: '*.webhook-company.org' + user: + password: "" + username: "" +# '*' is the default match. +- name: '*' + user: + token: "" +``` + +当然,您需要设置 webhook 服务器来处理这些身份验证。 + + + +### 请求 + +向 Webhooks 发送 POST 请求,头域带上`Content-Type:application/json`,与`admission.k8s.io` API groups 中的`AdmissionReview` API 对象一起使用 +序列化为 JSON 作为主体。 + +Webhooks 可以指定他们接受的`AdmissionReview`对象的版本在配置中使用`admissionReviewVersions`字段: + +{{< tabs name="ValidatingWebhookConfiguration_admissionReviewVersions" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + admissionReviewVersions: ["v1", "v1beta1"] + ... +``` + +创建时,`admissionReviewVersions`是必填字段`admissionregistration.k8s.io/v1` Webhook配置。 +需要 Webhooks 支持至少一项`AdmissionReview`当前和以前的 apiserver 可以解释的版本。 + +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + admissionReviewVersions: ["v1beta1"] + ... +``` + + +如果未指定`admissionReviewVersions`,则创建时的默认值`admissionregistration.k8s.io/v1beta1` Webhook 配置为`v1beta1`。 +{{% /tab %}} +{{< /tabs >}} + + +apiserver 在其支持的`admissionReviewVersions`列表中发送第一个`AdmissionReview`版本。如果 apiserver 不支持列表中的任何版本,则不允许创建配置。 +如果 apiserver 遇到先前创建的 Webhook 配置,并且不支持任何`AdmissionReview` +apiserver 知道如何发送的版本,调用 Webhook 的尝试将失败,并受 [失败策略](#失败策略) 的约束。 + +此示例显示了`AdmissionReview`对象中包含的数据请求更新apps/v1 Deployment 的 scale 子资源: + +{{< tabs name="AdmissionReview_request" >}} +{{% tab name="admission.k8s.io/v1" %}} +```yaml +{ + "apiVersion": "admission.k8s.io/v1", + "kind": "AdmissionReview", + "request": { + # Random uid uniquely identifying this admission call + "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", + + # Fully-qualified group/version/kind of the incoming object + "kind": {"group":"autoscaling","version":"v1","kind":"Scale"}, + # Fully-qualified group/version/kind of the resource being modified + "resource": {"group":"apps","version":"v1","resource":"deployments"}, + # subresource, if the request is to a subresource + "subResource": "scale", + + # Fully-qualified group/version/kind of the incoming object in the original request to the API server. + # This only differs from `kind` if the webhook specified `matchPolicy: Equivalent` and the + # original request to the API server was converted to a version the webhook registered for. + "requestKind": {"group":"autoscaling","version":"v1","kind":"Scale"}, + # Fully-qualified group/version/kind of the resource being modified in the original request to the API server. + # This only differs from `resource` if the webhook specified `matchPolicy: Equivalent` and the + # original request to the API server was converted to a version the webhook registered for. + "requestResource": {"group":"apps","version":"v1","resource":"deployments"}, + # subresource, if the request is to a subresource + # This only differs from `subResource` if the webhook specified `matchPolicy: Equivalent` and the + # original request to the API server was converted to a version the webhook registered for. + "requestSubResource": "scale", + + # Name of the resource being modified + "name": "my-deployment", + # Namespace of the resource being modified, if the resource is namespaced (or is a Namespace object) + "namespace": "my-namespace", + + # operation can be CREATE, UPDATE, DELETE, or CONNECT + "operation": "UPDATE", + + "userInfo": { + # Username of the authenticated user making the request to the API server + "username": "admin", + # UID of the authenticated user making the request to the API server + "uid": "014fbff9a07c", + # Group memberships of the authenticated user making the request to the API server + "groups": ["system:authenticated","my-admin-group"], + # Arbitrary extra info associated with the user making the request to the API server. + # This is populated by the API server authentication layer and should be included + # if any SubjectAccessReview checks are performed by the webhook. + "extra": { + "some-key":["some-value1", "some-value2"] + } + }, + + # object is the new object being admitted. + # It is null for DELETE operations. + "object": {"apiVersion":"autoscaling/v1","kind":"Scale",...}, + # oldObject is the existing object. + # It is null for CREATE and CONNECT operations. + "oldObject": {"apiVersion":"autoscaling/v1","kind":"Scale",...}, + # options contains the options for the operation being admitted, like meta.k8s.io/v1 CreateOptions, UpdateOptions, or DeleteOptions. + # It is null for CONNECT operations. + "options": {"apiVersion":"meta.k8s.io/v1","kind":"UpdateOptions",...}, + + # dryRun indicates the API request is running in dry run mode and will not be persisted. + # Webhooks with side effects should avoid actuating those side effects when dryRun is true. + # See http://k8s.io/docs/reference/using-api/api-concepts/#make-a-dry-run-request for more details. + "dryRun": false + } +} +``` +{{% /tab %}} +{{% tab name="admission.k8s.io/v1beta1" %}} +```yaml +{ + # Deprecated in v1.16 in favor of admission.k8s.io/v1 + "apiVersion": "admission.k8s.io/v1beta1", + "kind": "AdmissionReview", + "request": { + # Random uid uniquely identifying this admission call + "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", + + # Fully-qualified group/version/kind of the incoming object + "kind": {"group":"autoscaling","version":"v1","kind":"Scale"}, + # Fully-qualified group/version/kind of the resource being modified + "resource": {"group":"apps","version":"v1","resource":"deployments"}, + # subresource, if the request is to a subresource + "subResource": "scale", + + # Fully-qualified group/version/kind of the incoming object in the original request to the API server. + # This only differs from `kind` if the webhook specified `matchPolicy: Equivalent` and the + # original request to the API server was converted to a version the webhook registered for. + # Only sent by v1.15+ API servers. + "requestKind": {"group":"autoscaling","version":"v1","kind":"Scale"}, + # Fully-qualified group/version/kind of the resource being modified in the original request to the API server. + # This only differs from `resource` if the webhook specified `matchPolicy: Equivalent` and the + # original request to the API server was converted to a version the webhook registered for. + # Only sent by v1.15+ API servers. + "requestResource": {"group":"apps","version":"v1","resource":"deployments"}, + # subresource, if the request is to a subresource + # This only differs from `subResource` if the webhook specified `matchPolicy: Equivalent` and the + # original request to the API server was converted to a version the webhook registered for. + # Only sent by v1.15+ API servers. + "requestSubResource": "scale", + + # Name of the resource being modified + "name": "my-deployment", + # Namespace of the resource being modified, if the resource is namespaced (or is a Namespace object) + "namespace": "my-namespace", + + # operation can be CREATE, UPDATE, DELETE, or CONNECT + "operation": "UPDATE", + + "userInfo": { + # Username of the authenticated user making the request to the API server + "username": "admin", + # UID of the authenticated user making the request to the API server + "uid": "014fbff9a07c", + # Group memberships of the authenticated user making the request to the API server + "groups": ["system:authenticated","my-admin-group"], + # Arbitrary extra info associated with the user making the request to the API server. + # This is populated by the API server authentication layer and should be included + # if any SubjectAccessReview checks are performed by the webhook. + "extra": { + "some-key":["some-value1", "some-value2"] + } + }, + + # object is the new object being admitted. + # It is null for DELETE operations. + "object": {"apiVersion":"autoscaling/v1","kind":"Scale",...}, + # oldObject is the existing object. + # It is null for CREATE and CONNECT operations (and for DELETE operations in API servers prior to v1.15.0) + "oldObject": {"apiVersion":"autoscaling/v1","kind":"Scale",...}, + # options contains the options for the operation being admitted, like meta.k8s.io/v1 CreateOptions, UpdateOptions, or DeleteOptions. + # It is null for CONNECT operations. + # Only sent by v1.15+ API servers. + "options": {"apiVersion":"meta.k8s.io/v1","kind":"UpdateOptions",...}, + + # dryRun indicates the API request is running in dry run mode and will not be persisted. + # Webhooks with side effects should avoid actuating those side effects when dryRun is true. + # See http://k8s.io/docs/reference/using-api/api-concepts/#make-a-dry-run-request for more details. + "dryRun": false + } +} +``` +{{% /tab %}} +{{< /tabs >}} + +### 响应 + +Webhooks 会以 200 HTTP 状态代码`Content-Type:application/json`响应,以及包含`AdmissionReview`对象的xaingy(与发送的版本相同), +带有`response`节的序列,并序列化为 JSON。 + +`response`节至少必须包含以下字段: +*`uid`,从发送到 webhook 的`request.uid`复制而来 +*`allowed`,设置为`true`或`false` + +Webhook 允许请求的最简单响应示例: + +{{< tabs name="AdmissionReview_response_allow" >}} +{{% tab name="admission.k8s.io/v1" %}} +```json +{ + "apiVersion": "admission.k8s.io/v1", + "kind": "AdmissionReview", + "response": { + "uid": "", + "allowed": true + } +} +``` +{{% /tab %}} +{{% tab name="admission.k8s.io/v1beta1" %}} +```json +{ + "apiVersion": "admission.k8s.io/v1beta1", + "kind": "AdmissionReview", + "response": { + "uid": "", + "allowed": true + } +} +``` +{{% /tab %}} +{{< /tabs >}} + +Webhook 禁止请求的最简单响应示例: + +{{< tabs name="AdmissionReview_response_forbid_minimal" >}} +{{% tab name="admission.k8s.io/v1" %}} +```json +{ + "apiVersion": "admission.k8s.io/v1", + "kind": "AdmissionReview", + "response": { + "uid": "", + "allowed": false + } +} +``` +{{% /tab %}} +{{% tab name="admission.k8s.io/v1beta1" %}} +```json +{ + "apiVersion": "admission.k8s.io/v1beta1", + "kind": "AdmissionReview", + "response": { + "uid": "", + "allowed": false + } +} +``` +{{% /tab %}} +{{< /tabs >}} + +当拒绝请求时,webhook 可以使用`status`字段自定义http代码和消息体返回给用户。 +指定的状态对象返回给用户。有关状态类型的详细信息,请参见 [API 文档](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.14/#status-v1-meta)。 +禁止请求,定制 HTTP 状态代码和显示给用户的消息的响应示例: + +{{< tabs name="AdmissionReview_response_forbid_details" >}} +{{% tab name="admission.k8s.io/v1" %}} +```json +{ + "apiVersion": "admission.k8s.io/v1", + "kind": "AdmissionReview", + "response": { + "uid": "", + "allowed": false, + "status": { + "code": 403, + "message": "You cannot do this because it is Tuesday and your name starts with A" + } + } +} +``` +{{% /tab %}} +{{% tab name="admission.k8s.io/v1beta1" %}} +```json +{ + "apiVersion": "admission.k8s.io/v1beta1", + "kind": "AdmissionReview", + "response": { + "uid": "", + "allowed": false, + "status": { + "code": 403, + "message": "You cannot do this because it is Tuesday and your name starts with A" + } + } +} +``` +{{% /tab %}} +{{< /tabs >}} + +当允许请求时,变异接纳 Webhook 也可以选择修改传入对象。这是通过在响应中使用`patch`和`patchType`字段来完成的。 +当前唯一支持的`patchType`是`JSONPatch`。有关更多详细信息,请参见 [JSON 补丁](http://jsonpatch.com/) 文档。 +对于`patchType:JSONPatch`,`patch`字段包含一个以 base64 编码的 JSON 补丁操作数组。 + +例如,设置`spec.replicas`的单个补丁操作将是`[{"op":"add","path":"/spec/replicas","value":3}]]`。 + +以 Base64 编码,这将是`W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0=` + +因此,添加该标签的 webhook 响应为: + +{{< tabs name="AdmissionReview_response_modify" >}} +{{% tab name="admission.k8s.io/v1" %}} +```json +{ + "apiVersion": "admission.k8s.io/v1", + "kind": "AdmissionReview", + "response": { + "uid": "", + "allowed": true, + "patchType": "JSONPatch", + "patch": "W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0=" + } +} +``` +{{% /tab %}} +{{% tab name="admission.k8s.io/v1beta1" %}} +```json +{ + "apiVersion": "admission.k8s.io/v1beta1", + "kind": "AdmissionReview", + "response": { + "uid": "", + "allowed": true, + "patchType": "JSONPatch", + "patch": "W3sib3AiOiAiYWRkIiwgInBhdGgiOiAiL3NwZWMvcmVwbGljYXMiLCAidmFsdWUiOiAzfV0=" + } +} +``` +{{% /tab %}} +{{< /tabs >}} + +## Webhook-配置 + +要注册 admssion webhook,请创建`MutatingWebhookConfiguration`或`ValidatingWebhookConfiguration` API 对象。 + +每种配置可以包含一个或多个 Web 钩子。如果在单个配置中指定了多个 webhook,则应为每个 webhook 赋予一个唯一的名称。 +这在`admissionregistration.k8s.io/v1`中是必需的,但在使用`admissionregistration.k8s.io/v1beta1`时强烈建议, +为了使生成的审核日志和指标更易于与活动配置匹配。 + +每个 Webhook 定义以下内容。 + + + +### 匹配请求-规则 + +每个 Webhook 必须指定用于确定是否应将对 apiserver 的请求发送到 Webhook 的规则列表。 +每个规则都指定一个或多个操作,apiGroups,apiVersions 和资源以及资源范围: + +*`operations`列出一个或多个要匹配的操作。可以是`CREATE`,`UPDATE`,`DELETE`,`CONNECT`或 `*` 以匹配所有内容。 + +*`apiGroups`列出了一个或多个要匹配的 API 组。``是核心 API 组。`*` 匹配所有 API 组。 + +*`apiVersions`列出了一个或多个要匹配的 API 版本。`*` 匹配所有 API 版本。 + +*`resources`列出了一个或多个要匹配的资源。 + *`*`匹配所有资源,但不匹配子资源。 + *`*/*` 匹配所有资源和子资源。 + *`pod/*` 匹配 pod 的所有子资源。 + *`*/status` 匹配所有状态子资源。 + +*`scope`指定要匹配的范围。有效值为`Cluster`,`Namespaced`和 `*`。子资源匹配其父资源的范围。在 v1.14+ 中受支持。默认值为`*`,匹配 1.14 之前的行为。 + *`Cluster`表示只有群集作用域的资源才能匹配此规则(名称空间 API 对象是群集作用域的)。 + *`Namespaced`意味着只有命名空间资源才符合此规则。 + *`*` 表示没有范围限制。 + +如果传入请求与任何 Webhook 规则的指定操作,组,版本,资源和范围匹配,则该请求将发送到 Webhook。 + +以下是可用于指定应拦截哪些资源的规则的其他示例。 + +将`CREATE`或`UPDATE`请求匹配到`apps/v1`和`apps/v1beta1`,`deployments`和`replicasets`: + +{{< tabs name="ValidatingWebhookConfiguration_rules_1" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["apps"] + apiVersions: ["v1", "v1beta1"] + resources: ["deployments", "replicasets"] + scope: "Namespaced" + ... +``` +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + rules: + - operations: ["CREATE", "UPDATE"] + apiGroups: ["apps"] + apiVersions: ["v1", "v1beta1"] + resources: ["deployments", "replicasets"] + scope: "Namespaced" + ... +``` +{{% /tab %}} +{{< /tabs >}} + + +匹配所有 API 组和版本中的所有资源(但不包括子资源)的创建请求: + +{{< tabs name="ValidatingWebhookConfiguration_rules_2" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + rules: + - operations: ["CREATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + scope: "*" + ... +``` +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + rules: + - operations: ["CREATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + scope: "*" + ... +``` +{{% /tab %}} +{{< /tabs >}} + +Match update requests for all `status` subresources in all API groups and versions: + +{{< tabs name="ValidatingWebhookConfiguration_rules_3" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + rules: + - operations: ["UPDATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*/status"] + scope: "*" + ... +``` +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + rules: + - operations: ["UPDATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*/status"] + scope: "*" + ... +``` +{{% /tab %}} +{{< /tabs >}} + +### Matching requests: objectSelector + +### 匹配请求-对象选择器 + +在v1.15 +中,基于Web服务的标签,webhook 可以选择限制拦截哪些请求 +通过指定一个 objectSelector 来发送它们的对象。如果指定,则为 objectSelector同时针对将要发送到Webhook的对象和oldObject进行评估, +并且如果两个对象中的任何一个与选择器都匹配,则视为匹配。 + +空对象(对于 create 而言为 oldObject,对于 delete 而言为 newObject), +或没有标签的对象(例如 DeploymentDeployRollback 或 PodProxyOptions 对象) +被认为不匹配。 + +仅在选择加入 Webhook 时才使用对象选择器,因为最终用户可以通过设置标签来跳过 admission Webhook。 + +这个例子展示了一个可变的 webhook,它将匹配带有标签`foo:bar`的任何资源的`CREATE`: + +{{< tabs name="ValidatingWebhookConfiguration_example_1" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + objectSelector: + matchLabels: + foo: bar + rules: + - operations: ["CREATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + scope: "*" + ... +``` +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + objectSelector: + matchLabels: + foo: bar + rules: + - operations: ["CREATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + scope: "*" + ... +``` +{{% /tab %}} +{{< /tabs >}} + +有关标签选择器的更多示例,请参见 [更多](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels)。 + +### 匹配请求-命名空间选择器 + +Webhooks 可以选择限制拦截对命名空间资源的请求, +通过指定`namespaceSelector`,基于包含名称空间的标签。 + +namespaceSelector 命名空间选择器决定是否在对命名空间资源的请求上运行 webhook(或命名空间对象),取决于命名空间的标签是否与选择器匹配。 +如果对象本身是名称空间,则对`object.metadata.labels`执行匹配。 +如果对象是除命名空间以外的群集范围内的资源,则`namespaceSelector`无效。 + +这个例子展示了一个可变的webhook,它匹配命名空间内任何命名空间资源的`CREATE` +没有`0`或`1`的`runlevel`标签: +{{< tabs name="MutatingWebhookConfiguration_namespaceSelector_1" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + namespaceSelector: + matchExpressions: + - key: runlevel + operator: NotIn + values: ["0","1"] + rules: + - operations: ["CREATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + scope: "Namespaced" + ... +``` +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + namespaceSelector: + matchExpressions: + - key: runlevel + operator: NotIn + values: ["0","1"] + rules: + - operations: ["CREATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + scope: "Namespaced" + ... +``` +{{% /tab %}} +{{< /tabs >}} + + +此示例显示了一个验证 Webhook,该 Webhook 与名称空间内任何名称空间资源的`CREATE`匹配 +与`产品`或`阶段`的`环境`相关联: + +{{< tabs name="ValidatingWebhookConfiguration_namespaceSelector_2" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + namespaceSelector: + matchExpressions: + - key: environment + operator: In + values: ["prod","staging"] + rules: + - operations: ["CREATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + scope: "Namespaced" + ... +``` +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + namespaceSelector: + matchExpressions: + - key: environment + operator: In + values: ["prod","staging"] + rules: + - operations: ["CREATE"] + apiGroups: ["*"] + apiVersions: ["*"] + resources: ["*"] + scope: "Namespaced" + ... +``` +{{% /tab %}} +{{< /tabs >}} + + +有关标签选择器的更多示例,请参见 [更多](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels)。 + +### 匹配请求-策略匹配 + +apiserver 可以通过多个 API 组或版本使对象可用。 +例如,Kubernetes apiserver 允许创建和修改`Deployment`对象 +通过 `extensions/v1beta1`,`apps/v1beta1`,`apps/v1beta2`和`apps/v1` APIs 进行。 + +例如,如果一个 Webhook 仅为某些`Api groups/version`指定了规则(例如`apiGroups:["apps"]`,`apiVersions:[`v1`,`v1beta1`]`), +并提出了通过另一个`Api groups/version`(例如`extensions/v1beta1`)修改资源的请求, +该请求将不会发送到 Webhook。 + +在 v1.15+ 中,`matchPolicy`允许 webhook 定义如何使用其`rules`匹配传入的请求。 +允许的值为`Exact`或`Equivalent`。 + +*`Exact`表示仅当请求与指定规则完全匹配时才应拦截该请求。 +*`Equivalent`表示如果修改了`rules`中列出的资源,即使通过另一个`Api groups/version`,也应拦截请求。 + +在上面给出的示例中,仅为`apps/v1`注册的 webhook 可以使用`matchPolicy`,`matchPolicy:Exact`表示将不会将`extensions/v1beta1`请求发送到 Webhook +*`matchPolicy:Equivalent`意味着将`extensions/v1beta1`请求发送到 webhook(将对象转换为 webhook 指定的版本:`apps/v1`) + +建议指定`Equivalent`,并确保 Webhook 继续拦截他们期望在升级时启用 apiserver 中资源的新版本的资源。 + +当资源停止由 apiserver 提供服务时,它不再被视为等同于仍在提供服务的该资源的其他版本。 +例如,计划在 v1.16 中默认停止使用已弃用的`extensions/v1beta1`部署。 +一旦发生,带有`apiGroups:["extensions"]`,`apiVersions:["v1beta1"]`,`resources:["deployments"]`规则的 webhook +将不再拦截通过`apps/v1` API 创建的部署。因此,webhooks 应该更优先注册用于稳定版本的资源。 + +此示例显示了一个验证 Webhook,该 Webhook 拦截对部署的修改(无论 API 组或版本), +并始终会发送一个`apps/v1`部署对象: + +{{< tabs name="ValidatingWebhookConfiguration_matchPolicy" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + matchPolicy: Equivalent + rules: + - operations: ["CREATE","UPDATE","DELETE"] + apiGroups: ["apps"] + apiVersions: ["v1"] + resources: ["deployments"] + scope: "Namespaced" + ... +``` + +使用`admissionregistration.k8s.io/v1`创建的 admission webhhok 默认为`Equivalent`。 + +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + matchPolicy: Equivalent + rules: + - operations: ["CREATE","UPDATE","DELETE"] + apiGroups: ["apps"] + apiVersions: ["v1"] + resources: ["deployments"] + scope: "Namespaced" + ... +``` + +使用`admissionregistration.k8s.io/v1beta1`创建的 admission webhhok 默认为`Exact`。 +{{% /tab %}} +{{< /tabs >}} + +### 调用 Webhook + +apiserver 确定请求应发送到 Webhook 后, +它需要知道如何调用 Webhook。这在`clientConfig`中指定 webhook 配置的节。 + +可以通过 URL 或服务引用来调用 Webhooks,并且可以选择包含自定义 CA 包,以用于验证 TLS 连接。 + + +#### URL + +url以标准URL形式给出webhook的位置(`scheme://host:port/path`)。 + +`host`不应引用集群中运行的服务;采用通过指定`service`字段来提供服务引用。主机可以通过某些 apiserver 中的外部 DNS 进行解析 +(例如,`kube-apiserver`无法解析集群内 DNS 违反分层规则)。主机也可以是IP地址。 + +请注意,将 localhost 或 127.0.0.1 用作主机是除非您非常小心在所有主机上运行此 Webhook,否则风险很大 +运行一个 apiserver 可能需要对此进行调用 webhook。这样的安装很可能是不可移植的,即不容易出现在新集群中。 + +方案必须为`https`; URL 必须以`https://`开头。 + +尝试使用用户或基本身份验证,例如不允许使用`user:password@`。片段(`#...`)和查询参数(`?...`)也不允许。 + +这是配置为调用 URL 的可变 Webhook 的示例(并且期望使用系统信任根来验证 TLS 证书,因此不指定 caBundle): +{{< tabs name="MutatingWebhookConfiguration_url" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + clientConfig: + url: "https://my-webhook.example.com:9443/my-webhook-path" + ... +``` +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + clientConfig: + url: "https://my-webhook.example.com:9443/my-webhook-path" + ... +``` +{{% /tab %}} +{{< /tabs >}} + +#### 服务参考 + +clientConfig 内部的 service 节是对该 Webhook 服务的引用。如果 Webhook 在集群中运行,则应使用`service`而不是`url`。 +服务名称空间和名称是必需的。端口是可选的,默认为 443。该路径是可选的,默认为`/`。 + +这是配置为在端口`1234`上调用服务的可变 Webhook 的示例在子路径`/my-path`下,并针对 ServerName 验证 TLS 连接 +使用自定义 CA 包的`my-service-name.my-service-namespace.svc`: + +{{< tabs name="MutatingWebhookConfiguration_service" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + clientConfig: + caBundle: "Ci0tLS0tQk......tLS0K" + service: + namespace: my-service-namespace + name: my-service-name + path: /my-path + port: 1234 + ... +``` +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + clientConfig: + caBundle: "Ci0tLS0tQk......tLS0K" + service: + namespace: my-service-namespace + name: my-service-name + path: /my-path + port: 1234 + ... +``` +{{% /tab %}} +{{< /tabs >}} + +### 副作用 + +Webhook 通常只对发送给他们的`AdmissionReview`的内容起作用。 +但是,某些 Webhook 在处理接纳请求时会进行带外更改。 + +进行带外更改(`副作用`)的 Webhooks 也必须具有协调机制(如控制器)定期确定世界的实际状态并进行调整录入 Webhook 修改的带外数据以反映现实情况。 +这是因为对 admission Webhook 的调用不能保证所准入的对象将原样保留或完全保留。后来的 webhook 可以修改对象的内容,在写入存储设备时可能会发生冲突, +否则服务器可以在持久保存对象之前关闭电源。 + +另外,当处理`dryRun:true`接纳请求时,具有副作用的 webhooks 必须跳过那些副作用。 +一个webhook必须明确指出在使用`dryRun`运行时不会产生副作用, +否则试运行请求将不会发送到 Webhook,而 API 请求将失败。 + +Webhooks 使用 webhook 配置中的`sideEffects`字段指示它们是否有副作用: +*`Unknown`:未知有关调用 Webhook 的副作用的信息。 +如果带有`dryRun:true`的请求将触发对该 Webhook 的调用,则该请求将失败,并且不会调用该 Webhook。 +*`None`:调用 webhook 不会有副作用。 +*`Some`:调用 webhook 可能会有副作用。 +如果具有 dry-run 属性的请求将触发对此 Webhook 的调用,则该请求将失败,并且不会调用该 Webhook。 +*`NoneOnDryRun`:调用 webhook 可能会有副作用, +但是如果将带有`dryRun:true`的请求发送到 Webhook,则该 Webhook 将抑制副作用(该 Webhook 可识别`dryRun`)。 + +允许值: +*在`admissionregistration.k8s.io/v1beta1`中,`sideEffects`可以设置为`Unknown`,`None`,`Some`,或者`NoneOnDryRun`,并且默认为`Unknown`。 +*在`admissionregistration.k8s.io/v1`中,`sideEffects`必须设置为`None`或`NoneOnDryRun`。 + +这是一个验证 webhook 的示例,表明它对`dryRun:true`请求没有副作用: +{{< tabs name="ValidatingWebhookConfiguration_sideEffects" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + sideEffects: NoneOnDryRun + ... +``` +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + sideEffects: NoneOnDryRun + ... +``` +{{% /tab %}} +{{< /tabs >}} + + +### 超时 + +由于 Webhooks 会增加 API 请求的延迟,因此应尽快评估。timeoutSeconds 允许配置 apiserver 等待 Webhook 响应的时间在将通话视为失败之前。 + +如果超时在 Webhook 响应之前到期,则 Webhook 调用将被忽略或 API 调用将基于 [失败策略](#失败策略) 被拒绝。 + +超时值必须在 1 到 30 秒之间。 + +这是一个自定义超时为 2 秒的验证 Webhook 的示例: + +{{< tabs name="ValidatingWebhookConfiguration_timeoutSeconds" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + timeoutSeconds: 2 + ... +``` + +使用`admissionregistration.k8s.io/v1`创建的 admission Webhook 默认超时为 10 秒。 +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: ValidatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + timeoutSeconds: 2 + ... +``` + +使用`admissionregistration.k8s.io/v1`创建的 admission Webhook 默认超时为 30 秒。 +{{% /tab %}} +{{< /tabs >}} + +### 撤销策略 + +可变准入插件(包括 Webhooks)的单次订购不适用于所有情况(例如,请参见 [更多](#https://issue.k8s.io/64333)。可变的 Webhook 可以添加新的子结构 +到对象(例如向`pod`中添加`container`),以及其他已经运行可能会对这些新结构有影响(例如在所有容器上设置`imagePullPolicy`)。 + +在 v1.15+ 中,允许准入插件观察到其他插件所做的更改,如果可变的 Webhook 修改了一个对象,则会重新运行内置的可变准入插件, +并且可变的 Webhook 可以指定`reinvocationPolicy`来控制是否也重新调用它们。 + +可以将`reinvocationPolicy`设置为`Never`或者`IfNeeded`. 默认为`Never`.。 + +*`Never`:Webhook 在一次接纳评估中不得被多次调用 +*`IfNeeded`:如果对象被接纳,则可以再次调用 Webhook 作为准入评估的一部分 +最初的 webhook 调用之后,其他准入插件会被修改。 + +要注意的重要元素是: + +*附加调用的数量不能保证完全是一个。 +*如果其他调用导致对该对象的进一步修改,则不能保证再次调用 webhooks。 +*使用此选项的 Webhook 可能会重新排序,以最大程度地减少其他调用。 +*要在所有可变都保证完成后验证对象,请改用 验证 admission Webhook(建议对有副作用的 Webhook 使用)。 + +这是一个可变的 webhook 选择在以后的准入插件修改对象时重新调用的示例: + +{{< tabs name="MutatingWebhookConfiguration_reinvocationPolicy" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + reinvocationPolicy: IfNeeded + ... +``` +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + reinvocationPolicy: IfNeeded + ... +``` +{{% /tab %}} +{{< /tabs >}} + + +可变的 Webhook 必须是 [幂等](#幂等),能够成功处理他们已经允许的对象并可能进行修改。可变的 Webhook 都是如此,因为它们可以 +进行任何更改用户提供的对象中可能已经存在一个对象,但是对于选择重新调用的 Webhook 来说这是必不可少的。 + +### 失败策略 + +`failurePolicy`定义了来自 admission webhook 的无法识别的错误和超时错误被处理。允许的值为`Ignore`或者`Fail`。 + +*`Ignore`意味着调用 webhook 的错误将被忽略并且允许 API 请求继续。 +*`Fail`表示调用 webhook 的错误导致准入失败并且 API 请求被拒绝。 + +这是一个变异的 Webhook,配置为在调用接纳 Webhook 遇到错误时拒绝 API 请求: + +{{< tabs name="MutatingWebhookConfiguration_failurePolicy" >}} +{{% tab name="admissionregistration.k8s.io/v1" %}} +```yaml +apiVersion: admissionregistration.k8s.io/v1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + failurePolicy: Fail + ... +``` + +使用`admissionregistration.k8s.io/v1`创建的 admission Webhook 将默认`failurePolicy`设置为`Fail`。 +{{% /tab %}} +{{% tab name="admissionregistration.k8s.io/v1beta1" %}} +```yaml +# Deprecated in v1.16 in favor of admissionregistration.k8s.io/v1 +apiVersion: admissionregistration.k8s.io/v1beta1 +kind: MutatingWebhookConfiguration +... +webhooks: +- name: my-webhook.example.com + failurePolicy: Fail + ... +``` + +使用`admissionregistration.k8s.io/v1`创建的 admission Webhook 将默认`failurePolicy`设置为`Ignore`。 +{{% /tab %}} +{{< /tabs >}} + +## 监控 Admission Webhook + +apiserver 提供了监控 admission Webhook 行为的方法。这些监控机制可帮助集群管理员回答以下问题: + +1. 哪个可变 webhook 使 API 请求中的对象变化? + +2. 可变 webhook 应用于对象有什么变化? + +3. 哪些 webhook 经常拒绝 API 请求?是什么原因拒绝? + + +### 更改 Webhook 审核注释 + +有时候了解API要求中的哪个可变 webhook 修改了对象,以及 webhook 适用。 + +在 v1.16+ 中,kube-apiserver 在每个可变的 Webhook 上执行 [auditing](/docs/tasks/debug-application-cluster/audit/)调用。每次调用都会生成审核注释 +捕获请求对象是否因调用而发生了变化,并可选地生成注释来捕获应用的对象来自 Webhook 接纳响应的补丁。在审核事件中为注释的给定阶段的给定请求设置注释。 +它的执行,然后根据某种策略进行预处理,并写入后端。 + +事件的审核级别确定要记录哪些注释: + +- 在`Metadata`审核级别或更高级别,带有键的注释`mutation.webhook.admission.k8s.io/round_{round idx} _index_ {order idx}`记录了 JSON 有效负载,表明 +Webhook 会针对给定的请求以及是否更改了对象而被调用。 + +例如,对于正在被重新调用的 Webhook,记录了以下注释。Webhook 在更改 webhook 链,并且在调用期间未更改请求对象。 +```yaml +# the audit event recorded +{ + "kind": "Event", + "apiVersion": "audit.k8s.io/v1", + "annotations": { + "mutation.webhook.admission.k8s.io/round_1_index_2": "{\"configuration\":\"my-mutating-webhook-configuration.example.com\",\"webhook\":\"my-webhook.example.com\",\"mutated\": false}" + # other annotations + ... + } + # other fields + ... +} +``` + +```yaml +# the annotation value deserialized +{ + "configuration": "my-mutating-webhook-configuration.example.com", + "webhook": "my-webhook.example.com", + "mutated": false +} +``` + +The following annotatino gets recorded for a webhook being invoked in the first round. The webhook is ordered the first in\ +the mutating webhook chain, and mutated the request object during the invocation. + +```yaml +# the audit event recorded +{ + "kind": "Event", + "apiVersion": "audit.k8s.io/v1", + "annotations": { + "mutation.webhook.admission.k8s.io/round_0_index_0": "{\"configuration\":\"my-mutating-webhook-configuration.example.com\",\"webhook\":\"my-webhook-always-mutate.example.com\",\"mutated\": true}" + # other annotations + ... + } + # other fields + ... +} +``` + +```yaml +# the annotation value deserialized +{ + "configuration": "my-mutating-webhook-configuration.example.com", + "webhook": "my-webhook-always-mutate.example.com", + "mutated": true +} +``` + +- At `Request` audit level or higher, an annotation with key +`patch.webhook.admission.k8s.io/round_{round idx}_index_{order idx}` gets logged with JSON payload indicating +a webhook gets invoked for given request and what patch gets applied to the request object. + +For example, the following annotation gets recorded for a webhook being reinvoked. The webhook is ordered the fourth in the +mutating webhook chain, and responded with a JSON patch which got applied to the request object. + +```yaml +# the audit event recorded +{ + "kind": "Event", + "apiVersion": "audit.k8s.io/v1", + "annotations": { + "patch.webhook.admission.k8s.io/round_1_index_3": "{\"configuration\":\"my-other-mutating-webhook-configuration.example.com\",\"webhook\":\"my-webhook-always-mutate.example.com\",\"patch\":[{\"op\":\"add\",\"path\":\"/data/mutation-stage\",\"value\":\"yes\"}],\"patchType\":\"JSONPatch\"}" + # other annotations + ... + } + # other fields + ... +} +``` + +```yaml +# the annotation value deserialized +{ + "configuration": "my-other-mutating-webhook-configuration.example.com", + "webhook": "my-webhook-always-mutate.example.com", + "patchType": "JSONPatch", + "patch": [ + { + "op": "add", + "path": "/data/mutation-stage", + "value": "yes" + } + ] +} +``` + + +### Amission webhook 监控指标 + +Kube-apiserver 从`/metrics`端点公开 Prometheus 指标,可用于监控和诊断 apiserver 状态。以下指标记录与准入网络挂钩相关的状态。 + +#### Apiserver Admission Webhook 拒绝次数 + +有时,了解哪些 Admission Webhook 经常拒绝 API 请求非常有用,并且拒绝的原因。 + +在 v1.16+ 中,kube-apiserver 公开了 Prometheus 计数器度量记录 Admission Webhook 拒绝。度量标准被标记为识别 Webhook 拒绝的原因: + +-`name`:拒绝请求 Webhook 的名称。 +-`operation`:请求的操作类型,可以是`CREATE`之一,更新,删除和连接。 +-`type`:Admission webhook 类型,可以是`admit`和`validating`中的一种。 +-`error_type`:标识在 webhook 调用期间是否发生了错误导致了拒绝。其值可以是以下之一: + -`calling_webhook_error`:发生了来自Admission Webhook 的无法识别的错误或超时错误,并且 + webhook 的 [失败策略](#失败策略) 设置为`Fail`。 + -`no_error`:未发生错误。Webhook 在准入中以`allowed:false`拒绝了请求响应。 + 度量标签`rejection_code`记录了在准入响应中设置的`.status.code`。 + -`apiserver_internal_error`:发生 apiserver 内部错误。 +-`rejection_code`:在以下情况下在准入响应中设置的 HTTP 状态代码 webhook 拒绝了请求。 + +<-- +Example of the rejection count metrics: +--> + +拒绝计数指标示例: + +``` +# HELP apiserver_admission_webhook_rejection_count [ALPHA] Admission webhook rejection count, identified by name and broken out for each admission type (validating or admit) and operation. Additional labels specify an error type (calling_webhook_error or apiserver_internal_error if an error occurred; no_error otherwise) and optionally a non-zero rejection code if the webhook rejects the request with an HTTP status code (honored by the apiserver when the code is greater or equal to 400). Codes greater than 600 are truncated to 600, to keep the metrics cardinality bounded. +# TYPE apiserver_admission_webhook_rejection_count counter +apiserver_admission_webhook_rejection_count{error_type="calling_webhook_error",name="always-timeout-webhook.example.com",operation="CREATE",rejection_code="0",type="validating"} 1 +apiserver_admission_webhook_rejection_count{error_type="calling_webhook_error",name="invalid-admission-response-webhook.example.com",operation="CREATE",rejection_code="0",type="validating"} 1 +apiserver_admission_webhook_rejection_count{error_type="no_error",name="deny-unwanted-configmap-data.example.com",operation="CREATE",rejection_code="400",type="validating"} 13 +``` + + + +## 最佳实践和警告 + +### 幂等 + +一个幂等的可变 Admission Webhook 能够成功处理它已经被接纳的对象并可能进行修改。可以多次应用准入,而不会改变结果初始应用程序。 + +#### 幂等可变 Webhook 的示例: + +1. 对于`CREATE` Pod 请求,请设置以下字段的`.spec.securityContext.runAsNonRoot`字段:转换为`true`,以实施安全性最佳做法。 + +2. 对于`CREATE` Pod 请求,如果字段`.spec.containers[].resources.limits`未设置容器的容器,请设置默认资源限制。 + +3. 对于`CREATE` Pod 请求,如果尚不存在名称为`foo-sidecar`的容器,则注入名称为`foo-sidecar`的边车容器。 + +在上述情况下,可以安全地重新调用 Webhook,或接受已设置字段的对象。 + + + +#### 非幂等可变 Admission Webhooks 的示例: + +1.对于`CREATE` pod 请求,注入一个名为`foo-sidecar`的边车容器当前时间戳后缀(例如`foo-sidecar-19700101-000000`)。 + +2.对于`CREATE/UPDATE` pod 请求,如果设置了标签`env`,则拒绝该请求,否则,将`env:prod`标签添加到标签组中。 + +3.对于`CREATE` pod 请求,附加一个名为`foo-sidecar`的 sidecar 容器而无需查看是否已经有`foo-sidecar`容器。 + +在上述第一种情况下,重新调用 Webhook 可能导致同一侧边车每次被多次注入 Pod 使用不同的容器名称。同样,如果 sidecar 已存在,则 webhook 可以注入重复的容器。 + +在上述第二种情况下,重新调用 Webhook 将导致 Webhook 自身输出失败。 + +在上述第三种情况下,重新调用 Webhook 将导致 pod 规范中的容器重复,这使得该请求无效,并被 apiserver 拒绝。 + + +### 拦截对象的所有版本 + +建议通过设置`.webhooks[].matchPolicy`,Admission webhooks 应该始终拦截对象的所有版本。到`Equivalent`。建议 Admission Webhook 应该优先注册资源的稳定版本。 +如果未能拦截对象的所有版本,则可能导致某些请求中的请求未实施准入策略版本。有关示例,请参见 [匹配请求-策略匹配](#匹配请求-策略匹配)。 + + +### 可用性 + +建议 Admission webhook 尽快评估(通常以毫秒为单位),因为它们会增加 API 请求的延迟。期望对 Webhooks 使用较小的超时。有关更多详细信息,请参见 [超时](#超时)。 + +建议 Admission Webhook 应该利用某种形式的负载平衡,以提供高可用性和性能优势。如果群集中正在运行 Webhook,则可以在服务后面运行多个 Webhook 后端利用服务支持的负载平衡。 + + + +### 确保看到对象的最终状态 + +需要确保他们看到对象的最终状态以实施策略的 Admission Webhook 应该使用一个有效的 Admission webhook,因为可以通过更改 webhooks 看到对象后对其进行修改。 + +例如,一个可变 Webhook 配置为在每个容器上注入一个名称为`foo-sidecar`的边车容器。 +`CREATE`pod 请求。如果*必须*提供 sidecar,则还应该配置一个有效的 Admission webhook 来拦截`CREATE` pod 请求并进行验证 +在要创建的对象中存在一个具有预期配置的名称为`foo-sidecar`的容器。 + + +### 避免自托管的 Webhooks 中出现死锁 + +如果配置了群集,则在群集内运行的 Webhook 可能会导致死锁拦截启动自己的 Pod 所需的资源。 + +例如,可变 Admission Webhook 被配置为仅当在标签中设置了某个标签时才接纳`CREATE` pod 请求(例如`env:prod`)。Webhook 服务器在未设置`env`标签的部署中运行。 +当运行 Webhook 服务器 Pod 的节点变得不正常后,webhook 部署将尝试将 Pod 重新安排到另一个节点。但是请求将 +因为未设置`env`标签,所以现有的 webhook 服务器拒绝了它,并且无法进行迁移。 + +建议使用 [namespaceSelector](#匹配请求-命名空间选择器) 排除运行 Webhook 的名称空间。 + + +### Side Effects + +建议 Admission Webhook 尽可能避免副作用,这意味着 Webhook 只能在发送给他们的`AdmissionReview`的内容,请勿进行带外更改。如果 Webhook 没有任何副作用,将`.webhooks[].sideEffects`字段应设置为`None`。 + +如果在准入评估过程中需要副作用,则在处理 AdmissionReview 对象将`DryRun`设置为`true`,并将`.webhooks[].sideEffects`字段设置为`NoneOnDryRun`。有关更多详细信息,请参见 [副作用](#副作用)。 + + + +### 避免对 kube-system 名称空间进行操作 + +`kube-system`名称空间包含由 Kubernetes 系统创建的对象,例如服务负责控制平面组件,如`kube-dns`之类的 Pod。 +意外地更改或拒绝`kube-system`名称空间中的请求导致控制平面组件停止运行或引入未知行为。 +如果您的 Webhook 不打算修改控制平面上 Kubernetes 的行为,将`kube-system`命名空间排除在使用 [命名空间选择器](#匹配请求-命名空间选择器)。 +{{% /capture %}} diff --git a/content/zh/docs/reference/access-authn-authz/node.md b/content/zh/docs/reference/access-authn-authz/node.md new file mode 100644 index 0000000000..255efffdc4 --- /dev/null +++ b/content/zh/docs/reference/access-authn-authz/node.md @@ -0,0 +1,201 @@ +--- +title: 使用 Node 鉴权 +content_template: templates/concept +weight: 90 +--- + + +{{% capture overview %}} +节点鉴权是一种特殊用途的鉴权模式,专门对 kubelet 发出的 API 请求进行鉴权。 + +{{% /capture %}} + +{{% capture body %}} +## 概述 + + +节点鉴权器允许 kubelet 执行 API 操作。包括: + + +读取操作: + + +* services +* endpoints +* nodes +* pods +* secrets、configmaps、以及绑定到 kubelet 的节点的 pod 的持久卷申领和持久卷 + + +写入操作: + + +* 节点和节点状态(启用 `NodeRestriction` 准入插件以限制 kubelet 只能修改自己的节点) +* Pod 和 Pod 状态 (启用 `NodeRestriction` 准入插件以限制 kubelet 只能修改绑定到自身的 Pod) +* 事件 + + +鉴权相关操作: + + +* 对于基于 TLS 的启动引导过程时使用的 certificationsigningrequests API 的读/写权限 +* 为委派的身份验证/授权检查创建 tokenreviews 和 subjectaccessreviews 的能力 + + +在将来的版本中,节点鉴权器可能会添加或删除权限,以确保 kubelet 具有正确操作所需的最小权限集。 + + +为了获得节点鉴权器的授权,kubelet 必须使用一个凭证以表示它在 `system:nodes` 组中,用户名为 `system:node:`。 +上述的组名和用户名格式要与 [kubelet TLS 启动引导](/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/)过程中为每个 kubelet 创建的标识相匹配。 + + +要启用节点授权器,请使用 `--authorization-mode = Node` 启动 apiserver。 + + +要限制 kubelet 具有写入权限的 API 对象,请使用 `--enable-admission-plugins=...,NodeRestriction,...` 启动 apiserver,从而启用 [NodeRestriction](/docs/reference/access-authn-authz/admission-controllers#NodeRestriction) 准入插件。 + + +## 迁移考虑因素 + + +### 在 `system:nodes` 组之外的 Kubelet + + +`system:nodes` 组之外的 kubelet 不会被 `Node` 鉴权模式授权,并且需要继续通过当前授权它们的机制来授权。 +节点准入插件不会限制来自这些 kubelet 的请求。 + + +### 具有无差别用户名的 Kubelet + + +在一些部署中,kubelet 具有 `system:nodes` 组的凭证,但是无法给出它们所关联的节点的标识,因为它们没有 `system:node:...` 格式的用户名。 +这些 kubelet 不会被 `Node` 授权模式授权,并且需要继续通过当前授权它们的任何机制来授权。 + + +因为默认的节点标识符实现不会把它当作节点身份标识,`NodeRestriction` 准入插件会忽略来自这些 kubelet 的请求。 + + +### 相对于以前使用 RBAC 的版本的更新 + + +升级的 1.7 之前的使用 [RBAC](/docs/reference/access-authn-authz/rbac/) 的集群将继续按原样运行,因为 `system:nodes` 组绑定已经存在。 + + +如果集群管理员希望开始使用 `Node` 鉴权器和 `NodeRestriction` 准入插件来限制节点对 API 的访问,这一需求可以通过下列操作来完成且不会影响已部署的应用: + + +1. 启用 `Node` 鉴权模式 (`--authorization-mode=Node,RBAC`) 和 `NodeRestriction` 准入插件 +2. 确保所有 kubelet 的凭据符合组/用户名要求 +3. 审核 apiserver 日志以确保 `Node` 鉴权器不会拒绝来自 kubelet 的请求(日志中没有持续的 `NODE DENY` 消息) +4. 删除 `system:node` 集群角色绑定 + + +### RBAC 节点权限 + + +在 1.6 版本中,当使用 [RBAC 鉴权模式](/docs/reference/access-authn-authz/rbac/) 时,`system:nodes` 集群角色会被自动绑定到 `system:node` 组。 + + +在 1.7 版本中,不再推荐将 `system:nodes` 组自动绑定到 `system:node` 角色,因为节点鉴权器通过对 secret 和 configmap 访问的额外限制完成了相同的任务。 +如果同时启用了 `Node` 和 `RBAC` 授权模式,1.7 版本则不会创建 `system:nodes` 组到 `system:node` 角色的自动绑定。 + + +在 1.8 版本中,绑定将根本不会被创建。 + + +使用 RBAC 时,将继续创建 `system:node` 集群角色,以便与将其他用户或组绑定到该角色的部署方法兼容。 + +{{% /capture %}} diff --git a/content/zh/docs/reference/access-authn-authz/service-accounts-admin.md b/content/zh/docs/reference/access-authn-authz/service-accounts-admin.md index f8ad257203..0cf89e8ec7 100644 --- a/content/zh/docs/reference/access-authn-authz/service-accounts-admin.md +++ b/content/zh/docs/reference/access-authn-authz/service-accounts-admin.md @@ -4,58 +4,58 @@ approvers: - davidopp - lavalamp - liggitt -title: 管理Service Accounts +title: 管理 Service Accounts --- *这是一篇针对service accounts(服务账户)的集群管理员指南。 它呈现了 [User Guide to Service Accounts](/docs/user-guide/service-accounts)中的信息。* -*对授权和用户账户的支持已在规划中,当前并不完备,为了更好地描述service accounts,有时这些不完善的特性也会被提及。* +*对授权和用户账户的支持已在规划中,当前并不完备,为了更好地描述 service accounts,有时这些不完善的特性也会被提及。* ## 用户账户与服务账户 Kubernetes 区分用户账户和服务账户的概念主要基于以下原因: - - 用户账户是针对人而言的。 服务账户是针对运行在pod中的进程而言的。 - - 用户账户是全局性的。 其名称在集群各namespace中都是全局唯一的,未来的用户资源不会做namespace隔离, - 服务账户是namespace隔离的。 - - 通常情况下,集群的用户账户可能会从企业数据库进行同步,其创建需要特殊权限,并且涉及到复杂的业务流程。 服务账户创建的目的是为了更轻量,允许集群用户为了具体的任务创建服务账户 (即权限最小化原则)。 + - 用户账户是针对人而言的。 服务账户是针对运行在 pod 中的进程而言的。 + - 用户账户是全局性的。 其名称在集群各 namespace 中都是全局唯一的,未来的用户资源不会做 namespace 隔离, + 服务账户是 namespace 隔离的。 + - 通常情况下,集群的用户账户可能会从企业数据库进行同步,其创建需要特殊权限,并且涉及到复杂的业务流程。 服务账户创建的目的是为了更轻量,允许集群用户为了具体的任务创建服务账户 ( 即权限最小化原则 )。 - 对人员和服务账户审计所考虑的因素可能不同。 - - 针对复杂系统的配置可能包含系统组件相关的各种服务账户的定义。 因为服务账户可以定制化地创建,并且有namespace级别的名称,这种配置是很轻量的。 + - 针对复杂系统的配置可能包含系统组件相关的各种服务账户的定义。 因为服务账户可以定制化地创建,并且有 namespace 级别的名称,这种配置是很轻量的。 ## 服务账户的自动化 -三个独立组件协作完成服务账户相关的自动化: +三个独立组件协作完成服务账户相关的自动化 : - 服务账户准入控制器(Service account admission controller) - - Token控制器(Token controller) + - Token 控制器(Token controller) - 服务账户控制器(Service account controller) ### 服务账户准入控制器 -对pod的改动通过一个被称为[Admission Controller](/docs/admin/admission-controllers)的插件来实现。它是apiserver的一部分。 -当pod被创建或更新时,它会同步地修改pod。 当该插件处于激活状态(在大多数发行版中都是默认的),当pod被创建或更新时它会进行以下动作: +对 pod 的改动通过一个被称为 [Admission Controller](/docs/admin/admission-controllers) 的插件来实现。它是 apiserver 的一部分。 +当 pod 被创建或更新时,它会同步地修改 pod。 当该插件处于激活状态 ( 在大多数发行版中都是默认的 ),当 pod 被创建或更新时它会进行以下动作: - 1. 如果该pod没有 `ServiceAccount` 设置,将其 `ServiceAccount` 设为 `default`。 - 2. 保证pod所关联的 `ServiceAccount` 存在,否则拒绝该pod。 - 4. 如果pod不包含 `ImagePullSecrets`设置,那么 将 `ServiceAccount`中的`ImagePullSecrets` 信息添加到pod中。 - 5. 将一个包含用于API访问的token的 `volume` 添加到pod中。 - 6. 将挂载于 `/var/run/secrets/kubernetes.io/serviceaccount` 的 `volumeSource`添加到pod下的每个容器中。 + 1. 如果该 pod 没有 `ServiceAccount` 设置,将其 `ServiceAccount` 设为 `default`。 + 2. 保证 pod 所关联的 `ServiceAccount` 存在,否则拒绝该 pod。 + 4. 如果 pod 不包含 `ImagePullSecrets` 设置,那么 将 `ServiceAccount` 中的 `ImagePullSecrets` 信息添加到 pod 中。 + 5. 将一个包含用于 API 访问的 token 的 `volume` 添加到 pod 中。 + 6. 将挂载于 `/var/run/secrets/kubernetes.io/serviceaccount` 的 `volumeSource` 添加到 pod 下的每个容器中。 -### Token管理器 +### Token 管理器 -Token管理器是controller-manager的一部分。 以异步的形式工作: +Token 管理器是 controller-manager 的一部分。 以异步的形式工作: -- 检测服务账户的创建,并且创建相应的Secret以支持API访问。 -- 检测服务账户的删除,并且删除所有相应的服务账户Token Secret。 -- 检测Secret的增加,保证相应的服务账户存在,如有需要,为Secret增加token。 -- 检测Secret的删除,如有需要,从相应的服务账户中移除引用。 +- 检测服务账户的创建,并且创建相应的 Secret 以支持 API 访问。 +- 检测服务账户的删除,并且删除所有相应的服务账户 Token Secret。 +- 检测 Secret 的增加,保证相应的服务账户存在,如有需要,为 Secret 增加 token。 +- 检测 Secret 的删除,如有需要,从相应的服务账户中移除引用。 -你需要通过 `--service-account-private-key-file` 参数项传入一个服务账户私钥文件至Token管理器。 私钥用于为生成的服务账户token签名。 -同样地,你需要通过 `--service-account-key-file` 参数将对应的公钥传入kube-apiserver。 公钥用于认证过程中的token校验。 +你需要通过 `--service-account-private-key-file` 参数项传入一个服务账户私钥文件至 Token 管理器。 私钥用于为生成的服务账户 token 签名。 +同样地,你需要通过 `--service-account-key-file` 参数将对应的公钥传入 kube-apiserver。 公钥用于认证过程中的 token 校验。 #### 创建额外的 API tokens -控制器中有专门的循环来保证每个服务账户中都存在API token对应的Secret。 当需要为服务账户创建额外的API token时,创建一个类型为 `ServiceAccountToken` 的Secret,并在annotation中引用服务账户,控制器会生成token并更新: +控制器中有专门的循环来保证每个服务账户中都存在 API token 对应的 Secret。 当需要为服务账户创建额外的 API token 时,创建一个类型为 `ServiceAccountToken` 的 Secret,并在 annotation 中引用服务账户,控制器会生成 token 并更新 : secret.json: @@ -78,7 +78,7 @@ kubectl create -f ./secret.json kubectl describe secret mysecretname ``` -#### 删除/失效 服务账户token +#### 删除 / 失效 服务账户 token ```shell kubectl delete secret mysecretname diff --git a/content/zh/docs/reference/access-authn-authz/webhook.md b/content/zh/docs/reference/access-authn-authz/webhook.md index e80fed7dc2..0078ea15d5 100644 --- a/content/zh/docs/reference/access-authn-authz/webhook.md +++ b/content/zh/docs/reference/access-authn-authz/webhook.md @@ -1,45 +1,116 @@ --- -approvers: +reviewers: +- erictune +- lavalamp +- deads2k +- liggitt +title: Webhook 模式 +content_template: templates/concept +weight: 95 +--- + {{% capture overview %}} -WebHook 是一种 HTTP 回调:某些条件下触发的 HTTP POST 请求;通过 HTTP POST 发送的简单事件通知。一个基于 web 应用实现的 WebHook 会在特定事件发生时把消息发送给特定的 URL 。 + +WebHook 是一种 HTTP 回调:某些条件下触发的 HTTP POST 请求;通过 HTTP POST 发送的简单事件通知。一个基于 web 应用实现的 WebHook 会在特定事件发生时把消息发送给特定的 URL。 {{% /capture %}} {{% capture body %}} + 具体来说,当在判断用户权限时,`Webhook` 模式会使 Kubernetes 查询外部的 REST 服务。 + ## 配置文件格式 + `Webhook` 模式需要一个 HTTP 配置文件,通过 `--authorization-webhook-config-file=SOME_FILENAME` 的参数声明。 -配置文件的格式使用 [kubeconfig](/docs/concepts/cluster-administration/authenticate-across-clusters-kubeconfig/)。 -在文件中,"users" 代表着 API 服务器的 webhook,而 "cluster" 代表着远程服务。 + +配置文件的格式使用 [kubeconfig](/docs/tasks/access-application-cluster/configure-access-multiple-clusters/)。在文件中,"users" 代表着 API 服务器的 webhook,而 "cluster" 代表着远程服务。 + 使用 HTTPS 客户端认证的配置例子: + +```yaml +# Kubernetes API 版本 +apiVersion: v1 +# API 对象种类 +kind: Config # clusters 代表远程服务。 clusters: - name: name-of-remote-authz-service cluster: - certificate-authority: /path/to/ca.pem # 对远程服务进行身份认证的CA。 - server: https://authz.example.com/authorize # 远程服务的查询 URL. 必须使用 'https'。 + # 对远程服务进行身份认证的 CA。 + certificate-authority: /path/to/ca.pem + # 远程服务的查询 URL。必须使用 'https'。 + server: https://authz.example.com/authorize -# users 代表 API 服务器的 webhook 配置. +# users 代表 API 服务器的 webhook 配置 users: - name: name-of-api-server user: - client-certificate: /path/to/cert.pem # webhook plugin 使用的 cert。 - client-key: /path/to/key.pem # cert 所对应的 key。 + client-certificate: /path/to/cert.pem # webhook plugin 使用 cert + client-key: /path/to/key.pem # cert 所对应的 key -# kubeconfig 文件必须有 context 。 需要提供一个给 API 服务器。 +# kubeconfig 文件必须有 context。需要提供一个给 API 服务器。 current-context: webhook contexts: - context: @@ -48,16 +119,32 @@ contexts: name: webhook ``` - + ## 请求载荷 -在做认证决策时,API 服务器会 POST 一个 JSON 序列化的 api.authorization.v1beta1.SubjectAccessReview 对象来描述这个动作。这个对象包含了描述用户请求的字段,同时也包含了需要被访问资源或者请求特征的具体信息。 - -需要注意的是 webhook API 对象与其他 Kubernetes API 对象一样都同样都服从 [版本兼容规则](/docs/api/) 。 -实施人员应该了解 beta 对象的更宽松的兼容性承诺,同时确认请求的 "apiVersion" 字段以确保能被正确地反序列化。 -此外,API 服务器还必须启用 `authorization.k8s.io/v1beta1` API 扩展组(`--runtime-config=authorization.k8s.io/v1beta1=true`)。 + +在做认证决策时,API 服务器会 POST 一个 JSON 序列化的 `authorization.k8s.io/v1beta1` `SubjectAccessReview` 对象来描述这个动作。这个对象包含了描述用户请求的字段,同时也包含了需要被访问资源或请求特征的具体信息。 + +需要注意的是 webhook API 对象与其他 Kubernetes API 对象一样都同样都服从[版本兼容规则](/docs/concepts/overview/kubernetes-api/)。实施人员应该了解 beta 对象的更宽松的兼容性承诺,同时确认请求的 "apiVersion" 字段能被正确地反序列化。此外,API 服务器还必须启用 `authorization.k8s.io/v1beta1` API 扩展组 (`--runtime-config=authorization.k8s.io/v1beta1=true`)。 + 一个请求内容的例子: ```json @@ -80,9 +167,12 @@ contexts: } ``` -远程服务被预期能填写请求和反馈的 SubjectAccessReviewStatus 字段,无论是允许访问还是拒绝访问。 -反馈内容的 "spec" 字段是被忽略的,也是可以被省略的。当请求是被允许的时候,返回的响应如下例所示: - + +期待远程服务填充请求的 `status` 字段并响应允许或禁止访问。响应主体的 `spec` 字段被忽略,可以省略。允许的响应将返回: ```json { "apiVersion": "authorization.k8s.io/v1beta1", @@ -93,8 +183,19 @@ contexts: } ``` + +为了禁止访问,有两种方法。 -如拒绝,远程服务器会返回: + +在大多数情况下,第一种方法是首选方法,它指示授权 webhook 不允许或对请求"无意见",但是,如果配置了其他授权者,则可以给他们机会允许请求。如果没有其他授权者,或者没有一个授权者,则该请求被禁止。webhook 将返回: ```json { @@ -107,8 +208,30 @@ contexts: } ``` + +第二种方法立即拒绝其他配置的授权者进行短路评估。仅应由对集群的完整授权者配置有详细了解的 webhook 使用。webhook 将返回: -对于非资源的路径访问是这么发送的: +```json +{ + "apiVersion": "authorization.k8s.io/v1beta1", + "kind": "SubjectAccessReview", + "status": { + "allowed": false, + "denied": true, + "reason": "user does not have read access to the namespace" + } +} +``` + + +对于非资源的路径访问是这么发送的: ```json { @@ -128,15 +251,24 @@ contexts: } ``` - -非资源类的路径包括:`/api`, `/apis`, `/metrics`, `/resetMetrics`, + +非资源类的路径包括:`/api`, `/apis`, `/metrics`, `/resetMetrics`, +`/logs`, `/debug`, `/healthz`, `/swagger-ui/`, `/swaggerapi/`, `/ui`, 和 +`/version`。客户端需要访问 `/api`, `/api/*`, `/apis`, `/apis/*`, 和 `/version` 以便 能发现服务器上有什么资源和版本。对于其他非资源类的路径访问在没有 REST API 访问限制的情况下拒绝。 - -更多信息可以参考 uthorization.v1beta1 API 对象和 -[webhook.go](https://git.k8s.io/kubernetes/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go). + +更多信息可以参考 authorization.v1beta1 API 对象和[webhook.go](https://github.com/kubernetes/kubernetes/blob/{{< param "githubbranch" >}}/staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook/webhook.go)。 {{% /capture %}} diff --git a/content/zh/docs/reference/command-line-tools-reference/_index.md b/content/zh/docs/reference/command-line-tools-reference/_index.md index dcd66f2df9..7c2792e894 100644 --- a/content/zh/docs/reference/command-line-tools-reference/_index.md +++ b/content/zh/docs/reference/command-line-tools-reference/_index.md @@ -1,5 +1,13 @@ --- -title: 命令行工具 +title: 命令行工具参考 weight: 60 toc-hide: true --- + + diff --git a/content/zh/docs/reference/command-line-tools-reference/feature-gates.md b/content/zh/docs/reference/command-line-tools-reference/feature-gates.md new file mode 100644 index 0000000000..dae2db093b --- /dev/null +++ b/content/zh/docs/reference/command-line-tools-reference/feature-gates.md @@ -0,0 +1,679 @@ + +--- +title: 功能开关 +weight: 10 +title: 功能开关 +content_template: templates/concept +--- + +{{% capture overview %}} + +本页详述了管理员可以在不同的 Kubernetes 组件上指定的各种功能开关。 +{{% /capture %}} + +{{% capture body %}} + +## 概述 + + +功能开关是一组描述 alpha 或实验功能的键值对。 + +管理员可以在每个组件上使用 `--feature-gates` 命令行参数来打开或关闭功能。每个组件都支持该组件唯一的一组功能开关。 +使用 `-h` 参数来查看所有组件的完整功能开关。 +要为诸如 kubelet 之类的组件设置功能开关,请使用分配给功能键值对列表的 `--feature-gates` 参数: + +```shell +--feature-gates="...,DynamicKubeletConfig=true" +``` + + +下表总结了可以在不同的 Kubernetes 组件上设置的功能开关。 + + +- 引入功能或更改其发布阶段后,"Since" 列将包含 Kubernetes 版本。 +- "Until" 列(如果不为空)包含最后一个 Kubernetes 版本,您仍可以在其中使用功能开关。 +- 如果某个功能处于 Alpha 或 Beta 状态,则可以在 Alpha 或者 Beta 功能开关表中找到该功能。 +- 如果某个功能稳定(GA)或已弃用,则可以在 GA 或者不推荐使用的功能开关表中找到该功能的所有阶段。 + + +### Alpha 或 Beta 功能的功能开关 + + +{{< table caption="Alpha 或 Beta 状态中功能的功能开关" >}} + +| 功能 | 默认值 | 状态 | 开始(Since) | 结束(Until) | +|---------|---------|-------|-------|-------| +| `APIListChunking` | `false` | Alpha | 1.8 | 1.8 | +| `APIListChunking` | `true` | Beta | 1.9 | | +| `APIResponseCompression` | `false` | Alpha | 1.7 | | +| `AppArmor` | `true` | Beta | 1.4 | | +| `AttachVolumeLimit` | `true` | Alpha | 1.11 | 1.11 | +| `AttachVolumeLimit` | `true` | Beta | 1.12 | | +| `BalanceAttachedNodeVolumes` | `false` | Alpha | 1.11 | | +| `BlockVolume` | `false` | Alpha | 1.9 | 1.12 | +| `BlockVolume` | `true` | Beta | 1.13 | - | +| `BoundServiceAccountTokenVolume` | `false` | Alpha | 1.13 | | +| `CPUManager` | `false` | Alpha | 1.8 | 1.9 | +| `CPUManager` | `true` | Beta | 1.10 | | +| `CRIContainerLogRotation` | `false` | Alpha | 1.10 | 1.10 | +| `CRIContainerLogRotation` | `true` | Beta| 1.11 | | +| `CSIBlockVolume` | `false` | Alpha | 1.11 | 1.13 | +| `CSIBlockVolume` | `true` | Beta | 1.14 | | +| `CSIDriverRegistry` | `false` | Alpha | 1.12 | 1.13 | +| `CSIDriverRegistry` | `true` | Beta | 1.14 | | +| `CSIInlineVolume` | `false` | Alpha | 1.15 | 1.15 | +| `CSIInlineVolume` | `true` | Beta | 1.16 | - | +| `CSIMigration` | `false` | Alpha | 1.14 | | +| `CSIMigrationAWS` | `false` | Alpha | 1.14 | | +| `CSIMigrationAzureDisk` | `false` | Alpha | 1.15 | | +| `CSIMigrationAzureFile` | `false` | Alpha | 1.15 | | +| `CSIMigrationGCE` | `false` | Alpha | 1.14 | | +| `CSIMigrationOpenStack` | `false` | Alpha | 1.14 | | +| `CSINodeInfo` | `false` | Alpha | 1.12 | 1.13 | +| `CSINodeInfo` | `true` | Beta | 1.14 | | +| `CustomCPUCFSQuotaPeriod` | `false` | Alpha | 1.12 | | +| `CustomResourceDefaulting` | `false` | Alpha| 1.15 | 1.15 | +| `CustomResourceDefaulting` | `true` | Beta | 1.16 | | +| `DevicePlugins` | `false` | Alpha | 1.8 | 1.9 | +| `DevicePlugins` | `true` | Beta | 1.10 | | +| `DryRun` | `false` | Alpha | 1.12 | 1.12 | +| `DryRun` | `true` | Beta | 1.13 | | +| `DynamicAuditing` | `false` | Alpha | 1.13 | | +| `DynamicKubeletConfig` | `false` | Alpha | 1.4 | 1.10 | +| `DynamicKubeletConfig` | `true` | Beta | 1.11 | | +| `EndpointSlice` | `false` | Alpha | 1.16 | | +| `EphemeralContainers` | `false` | Alpha | 1.16 | | +| `ExpandCSIVolumes` | `false` | Alpha | 1.14 | 1.15 | +| `ExpandCSIVolumes` | `true` | Beta | 1.16 | | +| `ExpandInUsePersistentVolumes` | `false` | Alpha | 1.11 | 1.14 | +| `ExpandInUsePersistentVolumes` | `true` | Beta | 1.15 | | +| `ExpandPersistentVolumes` | `false` | Alpha | 1.8 | 1.10 | +| `ExpandPersistentVolumes` | `true` | Beta | 1.11 | | +| `ExperimentalHostUserNamespaceDefaulting` | `false` | Beta | 1.5 | | +| `EvenPodsSpread` | `false` | Alpha | 1.16 | | +| `HPAScaleToZero` | `false` | Alpha | 1.16 | | +| `HyperVContainer` | `false` | Alpha | 1.10 | | +| `KubeletPodResources` | `false` | Alpha | 1.13 | 1.14 | +| `KubeletPodResources` | `true` | Beta | 1.15 | | +| `LegacyNodeRoleBehavior` | `true` | Alpha | 1.16 | | +| `LocalStorageCapacityIsolation` | `false` | Alpha | 1.7 | 1.9 | +| `LocalStorageCapacityIsolation` | `true` | Beta | 1.10 | | +| `LocalStorageCapacityIsolationFSQuotaMonitoring` | `false` | Alpha | 1.15 | | +| `MountContainers` | `false` | Alpha | 1.9 | | +| `NodeDisruptionExclusion` | `false` | Alpha | 1.16 | | +| `NodeLease` | `false` | Alpha | 1.12 | 1.13 | +| `NodeLease` | `true` | Beta | 1.14 | | +| `NonPreemptingPriority` | `false` | Alpha | 1.15 | | +| `PodOverhead` | `false` | Alpha | 1.16 | - | +| `PodShareProcessNamespace` | `false` | Alpha | 1.10 | 1.11 | +| `PodShareProcessNamespace` | `true` | Beta | 1.12 | | +| `ProcMountType` | `false` | Alpha | 1.12 | | +| `QOSReserved` | `false` | Alpha | 1.11 | | +| `RemainingItemCount` | `false` | Alpha | 1.15 | | +| `RequestManagement` | `false` | Alpha | 1.15 | | +| `ResourceLimitsPriorityFunction` | `false` | Alpha | 1.9 | | +| `ResourceQuotaScopeSelectors` | `false` | Alpha | 1.11 | 1.11 | +| `ResourceQuotaScopeSelectors` | `true` | Beta | 1.12 | | +| `RotateKubeletClientCertificate` | `true` | Beta | 1.8 | | +| `RotateKubeletServerCertificate` | `false` | Alpha | 1.7 | 1.11 | +| `RotateKubeletServerCertificate` | `true` | Beta | 1.12 | | +| `RunAsGroup` | `true` | Beta | 1.14 | | +| `RuntimeClass` | `false` | Alpha | 1.12 | 1.13 | +| `RuntimeClass` | `true` | Beta | 1.14 | | +| `ScheduleDaemonSetPods` | `false` | Alpha | 1.11 | 1.11 | +| `ScheduleDaemonSetPods` | `true` | Beta | 1.12 | | +| `SCTPSupport` | `false` | Alpha | 1.12 | | +| `ServerSideApply` | `false` | Alpha | 1.14 | 1.15 | +| `ServerSideApply` | `true` | Beta | 1.16 | | +| `ServiceLoadBalancerFinalizer` | `false` | Alpha | 1.15 | | +| `ServiceNodeExclusion` | `false` | Alpha | 1.8 | | +| `StartupProbe` | `false` | Alpha | 1.16 | | +| `StorageVersionHash` | `false` | Alpha | 1.14 | 1.14 | +| `StorageVersionHash` | `true` | Beta | 1.15 | | +| `StreamingProxyRedirects` | `false` | Beta | 1.5 | 1.5 | +| `StreamingProxyRedirects` | `true` | Beta | 1.6 | | +| `SupportNodePidsLimit` | `false` | Alpha | 1.14 | 1.14 | +| `SupportNodePidsLimit` | `true` | Beta | 1.15 | | +| `SupportPodPidsLimit` | `false` | Alpha | 1.10 | 1.13 | +| `SupportPodPidsLimit` | `true` | Beta | 1.14 | | +| `Sysctls` | `true` | Beta | 1.11 | | +| `TaintBasedEvictions` | `false` | Alpha | 1.6 | 1.12 | +| `TaintBasedEvictions` | `true` | Beta | 1.13 | | +| `TaintNodesByCondition` | `false` | Alpha | 1.8 | 1.11 | +| `TaintNodesByCondition` | `true` | Beta | 1.12 | | +| `TokenRequest` | `false` | Alpha | 1.10 | 1.11 | +| `TokenRequest` | `true` | Beta | 1.12 | | +| `TokenRequestProjection` | `false` | Alpha | 1.11 | 1.11 | +| `TokenRequestProjection` | `true` | Beta | 1.12 | | +| `TTLAfterFinished` | `false` | Alpha | 1.12 | | +| `TopologyManager` | `false` | Alpha | 1.16 | | +| `ValidateProxyRedirects` | `false` | Alpha | 1.10 | 1.13 | +| `ValidateProxyRedirects` | `true` | Beta | 1.14 | | +| `VolumePVCDataSource` | `false` | Alpha | 1.15 | 1.15 | +| `VolumePVCDataSource` | `true` | Beta | 1.16 | | +| `VolumeSubpathEnvExpansion` | `false` | Alpha | 1.14 | 1.14 | +| `VolumeSubpathEnvExpansion` | `true` | Beta | 1.15 | | +| `VolumeSnapshotDataSource` | `false` | Alpha | 1.12 | - | +| `WatchBookmark` | `false` | Alpha | 1.15 | 1.15 | +| `WatchBookmark` | `true` | Beta | 1.16 | | +| `WindowsGMSA` | `false` | Alpha | 1.14 | | +| `WindowsGMSA` | `true` | Beta | 1.16 | | +| `WinDSR` | `false` | Alpha | 1.14 | | +| `WinOverlay` | `false` | Alpha | 1.14 | | +{{< /table >}} + + +### 已完成或不推荐使用的功能的功能开关 + + +{{< table caption="已完成或不推荐使用的功能的功能开关" >}} + +| 功能 | 默认值 | 状态 | 开始(Since) | 结束(Until) | +|---------|---------|-------|-------|-------| +| `Accelerators` | `false` | Alpha | 1.6 | 1.10 | +| `Accelerators` | - | Deprecated | 1.11 | - | +| `AdvancedAuditing` | `false` | Alpha | 1.7 | 1.7 | +| `AdvancedAuditing` | `true` | Beta | 1.8 | 1.11 | +| `AdvancedAuditing` | `true` | GA | 1.12 | - | +| `AffinityInAnnotations` | `false` | Alpha | 1.6 | 1.7 | +| `AffinityInAnnotations` | - | Deprecated | 1.8 | - | +| `AllowExtTrafficLocalEndpoints` | `false` | Beta | 1.4 | 1.6 | +| `AllowExtTrafficLocalEndpoints` | `true` | GA | 1.7 | - | +| `CSIPersistentVolume` | `false` | Alpha | 1.9 | 1.9 | +| `CSIPersistentVolume` | `true` | Beta | 1.10 | 1.12 | +| `CSIPersistentVolume` | `true` | GA | 1.13 | - | +| `CustomPodDNS` | `false` | Alpha | 1.9 | 1.9 | +| `CustomPodDNS` | `true` | Beta| 1.10 | 1.13 | +| `CustomPodDNS` | `true` | GA | 1.14 | - | +| `CustomResourcePublishOpenAPI` | `false` | Alpha| 1.14 | 1.14 | +| `CustomResourcePublishOpenAPI` | `true` | Beta| 1.15 | 1.15 | +| `CustomResourcePublishOpenAPI` | `true` | GA | 1.16 | - | +| `CustomResourceSubresources` | `false` | Alpha | 1.10 | 1.10 | +| `CustomResourceSubresources` | `true` | Beta | 1.11 | 1.15 | +| `CustomResourceSubresources` | `true` | GA | 1.16 | - | +| `CustomResourceValidation` | `false` | Alpha | 1.8 | 1.8 | +| `CustomResourceValidation` | `true` | Beta | 1.9 | 1.15 | +| `CustomResourceValidation` | `true` | GA | 1.16 | - | +| `CustomResourceWebhookConversion` | `false` | Alpha | 1.13 | 1.14 | +| `CustomResourceWebhookConversion` | `true` | Beta | 1.15 | 1.15 | +| `CustomResourceWebhookConversion` | `true` | GA | 1.16 | - | +| `DynamicProvisioningScheduling` | `false` | Alpha | 1.11 | 1.11 | +| `DynamicProvisioningScheduling` | - | Deprecated| 1.12 | - | +| `DynamicVolumeProvisioning` | `true` | Alpha | 1.3 | 1.7 | +| `DynamicVolumeProvisioning` | `true` | GA | 1.8 | - | +| `EnableEquivalenceClassCache` | `false` | Alpha | 1.8 | 1.14 | +| `EnableEquivalenceClassCache` | - | Deprecated | 1.15 | - | +| `ExperimentalCriticalPodAnnotation` | `false` | Alpha | 1.5 | 1.12 | +| `ExperimentalCriticalPodAnnotation` | `false` | Deprecated | 1.13 | - | +| `GCERegionalPersistentDisk` | `true` | Beta | 1.10 | 1.12 | +| `GCERegionalPersistentDisk` | `true` | GA | 1.13 | - | +| `HugePages` | `false` | Alpha | 1.8 | 1.9 | +| `HugePages` | `true` | Beta| 1.10 | 1.13 | +| `HugePages` | `true` | GA | 1.14 | - | +| `Initializers` | `false` | Alpha | 1.7 | 1.13 | +| `Initializers` | - | Deprecated | 1.14 | - | +| `KubeletConfigFile` | `false` | Alpha | 1.8 | 1.9 | +| `KubeletConfigFile` | - | Deprecated | 1.10 | - | +| `KubeletPluginsWatcher` | `false` | Alpha | 1.11 | 1.11 | +| `KubeletPluginsWatcher` | `true` | Beta | 1.12 | 1.12 | +| `KubeletPluginsWatcher` | `true` | GA | 1.13 | - | +| `MountPropagation` | `false` | Alpha | 1.8 | 1.9 | +| `MountPropagation` | `true` | Beta | 1.10 | 1.11 | +| `MountPropagation` | `true` | GA | 1.12 | - | +| `PersistentLocalVolumes` | `false` | Alpha | 1.7 | 1.9 | +| `PersistentLocalVolumes` | `true` | Beta | 1.10 | 1.13 | +| `PersistentLocalVolumes` | `true` | GA | 1.14 | - | +| `PodPriority` | `false` | Alpha | 1.8 | 1.10 | +| `PodPriority` | `true` | Beta | 1.11 | 1.13 | +| `PodPriority` | `true` | GA | 1.14 | - | +| `PodReadinessGates` | `false` | Alpha | 1.11 | 1.11 | +| `PodReadinessGates` | `true` | Beta | 1.12 | 1.13 | +| `PodReadinessGates` | `true` | GA | 1.14 | - | +| `PVCProtection` | `false` | Alpha | 1.9 | 1.9 | +| `PVCProtection` | - | Deprecated | 1.10 | - | +| `StorageObjectInUseProtection` | `true` | Beta | 1.10 | 1.10 | +| `StorageObjectInUseProtection` | `true` | GA | 1.11 | - | +| `SupportIPVSProxyMode` | `false` | Alpha | 1.8 | 1.8 | +| `SupportIPVSProxyMode` | `false` | Beta | 1.9 | 1.9 | +| `SupportIPVSProxyMode` | `true` | Beta | 1.10 | 1.10 | +| `SupportIPVSProxyMode` | `true` | GA | 1.11 | - | +| `VolumeScheduling` | `false` | Alpha | 1.9 | 1.9 | +| `VolumeScheduling` | `true` | Beta | 1.10 | 1.12 | +| `VolumeScheduling` | `true` | GA | 1.13 | - | +| `VolumeSubpath` | `true` | GA | 1.13 | - | +{{< /table >}} + + +## 使用功能 + + +### 功能阶段 + + +处于 *Alpha*、*Beta*、*GA* 阶段的功能 + +*Alpha* 功能代表: + + +* 默认禁用。 +* 可能有错误,启用此功能可能会导致错误。 +* 随时可能删除对此功能的支持,恕不另行通知。 +* 在以后的软件版本中,API 可能会以不兼容的方式更改,恕不另行通知。 +* 建议将其仅用于短期测试集群中,因为开启功能会增加错误的风险,并且缺乏长期支持。 + + +*Beta* 功能代表: + + +* 默认禁用。 +* 该功能已经经过良好测试。启用该功能是安全的。 +* 尽管详细信息可能会更改,但不会放弃对整体功能的支持。 +* 对象的架构或语义可能会在随后的 Beta 或稳定版本中以不兼容的方式更改。当发生这种情况时,我们将提供迁移到下一版本的说明。此功能可能需要删除、编辑和重新创建 API 对象。编辑过程可能需要慎重操作,因为这可能会导致依赖该功能的应用程序停机。 +* 推荐仅用于非关键业务用途,因为在后续版本中可能会发生不兼容的更改。如果您具有多个可以独立升级的集群,则可以放宽此限制。 + +{{< note >}} + +请尝试使用 *Beta* 功能并提供有关它们的反馈! +功能退出 Beta 后,对我们进行更多更改可能不切实际。 +{{< /note >}} + + +*GA* 功能也称为 *稳定* 功能,*GA* 功能代表着: + + +* 不再需要相应的功能开关。 +* 对于许多后续版本,功能的稳定版本将出现在发行的软件中。 + + +### 功能开关 + + +每个功能开关均设计用于启用或禁用特定功能: + + +- `Accelerators`:使用 Docker 时启用 Nvidia GPU 支持。 +- `AdvancedAuditing`:启用[高级审查功能](/docs/tasks/debug-application-cluster/audit/#advanced-audit)。 +- `AffinityInAnnotations`(*已弃用*):启用 [Pod 亲和力或反亲和力](/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity)。 +- `AllowExtTrafficLocalEndpoints`:启用服务用于将外部请求路由到节点本地终端。 +- `APIListChunking`:启用 API 客户端以块的形式从 API 服务器检索(“LIST” 或 “GET”)资源。 +- `APIResponseCompression`:压缩 “LIST” 或 “GET” 请求的 API 响应。 +- `AppArmor`:使用 Docker 时,在 Linux 节点上启用基于 AppArmor 机制的强制访问控制。有关更多详细信息,请参见 [AppArmor 教程](/docs/tutorials/clusters/apparmor/)。 + +- `AttachVolumeLimit`:启用卷插件用于报告可连接到节点的卷数限制。有关更多详细信息,请参见[动态卷限制](/docs/concepts/storage/storage-limits/#dynamic-volume-limits)。 +- `BalanceAttachedNodeVolumes`:包括要在调度时进行平衡资源分配的节点上的卷数。scheduler 在决策时会优先考虑 CPU、内存利用率和卷数更近的节点。 +- `BlockVolume`:在 Pod 中启用原始块设备的定义和使用。有关更多详细信息,请参见[原始块卷支持](/docs/concepts/storage/persistent-volumes/#raw-block-volume-support)。 +- `BoundServiceAccountTokenVolume`:迁移 ServiceAccount 卷以使用由 ServiceAccountTokenVolumeProjection 组成的预计卷。有关更多详细信息,请参见 [Service Account Token 卷](https://git.k8s.io/community/contributors/design-proposals/storage/svcacct-token-volume-source.md)。 +- `CPUManager`:启用容器级别的 CPU 亲和力支持,有关更多详细信息,请参见 [CPU 管理策略](/docs/tasks/administer-cluster/cpu-management-policies/)。 + +- `CRIContainerLogRotation`:为 cri 容器运行时启用容器日志轮换。 +- `CSIBlockVolume`:启用外部 CSI 卷驱动程序用于支持块存储。有关更多详细信息,请参见 [`csi` 原始块卷支持](/docs/concepts/storage/volumes/#csi-raw-block-volume-support)。 +- `CSIDriverRegistry`:在 csi.storage.k8s.io 中启用与 CSIDriver API 对象有关的所有逻辑。 +- `CSIInlineVolume`:为 Pod 启用 CSI 内联卷支持。 +- `CSIMigration`:确保填充和转换逻辑能够将卷操作从内嵌插件路由到相应的预安装 CSI 插件。 +- `CSIMigrationAWS`:确保填充和转换逻辑能够将卷操作从 AWS-EBS 内嵌插件路由到 EBS CSI 插件。 +- `CSIMigrationAzureDisk`:确保填充和转换逻辑能够将卷操作从 Azure 磁盘内嵌插件路由到 Azure 磁盘 CSI 插件。 +- `CSIMigrationAzureFile`:确保填充和转换逻辑能够将卷操作从 Azure 文件内嵌插件路由到 Azure 文件 CSI 插件。 + +- `CSIMigrationGCE`:确保填充和转换逻辑能够将卷操作从 GCE-PD 内嵌插件路由到 PD CSI 插件 +- `CSIMigrationOpenStack`:确保填充和转换逻辑能够将卷操作从 Cinder 内嵌插件路由到 Cinder CSI 插件。 +- `CSINodeInfo`:在 csi.storage.k8s.io 中启用与 CSINodeInfo API 对象有关的所有逻辑。 +- `CSIPersistentVolume`:启用发现并挂载通过 [CSI(容器存储接口)](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/container-storage-interface.md)兼容卷插件配置的卷。有关更多详细信息,请参见 [`csi` 卷类型](/docs/concepts/storage/volumes/#csi)。 + +- `CustomCPUCFSQuotaPeriod`:使节点能够更改 CPUCFSQuotaPeriod。 +- `CustomPodDNS`:使用其 `dnsConfig` 属性启用 Pod 的自定义 DNS 设置。有关更多详细信息,请参见 [Pod 的 DNS 配置](/docs/concepts/services-networking/dns-pod-service/#pods-dns-config)。 +- `CustomResourceDefaulting`:为 OpenAPI v3 验证架构中的默认值启用 CRD 支持。 +- `CustomResourcePublishOpenAPI`:启用 CRD OpenAPI 规范的发布。 +- `CustomResourceSubresources`:对于从 [CustomResourceDefinition](/docs/concepts/api-extension/custom-resources/) 中创建的资源启用 `/status` 和 `/scale` 子资源。 +- `CustomResourceValidation`:对于从 [CustomResourceDefinition](/docs/concepts/api-extension/custom-resources/) 中创建的资源启用基于架构的验证。 +- `CustomResourceWebhookConversion`:对于从 [CustomResourceDefinition](/docs/concepts/api-extension/custom-resources/) 中创建的资源启用基于 Webhook 的转换。 + 对正在运行的 Pod 进行故障排除。 + +- `DevicePlugins`:在节点上启用基于 [device-plugins](/docs/concepts/cluster-administration/device-plugins/) 的资源供应。 +- `DryRun`:启用服务器端 [dry run](/docs/reference/using-api/api-concepts/#dry-run) 请求,以便无需提交即可测试验证、合并和差异化。 +- `DynamicAuditing`:确保[动态审查](/docs/tasks/debug-application-cluster/audit/#dynamic-backend)。 +- `DynamicKubeletConfig`:启用 kubelet 的动态配置。请参阅[重新配置 kubelet](/docs/tasks/administer-cluster/reconfigure-kubelet/)。 +- `DynamicProvisioningScheduling`:扩展默认 scheduler 以了解卷拓扑并处理 PV 配置。此功能已在 v1.12 中完全由 `VolumeScheduling` 功能取代。 +- `DynamicVolumeProvisioning`(*已弃用*):启用持久化卷到 Pod 的[动态预配置](/docs/concepts/storage/dynamic-provisioning/)。 + +- `EnableAggregatedDiscoveryTimeout` (*已弃用*):对聚集的发现调用启用五秒钟超时设置。 +- `EnableEquivalenceClassCache`:调度 Pod 时,使 scheduler 缓存节点的等效项。 +- `EphemeralContainers`:启用添加 {{< glossary_tooltip text="临时容器" term_id="ephemeral-container" >}} 到正在运行的 Pod 的功能。 +- `EvenPodsSpread`:使 Pod 能够在拓扑域之间平衡调度。请参阅 [Even Pods Spread](/docs/concepts/configuration/even-pods-spread)。 +- `ExpandInUsePersistentVolumes`:启用扩展使用中的 PVC。请查阅 [调整使用中的 PersistentVolumeClaim 的大小](/docs/concepts/storage/persistent-volumes/#resizing-an-in-use-persistentvolumeclaim)。 +- `ExpandPersistentVolumes`:启用持久卷的扩展。请查阅[扩展永久卷声明](/docs/concepts/storage/persistent-volumes/#expanding-persistent-volumes-claims)。 +- `ExperimentalCriticalPodAnnotation`:启用将特定 Pod 注解为 *critical* 的方式,用于[确保其调度](/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/)。从 v1.13 开始,Pod 优先级和抢占功能已弃用此功能。 + +- `ExperimentalHostUserNamespaceDefaultingGate`:启用默认的用户命名空间进行托管。这适用于使用其他主机命名空间、主机安装的容器,或具有特权或使用特定的非命名空间功能(例如MKNODE、SYS_MODULE等)的容器。如果在 Docker 守护程序中启用了用户命名空间重新映射,则启用此选项。 +- `EndpointSlice`:启用端点切片以实现更多可扩展的网络端点。需要启用相应的 API 和控制器,请参阅[启用端点切片](/docs/tasks/administer-cluster/enabling-endpoint-slices/)。 +- `GCERegionalPersistentDisk`:在 GCE 上启用区域 PD 功能。 +- `HugePages`: 启用分配和使用预分配的 [huge pages](/docs/tasks/manage-hugepages/scheduling-hugepages/)。 + +- `HyperVContainer`:为 Windows 容器启用[Hyper-V 隔离](https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/hyperv-container)。 +- `HPAScaleToZero`:使用自定义指标或外部指标时,可将 `HorizontalPodAutoscaler` 资源的 `minReplicas` 设置为 0。 +- `KubeletConfigFile`:启用从使用配置文件指定的文件中加载 kubelet 配置。有关更多详细信息,请参见[通过配置文件设置 kubelet 参数](/docs/tasks/administer-cluster/kubelet-config-file/)。 +- `KubeletPluginsWatcher`:启用基于探针的插件监视应用程序,使 kubelet 能够发现插件,例如 [CSI 卷驱动程序](/docs/concepts/storage/volumes/#csi)。 +- `KubeletPodResources`:启用 kubelet 的 pod 资源 grpc 端点。有关更多详细信息,请参见[支持设备监控](https://git.k8s.io/community/keps/sig-node/compute-device-assignment.md)。 +- `LegacyNodeRoleBehavior`:禁用此选项后,服务负载均衡器中的旧版操作和节点中断将忽略 `node-role.kubernetes.io/master` 标签,而使用特定于功能的标签。 + +- `LocalStorageCapacityIsolation`:启用[本地临时存储](/docs/concepts/configuration/manage-compute-resources-container/)的消耗,以及 [emptyDir 卷](/docs/concepts/storage/volumes/#emptydir) 的 `sizeLimit` 属性。 +- `LocalStorageCapacityIsolationFSQuotaMonitoring`:如果为[本地临时存储](/docs/concepts/configuration/manage-compute-resources-container/)启用了 `LocalStorageCapacityIsolation`,并且 [emptyDir 卷](/docs/concepts/storage/volumes/#emptydir) 的后备文件系统支持项目配额,并且启用了这些配额,请使用项目配额来监视 [emptyDir 卷](/docs/concepts/storage/volumes/#emptydir)的存储消耗而不是遍历文件系统,以此获得更好的性能和准确性。 +- `MountContainers`:在主机上启用将应用程序容器用作卷安装程序。 +- `MountPropagation`:启用将一个容器安装的共享卷共享到其他容器或 Pod。有关更多详细信息,请参见 [mount propagation](/docs/concepts/storage/volumes/#mount-propagation)。 +- `NodeDisruptionExclusion`:启用节点标签 `node.kubernetes.io/exclude-disruption`,以防止在区域故障期间驱逐节点。 + +- `NodeLease`:启用新的租赁 API 以报告节点心跳,可用作节点运行状况信号。 +- `NonPreemptingPriority`:为 PriorityClass 和 Pod 启用 NonPreempting 选项。 +- `PersistentLocalVolumes`:在 Pod 中启用 “本地” 卷类型的使用。如果请求 “本地” 卷,则必须指定 Pod 亲和力。 +- `PodOverhead`:启用 [PodOverhead](/docs/concepts/configuration/pod-overhead/) 功能以解决 Pod 开销。 +- `PodPriority`:根据[优先级](/docs/concepts/configuration/pod-priority-preemption/)启用 Pod 的调度和抢占。 +- `PodReadinessGates`:启用 `PodReadinessGate` 字段的设置以扩展 Pod 准备状态评估。有关更多详细信息,请参见 [Pod readiness 功能开关](/docs/concepts/workloads/pods/pod-lifecycle/#pod-readiness-gate)。 + +- `PodShareProcessNamespace`:在 Pod 中启用 `shareProcessNamespace` 的设置,以便在 Pod 中运行的容器之间共享单个进程命名空间。更多详细信息,请参见[在 Pod 中的容器之间共享进程命名空间](/docs/tasks/configure-pod-container/share-process-namespace/)。 +- `ProcMountType`:启用对容器的 ProcMountType 的控制。 +- `PVCProtection`:启用防止任何 Pod 仍使用 PersistentVolumeClaim(PVC) 删除的功能。可以在[此处](/docs/tasks/administer-cluster/storage-object-in-use-protection/)中找到更多详细信息。 +- `QOSReserved`:允许在 QoS 级别进行资源预留,以防止处于较低 QoS 级别的 Pod 突发进入处于较高 QoS 级别的请求资源(仅适用于内存)。 +- `ResourceLimitsPriorityFunction`:启用 scheduler 优先级功能,该功能将最低可能得 1 分配给至少满足输入 Pod 的 cpu 和内存限制之一的节点,目的是打破得分相同的节点之间的联系。 + +- `RequestManagement`:在每个服务器上启用具有优先级和公平性的管理请求并发性。 +- `ResourceQuotaScopeSelectors`:启用资源配额范围选择器。 +- `RotateKubeletClientCertificate`:在 kubelet 上启用客户端 TLS 证书的轮换。有关更多详细信息,请参见 [kubelet 配置](/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#kubelet-configuration)。 +- `RotateKubeletServerCertificate`:在 kubelet 上启用服务器 TLS 证书的轮换。有关更多详细信息,请参见 [kubelet 配置](/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#kubelet-configuration)。 +- `RunAsGroup`:启用对容器初始化过程中设置的主要组 ID 的控制。 +- `RuntimeClass`:启用[RuntimeClass](/docs/concepts/containers/runtime-class/) 功能用于选择容器运行时配置。 +- `ScheduleDaemonSetPods`:启用 DaemonSet Pods 由默认调度程序而不是 DaemonSet 控制器进行调度。 + +- `SCTPSupport`:在 “服务”、“端点”、“NetworkPolicy” 和 “Pod” 定义中,将 SCTP 用作 “协议” 值。 +- `ServerSideApply`:在 API 服务器上启用[服务器端应用(SSA)](/docs/reference/using-api/api-concepts/#server-side-apply) 路径。 +- `ServiceLoadBalancerFinalizer`:为服务负载均衡器启用终结器保护。 +- `ServiceNodeExclusion`:启用从云提供商创建的负载均衡器中排除节点。如果节点标记有 `alpha.service-controller.kubernetes.io/exclude-balancer` 键(启用 `LegacyNodeRoleBehavior` 时)或 `node.kubernetes.io/exclude-from-external-load-balancers`,则可以排除节点。 +- `StartupProbe`:在 kubelet 中启用 [startup](/docs/concepts/workloads/pods/pod-lifecycle/#when-should-you-use-a-startup-probe) 探针。 +- `StorageObjectInUseProtection`:如果仍在使用 PersistentVolume 或 PersistentVolumeClaim 对象,则将其推迟。 + +- `StorageVersionHash`:允许 apiserver 在发现中公开存储版本的哈希值。 +- `StreamingProxyRedirects`:指示 API 服务器拦截(并遵循)从后端(kubelet)进行重定向以处理流请求。流请求的例子包括 `exec`、`attach` 和 `port-forward` 请求。 +- `SupportIPVSProxyMode`:启用使用 IPVS 提供集群内服务负载平衡。有关更多详细信息,请参见[服务代理](/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies)。 +- `SupportPodPidsLimit`:启用支持限制 Pod 中的进程 PID。 +- `Sysctls`:启用对可以为每个 Pod 设置的命名空间内核参数(sysctls)的支持。有关更多详细信息,请参见 [sysctls](/docs/tasks/administer-cluster/sysctl-cluster/)。 + +- `TaintBasedEvictions`:根据节点上的污点和 Pod 上的容忍度启用从节点驱逐 Pod 的功能。有关更多详细信息,请参见[污点和容忍度](/docs/concepts/configuration/taint-and-toleration/)。 +- `TaintNodesByCondition`:根据[节点条件](/docs/concepts/configuration/taint-and-toleration/)启用自动在节点标记污点。 +- `TokenRequest`:在服务帐户资源上启用 `TokenRequest` 端点。 +- `TokenRequestProjection`:启用通过 [`projected` 卷](/docs/concepts/storage/volumes/#projected) 将服务帐户令牌注入到 Pod 中的功能。 +- `TTLAfterFinished`:完成执行后,允许 [TTL 控制器](/docs/concepts/workloads/controllers/ttlafterfinished/)清理资源。 + +- `VolumePVCDataSource`:启用对将现有 PVC 指定数据源的支持。 +- `VolumeScheduling`:启用卷拓扑感知调度,并使 PersistentVolumeClaim(PVC)绑定调度决策;当与 PersistentLocalVolumes 功能开关一起使用时,还可以使用 `PersistentLocalVolumes` 卷类型。 +- `VolumeSnapshotDataSource`:启用卷快照数据源支持。 + +- `VolumeSubpathEnvExpansion`:启用 `subPathExpr` 字段用于将环境变量扩展为 `subPath`。 +- `WatchBookmark`:启用对监测 bookmark 事件的支持。 +- `WindowsGMSA`:允许将 GMSA 凭据规范从 Pod 传递到容器运行时。 +- `WinDSR`:允许 kube-proxy 为 Windows 创建 DSR 负载均衡器。 +- `WinOverlay`:允许 kube-proxy 在 Windows 的 overlay 模式下运行。 + +{{% /capture %}} diff --git a/content/zh/docs/reference/command-line-tools-reference/kube-apiserver.md b/content/zh/docs/reference/command-line-tools-reference/kube-apiserver.md index 061865f7db..f24899755f 100644 --- a/content/zh/docs/reference/command-line-tools-reference/kube-apiserver.md +++ b/content/zh/docs/reference/command-line-tools-reference/kube-apiserver.md @@ -9,7 +9,7 @@ notitle: true ### 概要 -Kubernetes API server 为 api 对象验证并配置数据,包括 pods、 services、 replicationcontrollers和其它 api 对象。API Server 提供 REST 操作和到集群共享状态的前端,所有其他组件通过它进行交互。 +Kubernetes API server 为 api 对象验证并配置数据,包括 pods、 services、 replicationcontrollers 和其它 api 对象。API Server 提供 REST 操作和到集群共享状态的前端,所有其他组件通过它进行交互。 ``` kube-apiserver @@ -18,99 +18,99 @@ kube-apiserver ### 选项 ``` - --admission-control stringSlice 控制资源进入集群的准入控制插件的顺序列表。逗号分隔的NamespaceLifecycle列表。(默认值[AlwaysAdmit]) + --admission-control stringSlice 控制资源进入集群的准入控制插件的顺序列表。逗号分隔的 NamespaceLifecycle 列表。(默认值 [AlwaysAdmit]) --admission-control-config-file string 包含准入控制配置的文件。 - --advertise-address ip 向集群成员通知apiserver消息的IP地址。这个地址必须能够被集群中其他成员访问。如果IP地址为空,将会使用--bind-address,如果未指定--bind-address,将会使用主机的默认接口地址。 + --advertise-address ip 向集群成员通知 apiserver 消息的 IP 地址。这个地址必须能够被集群中其他成员访问。如果 IP 地址为空,将会使用 --bind-address,如果未指定 --bind-address,将会使用主机的默认接口地址。 - --allow-privileged 如果为true, 将允许特权容器. + --allow-privileged 如果为 true, 将允许特权容器。 - --anonymous-auth 启用到API server的安全端口的匿名请求。未被其他认证方法拒绝的请求被当做匿名请求。匿名请求的用户名为system:anonymous,用户组名为system:unauthenticated。(默认值true) + --anonymous-auth 启用到 API server 的安全端口的匿名请求。未被其他认证方法拒绝的请求被当做匿名请求。匿名请求的用户名为 system:anonymous,用户组名为 system:unauthenticated。(默认值 true) - --apiserver-count int 集群中运行的apiserver数量,必须为正数。(默认值1) + --apiserver-count int 集群中运行的 apiserver 数量,必须为正数。(默认值 1) --audit-log-maxage int 基于文件名中的时间戳,旧审计日志文件的最长保留天数。 - --audit-log-maxbackup int 旧审计日志文件的最大保留个数. + --audit-log-maxbackup int 旧审计日志文件的最大保留个数。 --audit-log-maxsize int 审计日志被轮转前的最大兆字节数。 - --audit-log-path string 如果设置该值,所有到apiserver的请求都将会被记录到这个文件。'-'表示记录到标准输出。 + --audit-log-path string 如果设置该值,所有到 apiserver 的请求都将会被记录到这个文件。'-' 表示记录到标准输出。 - --audit-policy-file string 定义审计策略配置的文件的路径。需要打开'AdvancedAuditing'特性开关。AdvancedAuditing需要一个配置来启用审计功能。 + --audit-policy-file string 定义审计策略配置的文件的路径。需要打开 'AdvancedAuditing' 特性开关。AdvancedAuditing 需要一个配置来启用审计功能。 - --audit-webhook-config-file string 一个具有kubeconfig格式文件的路径,该文件定义了审计的webhook配置。需要打开'AdvancedAuditing'特性开关。 + --audit-webhook-config-file string 一个具有 kubeconfig 格式文件的路径,该文件定义了审计的 webhook 配置。需要打开 'AdvancedAuditing' 特性开关。 - --audit-webhook-mode string 发送审计事件的策略。 Blocking模式表示正在发送事件时应该阻塞服务器的响应。 Batch模式使webhook异步缓存和发送事件。 Known模式为batch,blocking。 (默认值"batch") + --audit-webhook-mode string 发送审计事件的策略。 Blocking 模式表示正在发送事件时应该阻塞服务器的响应。 Batch 模式使 webhook 异步缓存和发送事件。 Known 模式为 batch,blocking。(默认值 "batch") - --authentication-token-webhook-cache-ttl duration 从webhook令牌认证者获取的响应的缓存时长。(默认值2m0s) + --authentication-token-webhook-cache-ttl duration 从 webhook 令牌认证者获取的响应的缓存时长。( 默认值 2m0s) - --authentication-token-webhook-config-file string 包含webhook配置的文件,用于令牌认证,具有kubeconfig格式。API server将查询远程服务来决定对bearer令牌的认证。 + --authentication-token-webhook-config-file string 包含 webhook 配置的文件,用于令牌认证,具有 kubeconfig 格式。API server 将查询远程服务来决定对 bearer 令牌的认证。 - --authorization-mode string 在安全端口上进行权限验证的插件的顺序列表。以逗号分隔的列表,包括:AlwaysAllow,AlwaysDeny,ABAC,Webhook,RBAC,Node.(默认值"AlwaysAllow") + --authorization-mode string 在安全端口上进行权限验证的插件的顺序列表。以逗号分隔的列表,包括:AlwaysAllow,AlwaysDeny,ABAC,Webhook,RBAC,Node.(默认值 "AlwaysAllow") + + --authorization-policy-file string 包含权限验证策略的 csv 文件,和 --authorization-mode=ABAC 一起使用,作用在安全端口上。 + + --authorization-webhook-cache-authorized-ttl duration 从 webhook 授权者获得的 'authorized' 响应的缓存时长。(默认值 5m0s) + + --authorization-webhook-cache-unauthorized-ttl duration 从 webhook 授权者获得的 'unauthorized' 响应的缓存时长。(默认值 30s) + + --authorization-webhook-config-file string 包含 webhook 配置的 kubeconfig 格式文件,和 --authorization-mode=Webhook 一起使用。API server 将查询远程服务来决定对 API server 安全端口的访问。 + + --azure-container-registry-config string 包含 Azure 容器注册表配置信息的文件的路径。 - --authorization-policy-file string 包含权限验证策略的csv文件,和--authorization-mode=ABAC一起使用,作用在安全端口上。 + --basic-auth-file string 如果设置该值,这个文件将会被用于准许通过 http 基本认证到 API server 安全端口的请求。 - --authorization-webhook-cache-authorized-ttl duration 从webhook授权者获得的'authorized'响应的缓存时长。(默认值5m0s) + --bind-address ip 监听 --seure-port 的 IP 地址。被关联的接口必须能够被集群其它节点和 CLI/web 客户端访问。如果为空,则将使用所有接口(0.0.0.0)。(默认值 0.0.0.0) - --authorization-webhook-cache-unauthorized-ttl duration 从webhook授权者获得的'unauthorized'响应的缓存时长。(默认值30s) - - --authorization-webhook-config-file string 包含webhook配置的kubeconfig格式文件,和--authorization-mode=Webhook一起使用。API server将查询远程服务来决定对API server安全端口的访问。 - - --azure-container-registry-config string 包含Azure容器注册表配置信息的文件的路径。 - - --basic-auth-file string 如果设置该值,这个文件将会被用于准许通过http基本认证到API server安全端口的请求。 - - --bind-address ip 监听--seure-port的IP地址。被关联的接口必须能够被集群其它节点和CLI/web客户端访问。如果为空,则将使用所有接口(0.0.0.0)。(默认值0.0.0.0) - - --cert-dir string 存放TLS证书的目录。如果提供了--tls-cert-file和--tls-private-key-file选项,该标志将被忽略。(默认值 "/var/run/kubernetes") - - --client-ca-file string 如果设置此标志,对于任何请求,如果存包含client-ca-file中的authorities签名的客户端证书,将会使用客户端证书中的CommonName对应的身份进行认证。 - - --cloud-config string 云服务提供商配置文件路径。空字符串表示无配置文件. + --cert-dir string 存放 TLS 证书的目录。如果提供了 --tls-cert-file 和 --tls-private-key-file 选项,该标志将被忽略。(默认值 "/var/run/kubernetes") + --client-ca-file string 如果设置此标志,对于任何请求,如果存包含 client-ca-file 中的 authorities 签名的客户端证书,将会使用客户端证书中的 CommonName 对应的身份进行认证。 + + --cloud-config string 云服务提供商配置文件路径。空字符串表示无配置文件 . + --cloud-provider string 云服务提供商,空字符串表示无提供商。 + + --contention-profiling 如果已经启用 profiling,则启用锁竞争 profiling。 - --contention-profiling 如果已经启用profiling,则启用锁竞争profiling。 + --cors-allowed-origins stringSlice CORS 的域列表,以逗号分隔。合法的域可以是一个匹配子域名的正则表达式。如果这个列表为空则不会启用 CORS. - --cors-allowed-origins stringSlice CORS的域列表,以逗号分隔。合法的域可以是一个匹配子域名的正则表达式。如果这个列表为空则不会启用CORS. + --delete-collection-workers int 用于 DeleteCollection 调用的工作者数量。这被用于加速 namespace 的清理。( 默认值 1) - --delete-collection-workers int 用于DeleteCollection调用的工作者数量。这被用于加速namespace的清理。(默认值1) + --deserialization-cache-size int 在内存中缓存的反序列化 json 对象的数量。 - --deserialization-cache-size int 在内存中缓存的反序列化json对象的数量。 + --enable-aggregator-routing 打开到 endpoints IP 的 aggregator 路由请求,替换 cluster IP。 - --enable-aggregator-routing 打开到endpoints IP的aggregator路由请求,替换cluster IP。 + --enable-garbage-collector 启用通用垃圾回收器 . 必须与 kube-controller-manager 对应的标志保持同步。 (默认值 true) - --enable-garbage-collector 启用通用垃圾回收器. 必须与kube-controller-manager对应的标志保持同步。 (默认值true) + --enable-logs-handler 如果为 true,则为 apiserver 日志功能安装一个 /logs 处理器。(默认值 true) - --enable-logs-handler 如果为true,则为apiserver日志功能安装一个/logs处理器。(默认值true) + --enable-swagger-ui 在 apiserver 的 /swagger-ui 路径启用 swagger ui。 - --enable-swagger-ui 在apiserver的/swagger-ui路径启用swagger ui。 + --etcd-cafile string 用于保护 etcd 通信的 SSL CA 文件。 - --etcd-cafile string 用于保护etcd通信的SSL CA文件。 + --etcd-certfile string 用于保护 etcd 通信的的 SSL 证书文件。 - --etcd-certfile string 用于保护etcd通信的的SSL证书文件。 + --etcd-keyfile string 用于保护 etcd 通信的 SSL 密钥文件 . - --etcd-keyfile string 用于保护etcd通信的SSL密钥文件. + --etcd-prefix string 附加到所有 etcd 中资源路径的前缀。 (默认值 "/registry") - --etcd-prefix string 附加到所有etcd中资源路径的前缀。 (默认值"/registry") + --etcd-quorum-read 如果为 true, 启用 quorum 读。 - --etcd-quorum-read 如果为true, 启用quorum读。 + --etcd-servers stringSlice 连接的 etcd 服务器列表 , 形式为(scheme://ip:port),使用逗号分隔。 - --etcd-servers stringSlice 连接的etcd服务器列表,形式为(scheme://ip:port),使用逗号分隔。 + --etcd-servers-overrides stringSlice 针对单个资源的 etcd 服务器覆盖配置 , 以逗号分隔。 单个配置覆盖格式为 : group/resource#servers, 其中 servers 形式为 http://ip:port, 以分号分隔。 - --etcd-servers-overrides stringSlice 针对单个资源的etcd服务器覆盖配置, 以逗号分隔。 单个配置覆盖格式为: group/resource#servers, 其中servers形式为http://ip:port, 以分号分隔。 + --event-ttl duration 事件驻留时间。(默认值 1h0m0s) - --event-ttl duration 事件驻留时间。(默认值1h0m0s) + --enable-bootstrap-token-auth 启用此选项以允许 'kube-system' 命名空间中的 'bootstrap.kubernetes.io/token' 类型密钥可以被用于 TLS 的启动认证。 - --enable-bootstrap-token-auth 启用此选项以允许'kube-system'命名空间中的'bootstrap.kubernetes.io/token'类型密钥可以被用于TLS的启动认证。 + --experimental-encryption-provider-config string 包含加密提供程序的配置的文件,该加密提供程序被用于在 etcd 中保存密钥。 - --experimental-encryption-provider-config string 包含加密提供程序的配置的文件,该加密提供程序被用于在etcd中保存密钥。 + --external-hostname string 为此 master 生成外部 URL 时使用的主机名 ( 例如 Swagger API 文档 )。 - --external-hostname string 为此master生成外部URL时使用的主机名(例如Swagger API文档)。 - - --feature-gates mapStringBool 一个描述alpha/experimental特性开关的键值对列表。 选项包括: + --feature-gates mapStringBool 一个描述 alpha/experimental 特性开关的键值对列表。 选项包括 : Accelerators=true|false (ALPHA - default=false) AdvancedAuditing=true|false (ALPHA - default=false) AffinityInAnnotations=true|false (ALPHA - default=false) @@ -128,102 +128,102 @@ RotateKubeletServerCertificate=true|false (ALPHA - default=false) StreamingProxyRedirects=true|false (BETA - default=true) TaintBasedEvictions=true|false (ALPHA - default=false) - --google-json-key string 用于认证的Google Cloud Platform服务账号的JSON密钥。 + --google-json-key string 用于认证的 Google Cloud Platform 服务账号的 JSON 密钥。 - --insecure-allow-any-token username/group1,group2 如果设置该值, 你的服务将处于非安全状态。任何令牌都将会被允许,并将从令牌中把用户信息解析成为username/group1,group2。 + --insecure-allow-any-token username/group1,group2 如果设置该值 , 你的服务将处于非安全状态。任何令牌都将会被允许,并将从令牌中把用户信息解析成为 username/group1,group2。 - --insecure-bind-address ip 用于监听--insecure-port的IP地址 (设置成0.0.0.0表示监听所有接口)。(默认值127.0.0.1) + --insecure-bind-address ip 用于监听 --insecure-port 的 IP 地址 ( 设置成 0.0.0.0 表示监听所有接口 )。(默认值 127.0.0.1) - --insecure-port int 用于监听不安全和为认证访问的端口。这个配置假设你已经设置了防火墙规则,使得这个端口不能从集群外访问。对集群的公共地址的443端口的访问将被代理到这个端口。默认设置中使用nginx实现。(默认值8080) + --insecure-port int 用于监听不安全和为认证访问的端口。这个配置假设你已经设置了防火墙规则,使得这个端口不能从集群外访问。对集群的公共地址的 443 端口的访问将被代理到这个端口。默认设置中使用 nginx 实现。(默认值 8080) - --kubelet-certificate-authority string 证书authority的文件路径。 + --kubelet-certificate-authority string 证书 authority 的文件路径。 - --kubelet-client-certificate string 用于TLS的客户端证书文件路径。 + --kubelet-client-certificate string 用于 TLS 的客户端证书文件路径。 - --kubelet-client-key string 用于TLS的客户端证书密钥文件路径. + --kubelet-client-key string 用于 TLS 的客户端证书密钥文件路径 . - --kubelet-https 为kubelet启用https。 (默认值true) + --kubelet-https 为 kubelet 启用 https。 (默认值 true) - --kubelet-preferred-address-types stringSlice 用于kubelet连接的首选NodeAddressTypes列表。 (默认值[Hostname,InternalDNS,InternalIP,ExternalDNS,ExternalIP]) + --kubelet-preferred-address-types stringSlice 用于 kubelet 连接的首选 NodeAddressTypes 列表。 ( 默认值[Hostname,InternalDNS,InternalIP,ExternalDNS,ExternalIP]) - --kubelet-read-only-port uint 已废弃: kubelet端口. (默认值10255) + --kubelet-read-only-port uint 已废弃 : kubelet 端口 . (默认值 10255) - --kubelet-timeout duration kubelet操作超时时间。(默认值 + --kubelet-timeout duration kubelet 操作超时时间。(默认值 5s) - --kubernetes-service-node-port int 如果不为0,Kubernetes master服务(用于创建/管理apiserver)将会使用NodePort类型,并将这个值作为端口号。如果为0,Kubernetes master服务将会使用ClusterIP类型。 + --kubernetes-service-node-port int 如果不为 0,Kubernetes master 服务(用于创建 / 管理 apiserver)将会使用 NodePort 类型,并将这个值作为端口号。如果为 0,Kubernetes master 服务将会使用 ClusterIP 类型。 - --master-service-namespace string 已废弃: 注入到pod中的kubernetes master服务的命名空间。(默认值"default") + --master-service-namespace string 已废弃 : 注入到 pod 中的 kubernetes master 服务的命名空间。(默认值 "default") - --max-connection-bytes-per-sec int 如果不为0,每个用户连接将会被限速为该值(bytes/sec)。当前只应用于长时间运行的请求。 + --max-connection-bytes-per-sec int 如果不为 0,每个用户连接将会被限速为该值(bytes/sec)。当前只应用于长时间运行的请求。 - --max-mutating-requests-inflight int 在给定时间内进行中可变请求的最大数量。当超过该值时,服务将拒绝所有请求。0值表示没有限制。(默认值200) + --max-mutating-requests-inflight int 在给定时间内进行中可变请求的最大数量。当超过该值时,服务将拒绝所有请求。0 值表示没有限制。(默认值 200) - --max-requests-inflight int 在给定时间内进行中不可变请求的最大数量。当超过该值时,服务将拒绝所有请求。0值表示没有限制。(默认值400) + --max-requests-inflight int 在给定时间内进行中不可变请求的最大数量。当超过该值时,服务将拒绝所有请求。0 值表示没有限制。(默认值 400) - --min-request-timeout int 一个可选字段,表示一个handler在一个请求超时前,必须保持它处于打开状态的最小秒数。当前只对监听请求handler有效,它基于这个值选择一个随机数作为连接超时值,以达到分散负载的目的(默认值1800)。 + --min-request-timeout int 一个可选字段,表示一个 handler 在一个请求超时前,必须保持它处于打开状态的最小秒数。当前只对监听请求 handler 有效,它基于这个值选择一个随机数作为连接超时值,以达到分散负载的目的(默认值 1800)。 + + --oidc-ca-file string 如果设置该值,将会使用 oidc-ca-file 中的任意一个 authority 对 OpenID 服务的证书进行验证,否则将会使用主机的根 CA 对其进行验证。 + + --oidc-client-id string 使用 OpenID 连接的客户端的 ID,如果设置了 oidc-issuer-url,则必须设置这个值。 + + --oidc-groups-claim string 如果提供该值,这个自定义 OpenID 连接名将指定给特定的用户组。该声明值需要是一个字符串或字符串数组。此标志为实验性的,请查阅验证相关文档进一步了解详细信息。 - --oidc-ca-file string 如果设置该值,将会使用oidc-ca-file中的任意一个authority对OpenID服务的证书进行验证,否则将会使用主机的根CA对其进行验证。 + --oidc-issuer-url string OpenID 颁发者 URL,只接受 HTTPS 方案。如果设置该值,它将被用于验证 OIDC JSON Web Token(JWT)。 + + --oidc-username-claim string 用作用户名的 OpenID 声明值。注意,不保证除默认 ('sub') 外的其他声明值的唯一性和不变性。此标志为实验性的,请查阅验证相关文档进一步了解详细信息。 + + --profiling 在 web 接口 host:port/debug/pprof/ 上启用 profiling。(默认值 true) + + --proxy-client-cert-file string 当必须调用外部程序时,用于证明 aggregator 或者 kube-apiserver 的身份的客户端证书。包括代理到用户 api-server 的请求和调用 webhook 准入控制插件的请求。它期望这个证书包含一个来自于 CA 中的 --requestheader-client-ca-file 标记的签名。该 CA 在 kube-system 命名空间的 'extension-apiserver-authentication' configmap 中发布。从 Kube-aggregator 收到调用的组件应该使用该 CA 进行他们部分的双向 TLS 验证。 + + --proxy-client-key-file string 当必须调用外部程序时,用于证明 aggregator 或者 kube-apiserver 的身份的客户端证书密钥。包括代理到用户 api-server 的请求和调用 webhook 准入控制插件的请求。 + + --repair-malformed-updates 如果为 true,服务将会尽力修复更新请求以通过验证,例如:将更新请求 UID 的当前值设置为空。在我们修复了所有发送错误格式请求的客户端后,可以关闭这个标志。 - --oidc-client-id string 使用OpenID连接的客户端的ID,如果设置了oidc-issuer-url,则必须设置这个值。 - - --oidc-groups-claim string 如果提供该值,这个自定义OpenID连接名将指定给特定的用户组。该声明值需要是一个字符串或字符串数组。此标志为实验性的,请查阅验证相关文档进一步了解详细信息。 - - --oidc-issuer-url string OpenID颁发者URL,只接受HTTPS方案。如果设置该值,它将被用于验证OIDC JSON Web Token(JWT)。 - - --oidc-username-claim string 用作用户名的OpenID声明值。注意,不保证除默认 ('sub')外的其他声明值的唯一性和不变性。此标志为实验性的,请查阅验证相关文档进一步了解详细信息。 - - --profiling 在web接口host:port/debug/pprof/上启用profiling。(默认值true) - - --proxy-client-cert-file string 当必须调用外部程序时,用于证明aggregator或者kube-apiserver的身份的客户端证书。包括代理到用户api-server的请求和调用webhook准入控制插件的请求。它期望这个证书包含一个来自于CA中的--requestheader-client-ca-file标记的签名。该CA在kube-system命名空间的'extension-apiserver-authentication' configmap中发布。从Kube-aggregator收到调用的组件应该使用该CA进行他们部分的双向TLS验证。 - - --proxy-client-key-file string 当必须调用外部程序时,用于证明aggregator或者kube-apiserver的身份的客户端证书密钥。包括代理到用户api-server的请求和调用webhook准入控制插件的请求。 - - --repair-malformed-updates 如果为true,服务将会尽力修复更新请求以通过验证,例如:将更新请求UID的当前值设置为空。在我们修复了所有发送错误格式请求的客户端后,可以关闭这个标志。 - - --requestheader-allowed-names stringSlice 使用--requestheader-username-headers指定的,允许在头部提供用户名的客户端证书通用名称列表。如果为空,任何通过--requestheader-client-ca-file中authorities验证的客户端证书都是被允许的。 - - --requestheader-client-ca-file string 在信任请求头中以--requestheader-username-headers指示的用户名之前,用于验证接入请求中客户端证书的根证书捆绑。 - - --requestheader-extra-headers-prefix stringSlice 用于检查的请求头的前缀列表。建议使用X-Remote-Extra-。 - - --requestheader-group-headers stringSlice 用于检查群组的请求头列表。建议使用X-Remote-Group. - - --requestheader-username-headers stringSlice 用于检查用户名的请求头列表。建议使用X-Remote-User。 - - --runtime-config mapStringString 传递给apiserver用于描述运行时配置的键值对集合。 apis/键可以被用来打开/关闭特定的api版本。apis//键被用来打开/关闭特定的资源. api/all和api/legacy键分别用于控制所有的和遗留的api版本. - - --secure-port int 用于监听具有认证授权功能的HTTPS协议的端口。如果为0,则不会监听HTTPS协议。 (默认值6443) - - --service-account-key-file stringArray 包含PEM加密的x509 RSA或ECDSA私钥或公钥的文件,用于验证ServiceAccount令牌。如果设置该值,--tls-private-key-file将会被使用。指定的文件可以包含多个密钥,并且这个标志可以和不同的文件一起多次使用。 - - --service-cluster-ip-range ipNet CIDR表示的IP范围,服务的cluster ip将从中分配。 一定不要和分配给nodes和pods的IP范围产生重叠。 - - --ssh-keyfile string 如果不为空,在使用安全的SSH代理访问节点时,将这个文件作为用户密钥文件。 - - --storage-backend string 持久化存储后端。 选项为: 'etcd3' (默认), 'etcd2'. + --requestheader-allowed-names stringSlice 使用 --requestheader-username-headers 指定的,允许在头部提供用户名的客户端证书通用名称列表。如果为空,任何通过 --requestheader-client-ca-file 中 authorities 验证的客户端证书都是被允许的。 + + --requestheader-client-ca-file string 在信任请求头中以 --requestheader-username-headers 指示的用户名之前,用于验证接入请求中客户端证书的根证书捆绑。 + + --requestheader-extra-headers-prefix stringSlice 用于检查的请求头的前缀列表。建议使用 X-Remote-Extra-。 + --requestheader-group-headers stringSlice 用于检查群组的请求头列表。建议使用 X-Remote-Group. + + --requestheader-username-headers stringSlice 用于检查用户名的请求头列表。建议使用 X-Remote-User。 + + --runtime-config mapStringString 传递给 apiserver 用于描述运行时配置的键值对集合。 apis/ 键可以被用来打开 / 关闭特定的 api 版本。apis// 键被用来打开 / 关闭特定的资源 . api/all 和 api/legacy 键分别用于控制所有的和遗留的 api 版本 . + + --secure-port int 用于监听具有认证授权功能的 HTTPS 协议的端口。如果为 0,则不会监听 HTTPS 协议。 (默认值 6443) + + --service-account-key-file stringArray 包含 PEM 加密的 x509 RSA 或 ECDSA 私钥或公钥的文件,用于验证 ServiceAccount 令牌。如果设置该值,--tls-private-key-file 将会被使用。指定的文件可以包含多个密钥,并且这个标志可以和不同的文件一起多次使用。 + + --service-cluster-ip-range ipNet CIDR 表示的 IP 范围,服务的 cluster ip 将从中分配。 一定不要和分配给 nodes 和 pods 的 IP 范围产生重叠。 + + --ssh-keyfile string 如果不为空,在使用安全的 SSH 代理访问节点时,将这个文件作为用户密钥文件。 + + --storage-backend string 持久化存储后端。 选项为 : 'etcd3' ( 默认 ), 'etcd2'. + --storage-media-type string 在存储中保存对象的媒体类型。某些资源或者存储后端可能仅支持特定的媒体类型,并且忽略该配置项。(默认值 "application/vnd.kubernetes.protobuf") - - --storage-versions string 按组划分资源存储的版本。 以"group1/version1,group2/version2,..."的格式指定。当对象从一组移动到另一组时, 你可以指定"group1=group2/v1beta1,group3/v1beta1,..."的格式。你只需要传入你希望从结果中改变的组的列表。默认为从KUBE_API_VERSIONS环境变量集成而来,所有注册组的首选版本列表。 (默认值"admission.k8s.io/v1alpha1,admissionregistration.k8s.io/v1alpha1,apps/v1beta1,authentication.k8s.io/v1,authorization.k8s.io/v1,autoscaling/v1,batch/v1,certificates.k8s.io/v1beta1,componentconfig/v1alpha1,extensions/v1beta1,federation/v1beta1,imagepolicy.k8s.io/v1alpha1,networking.k8s.io/v1,policy/v1beta1,rbac.authorization.k8s.io/v1beta1,settings.k8s.io/v1alpha1,storage.k8s.io/v1,v1") - - --target-ram-mb int apiserver内存限制,单位为MB(用于配置缓存大小等)。 - - --tls-ca-file string 如果设置该值,这个证书authority将会被用于从Admission Controllers过来的安全访问。它必须是一个PEM加密的合法CA捆绑包。此外, 该证书authority可以被添加到以--tls-cert-file提供的证书文件中. - - --tls-cert-file string 包含用于HTTPS的默认x509证书的文件。(如果有CA证书,则附加于server证书之后)。如果启用了HTTPS服务,并且没有提供--tls-cert-file和--tls-private-key-file,则将为公共地址生成一个自签名的证书和密钥并保存于/var/run/kubernetes目录。 - - --tls-private-key-file string 包含匹配--tls-cert-file的x509证书私钥的文件。 - - --tls-sni-cert-key namedCertKey 一对x509证书和私钥的文件路径, 可以使用符合正式域名的域形式作为后缀。 如果没有提供域形式后缀, 则将提取证书名。 非通配符版本优先于通配符版本, 显示的域形式优先于证书中提取的名字。 对于多个密钥/证书对, 请多次使用--tls-sni-cert-key。例如: "example.crt,example.key" or "foo.crt,foo.key:*.foo.com,foo.com". (默认值[]) - - --token-auth-file string 如果设置该值,这个文件将被用于通过令牌认证来保护API服务的安全端口。 - + + --storage-versions string 按组划分资源存储的版本。 以 "group1/version1,group2/version2,..." 的格式指定。当对象从一组移动到另一组时 , 你可以指定 "group1=group2/v1beta1,group3/v1beta1,..." 的格式。你只需要传入你希望从结果中改变的组的列表。默认为从 KUBE_API_VERSIONS 环境变量集成而来,所有注册组的首选版本列表。 (默认值 "admission.k8s.io/v1alpha1,admissionregistration.k8s.io/v1alpha1,apps/v1beta1,authentication.k8s.io/v1,authorization.k8s.io/v1,autoscaling/v1,batch/v1,certificates.k8s.io/v1beta1,componentconfig/v1alpha1,extensions/v1beta1,federation/v1beta1,imagepolicy.k8s.io/v1alpha1,networking.k8s.io/v1,policy/v1beta1,rbac.authorization.k8s.io/v1beta1,settings.k8s.io/v1alpha1,storage.k8s.io/v1,v1") + + --target-ram-mb int apiserver 内存限制,单位为 MB( 用于配置缓存大小等 )。 + + --tls-ca-file string 如果设置该值,这个证书 authority 将会被用于从 Admission Controllers 过来的安全访问。它必须是一个 PEM 加密的合法 CA 捆绑包。此外 , 该证书 authority 可以被添加到以 --tls-cert-file 提供的证书文件中 . + + --tls-cert-file string 包含用于 HTTPS 的默认 x509 证书的文件。(如果有 CA 证书,则附加于 server 证书之后)。如果启用了 HTTPS 服务,并且没有提供 --tls-cert-file 和 --tls-private-key-file,则将为公共地址生成一个自签名的证书和密钥并保存于 /var/run/kubernetes 目录。 + + --tls-private-key-file string 包含匹配 --tls-cert-file 的 x509 证书私钥的文件。 + + --tls-sni-cert-key namedCertKey 一对 x509 证书和私钥的文件路径 , 可以使用符合正式域名的域形式作为后缀。 如果没有提供域形式后缀 , 则将提取证书名。 非通配符版本优先于通配符版本 , 显示的域形式优先于证书中提取的名字。 对于多个密钥 / 证书对, 请多次使用 --tls-sni-cert-key。例如 : "example.crt,example.key" or "foo.crt,foo.key:*.foo.com,foo.com". (默认值[]) + + --token-auth-file string 如果设置该值,这个文件将被用于通过令牌认证来保护 API 服务的安全端口。 + --version version[=true] 打印版本信息并退出。 - - --watch-cache 启用apiserver的监视缓存。(默认值true) - - --watch-cache-sizes stringSlice 每种资源(pods, nodes等)的监视缓存大小列表,以逗号分隔。每个缓存配置的形式为:resource#size,size是一个数字。在watch-cache启用时生效。 + + --watch-cache 启用 apiserver 的监视缓存。(默认值 true) + + --watch-cache-sizes stringSlice 每种资源(pods, nodes 等)的监视缓存大小列表,以逗号分隔。每个缓存配置的形式为:resource#size,size 是一个数字。在 watch-cache 启用时生效。 ``` ###### Auto generated by spf13/cobra on 11-Jul-2017 diff --git a/content/zh/docs/reference/command-line-tools-reference/kube-controller-manager.md b/content/zh/docs/reference/command-line-tools-reference/kube-controller-manager.md new file mode 100644 index 0000000000..448f0de7ae --- /dev/null +++ b/content/zh/docs/reference/command-line-tools-reference/kube-controller-manager.md @@ -0,0 +1,818 @@ +--- +title: kube-controller-manager +notitle: true +--- + +## kube-controller-manager + + + +### 概述 + + + +Kubernetes 控制器管理器是一个守护进程,嵌入了 Kubernetes 附带的核心控制循环。 在机器人和自动化的应用中,控制回路是一个永不休止的循环,用于调节系统状态。 在 Kubernetes 中,控制器是一个控制循环,它通过 apiserver 监视集群的共享状态,并尝试进行更改以将当前状态转为所需状态。现今,Kubernetes 自带的控制器包括副本控制器,节点控制器,命名空间控制器和serviceaccounts 控制器。 + +``` +kube-controller-manager [flags] +``` + + +### 选项 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--allocate-node-cidrs
Should CIDRs for Pods be allocated and set on the cloud provider.
--alsologtostderr
log to standard error as well as files
--attach-detach-reconcile-sync-period duration     Default: 1m0s
The reconciler sync wait time between volume attach detach. This duration must be larger than one second, and increasing this value from the default may allow for volumes to be mismatched with pods.
--authentication-kubeconfig string
kubeconfig file pointing at the 'core' kubernetes server with enough rights to create tokenaccessreviews.authentication.k8s.io. This is optional. If empty, all token requests are considered to be anonymous and no client CA is looked up in the cluster.
--authentication-skip-lookup
If false, the authentication-kubeconfig will be used to lookup missing authentication configuration from the cluster.
--authentication-token-webhook-cache-ttl duration     Default: 10s
The duration to cache responses from the webhook token authenticator.
--authentication-tolerate-lookup-failure
If true, failures to look up missing authentication configuration from the cluster are not considered fatal. Note that this can result in authentication that treats all requests as anonymous.
--authorization-always-allow-paths stringSlice     Default: [/healthz]
A list of HTTP paths to skip during authorization, i.e. these are authorized without contacting the 'core' kubernetes server.
--authorization-kubeconfig string
kubeconfig file pointing at the 'core' kubernetes server with enough rights to create subjectaccessreviews.authorization.k8s.io. This is optional. If empty, all requests not skipped by authorization are forbidden.
--authorization-webhook-cache-authorized-ttl duration     Default: 10s
The duration to cache 'authorized' responses from the webhook authorizer.
--authorization-webhook-cache-unauthorized-ttl duration     Default: 10s
The duration to cache 'unauthorized' responses from the webhook authorizer.
--azure-container-registry-config string
Path to the file containing Azure container registry configuration information.
--bind-address ip     Default: 0.0.0.0
The IP address on which to listen for the --secure-port port. The associated interface(s) must be reachable by the rest of the cluster, and by CLI/web clients. If blank, all interfaces will be used (0.0.0.0 for all IPv4 interfaces and :: for all IPv6 interfaces).
--cert-dir string
The directory where the TLS certs are located. If --tls-cert-file and --tls-private-key-file are provided, this flag will be ignored.
--cidr-allocator-type string     Default: "RangeAllocator"
Type of CIDR allocator to use
--client-ca-file string
If set, any request presenting a client certificate signed by one of the authorities in the client-ca-file is authenticated with an identity corresponding to the CommonName of the client certificate.
--cloud-config string
The path to the cloud provider configuration file. Empty string for no configuration file.
--cloud-provider string
The provider for cloud services. Empty string for no provider.
--cluster-cidr string
CIDR Range for Pods in cluster. Requires --allocate-node-cidrs to be true
--cluster-name string     Default: "kubernetes"
The instance prefix for the cluster.
--cluster-signing-cert-file string     Default: "/etc/kubernetes/ca/ca.pem"
Filename containing a PEM-encoded X509 CA certificate used to issue cluster-scoped certificates
--cluster-signing-key-file string     Default: "/etc/kubernetes/ca/ca.key"
Filename containing a PEM-encoded RSA or ECDSA private key used to sign cluster-scoped certificates
--concurrent-deployment-syncs int32     Default: 5
The number of deployment objects that are allowed to sync concurrently. Larger number = more responsive deployments, but more CPU (and network) load
--concurrent-endpoint-syncs int32     Default: 5
The number of endpoint syncing operations that will be done concurrently. Larger number = faster endpoint updating, but more CPU (and network) load
--concurrent-gc-syncs int32     Default: 20
The number of garbage collector workers that are allowed to sync concurrently.
--concurrent-namespace-syncs int32     Default: 10
The number of namespace objects that are allowed to sync concurrently. Larger number = more responsive namespace termination, but more CPU (and network) load
--concurrent-replicaset-syncs int32     Default: 5
The number of replica sets that are allowed to sync concurrently. Larger number = more responsive replica management, but more CPU (and network) load
--concurrent-resource-quota-syncs int32     Default: 5
The number of resource quotas that are allowed to sync concurrently. Larger number = more responsive quota management, but more CPU (and network) load
--concurrent-service-syncs int32     Default: 1
The number of services that are allowed to sync concurrently. Larger number = more responsive service management, but more CPU (and network) load
--concurrent-serviceaccount-token-syncs int32     Default: 5
The number of service account token objects that are allowed to sync concurrently. Larger number = more responsive token generation, but more CPU (and network) load
--concurrent-ttl-after-finished-syncs int32     Default: 5
The number of TTL-after-finished controller workers that are allowed to sync concurrently.
--concurrent_rc_syncs int32     Default: 5
The number of replication controllers that are allowed to sync concurrently. Larger number = more responsive replica management, but more CPU (and network) load
--configure-cloud-routes     Default: true
Should CIDRs allocated by allocate-node-cidrs be configured on the cloud provider.
--contention-profiling
Enable lock contention profiling, if profiling is enabled
--controller-start-interval duration
Interval between starting controller managers.
--controllers stringSlice     Default: [*]
A list of controllers to enable. '*' enables all on-by-default controllers, 'foo' enables the controller named 'foo', '-foo' disables the controller named 'foo'.
All controllers: attachdetach, bootstrapsigner, cloud-node-lifecycle, clusterrole-aggregation, cronjob, csrapproving, csrcleaner, csrsigning, daemonset, deployment, disruption, endpoint, garbagecollector, horizontalpodautoscaling, job, namespace, nodeipam, nodelifecycle, persistentvolume-binder, persistentvolume-expander, podgc, pv-protection, pvc-protection, replicaset, replicationcontroller, resourcequota, root-ca-cert-publisher, route, service, serviceaccount, serviceaccount-token, statefulset, tokencleaner, ttl, ttl-after-finished
Disabled-by-default controllers: bootstrapsigner, tokencleaner
--deployment-controller-sync-period duration     Default: 30s
Period for syncing the deployments.
--disable-attach-detach-reconcile-sync
Disable volume attach detach reconciler sync. Disabling this may cause volumes to be mismatched with pods. Use wisely.
--enable-dynamic-provisioning     Default: true
Enable dynamic provisioning for environments that support it.
--enable-garbage-collector     Default: true
Enables the generic garbage collector. MUST be synced with the corresponding flag of the kube-apiserver.
--enable-hostpath-provisioner
Enable HostPath PV provisioning when running without a cloud provider. This allows testing and development of provisioning features. HostPath provisioning is not supported in any way, won't work in a multi-node cluster, and should not be used for anything other than testing or development.
--enable-taint-manager     Default: true
WARNING: Beta feature. If set to true enables NoExecute Taints and will evict all not-tolerating Pod running on Nodes tainted with this kind of Taints.
--experimental-cluster-signing-duration duration     Default: 8760h0m0s
The length of duration signed certificates will be given.
--external-cloud-volume-plugin string
The plugin to use when cloud provider is set to external. Can be empty, should only be set when cloud-provider is external. Currently used to allow node and volume controllers to work for in tree cloud providers.
--feature-gates mapStringBool
A set of key=value pairs that describe feature gates for alpha/experimental features. Options are:
APIListChunking=true|false (BETA - default=true)
APIResponseCompression=true|false (ALPHA - default=false)
AllAlpha=true|false (ALPHA - default=false)
AppArmor=true|false (BETA - default=true)
AttachVolumeLimit=true|false (BETA - default=true)
BalanceAttachedNodeVolumes=true|false (ALPHA - default=false)
BlockVolume=true|false (BETA - default=true)
BoundServiceAccountTokenVolume=true|false (ALPHA - default=false)
CPUManager=true|false (BETA - default=true)
CRIContainerLogRotation=true|false (BETA - default=true)
CSIBlockVolume=true|false (BETA - default=true)
CSIDriverRegistry=true|false (BETA - default=true)
CSIInlineVolume=true|false (ALPHA - default=false)
CSIMigration=true|false (ALPHA - default=false)
CSIMigrationAWS=true|false (ALPHA - default=false)
CSIMigrationGCE=true|false (ALPHA - default=false)
CSIMigrationOpenStack=true|false (ALPHA - default=false)
CSINodeInfo=true|false (BETA - default=true)
CustomCPUCFSQuotaPeriod=true|false (ALPHA - default=false)
CustomResourcePublishOpenAPI=true|false (ALPHA - default=false)
CustomResourceSubresources=true|false (BETA - default=true)
CustomResourceValidation=true|false (BETA - default=true)
CustomResourceWebhookConversion=true|false (ALPHA - default=false)
DebugContainers=true|false (ALPHA - default=false)
DevicePlugins=true|false (BETA - default=true)
DryRun=true|false (BETA - default=true)
DynamicAuditing=true|false (ALPHA - default=false)
DynamicKubeletConfig=true|false (BETA - default=true)
ExpandCSIVolumes=true|false (ALPHA - default=false)
ExpandInUsePersistentVolumes=true|false (ALPHA - default=false)
ExpandPersistentVolumes=true|false (BETA - default=true)
ExperimentalCriticalPodAnnotation=true|false (ALPHA - default=false)
ExperimentalHostUserNamespaceDefaulting=true|false (BETA - default=false)
HyperVContainer=true|false (ALPHA - default=false)
KubeletPodResources=true|false (ALPHA - default=false)
LocalStorageCapacityIsolation=true|false (BETA - default=true)
MountContainers=true|false (ALPHA - default=false)
NodeLease=true|false (BETA - default=true)
PodShareProcessNamespace=true|false (BETA - default=true)
ProcMountType=true|false (ALPHA - default=false)
QOSReserved=true|false (ALPHA - default=false)
ResourceLimitsPriorityFunction=true|false (ALPHA - default=false)
ResourceQuotaScopeSelectors=true|false (BETA - default=true)
RotateKubeletClientCertificate=true|false (BETA - default=true)
RotateKubeletServerCertificate=true|false (BETA - default=true)
RunAsGroup=true|false (BETA - default=true)
RuntimeClass=true|false (BETA - default=true)
SCTPSupport=true|false (ALPHA - default=false)
ScheduleDaemonSetPods=true|false (BETA - default=true)
ServerSideApply=true|false (ALPHA - default=false)
ServiceNodeExclusion=true|false (ALPHA - default=false)
StorageVersionHash=true|false (ALPHA - default=false)
StreamingProxyRedirects=true|false (BETA - default=true)
SupportNodePidsLimit=true|false (ALPHA - default=false)
SupportPodPidsLimit=true|false (BETA - default=true)
Sysctls=true|false (BETA - default=true)
TTLAfterFinished=true|false (ALPHA - default=false)
TaintBasedEvictions=true|false (BETA - default=true)
TaintNodesByCondition=true|false (BETA - default=true)
TokenRequest=true|false (BETA - default=true)
TokenRequestProjection=true|false (BETA - default=true)
ValidateProxyRedirects=true|false (BETA - default=true)
VolumeSnapshotDataSource=true|false (ALPHA - default=false)
VolumeSubpathEnvExpansion=true|false (ALPHA - default=false)
WinDSR=true|false (ALPHA - default=false)
WinOverlay=true|false (ALPHA - default=false)
WindowsGMSA=true|false (ALPHA - default=false)
--flex-volume-plugin-dir string     Default: "/usr/libexec/kubernetes/kubelet-plugins/volume/exec/"
Full path of the directory in which the flex volume plugin should search for additional third party volume plugins.
-h, --help
help for kube-controller-manager
--horizontal-pod-autoscaler-cpu-initialization-period duration     Default: 5m0s
The period after pod start when CPU samples might be skipped.
--horizontal-pod-autoscaler-downscale-stabilization duration     Default: 5m0s
The period for which autoscaler will look backwards and not scale down below any recommendation it made during that period.
--horizontal-pod-autoscaler-initial-readiness-delay duration     Default: 30s
The period after pod start during which readiness changes will be treated as initial readiness.
--horizontal-pod-autoscaler-sync-period duration     Default: 15s
The period for syncing the number of pods in horizontal pod autoscaler.
--horizontal-pod-autoscaler-tolerance float     Default: 0.1
The minimum change (from 1.0) in the desired-to-actual metrics ratio for the horizontal pod autoscaler to consider scaling.
--http2-max-streams-per-connection int
The limit that the server gives to clients for the maximum number of streams in an HTTP/2 connection. Zero means to use golang's default.
--kube-api-burst int32     Default: 30
Burst to use while talking with kubernetes apiserver.
--kube-api-content-type string     Default: "application/vnd.kubernetes.protobuf"
Content type of requests sent to apiserver.
--kube-api-qps float32     Default: 20
QPS to use while talking with kubernetes apiserver.
--kubeconfig string
Path to kubeconfig file with authorization and master location information.
--large-cluster-size-threshold int32     Default: 50
Number of nodes from which NodeController treats the cluster as large for the eviction logic purposes. --secondary-node-eviction-rate is implicitly overridden to 0 for clusters this size or smaller.
--leader-elect     Default: true
Start a leader election client and gain leadership before executing the main loop. Enable this when running replicated components for high availability.
--leader-elect-lease-duration duration     Default: 15s
The duration that non-leader candidates will wait after observing a leadership renewal until attempting to acquire leadership of a led but unrenewed leader slot. This is effectively the maximum duration that a leader can be stopped before it is replaced by another candidate. This is only applicable if leader election is enabled.
--leader-elect-renew-deadline duration     Default: 10s
The interval between attempts by the acting master to renew a leadership slot before it stops leading. This must be less than or equal to the lease duration. This is only applicable if leader election is enabled.
--leader-elect-resource-lock endpoints     Default: "endpoints"
The type of resource object that is used for locking during leader election. Supported options are endpoints (default) and `configmaps`.
--leader-elect-retry-period duration     Default: 2s
The duration the clients should wait between attempting acquisition and renewal of a leadership. This is only applicable if leader election is enabled.
--log-backtrace-at traceLocation     Default: :0
when logging hits line file:N, emit a stack trace
--log-dir string
If non-empty, write log files in this directory
--log-file string
If non-empty, use this log file
--log-flush-frequency duration     Default: 5s
Maximum number of seconds between log flushes
--logtostderr     Default: true
log to standard error instead of files
--master string
The address of the Kubernetes API server (overrides any value in kubeconfig).
--min-resync-period duration     Default: 12h0m0s
The resync period in reflectors will be random between MinResyncPeriod and 2*MinResyncPeriod.
--namespace-sync-period duration     Default: 5m0s
The period for syncing namespace life-cycle updates
--node-cidr-mask-size int32     Default: 24
Mask size for node cidr in cluster.
--node-eviction-rate float32     Default: 0.1
Number of nodes per second on which pods are deleted in case of node failure when a zone is healthy (see --unhealthy-zone-threshold for definition of healthy/unhealthy). Zone refers to entire cluster in non-multizone clusters.
--node-monitor-grace-period duration     Default: 40s
Amount of time which we allow running Node to be unresponsive before marking it unhealthy. Must be N times more than kubelet's nodeStatusUpdateFrequency, where N means number of retries allowed for kubelet to post node status.
--node-monitor-period duration     Default: 5s
The period for syncing NodeStatus in NodeController.
--node-startup-grace-period duration     Default: 1m0s
Amount of time which we allow starting Node to be unresponsive before marking it unhealthy.
--pod-eviction-timeout duration     Default: 5m0s
The grace period for deleting pods on failed nodes.
--profiling
Enable profiling via web interface host:port/debug/pprof/
--pv-recycler-increment-timeout-nfs int32     Default: 30
the increment of time added per Gi to ActiveDeadlineSeconds for an NFS scrubber pod
--pv-recycler-minimum-timeout-hostpath int32     Default: 60
The minimum ActiveDeadlineSeconds to use for a HostPath Recycler pod. This is for development and testing only and will not work in a multi-node cluster.
--pv-recycler-minimum-timeout-nfs int32     Default: 300
The minimum ActiveDeadlineSeconds to use for an NFS Recycler pod
--pv-recycler-pod-template-filepath-hostpath string
The file path to a pod definition used as a template for HostPath persistent volume recycling. This is for development and testing only and will not work in a multi-node cluster.
--pv-recycler-pod-template-filepath-nfs string
The file path to a pod definition used as a template for NFS persistent volume recycling
--pv-recycler-timeout-increment-hostpath int32     Default: 30
the increment of time added per Gi to ActiveDeadlineSeconds for a HostPath scrubber pod. This is for development and testing only and will not work in a multi-node cluster.
--pvclaimbinder-sync-period duration     Default: 15s
The period for syncing persistent volumes and persistent volume claims
--requestheader-allowed-names stringSlice
List of client certificate common names to allow to provide usernames in headers specified by --requestheader-username-headers. If empty, any client certificate validated by the authorities in --requestheader-client-ca-file is allowed.
--requestheader-client-ca-file string
Root certificate bundle to use to verify client certificates on incoming requests before trusting usernames in headers specified by --requestheader-username-headers. WARNING: generally do not depend on authorization being already done for incoming requests.
--requestheader-extra-headers-prefix stringSlice     Default: [x-remote-extra-]
List of request header prefixes to inspect. X-Remote-Extra- is suggested.
--requestheader-group-headers stringSlice     Default: [x-remote-group]
List of request headers to inspect for groups. X-Remote-Group is suggested.
--requestheader-username-headers stringSlice     Default: [x-remote-user]
List of request headers to inspect for usernames. X-Remote-User is common.
--resource-quota-sync-period duration     Default: 5m0s
The period for syncing quota usage status in the system
--root-ca-file string
If set, this root certificate authority will be included in service account's token secret. This must be a valid PEM-encoded CA bundle.
--route-reconciliation-period duration     Default: 10s
The period for reconciling routes created for Nodes by cloud provider.
--secondary-node-eviction-rate float32     Default: 0.01
Number of nodes per second on which pods are deleted in case of node failure when a zone is unhealthy (see --unhealthy-zone-threshold for definition of healthy/unhealthy). Zone refers to entire cluster in non-multizone clusters. This value is implicitly overridden to 0 if the cluster size is smaller than --large-cluster-size-threshold.
--secure-port int     Default: 10257
The port on which to serve HTTPS with authentication and authorization.If 0, don't serve HTTPS at all.
--service-account-private-key-file string
Filename containing a PEM-encoded private RSA or ECDSA key used to sign service account tokens.
--service-cluster-ip-range string
CIDR Range for Services in cluster. Requires --allocate-node-cidrs to be true
--skip-headers
If true, avoid header prefixes in the log messages
--stderrthreshold severity     Default: 2
logs at or above this threshold go to stderr
--terminated-pod-gc-threshold int32     Default: 12500
Number of terminated pods that can exist before the terminated pod garbage collector starts deleting terminated pods. If <= 0, the terminated pod garbage collector is disabled.
--tls-cert-file string
File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert). If HTTPS serving is enabled, and --tls-cert-file and --tls-private-key-file are not provided, a self-signed certificate and key are generated for the public address and saved to the directory specified by --cert-dir.
--tls-cipher-suites stringSlice
Comma-separated list of cipher suites for the server. If omitted, the default Go cipher suites will be use. Possible values: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_3DES_EDE_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_RC4_128_SHA
--tls-min-version string
Minimum TLS version supported. Possible values: VersionTLS10, VersionTLS11, VersionTLS12
--tls-private-key-file string
File containing the default x509 private key matching --tls-cert-file.
--tls-sni-cert-key namedCertKey     Default: []
A pair of x509 certificate and private key file paths, optionally suffixed with a list of domain patterns which are fully qualified domain names, possibly with prefixed wildcard segments. If no domain patterns are provided, the names of the certificate are extracted. Non-wildcard matches trump over wildcard matches, explicit domain patterns trump over extracted names. For multiple key/certificate pairs, use the --tls-sni-cert-key multiple times. Examples: "example.crt,example.key" or "foo.crt,foo.key:*.foo.com,foo.com".
--unhealthy-zone-threshold float32     Default: 0.55
Fraction of Nodes in a zone which needs to be not Ready (minimum 3) for zone to be treated as unhealthy.
--use-service-account-credentials
If true, use individual service account credentials for each controller.
-v, --v Level
number for the log level verbosity
--version version[=true]
Print version information and quit
--vmodule moduleSpec
comma-separated list of pattern=N settings for file-filtered logging
+ + diff --git a/content/zh/docs/reference/command-line-tools-reference/kube-proxy.md b/content/zh/docs/reference/command-line-tools-reference/kube-proxy.md index 22b25fb48b..8f99505bf2 100644 --- a/content/zh/docs/reference/command-line-tools-reference/kube-proxy.md +++ b/content/zh/docs/reference/command-line-tools-reference/kube-proxy.md @@ -1,37 +1,37 @@ --- title: kube-proxy -notitle: true +content_template: templates/tool-reference +weight: 28 --- -## kube-proxy + + +{{% capture synopsis %}} -### 概要 - -Kubernetes 在每个节点上运行网络代理。这反映每个节点上 Kubernetes API 中定义的服务,并且可以做简单的 -TCP 和 UDP 流转发或在一组后端中轮询,进行 TCP 和 UDP 转发。目前服务集群 IP 和端口通过由服务代理打开的端口 -的 Docker-links-compatible 环境变量找到。有一个可选的为这些集群 IP 提供集群 DNS 的插件。用户必须 -通过 apiserver API 创建服务去配置代理。 +Kubernetes 网络代理在每个节点上运行。网络代理反映了每个节点上 Kubernetes API 中定义的服务,并且可以执行简单的 TCP、UDP 和 SCTP 流转发,或者在一组后端进行循环 TCP、UDP 和 SCTP 转发。当前可通过 Docker-links-compatible 环境变量找到服务集群 IP 和端口,这些环境变量指定了服务代理打开的端口。有一个可选的插件,可以为这些集群 IP 提供集群 DNS。用户必须使用 apiserver API 创建服务才能配置代理。 ``` kube-proxy [flags] ``` - -### 选项 +{{% /capture %}} + +{{% capture options %}} @@ -44,448 +44,597 @@ kube-proxy [flags] - - + 包含 Azure 容器仓库配置信息的文件的路径。 + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + + + + + + + + - - + - - + - - + - - + - - + - - + - - + + + + + + + + - - + - - + - - + - - + - - + - - + - - + - - + - - + - - +
--azure-container-registry-config string
包含 Azure 容器仓库配置信息的文件的路径。
--bind-address 0.0.0.0     默认: 0.0.0.0 + + --bind-address 0.0.0.0     默认值: 0.0.0.0 +
要服务的代理服务器的 IP 地址(对于所有 IPv4 接口设置为 0.0.0.0,对于所有 IPv6 接口设置为 ::) + + 代理服务器要使用的 IP 地址(对于所有 IPv4 接口设置为 0.0.0.0,对于所有 IPv6 接口设置为 ::) +
--cleanup
如果为 true,清理 iptables 和 ipvs 规则并退出。 + + 如果为 true,清理 iptables 和 ipvs 规则并退出。 +
--cleanup-ipvs     默认: true + + --cleanup-ipvs     默认值: true +
如果为 true,则使 kube-proxy 在运行之前清理 ipvs 规则。 默认为 true + + 如果设置为 true 并指定了 --cleanup,则 kube-proxy 除了常规清理外,还将刷新 IPVS 规则。 +
--cluster-cidr string
集群中的 CIDR 范围。 配置后,从该范围之外发送到服务集群 IP 的流量将被伪装,从 pod 发送到外部 LoadBalancer IP 的流量将被定向到相应的集群 IP + + 集群中 Pod 的 CIDR 范围。配置后,将从该范围之外发送到服务集群 IP 的流量被伪装,从 Pod 发送到外部 LoadBalancer IP 的流量将被重定向到相应的集群 IP。 +
--config string
配置文件的路径。 + + 配置文件的路径。 +
--config-sync-period duration     默认: 15m0s + + --config-sync-period duration     默认值: 15m0s +
来自 apiserver 的配置的刷新频率。必须大于 0。 + + 来自 apiserver 的配置的刷新频率。必须大于 0。 +
--conntrack-max-per-core int32     默认: 32768 + + --conntrack-max-per-core int32     默认值: 32768 +
每个 CPU 核跟踪的最大 NAT 连接数(0 表示保留原样限制并忽略 conntrack-min)。 + + 每个 CPU 核跟踪的最大 NAT 连接数(0 表示保留原样限制并忽略 conntrack-min)。 +
--conntrack-min int32     默认: 131072 + + --conntrack-min int32     默认值: 131072 +
要分配的最小 conntrack 条目数,不管 conntrack-max-per-core(设置 conntrack-max-per-core = 0 保留原样限制)。 + + 无论 conntrack-max-per-core 多少,要分配的 conntrack 条目的最小数量(将 conntrack-max-per-core 设置为 0 即可保持原样的限制)。 +
--conntrack-tcp-timeout-close-wait duration     默认: 1h0m0s + + --conntrack-tcp-timeout-close-wait duration     默认值: 1h0m0s +
处于 CLOSE_WAIT 状态的 TCP 连接的 NAT 超时 + + 处于 CLOSE_WAIT 状态的 TCP 连接的 NAT 超时 +
--conntrack-tcp-timeout-established duration     默认: 24h0m0s + + --conntrack-tcp-timeout-established duration     默认值: 24h0m0s +
已建立的 TCP 连接的空闲超时(0 保持原样) + + 已建立的 TCP 连接的空闲超时(0 保持原样) +
--feature-gates mapStringBool
一组 key=value 对,用于描述 alpha/experimental 特征的特征门。选项包括:
APIListChunking=true|false (BETA - 默认=true)
APIResponseCompression=true|false (ALPHA - 默认=false)
AdvancedAuditing=true|false (BETA - 默认=true)
AllAlpha=true|false (ALPHA - 默认=false)
AppArmor=true|false (BETA - 默认=true)
AttachVolumeLimit=true|false (ALPHA - 默认=false)
BalanceAttachedNodeVolumes=true|false (ALPHA - 默认=false)
BlockVolume=true|false (ALPHA - 默认=false)
CPUManager=true|false (BETA - 默认=true)
CRIContainerLogRotation=true|false (BETA - 默认=true)
CSIBlockVolume=true|false (ALPHA - 默认=false)
CSIPersistentVolume=true|false (BETA - 默认=true)
CustomPodDNS=true|false (BETA - 默认=true)
CustomResourceSubresources=true|false (BETA - 默认=true)
CustomResourceValidation=true|false (BETA - 默认=true)
DebugContainers=true|false (ALPHA - 默认=false)
DevicePlugins=true|false (BETA - 默认=true)
DynamicKubeletConfig=true|false (BETA - 默认=true)
DynamicProvisioningScheduling=true|false (ALPHA - 默认=false)
EnableEquivalenceClassCache=true|false (ALPHA - 默认=false)
ExpandInUsePersistentVolumes=true|false (ALPHA - 默认=false)
ExpandPersistentVolumes=true|false (BETA - 默认=true)
ExperimentalCriticalPodAnnotation=true|false (ALPHA - 默认=false)
ExperimentalHostUserNamespaceDefaulting=true|false (BETA - 默认=false)
GCERegionalPersistentDisk=true|false (BETA - 默认=true)
HugePages=true|false (BETA - 默认=true)
HyperVContainer=true|false (ALPHA - 默认=false)
KubeletPluginsWatcher=true|false (ALPHA - 默认=false)
LocalStorageCapacityIsolation=true|false (BETA - default=true)
MountContainers=true|false (ALPHA - 默认=false)
MountPropagation=true|false (BETA - 默认=true)
PersistentLocalVolumes=true|false (BETA - 默认=true)
PodPriority=true|false (BETA - 默认=true)
PodReadinessGates=true|false (BETA - 默认=false)
PodShareProcessNamespace=true|false (ALPHA - 默认=false)
QOSReserved=true|false (ALPHA - 默认=false)
ReadOnlyAPIDataVolumes=true|false (弃用 - 默认=true)
ResourceLimitsPriorityFunction=true|false (ALPHA - 默认=false)
ResourceQuotaScopeSelectors=true|false (ALPHA - 默认=false)
RotateKubeletClientCertificate=true|false (BETA - 默认=true)
RotateKubeletServerCertificate=true|false (ALPHA - 默认=false)
RunAsGroup=true|false (ALPHA - 默认=false)
ScheduleDaemonSetPods=true|false (ALPHA - 默认=false)
ServiceNodeExclusion=true|false (ALPHA - 默认=false)
ServiceProxyAllowExternalIPs=true|false (弃用 - 默认=false)
StorageObjectInUseProtection=true|false (default=true)
StreamingProxyRedirects=true|false (BETA - 默认=true)
SupportIPVSProxyMode=true|false (默认=true)
SupportPodPidsLimit=true|false (ALPHA - 默认=false)
Sysctls=true|false (BETA - 默认=true)
TaintBasedEvictions=true|false (ALPHA - 默认=false)
TaintNodesByCondition=true|false (ALPHA - 默认=false)
TokenRequest=true|false (ALPHA - 默认=false)
TokenRequestProjection=true|false (ALPHA - 默认=false)
VolumeScheduling=true|false (BETA - 默认=true)
VolumeSubpath=true|false (默认=true)
VolumeSubpathEnvExpansion=true|false (ALPHA - 默认=false)
+ + 一组键=值(key=value)对,描述了 alpha/experimental 的特征。可选项有:
APIListChunking=true|false (BETA - 默认值=true)
APIResponseCompression=true|false (BETA - 默认值=true)
AllAlpha=true|false (ALPHA - 默认值=false)
AppArmor=true|false (BETA - 默认值=true)
AttachVolumeLimit=true|false (BETA - 默认值=true)
BalanceAttachedNodeVolumes=true|false (ALPHA - 默认值=false)
BlockVolume=true|false (BETA - 默认值=true)
BoundServiceAccountTokenVolume=true|false (ALPHA - 默认值=false)
CPUManager=true|false (BETA - 默认值=true)
CRIContainerLogRotation=true|false (BETA - 默认值=true)
CSIBlockVolume=true|false (BETA - 默认值=true)
CSIDriverRegistry=true|false (BETA - 默认值=true)
CSIInlineVolume=true|false (BETA - 默认值=true)
CSIMigration=true|false (ALPHA - 默认值=false)
CSIMigrationAWS=true|false (ALPHA - 默认值=false)
CSIMigrationAzureDisk=true|false (ALPHA - 默认值=false)
CSIMigrationAzureFile=true|false (ALPHA - 默认值=false)
CSIMigrationGCE=true|false (ALPHA - 默认值=false)
CSIMigrationOpenStack=true|false (ALPHA - 默认值=false)
CSINodeInfo=true|false (BETA - 默认值=true)
CustomCPUCFSQuotaPeriod=true|false (ALPHA - 默认值=false)
CustomResourceDefaulting=true|false (BETA - 默认值=true)
DevicePlugins=true|false (BETA - 默认值=true)
DryRun=true|false (BETA - 默认值=true)
DynamicAuditing=true|false (ALPHA - 默认值=false)
DynamicKubeletConfig=true|false (BETA - 默认值=true)
EndpointSlice=true|false (ALPHA - 默认值=false)
EphemeralContainers=true|false (ALPHA - 默认值=false)
EvenPodsSpread=true|false (ALPHA - 默认值=false)
ExpandCSIVolumes=true|false (BETA - 默认值=true)
ExpandInUsePersistentVolumes=true|false (BETA - 默认值=true)
ExpandPersistentVolumes=true|false (BETA - 默认值=true)
ExperimentalHostUserNamespaceDefaulting=true|false (BETA - 默认值=false)
HPAScaleToZero=true|false (ALPHA - 默认值=false)
HyperVContainer=true|false (ALPHA - 默认值=false)
IPv6DualStack=true|false (ALPHA - 默认值=false)
KubeletPodResources=true|false (BETA - 默认值=true)
LegacyNodeRoleBehavior=true|false (ALPHA - 默认值=true)
LocalStorageCapacityIsolation=true|false (BETA - 默认值=true)
LocalStorageCapacityIsolationFSQuotaMonitoring=true|false (ALPHA - 默认值=false)
MountContainers=true|false (ALPHA - 默认值=false)
NodeDisruptionExclusion=true|false (ALPHA - 默认值=false)
NodeLease=true|false (BETA - 默认值=true)
NonPreemptingPriority=true|false (ALPHA - 默认值=false)
PodOverhead=true|false (ALPHA - 默认值=false)
PodShareProcessNamespace=true|false (BETA - 默认值=true)
ProcMountType=true|false (ALPHA - 默认值=false)
QOSReserved=true|false (ALPHA - 默认值=false)
RemainingItemCount=true|false (BETA - 默认值=true)
RemoveSelfLink=true|false (ALPHA - 默认值=false)
RequestManagement=true|false (ALPHA - 默认值=false)
ResourceLimitsPriorityFunction=true|false (ALPHA - 默认值=false)
ResourceQuotaScopeSelectors=true|false (BETA - 默认值=true)
RotateKubeletClientCertificate=true|false (BETA - 默认值=true)
RotateKubeletServerCertificate=true|false (BETA - 默认值=true)
RunAsGroup=true|false (BETA - 默认值=true)
RuntimeClass=true|false (BETA - 默认值=true)
SCTPSupport=true|false (ALPHA - 默认值=false)
ScheduleDaemonSetPods=true|false (BETA - 默认值=true)
ServerSideApply=true|false (BETA - 默认值=true)
ServiceLoadBalancerFinalizer=true|false (BETA - 默认值=true)
ServiceNodeExclusion=true|false (ALPHA - 默认值=false)
StartupProbe=true|false (ALPHA - 默认值=false)
StorageVersionHash=true|false (BETA - 默认值=true)
StreamingProxyRedirects=true|false (BETA - 默认值=true)
SupportNodePidsLimit=true|false (BETA - 默认值=true)
SupportPodPidsLimit=true|false (BETA - 默认值=true)
Sysctls=true|false (BETA - 默认值=true)
TTLAfterFinished=true|false (ALPHA - 默认值=false)
TaintBasedEvictions=true|false (BETA - 默认值=true)
TaintNodesByCondition=true|false (BETA - 默认值=true)
TokenRequest=true|false (BETA - 默认值=true)
TokenRequestProjection=true|false (BETA - 默认值=true)
TopologyManager=true|false (ALPHA - 默认值=false)
ValidateProxyRedirects=true|false (BETA - 默认值=true)
VolumePVCDataSource=true|false (BETA - 默认值=true)
VolumeSnapshotDataSource=true|false (ALPHA - 默认值=false)
VolumeSubpathEnvExpansion=true|false (BETA - 默认值=true)
WatchBookmark=true|false (BETA - 默认值=true)
WinDSR=true|false (ALPHA - 默认值=false)
WinOverlay=true|false (ALPHA - 默认值=false)
WindowsGMSA=true|false (BETA - 默认值=true)
WindowsRunAsUserName=true|false (ALPHA - 默认值=false) +
--healthz-bind-address 0.0.0.0     默认: 0.0.0.0:10256 + + --healthz-bind-address 0.0.0.0     默认值: 0.0.0.0:10256 +
服务健康检查的 IP 地址和端口(对于所有 IPv4 接口设置为 0.0.0.0,对于所有 IPv6 接口设置为 ::) + + 服务健康检查的 IP 地址和端口(对于所有 IPv4 接口设置为 0.0.0.0,对于所有 IPv6 接口设置为 ::) +
--healthz-port int32     默认: 10256 + + --healthz-port int32     默认值: 10256 +
绑定健康检查服务的端口。使用 0 禁用。 + + 绑定健康检查服务的端口。使用 0 表示禁用。 +
-h, --help
kube-proxy 帮助信息 + + kube-proxy 操作的帮助命令 +
--hostname-override string
如果非空,将使用此字符串作为标识而不是实际的主机名。 + + 如果非空,将使用此字符串作为标识而不是实际的主机名。 +
--iptables-masquerade-bit int32     默认: 14 + + --iptables-masquerade-bit int32     默认值: 14 +
如果使用纯 iptables 代理,则 fwmark 空间的位用于标记需要 SNAT 的数据包。 必须在 [0,31] 范围内。 + + 如果使用纯 iptables 代理,则 fwmark 空间的 bit 用于标记需要 SNAT 的数据包。必须在 [0,31] 范围内。 +
--iptables-min-sync-period duration
当端点和服务发生变化时,iptables 规则的刷新的最小间隔(例如 '5s','1m','2h22m')。 + + iptables 规则可以随着端点和服务的更改而刷新的最小间隔(例如 '5s'、'1m'、'2h22m')。 +
--iptables-sync-period duration     默认: 30s + + --iptables-sync-period duration     默认值: 30s +
iptables 规则刷新的最大时间间隔(例如 '5s','1m','2h22m')。必须大于 0。 + + 刷新 iptables 规则的最大间隔(例如 '5s'、'1m'、'2h22m')。必须大于 0。 +
--ipvs-exclude-cidrs stringSlice
以逗号分隔的 CIDR 列表,在清理 IPVS 规则时,不应该触及 ipvs proxier。 + + 逗号分隔的 CIDR 列表,ipvs 代理在清理 IPVS 规则时不应使用此列表。 +
--ipvs-min-sync-period duration
当端点和服务发生变化时,ipvs 规则的刷新的最小间隔(例如 '5s','1m','2h22m')。 + + ipvs 规则可以随着端点和服务的更改而刷新的最小间隔(例如 '5s'、'1m'、'2h22m')。 +
--ipvs-scheduler string
代理模式为 ipvs 时的 ipvs 调度器类型 + + 代理模式为 ipvs 时的 ipvs 调度器类型 +
--ipvs-sync-period duration     默认: 30s--ipvs-strict-arp
ipvs 规则刷新的最大时间间隔(例如 '5s','1m','2h22m')。必须大于 0。 + + 通过将 arp_ignore 设置为 1 并将 arp_announce 设置为 2 启用严格的 ARP +
--kube-api-burst int32     默认: 10 + + --ipvs-sync-period duration     默认值: 30s +
每秒与 kubernetes apiserver 交互的数量 + + 刷新 ipvs 规则的最大间隔(例如 '5s'、'1m'、'2h22m')。必须大于 0。 +
--kube-api-content-type string     默认: "application/vnd.kubernetes.protobuf" + + --kube-api-burst int32     默认值: 10 +
发送到 apiserver 的请求的内容类型。 + + 与 kubernetes apiserver 通信的数量 +
--kube-api-qps float32     默认: 5 + + --kube-api-content-type string     默认值: "application/vnd.kubernetes.protobuf" +
与 kubernetes apiserver 交互时使用的 QPS + + 发送到 apiserver 的请求的内容类型。 +
+ + --kube-api-qps float32     默认值: 5 +
+ + 与 kubernetes apiserver 交互时使用的 QPS +
--kubeconfig string
包含授权信息的 kubeconfig 文件的路径(master 位置由 master 标志设置)。 + + 包含授权信息的 kubeconfig 文件的路径(master 位置由 master 标志设置)。 +
--log-flush-frequency duration     默认: 5s + + --log-flush-frequency duration     默认值: 5s +
日志刷新最大间隔 + + 两次日志刷新之间的最大秒数 +
--masquerade-all
如果使用纯 iptables 代理,SNAT 所有通过服务句群 IP 发送的流量(这通常不需要) + + 如果使用纯 iptables 代理,则对通过服务集群 IP 发送的所有流量进行 SNAT(通常不需要) +
--master string
Kubernetes API 服务器的地址(覆盖 kubeconfig 中的任何值) + + Kubernetes API 服务器的地址(覆盖 kubeconfig 中的任何值) +
--metrics-bind-address 0.0.0.0     默认: 127.0.0.1:10249 + + --metrics-bind-address 0.0.0.0     默认值: 127.0.0.1:10249 +
要服务的度量服务器的 IP 地址和端口(对于所有 IPv4 接口设置为 0.0.0.0,对于所有 IPv6 接口设置为 ::) + + metrics 服务器要使用的 IP 地址(所有 IPv4 接口设置为 0.0.0.0,所有 IPv6 接口设置为 `::`) +
+ + --metrics-port int32     默认值: 10249 +
+ + 绑定 metrics 服务器的端口。使用 0 表示禁用。 +
--nodeport-addresses stringSlice
一个字符串值,指定用于 NodePorts 的地址。 值可以是有效的 IP 块(例如 1.2.3.0/24, 1.2.3.4/32)。 默认的空字符串切片([])表示使用所有本地地址。 + + 一个字符串值,指定用于 NodePorts 的地址。值可以是有效的 IP 块(例如 1.2.3.0/24, 1.2.3.4/32)。默认的空字符串切片([])表示使用所有本地地址。 +
--oom-score-adj int32     默认: -999 + + --oom-score-adj int32     默认值: -999 +
kube-proxy 进程的 oom-score-adj 值。 值必须在 [-1000,1000] 范围内 + + kube-proxy 进程中的 oom-score-adj 值必须在 [-1000,1000] 范围内 +
--profiling
如果为 true,则通过 Web 接口 /debug/pprof 启用性能分析。 + + 如果为 true,则通过 Web 接口 /debug/pprof 启用性能分析。 +
--proxy-mode ProxyMode
使用哪种代理模式:'userspace'(较旧)或 'iptables'(较快)或 'ipvs'(实验)。 如果为空,使用最佳可用代理(当前为 iptables)。 如果选择了 iptables 代理,无论如何,但系统的内核或 iptables 版本不足,这总是会回退到用户空间代理。 + + 使用哪种代理模式:'userspace'(较旧)或 'iptables'(较快)或 'ipvs'(实验)。如果为空,使用最佳可用代理(当前为 iptables)。如果选择了 iptables 代理,无论如何,但系统的内核或 iptables 版本较低,这总是会回退到用户空间代理。 +
--proxy-port-range port-range
主机端口的范围(beginPort-endPort,单端口或 beginPort + offset,包括),可以被代理服务流量消耗。 如果(未指定,0 或 0-0)则随机选择端口。 + + 可以使用代理服务流量的主机端口(包括 beginPort-endPort、single port、beginPort+offset)的范围。如果(未指定,0 或 0-0)则随机选择端口。 +
--udp-timeout duration     默认: 250ms + + --udp-timeout duration     默认值: 250ms +
空闲 UDP 连接将保持打开的时长(例如 '250ms','2s')。 必须大于 0。仅适用于 proxy-mode=userspace + + 空闲 UDP 连接将保持打开的时长(例如 '250ms','2s')。必须大于 0。仅适用于 proxy-mode=userspace +
--version version[=true]
打印版本信息并退出 + + 打印版本信息并退出 +
--write-config-to string
如果设置,将配置值写入此文件并退出。 + + 如果设置,将配置值写入此文件并退出。 +
+ + + +{{% /capture %}} diff --git a/content/zh/docs/reference/command-line-tools-reference/kube-scheduler.md b/content/zh/docs/reference/command-line-tools-reference/kube-scheduler.md index 90b4651d57..12268d5909 100644 --- a/content/zh/docs/reference/command-line-tools-reference/kube-scheduler.md +++ b/content/zh/docs/reference/command-line-tools-reference/kube-scheduler.md @@ -1,38 +1,37 @@ --- title: kube-scheduler -notitle: true +content_template: templates/tool-reference +weight: 28 --- -## kube-scheduler - - - - + +{{% capture synopsis %}} + -### 概要 - - -Kubernetes 调度器是一个策略丰富、拓扑感知、工作负载特定的功能,显著影响可用性、性能和容量。调度器需要考虑个人和集体 -的资源要求、服务质量要求、硬件/软件/政策约束、亲和力和反亲和力规范、数据局部性、负载间干扰、完成期限等。 -工作负载特定的要求必要时将通过 API 暴露。 +Kubernetes 调度器是一个策略丰富、拓扑感知、工作负载特定的功能,调度器显著影响可用性、性能和容量。调度器需要考虑个人和集体的资源要求、服务质量要求、硬件/软件/政策约束、亲和力和反亲和力规范、数据局部性、负载间干扰、完成期限等。工作负载特定的要求必要时将通过 API 暴露。 ``` kube-scheduler [flags] ``` - -### 选项 +{{% /capture %}} + +{{% capture options %}} @@ -42,339 +41,977 @@ kube-scheduler [flags] - - + - - + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + - - + 配置文件的路径。标志会覆盖此文件中的值。 + - - + 弃用: 如果启用了性能分析,则启用锁竞争分析 + - - + 一组 key=value 对,描述了 alpha/alpha/experimental 特征。 选项包括:
APIListChunking=true|false (BETA - 默认=true)
APIResponseCompression=true|false (BETA - 默认=true)
AllAlpha=true|false (ALPHA - 默认=false)
AppArmor=true|false (BETA - 默认=true)
AttachVolumeLimit=true|false (BETA - 默认=true)
BalanceAttachedNodeVolumes=true|false (ALPHA - 默认=false)
BlockVolume=true|false (BETA - 默认=true)
BoundServiceAccountTokenVolume=true|false (ALPHA - 默认=false)
CPUManager=true|false (BETA - 默认=true)
CRIContainerLogRotation=true|false (BETA - 默认=true)
CSIBlockVolume=true|false (BETA - 默认=true)
CSIDriverRegistry=true|false (BETA - 默认=true)
CSIInlineVolume=true|false (BETA - 默认=true)
CSIMigration=true|false (ALPHA - 默认=false)
CSIMigrationAWS=true|false (ALPHA - 默认=false)
CSIMigrationAzureDisk=true|false (ALPHA - 默认=false)
CSIMigrationAzureFile=true|false (ALPHA - 默认=false)
CSIMigrationGCE=true|false (ALPHA - 默认=false)
CSIMigrationOpenStack=true|false (ALPHA - 默认=false)
CSINodeInfo=true|false (BETA - 默认=true)
CustomCPUCFSQuotaPeriod=true|false (ALPHA - 默认=false)
CustomResourceDefaulting=true|false (BETA - 默认=true)
DevicePlugins=true|false (BETA - 默认=true)
DryRun=true|false (BETA - 默认=true)
DynamicAuditing=true|false (ALPHA - 默认=false)
DynamicKubeletConfig=true|false (BETA - 默认=true)
EndpointSlice=true|false (ALPHA - 默认=false)
EphemeralContainers=true|false (ALPHA - 默认=false)
EvenPodsSpread=true|false (ALPHA - 默认=false)
ExpandCSIVolumes=true|false (BETA - 默认=true)
ExpandInUsePersistentVolumes=true|false (BETA - 默认=true)
ExpandPersistentVolumes=true|false (BETA - 默认=true)
ExperimentalHostUserNamespaceDefaulting=true|false (BETA - 默认=false)
HPAScaleToZero=true|false (ALPHA - 默认=false)
HyperVContainer=true|false (ALPHA - 默认=false)
IPv6DualStack=true|false (ALPHA - 默认=false)
KubeletPodResources=true|false (BETA - 默认=true)
LegacyNodeRoleBehavior=true|false (ALPHA - 默认=true)
LocalStorageCapacityIsolation=true|false (BETA - 默认=true)
LocalStorageCapacityIsolationFSQuotaMonitoring=true|false (ALPHA - 默认=false)
MountContainers=true|false (ALPHA - 默认=false)
NodeDisruptionExclusion=true|false (ALPHA - 默认=false)
NodeLease=true|false (BETA - 默认=true)
NonPreemptingPriority=true|false (ALPHA - 默认=false)
PodOverhead=true|false (ALPHA - default=false)
PodShareProcessNamespace=true|false (BETA - 默认=true)
ProcMountType=true|false (ALPHA - 默认=false)
QOSReserved=true|false (ALPHA - 默认=false)
RemainingItemCount=true|false (BETA - 默认=true)
RemoveSelfLink=true|false (ALPHA - 默认=false)
RequestManagement=true|false (ALPHA - 默认=false)
ResourceLimitsPriorityFunction=true|false (ALPHA - 默认=false)
ResourceQuotaScopeSelectors=true|false (BETA - 默认=true)
RotateKubeletClientCertificate=true|false (BETA - 默认=true)
RotateKubeletServerCertificate=true|false (BETA - 默认=true)
RunAsGroup=true|false (BETA - 默认=true)
RuntimeClass=true|false (BETA - 默认=true)
SCTPSupport=true|false (ALPHA - 默认=false)
ScheduleDaemonSetPods=true|false (BETA - 默认=true)
ServerSideApply=true|false (BETA - 默认=true)
ServiceLoadBalancerFinalizer=true|false (BETA - 默认=true)
ServiceNodeExclusion=true|false (ALPHA - 默认=false)
StartupProbe=true|false (ALPHA - 默认=false)
StorageVersionHash=true|false (BETA - 默认=true)
StreamingProxyRedirects=true|false (BETA - 默认=true)
SupportNodePidsLimit=true|false (BETA - 默认=true)
SupportPodPidsLimit=true|false (BETA - 默认=true)
Sysctls=true|false (BETA - 默认=true)
TTLAfterFinished=true|false (ALPHA - 默认=false)
TaintBasedEvictions=true|false (BETA - 默认=true)
TaintNodesByCondition=true|false (BETA - 默认=true)
TokenRequest=true|false (BETA - 默认=true)
TokenRequestProjection=true|false (BETA - 默认=true)
TopologyManager=true|false (ALPHA - 默认=false)
ValidateProxyRedirects=true|false (BETA - 默认=true)
VolumePVCDataSource=true|false (BETA - 默认=true)
VolumeSnapshotDataSource=true|false (ALPHA - 默认=false)
VolumeSubpathEnvExpansion=true|false (BETA - 默认=true)
WatchBookmark=true|false (BETA - 默认=true)
WinDSR=true|false (ALPHA - 默认=false)
WinOverlay=true|false (ALPHA - 默认=false)
WindowsGMSA=true|false (BETA - 默认=true)
WindowsRunAsUserName=true|false (ALPHA - 默认=false) + + + + + + + + - - + - - + - - + - - + - - + - - + - - + + + + + + + + - - + - - + - - + - - + - - + - - + - - + + 领导者尝试在停止领导之前更新领导职位的间隔时间。该时间必须小于或等于租赁期限。仅在启用了领导者选举的情况下才适用。 - - + - - + - - + - - + - - + - - + - - + - - + - - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + Kubernetes API 服务器的地址(覆盖 kubeconfig 中的任何值) + - - + - - + - - + - - + - - + - - + - - + - - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + - - + + + + + + + + - - + 如果已设置,请将配置值写入此文件并退出。 +
--address string     默认: "0.0.0.0"--add-dir-header
弃用: 要监听 --port 端口的 IP 地址(对于所有 IPv4 接口设置为 0.0.0.0,对于所有 IPv6 接口设置为 ::)。 请参阅 --bind-address。 + + 如果为 true,则将文件目录添加到标题中 +
+ + --address string     默认: "0.0.0.0" +
+ + 弃用: 要监听 --port 端口的 IP 地址(对于所有 IPv4 接口设置为 0.0.0.0,对于所有 IPv6 接口设置为 ::)。 请参阅 --bind-address。 +
--algorithm-provider string
弃用: 要使用的调度算法,可选值:ClusterAutoscalerProvider |DefaultProvider + + 弃用: 要使用的调度算法,可选值:ClusterAutoscalerProvider | DefaultProvider +
--alsologtostderr
+ +
--authentication-kubeconfig string
+ +
--authentication-skip-lookup
+ + 如果为 false,则 authentication-kubeconfig 将用于从集群中查找缺少的身份验证配置。 +
+ + --authentication-token-webhook-cache-ttl duration     默认: 10s +
+ + 缓存来自 Webhook 令牌身份验证器的响应的持续时间。 +
+ + --authentication-tolerate-lookup-failure     默认: true +
+ + 如果为 true,则无法从集群中查找缺少的身份验证配置是致命的。请注意,这可能导致身份验证将所有请求视为匿名。 +
+ + --authorization-always-allow-paths stringSlice     默认: [/healthz] +
+ + 在授权过程中跳过的 HTTP 路径列表,即在不联系 'core' kubernetes 服务器的情况下被授权的 HTTP 路径。 +
--authorization-kubeconfig string
+ + 指向具有足够权限以创建 subjectaccessreviews.authorization.k8s.io 的 'core' kubernetes 服务器的 kubeconfig 文件。这是可选的。如果为空,则禁止所有未经授权跳过的请求。 +
+ + --authorization-webhook-cache-authorized-ttl duration     默认: 10s +
+ + 缓存来自 Webhook 授权者的 'authorized' 响应的持续时间。 +
+ + --authorization-webhook-cache-unauthorized-ttl duration     默认: 10s +
+ + 缓存来自 Webhook 授权者的 'unauthorized' 响应的持续时间。 +
--azure-container-registry-config string
包含 Azure 容器仓库配置信息的文件的路径。 + + 包含 Azure 容器仓库配置信息的文件的路径。 +
+ + --bind-address ip     默认: 0.0.0.0 +
+ + 侦听 --secure-port 端口的 IP 地址。集群的其余部分以及 CLI/ Web 客户端必须可以访问关联的接口。如果为空,将使用所有接口(所有 IPv4 接口使用 0.0.0.0,所有 IPv6 接口使用 ::)。 +
--cert-dir string
+ + TLS 证书所在的目录。如果提供了--tls-cert-file 和 --tls private-key-file,则将忽略此参数。 +
--client-ca-file string
+ + 如果已设置,由 client-ca-file 中的授权机构签名的客户端证书的任何请求都将使用与客户端证书的 CommonName 对应的身份进行身份验证。 +
--config string
配置文件的路径。标志会覆盖此文件中的值。
--contention-profiling
弃用: 如果启用了性能分析,则启用锁竞争分析
--feature-gates mapStringBool
一组 key=value 对,用于描述 alpha/experimental 特征的特征门。选项包括:
APIListChunking=true|false (BETA - 默认=true)
APIResponseCompression=true|false (ALPHA - 默认=false)
AdvancedAuditing=true|false (BETA - 默认=true)
AllAlpha=true|false (ALPHA - 默认=false)
AppArmor=true|false (BETA - 默认=true)
AttachVolumeLimit=true|false (ALPHA - 默认=false)
BalanceAttachedNodeVolumes=true|false (ALPHA - 默认=false)
BlockVolume=true|false (ALPHA - 默认=false)
CPUManager=true|false (BETA - 默认=true)
CRIContainerLogRotation=true|false (BETA - 默认=true)
CSIBlockVolume=true|false (ALPHA - 默认=false)
CSIPersistentVolume=true|false (BETA - 默认=true)
CustomPodDNS=true|false (BETA - 默认=true)
CustomResourceSubresources=true|false (BETA - 默认=true)
CustomResourceValidation=true|false (BETA - 默认=true)
DebugContainers=true|false (ALPHA - 默认=false)
DevicePlugins=true|false (BETA - 默认=true)
DynamicKubeletConfig=true|false (BETA - 默认=true)
DynamicProvisioningScheduling=true|false (ALPHA - 默认=false)
EnableEquivalenceClassCache=true|false (ALPHA - 默认=false)
ExpandInUsePersistentVolumes=true|false (ALPHA - 默认=false)
ExpandPersistentVolumes=true|false (BETA - 默认=true)
ExperimentalCriticalPodAnnotation=true|false (ALPHA - 默认=false)
ExperimentalHostUserNamespaceDefaulting=true|false (BETA - 默认=false)
GCERegionalPersistentDisk=true|false (BETA - 默认=true)
HugePages=true|false (BETA - 默认=true)
HyperVContainer=true|false (ALPHA - 默认=false)
KubeletPluginsWatcher=true|false (ALPHA - 默认=false)
LocalStorageCapacityIsolation=true|false (BETA - 默认=true)
MountContainers=true|false (ALPHA - 默认=false)
MountPropagation=true|false (BETA - 默认=true)
PersistentLocalVolumes=true|false (BETA - 默认=true)
PodPriority=true|false (BETA - 默认=true)
PodReadinessGates=true|false (BETA - 默认=false)
PodShareProcessNamespace=true|false (ALPHA - 默认=false)
QOSReserved=true|false (ALPHA - 默认=false)
ReadOnlyAPIDataVolumes=true|false (弃用 - 默认=true)
ResourceLimitsPriorityFunction=true|false (ALPHA - 默认=false)
ResourceQuotaScopeSelectors=true|false (ALPHA - 默认=false)
RotateKubeletClientCertificate=true|false (BETA - 默认=true)
RotateKubeletServerCertificate=true|false (ALPHA - 默认=false)
RunAsGroup=true|false (ALPHA - 默认=false)
ScheduleDaemonSetPods=true|false (ALPHA - 默认=false)
ServiceNodeExclusion=true|false (ALPHA - 默认=false)
ServiceProxyAllowExternalIPs=true|false (弃用 - 默认=false)
StorageObjectInUseProtection=true|false (默认=true)
StreamingProxyRedirects=true|false (BETA - 默认=true)
SupportIPVSProxyMode=true|false (默认=true)
SupportPodPidsLimit=true|false (ALPHA - 默认=false)
Sysctls=true|false (BETA - 默认=true)
TaintBasedEvictions=true|false (ALPHA - 默认=false)
TaintNodesByCondition=true|false (ALPHA - 默认=false)
TokenRequest=true|false (ALPHA - 默认=false)
TokenRequestProjection=true|false (ALPHA - 默认=false)
VolumeScheduling=true|false (BETA - 默认=true)
VolumeSubpath=true|false (默认=true)
VolumeSubpathEnvExpansion=true|false (ALPHA - 默认=false)
+ + --hard-pod-affinity-symmetric-weight int32     默认: 1 +
+ + 弃用: RequiredDuringScheduling 亲和力不是对称的,但是存在与每个 RequiredDuringScheduling 关联性规则相对应的隐式 PreferredDuringScheduling 关联性规则 --hard-pod-affinity-symmetric-weight 代表隐式 PreferredDuringScheduling 关联性规则的权重。权重必须在 0-100 范围内。此选项已移至策略配置文件。 +
-h, --help
kube-scheduler 帮助信息 + + kube-scheduler 帮助命令 +
--kube-api-burst int32     默认: 100--http2-max-streams-per-connection int
弃用: 每秒与 kubernetes apiserver 交互的数量 + + 服务器为客户端提供的 HTTP/2 连接最大限制。零表示使用 golang 的默认值。 +
--kube-api-content-type string     默认: "application/vnd.kubernetes.protobuf" + + --kube-api-burst int32     默认: 100 +
弃用: 发送到 apiserver 的请求的内容类型 + + 弃用: 与 kubernetes apiserver 通信时使用 +
--kube-api-qps float32     默认: 50 + + --kube-api-content-type string     默认: "application/vnd.kubernetes.protobuf" +
弃用: 与 kubernetes apiserver 交互时使用的 QPS + + 弃用: 发送到 apiserver 的请求的内容类型。 +
+ + --kube-api-qps float32     默认: 50 +
+ + 弃用: 与 kubernetes apiserver 通信时要使用的 QPS +
--kubeconfig string
弃用: 包含授权和 master 位置信息的 kubeconfig 文件的路径。 + + 弃用: 具有授权和主节点位置信息的 kubeconfig 文件的路径。 +
--leader-elect     默认: true + + --leader-elect     默认: true +
在执行主循环之前,启动 leader 选举客户端并获得领导能力。在运行复制组件以实现高可用性时启用此选项。 + + 在执行主循环之前,开始领导者选举并选出领导者。为实现高可用性,运行多副本的组件并选出领导者。 +
--leader-elect-lease-duration duration     默认: 15s + + --leader-elect-lease-duration duration     默认: 15s +
非 leader 候选人在观察领导层续约之后将等待的时间,直到试图获得领导但尚未更新的 leader 位置。这实际上是 leader 在被另一个候选人替换之前可以停止的最长持续时间。这仅适用于启用 leader 选举的情况。 + + 非领导者候选人在观察到领导者更新后将等待直到试图获得领导但未更新的领导者职位的等待时间。这实际上是领导者在被另一位候选人替代之前可以停止的最大持续时间。该情况仅在启用了领导者选举的情况下才适用。 +
--leader-elect-renew-deadline duration     默认: 10s + + --leader-elect-renew-deadline duration     默认: 10s +
代理 master 在停止领导之前更新领导位置的时间间隔。这必须小于或等于租约期限。这仅适用于启用 leader 选举的情况 + +
--leader-elect-resource-lock endpoints     默认: "endpoints" + + --leader-elect-resource-lock endpoints     默认: "endpoints" +
在 leader 选举期间用于锁定的资源对象的类型。支持的选项是 endpoints (默认) 和 `configmaps`。 + + 在领导者选举期间用于锁定的资源对象的类型。支持的选项是端点(默认)和 `configmaps` +
--leader-elect-retry-period duration     默认: 2s + + --leader-elect-resource-name string     默认: "kube-scheduler" +
客户端在尝试获取和更新领导之间应该等待的持续时间。这仅适用于启用leader选举的情况。 + + 在领导者选举期间用于锁定的资源对象的名称。 +
--lock-object-name string     默认: "kube-scheduler" + + --leader-elect-resource-namespace string     默认: "kube-system" +
弃用: 定义锁对象的名称。 + + 在领导者选举期间用于锁定的资源对象的命名空间。 +
--lock-object-namespace string     默认: "kube-system" + + --leader-elect-retry-period duration     默认: 2s +
弃用: 定义锁对象的命名空间。 + + 客户应在尝试获取和更新领导之间等待的时间。仅在启用了领导者选举的情况下才适用。 +
--log-flush-frequency duration     默认: 5s + + --lock-object-name string     默认: "kube-scheduler" +
日志刷新最大间隔 + + 弃用: 定义锁对象的名称。将被删除以便使用 Leader-elect-resource-name +
+ + --lock-object-namespace string     默认: "kube-system" +
+ + 弃用: 定义锁对象的命名空间。将被删除以便使用 leader-elect-resource-namespace。 +
+ + --log-backtrace-at traceLocation     默认: :0 +
+ + 当记录命中行文件:N 时发出堆栈跟踪 +
--log-dir string
+ + 如果为非空,则在此目录中写入日志文件 +
--log-file string
+ + 如果为非空,请使用此日志文件 +
+ + --log-file-max-size uint     默认: 1800 +
+ + 定义日志文件可以增长到的最大值。单位为兆字节。如果值为0,则最大文件大小为无限制。 +
+ + --log-flush-frequency duration     默认: 5s +
+ + 两次日志刷新之间的最大秒数 +
+ + --logtostderr     默认: true +
+ + 日志记录到标准错误而不是文件 +
--master string
Kubernetes API 服务器的地址(覆盖 kubeconfig 中的任何值)
--policy-config-file string
弃用: 包含调度器策略配置的文件。如果未提供策略 ConfigMap 或 --use-legacy-policy-config==true,则使用此文件 + + 弃用:具有调度程序策略配置的文件。如果未提供 policy ConfigMap 或 --use-legacy-policy-config = true,则使用此文件 +
--policy-configmap string
弃用: 包含调度器策略配置的 ConfigMap 对象的名称。如果 --use-legacy-policy-config==false,它必须在调度器初始化之前存在于系统命名空间中。配置必须作为 'Data' 映射中元素的值提供,其中 key='policy.cfg' + + 弃用: 包含调度程序策略配置的 ConfigMap 对象的名称。如果 --use-legacy-policy-config = false,则它必须在调度程序初始化之前存在于系统命名空间中。必须将配置作为键为 'policy.cfg' 的 'Data' 映射中元素的值提供 +
--policy-configmap-namespace string     默认: "kube-system" + + --policy-configmap-namespace string     默认: "kube-system" +
弃用: 策略 ConfigMap 所在的命名空间。 如果未提供此命名空间或为空,则将使用系统命名空间。 + + 弃用: 策略 ConfigMap 所在的命名空间。如果未提供或为空,则将使用 kube-system 命名空间。 +
--port int     默认: 10251 + + --port int     默认: 10251 +
弃用: 不安全地提供没有身份验证和授权的 HTTP 端口。 如果为0,则根本不提供 HTTPS。 请参阅 --secure-port。 + + 弃用: 在没有身份验证和授权的情况下不安全地为 HTTP 服务的端口。如果为0,则根本不提供 HTTP。请参见--secure-port。 +
--profiling
弃用: 通过 web 接口 host:port/debug/pprof/ 启动性能分析 + + 弃用: 通过 Web 界面主机启用配置文件:port/debug/pprof/ +
--scheduler-name string     默认: "default-scheduler"--requestheader-allowed-names stringSlice
弃用: 调度器名称,用于根据 pod 的 "spec.SchedulerName" 选择哪些 pod 将被此调度器处理。 + + 客户端证书通用名称列表允许在 --requestheader-username-headers 指定的头部中提供用户名。如果为空,则允许任何由权威机构 --requestheader-client-ca-file 验证的客户端证书。 +
--requestheader-client-ca-file string
+ + 在信任 --requestheader-username-headers 指定的头部中的用户名之前用于验证传入请求上的客户端证书的根证书包。警告:通常不依赖于传入请求已经完成的授权。 +
+ + --requestheader-extra-headers-prefix stringSlice     默认: [x-remote-extra-] +
+ + 要检查请求头部前缀列表。建议使用 X-Remote-Extra- +
+ + --requestheader-group-headers stringSlice     默认: [x-remote-group] +
+ + 用于检查组的请求头部列表。建议使用 X-Remote-Group。 +
+ + --requestheader-username-headers stringSlice     默认: [x-remote-user] +
+ + 用于检查用户名的请求头部列表。 X-Remote-User 很常见。 +
+ + --scheduler-name string     默认: "default-scheduler" +
+ + 弃用: 调度程序名称用于根据 Pod 的 "spec.schedulerName" 选择此调度程序将处理的 Pod。 +
+ + --secure-port int     默认: 10259 +
+ + 通过身份验证和授权为 HTTPS 服务的端口。如果为 0,则根本不提供 HTTPS。 +
--skip-headers
+ + 如果为 true,请在日志消息中避免头部前缀 +
--skip-log-headers
+ + 如果为true,则在打开日志文件时避免头部 +
+ + --stderrthreshold severity     默认: 2 +
+ + 达到或超过此阈值的日志转到 stderr +
--tls-cert-file string
+ + 包含默认的 HTTPS x509 证书的文件。(CA证书(如果有)在服务器证书之后并置)。如果启用了 HTTPS 服务,并且未提供 --tls-cert-file 和 --tls-private-key-file,则会为公共地址生成一个自签名证书和密钥,并将其保存到 --cert-dir 指定的目录中。 +
--tls-cipher-suites stringSlice
+ + 服务器的密码套件列表,以逗号分隔。如果省略,将使用默认的 Go 密码套件。可能的值: + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_3DES_EDE_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_RC4_128_SHA +
--tls-min-version string
+ + 支持的最低 TLS 版本。可能的值:VersionTLS10, VersionTLS11, VersionTLS12, VersionTLS13 +
--tls-private-key-file string
+ + 包含与 --tls-cert-file 匹配的默认 x509 私钥的文件。 +
+ + --tls-sni-cert-key namedCertKey     默认: [] +
+ + 一对 x509 证书和私钥文件路径,可选地后缀为完全限定域名的域模式列表,并可能带有前缀的通配符段。如果未提供域模式,则获取证书名称。非通配符匹配胜过通配符匹配,显式域模式胜过获取名称。 对于多个密钥/证书对,请多次使用 --tls-sni-cert-key。例如: "example.crt,example.key" 或者 "foo.crt,foo.key:*.foo.com,foo.com"。 +
--use-legacy-policy-config
弃用: 当设置为 true 时,调度器将忽略策略 ConfigMap 并使用策略配置文件 + + 弃用: 设置为 true 时,调度程序将忽略策略 ConfigMap 并使用策略配置文件 +
-v, --v Level
+ + 日志级别详细程度的数字 +
--version version[=true]
打印版本信息并退出 + + 打印版本信息并退出 +
--vmodule moduleSpec
+ + 以逗号分隔的 pattern = N 设置列表,用于文件过滤的日志记录 +
--write-config-to string
如果设置,将配置值写入此文件并退出。
+ + + +{{% /capture %}} + diff --git a/content/zh/docs/reference/command-line-tools-reference/kubelet.md b/content/zh/docs/reference/command-line-tools-reference/kubelet.md index 0413ade7d9..21dc60e41a 100644 --- a/content/zh/docs/reference/command-line-tools-reference/kubelet.md +++ b/content/zh/docs/reference/command-line-tools-reference/kubelet.md @@ -1,59 +1,49 @@ --- title: kubelet -notitle: true +content_template: templates/tool-reference +weight: 28 --- -## kubelet - +{{% capture synopsis %}} -### 概要 - +kubelet 是在每个 Node 节点上运行的主要 “节点代理”。它向 apiserver 注册节点时可以使用主机名(hostname);可以提供用于覆盖主机名的参数;还可以执行特定于某云服务商的逻辑。 -kubelet 是在每个节点上运行的主要 "节点代理"。kubelet 以 PodSpec 为单位来运行任务,PodSpec 是一个描述 pod 的 YAML 或 JSON 对象。 -kubelet 运行多种机制(主要通过 apiserver)提供的一组 PodSpec,并确保这些 PodSpecs 中描述的容器健康运行。 -不是 Kubernetes 创建的容器将不在 kubelet 的管理范围。 +kubelet 是基于 PodSpec 来工作的。每个 PodSpec 是一个描述 Pod 的 YAML 或 JSON 对象。kubelet 接受通过各种机制(主要是通过 apiserver)提供的一组 PodSpec,并确保这些 PodSpec 中描述的容器处于运行状态且运行状况良好。kubelet 不管理不是由 Kubernetes 创建的容器。 -除了来自 apiserver 的 PodSpec 之外,还有三种方法可以将容器清单提供给 Kubelet。 +除了来自 apiserver 的 PodSpec 之外,还可以通过以下三种方式将容器清单(manifest)提供给 kubelet。 -文件:通过命令行传入的文件路径。kubelet 将定期监听该路径下的文件以获得更新。监视周期默认为 20 秒,可通过参数进行配置。 + +File(文件):利用命令行参数给定路径。kubelet 周期性地监视此路径下的文件是否有更新。监视周期默认为 20s,且可通过参数进行配置。 -HTTP 端点:HTTP 端点以命令行参数传入。每 20 秒检查一次该端点(该时间间隔也是可以通过命令行配置的)。 + +HTTP endpoint(HTTP 端点):利用命令行参数指定 HTTP 端点。此端点每 20 秒被检查一次(也可以使用参数进行配置)。 -HTTP 服务:kubelet 还可以监听 HTTP 并响应简单的 API(当前未指定)以提交新的清单。 + +HTTP server(HTTP 服务器):kubelet 还可以侦听 HTTP 并响应简单的 API(当前未经过规范)来提交新的清单。 ``` kubelet [flags] ``` - -### 选项 +{{% /capture %}} + + +{{% capture options %}} @@ -63,50 +53,2108 @@ kubelet [flags] - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - + - - + + + + + + + + + + + + + + + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
--azure-container-registry-config string--add-dir-header
包含 Azure 容器注册配置信息的文件路径 + + 设置为 true 表示添加文件目录到 header 中 +
--address 0.0.0.0
+ + kubelet 的服务 IP 地址(所有 IPv4 接口设置为 0.0.0.0 ,所有 IPv6 接口设置为 “::”)(默认值为 0.0.0.0)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--allowed-unsafe-sysctls strings
+ + 设置允许的非安全 sysctls 或 sysctl 模式(以 * 结尾) 白名单。使用此参数,风险自担。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--alsologtostderr
+ + 设置为 true 表示将日志输出到文件的同时输出到 stderr +
--anonymous-auth
+ + 设置为 true 表示 kubelet 服务器可以接受匿名请求。未被任何认证组件拒绝的请求将被视为匿名请求。匿名请求的用户名为 system:anonymous,用户组为 system:unauthenticated。(默认值为 true)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--application-metrics-count-limit int
+ + 设置每个容器应用性能度量值存储的个数上限。(默认值为 100)。(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--authentication-token-webhook
+ + 使用 TokenReview API 对持有者令牌进行身份认证。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--authentication-token-webhook-cache-ttl duration
+ + webhook 令牌认证器返回的响应的缓存时间。(默认值为 2m0s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--authorization-mode string
+ + kubelet 服务器的鉴权模式。可选值包括:AlwaysAllow、Webhook。Webhook 模式使用 SubjectAccessReview API 鉴权。(默认值:“AlwaysAllow”)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--authorization-webhook-cache-authorized-ttl duration
+ + webhook 认证器所返回的 “己授权” 应答的缓存时间。(默认值为 5m0s)(默认值为 “AlwaysAllow”)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--authorization-webhook-cache-unauthorized-ttl duration
+ + webhook 认证器所返回的 “未授权” 应答的缓存时间。(默认值为 30s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--azure-container-registry-config string
+ + Azure 云上镜像库的配置文件路径。 +
--boot-id-file string
+ + 以逗号分隔的文件列表,用于检查引导 id(boot-id)。使用第 1 个存在 boot-id 的文件。(默认值为“/proc/sys/kernel/random/boot_id”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--bootstrap-checkpoint-path string
+ + <警告:alpha 功能> 存储检查点的目录的路径 +
--bootstrap-kubeconfig string
+ + kubeconfig 文件的路径,该文件将用于获取 kubelet 的客户端证书。如果 --kubeconfig 指定的文件不存在,则使用引导 kubeconfig 从 API 服务器请求客户端证书。成功后,将引用生成的客户端证书和密钥的 kubeconfig 文件写入 --kubeconfig 所指定的路径。客户端证书和密钥文件将存储在 --cert-dir 指向的目录中。 +
--cert-dir string
+ + TLS 证书所在的目录。如果设置了 --tls-cert-file 和 --tls-private-key-file,则该设置将被忽略。(默认值为 “/var/lib/kubelet/pki”) +
--cgroup-driver string
+ + kubelet 操作本机 cgroup 时使用的驱动程序。支持的选项包括 cgroupfs 或者 systemd(默认值为 cgroupfs)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) + /td> +
--cgroup-root string
+ + 为 pod 设置可选的根 cgroup。容器运行时会尽力而为。默认值:‘’,意味着将使用容器运行时的默认设置。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--cgroups-per-qos
+ + 启用创建 QoS cgroup 层次结构。此值为 true 时创建顶级的 QoS 和 Pod cgroup。(默认值为 true)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--chaos-chance float
+ + 如果大于 0.0,则引入随机客户端错误和延迟。用于测试。 +
--client-ca-file string
+ + 如果已设置客户端 CA 证书文件,则使用与客户端证书的 CommonName 对应的身份对任何携带 client-ca 文件中的授权机构之一签名的客户端证书的请求进行身份验证。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--cloud-config string
+ + 云服务商的配置文件路径。 +
--cloud-provider string
+ + 云服务商。设置为空字符串表示在没有云服务商的情况下运行。如果已设置云服务商,则云服务商将确定节点的名称(查阅云提供商文档以确定是否以及如何使用主机名)。 +
--cluster-dns strings
+ + 集群内 DNS 服务的 IP 地址,以逗号分隔。仅当 Pod 设置了 “dnsPolicy=ClusterFirst” 属性时可用。注意:列表中出现的所有 DNS 服务器必须包含相同的记录组,否则集群中的名称解析可能无法正常工作。无法保证名称解析过程中会牵涉到哪些 DNS 服务器。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--cluster-domain string
+ + 集群的域名。如果设置了此值,除了主机的搜索域外,kubelet 还将配置所有容器以搜索所指定的域名(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/)。 +
--cni-bin-dir string
+ + <警告:alpha 功能> 以逗号分隔的目录的完整路径列表,kubelet 将在其中搜索 CNI 插件可执行文件。仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。(默认为 “/opt/cni/bin”) +
--cni-cache-dir string
+ + <警告:alpha 功能> CNI 用于缓存文件的目录的完整路径。仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。(默认为 “/var/lib/cni/cache”) +
--cni-conf-dir string
+ + <警告:alpha 功能> 用来搜索 CNI 配置文件的目录的完整路径。仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。(默认为 “/etc/cni/net.d”) +
--config string
+ + kubelet 将从该文件加载其初始配置。该路径可以是绝对路径,也可以是相对路径。相对路径从 kubelet 的当前工作目录开始。省略此参数则使用内置的默认配置值。命令行参数会覆盖此文件中的配置。 +
--container-hints string
+ + 容器提示(hints)文件的位置。(默认值为 “/etc/cadvisor/container_hints.json”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--container-log-max-files int32
+ + <警告:beta 功能> 设置容器可以存在的容器日志文件个数上限。此值必须不小于 2。此参数只能与 --container-runtime=remote 参数一起使用。(默认值为 5)。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--container-log-max-size string
+ + <警告:beta 功能> 设置容器日志文件在轮转生成新文件时之前的最大值。此参数只能与 --container-runtime=remote 参数一起使用。(默认值为 “10Mi”)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--container-runtime string
+ + 要使用的容器运行时。目前支持 ‘docker’、‘remote’、‘rkt(已弃用)’。(默认值为 ‘docker’)。 +
--container-runtime-endpoint string
+ + [实验性特性] 容器运行时的远程服务端点。目前支持的类型包括 Linux 系统上的 UNIX 套接字、Windows 系统上支持的 npipe 和 TCP 端点。例如:‘unix:///var/run/dockershim.sock’、‘npipe:////./pipe/dockershim’。(默认值为 “unix:///var/run/dockershim.sock”) +
--containerd string
+ + 设置 containerd 的端点(默认值为 “/run/containerd/containerd.sock”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--contention-profiling
+ + 当启用了性能分析时,启用锁竞争分析(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--cpu-cfs-quota
+ + 设置为 true 表示启用 CPU CFS 配额,用于设置容器的 CPU 限制(默认值为 true)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--cpu-cfs-quota-period duration
+ + 设置 CPU CFS 配额周期,cpu.cfs_period_us。默认使用 Linux 内核所设置的默认值 (默认值为 100ms)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--cpu-manager-policy string
+ + 设置 CPU 管理器策略。可选值包括:‘none’ 和 ‘static’。默认值:“none”。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--cpu-manager-reconcile-period NodeStatusUpdateFrequency
+ + <警告:alpha 功能> 设置 CPU 管理器的调和时间。例如:‘10s’ 或者 ‘1m’。如果未设置,默认使用 NodeStatusUpdateFrequency 取值(默认值为 10s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--docker string
+ + docker 服务的端点地址(默认值为 “unix:///var/run/docker.sock”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--docker-endpoint string
+ + docker 端点使用该参数值进行通信。仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。(默认为 “unix:///var/run/docker.sock”) +
--docker-env-metadata-whitelist string
+ + docker 容器需要使用的以逗号分隔的环境变量键名列表(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--docker-only
+ + 设置为 true 表示除了根统计信息外,仅报告 Docker 容器的统计信息(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--docker-root string
+ + 已弃用:docker 根目录的路径(备用,默认值:/var/lib/docker)(默认值为 “/var/lib/docker”) +
--docker-tls
+ + 使用 TLS 连接 docker。(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--docker-tls-ca string
+ + 可信 CA 的路径(默认值为 “ca.pem”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--docker-tls-cert string
+ + 客户端证书的路径(默认值为 “cert.pem”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--docker-tls-key string
+ + 私钥文件路径(默认值为 “key.pem”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--dynamic-config-dir string
+ + 设置 kubelet 使用此目录来保存所下载的配置和跟踪配置运行状况。如果目录不存在,则创建该目录。该路径可以是绝对路径,也可以是相对路径。相对路径从 kubelet 的当前工作目录开始。设置此参数将启用动态 kubelet 配置。必须启用 DynamicKubeletConfig 特性开关才能传递此参数;由于该功能为 beta,此特性开关当前默认为 true。 +
--enable-cadvisor-json-endpoints
+ + 启用 cAdvisor JSON 数据的 /spec 和 /stats/* 端点。(默认值为 true) +
--enable-controller-attach-detach
+ + 设置为 true 表示启用 Attach/Detach 控制器进行来挂接和摘除调度到该节点的卷,同时禁用 kubelet 执行挂接和摘除操作(默认值为 true) +
--enable-debugging-handlers
+ + 设置为 true 表示启用服务器端点进行日志收集和在本地运行容器和命令(默认值为 true)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--enable-load-reader
+ + 设置为 true 表示启用读取 CPU 负载(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--enable-server
+ + 启动 kubelet 服务器(默认值为 true) +
--enforce-node-allocatable stringSlice
+ + 用逗号分隔的列表,包含由 kubelet 强制执行的节点可分配资源级别。可选配置为:‘none’、‘pods’、‘system-reserved’ 和 ‘kube-reserved’。在设置 ‘system-reserved’ 和 ‘kube-reserved’ 这两个值时,同时要求设置 ‘--system-reserved-cgroup’ 和 ‘--kube-reserved-cgroup’ 这两个参数。如果设置为 ‘none’,则不需要设置其他参数。更多信息请参考 https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources/。(默认值为 pods)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--event-burst int32
+ + 突发事件记录的个数上限,在遵从 event-qps 阈值约束的前提下临时允许事件记录达到此数目。仅在 --event-qps 大于 0 时使用(默认值为 10)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--event-qps int32
+ + 设置大于 0 的值表示限制每秒可生成的事件数量。设置为 0 表示不限制。(默认值为 5)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--event-storage-age-limit string
+ + 不同类型事件的最长保存时间。取值是键值对(key=value)的逗号分隔列表,其中键名是事件类型(例如:creation、oom)或者 “default”,键值是持续时间(duration)。所有未指定的事件类型都使用默认值(默认值为 “default=0”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--event-storage-event-limit string
+ + 每种事件类型的最大保存数量。取值是键值对(key=value)的逗号分隔列表,其中键名是事件类型(例如:creation、oom)或者 “default”,键值是一个整数(integer)。所有未指定的事件类型都使用默认值(默认值为 “default=0”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--eviction-hard mapStringString
+ + 触发 Pod 驱逐操作的一组硬性门限(例如:memory.available < 1Gi(内存可用值小于 1 G))设置。(默认值为 imagefs.available<15%,memory.available<100Mi,nodefs.available<10%,nodefs.inodesFree<5%)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--eviction-max-pod-grace-period int32
+ + 响应满足软驱逐阈值(soft eviction threshold)而终止 Pod 时使用的最长宽限期(以秒为单位)。如果设置为负数,则遵循 Pod 的指定值。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--eviction-minimum-reclaim mapStringString
+ + 当本节点压力过大时,kubelet 执行软性驱逐操作。此参数设置软性驱逐操作需要回收的资源的最小数量(例如:imagefs.available=2Gi)。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--eviction-pressure-transition-period duration
+ + kubelet 在触发软性 Pod 驱逐操作之前的最长等待时间。(默认值为 5m0s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--eviction-soft mapStringString
+ + 设置一组驱逐阈值(例如:memory.available<1.5Gi)。如果在相应的宽限期内达到该阈值,则会触发软性 Pod 驱逐操作。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--eviction-soft-grace-period mapStringString
+ + 设置一组驱逐宽限期,对应于触发软性 Pod 驱逐操作之前软性驱逐阈值所需持续的时间长短。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--exit-on-lock-contention
+ + 设置为 true 表示当发生锁文件竞争时 kubelet 可以退出。 +
--experimental-allocatable-ignore-eviction
+ + 设置为 true 表示在计算节点可分配资源数量时忽略硬性逐出阈值设置。请参考 https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources/。(默认值为 false)。 +
--experimental-bootstrap-kubeconfig string
+ + (已弃用:使用 --bootstrap-kubeconfig 参数) +
--experimental-check-node-capabilities-before-mount
+ + [实验性特性] 设置为 true 表示 kubelet 在进行挂载卷操作之前对本节点上所需的组件(如可执行文件等)进行检查 +
--experimental-kernel-memcg-notification
+ + 设置为 true 表示 kubelet 将会集成内核的 memcg 通知机制而不是使用轮询机制来判断是否达到了内存驱逐阈值。 +
--experimental-mounter-path string
+ + [实验性特性] 卷挂载器(mounter)可执行文件的路径。设置为空表示使用默认挂载器 mount。 +
--fail-swap-on
+ + 设置为 true 表示如果主机启用了交换分区,kubelet 将无法使用。(默认值为 true)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--feature-gates mapStringBool
+ + 用于 alpha 实验性质的特性开关组,每个开关以 key=value 形式表示。当前可用开关包括:
APIListChunking=true|false (BETA - default=true)
APIResponseCompression=true|false (BETA - default=true)
AllAlpha=true|false (ALPHA - default=false)
AppArmor=true|false (BETA - default=true)
AttachVolumeLimit=true|false (BETA - default=true)
BalanceAttachedNodeVolumes=true|false (ALPHA - default=false)
BlockVolume=true|false (BETA - default=true)
BoundServiceAccountTokenVolume=true|false (ALPHA - default=false)
CPUManager=true|false (BETA - default=true)
CRIContainerLogRotation=true|false (BETA - default=true) +
CSIBlockVolume=true|false (BETA - default=true)
CSIDriverRegistry=true|false (BETA - default=true)
CSIInlineVolume=true|false (BETA - default=true)
CSIMigration=true|false (ALPHA - default=false)
CSIMigrationAWS=true|false (ALPHA - default=false)
CSIMigrationAzureDisk=true|false (ALPHA - default=false)
CSIMigrationAzureFile=true|false (ALPHA - default=false)
CSIMigrationGCE=true|false (ALPHA - default=false)
CSIMigrationOpenStack=true|false (ALPHA - default=false)
CSINodeInfo=true|false (BETA - default=true)
CustomCPUCFSQuotaPeriod=true|false (ALPHA - default=false)
CustomResourceDefaulting=true|false (BETA - default=true)
DevicePlugins=true|false (BETA - default=true)
DryRun=true|false (BETA - default=true)
DynamicAuditing=true|false (ALPHA - default=false)
DynamicKubeletConfig=true|false (BETA - default=true)
EndpointSlice=true|false (ALPHA - default=false)
EphemeralContainers=true|false (ALPHA - default=false)
EvenPodsSpread=true|false (ALPHA - default=false)
ExpandCSIVolumes=true|false (BETA - default=true)
ExpandInUsePersistentVolumes=true|false (BETA - default=true)
ExpandPersistentVolumes=true|false (BETA - default=true)
ExperimentalHostUserNamespaceDefaulting=true|false (BETA - default=false)
HPAScaleToZero=true|false (ALPHA - default=false)
HyperVContainer=true|false (ALPHA - default=false)
IPv6DualStack=true|false (ALPHA - default=false)
KubeletPodResources=true|false (BETA - default=true)
LegacyNodeRoleBehavior=true|false (ALPHA - default=true)
LocalStorageCapacityIsolation=true|false (BETA - default=true)
LocalStorageCapacityIsolationFSQuotaMonitoring=true|false (ALPHA - default=false)
MountContainers=true|false (ALPHA - default=false)
NodeDisruptionExclusion=true|false (ALPHA - default=false)
NodeLease=true|false (BETA - default=true)
NonPreemptingPriority=true|false (ALPHA - default=false)
PodOverhead=true|false (ALPHA - default=false)
PodShareProcessNamespace=true|false (BETA - default=true)
ProcMountType=true|false (ALPHA - default=false)br/>QOSReserved=true|false (ALPHA - default=false)
RemainingItemCount=true|false (BETA - default=true)
RemoveSelfLink=true|false (ALPHA - default=false)
RequestManagement=true|false (ALPHA - default=false)
ResourceLimitsPriorityFunction=true|false (ALPHA - default=false)
ResourceQuotaScopeSelectors=true|false (BETA - default=true)
RotateKubeletClientCertificate=true|false (BETA - default=true)
RotateKubeletServerCertificate=true|false (BETA - default=true)
RunAsGroup=true|false (BETA - default=true)
RuntimeClass=true|false (BETA - default=true)
SCTPSupport=true|false (ALPHA - default=false)
ScheduleDaemonSetPods=true|false (BETA - default=true)
ServerSideApply=true|false (BETA - default=true)
ServiceLoadBalancerFinalizer=true|false (BETA - default=true)
ServiceNodeExclusion=true|false (ALPHA - default=false)
StartupProbe=true|false (ALPHA - default=false)
StorageVersionHash=true|false (BETA - default=true)
StreamingProxyRedirects=true|false (BETA - default=true)
SupportNodePidsLimit=true|false (BETA - default=true)
SupportPodPidsLimit=true|false (BETA - default=true)
Sysctls=true|false (BETA - default=true)
TTLAfterFinished=true|false (ALPHA - default=false)
TaintBasedEvictions=true|false (BETA - default=true)
TaintNodesByCondition=true|false (BETA - default=true)
TokenRequest=true|false (BETA - default=true)
TokenRequestProjection=true|false (BETA - default=true)
TopologyManager=true|false (ALPHA - default=false)
ValidateProxyRedirects=true|false (BETA - default=true)
VolumePVCDataSource=true|false (BETA - default=true)
VolumeSnapshotDataSource=true|false (ALPHA - default=false)
VolumeSubpathEnvExpansion=true|false (BETA - default=true)
WatchBookmark=true|false (BETA - default=true)
WinDSR=true|false (ALPHA - default=false)
WinOverlay=true|false (ALPHA - default=false)
WindowsGMSA=true|false (BETA - default=true)
WindowsRunAsUserName=true|false (ALPHA - default=false)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--file-check-frequency duration
+ + 检查配置文件中新数据的时间间隔(默认值为 20s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--global-housekeeping-interval duration
+ + 全局资源清理(housekeeping)操作的时间间隔。(默认值为 1m0s)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--hairpin-mode string
+ + 设置 kubelet 执行发夹模式(hairpin)网络地址转译的方式。该模式允许后端端点对其自身服务的访问能够再次经由负载均衡转发回自身。可选项包括 “promiscuous-bridge”、“hairpin-veth” 和 “none”。(默认值为 “promiscuous-bridge”)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--healthz-bind-address 0.0.0.0
+ + 用于运行 healthz 服务器的 IP 地址(对于所有 IPv4 接口,设置为 0.0.0.0;对于所有 IPv6 接口,设置为 `::`)(默认值为 127.0.0.1)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--healthz-port int32
+ + 本地 healthz 端点使用的端口(设置为 0 表示禁用)(默认值为 10248)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
-h, --help
kubelet 的帮助信息 + + kubelet 操作的帮助命令 +
--log-flush-frequency 间隔     默认: 5s--hostname-override string
日志刷新间隔的最大秒数 + + 如果为非空,将使用此字符串而不是实际的主机名作为节点标识。如果设置了 --cloud-provider,则云服务商将确定节点的名称(请查询云服务商文档以确定是否以及如何使用主机名)。 +
--housekeeping-interval duration
+ + 清理容器操作的时间间隔(默认值为 10 s) +
--http-check-frequency duration
+ + HTTP 服务以获取新数据的时间间隔(默认值为 20 s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--version version[=true]--image-gc-high-threshold int32
打印版本信息并退出 + + 镜像垃圾回收上限。磁盘使用空间达到该百分比时,镜像垃圾回收将持续工作。值必须在 [0,100] 范围内。要禁用镜像垃圾回收,请设置为 100。(默认值为 85)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--image-gc-low-threshold int32
+ + 镜像垃圾回收下限。磁盘使用空间在达到该百分比之前,镜像垃圾回收操作不会运行。值必须在 [0,100] 范围内,并且不得大于 --image-gc-high-threshold 的值。(默认值为 80)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--image-pull-progress-deadline duration
+ + 如果在该参数值所设置的期限之前没有拉取镜像的进展,镜像拉取操作将被取消。仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。(默认值为 1m0s) +
--image-service-endpoint string
+ + [实验性特性] 远程镜像服务的端点。若未设定则默认情况下使用 container-runtime-endpoint 的值。目前支持的类型包括在 Linux 系统上的 UNIX 套接字端点和 Windows 系统上的 npipe 和 TCP 端点。例如:‘unix:///var/run/dockershim.sock’、‘npipe:////./pipe/dockershim’。 +
--iptables-drop-bit int32
+ + 标记数据包将被丢弃的 fwmark 位设置。必须在 [0,31] 范围内。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--iptables-masquerade-bit int32
+ + 标记数据包将进行 SNAT 的 fwmark 位设置。必须在 [0,31] 范围内。请将此参数与 kube-proxy 中的相应参数匹配。(默认值为 14)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--keep-terminated-pod-volumes
+ + 设置为 true 表示 Pod 终止后仍然保留之前挂载过的卷,常用于调试与卷有关的问题。(已弃用:未来版本将会移除该参数) +
--kube-api-burst int32
+ + 每秒发送到 apiserver 的请求数量上限(默认值为 10)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--kube-api-content-type string
+ + 发送到 apiserver 的请求的内容类型。(默认值为 “application/vnd.kubernetes.protobuf”)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--kube-api-qps int32
+ + 与 apiserver 通信的每秒查询数(QPS) 值(默认值为 5)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--kube-reserved mapStringString
+ + kubernetes 系统预留的资源配置,以一组 ResourceName=ResourceQuantity 格式表示。(例如:cpu=200m,memory=500Mi,ephemeral-storage=1Gi)。当前支持用于根文件系统的 CPU、内存(memory)和本地临时存储。请参阅 http://kubernetes.io/docs/user-guide/compute-resources 获取更多信息。(默认值为 none)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--kube-reserved-cgroup string
+ + 给出某个顶层 cgroup 绝对名称,该 cgroup 用于管理带 ‘--kube-reserved’ 标签的 kubernetes 组件的计算资源。例如:‘/kube-reserved’。(默认值为 ‘’)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--kubeconfig string
+ + kubeconfig 配置文件的路径,指定如何连接到 API 服务器。提供 --kubeconfig 将启用 API 服务器模式,而省略 --kubeconfig 将启用独立模式。 +
--kubelet-cgroups string
+ + 用于创建和运行 kubelet 的 cgroup 的绝对名称。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--lock-file string
+ + <警告:alpha 功能> kubelet 使用的锁文件的路径。 +
--log-backtrace-at traceLocation
+ + 当日志逻辑执行到命中 file 的第 N 行时,转储调用堆栈(默认值为:0) +
--log-cadvisor-usage
+ + 设置为 true 表示将 cAdvisor 容器的使用情况写入日志(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--log-dir string
+ + 如果此值为非空,则在所指定的目录中写入日志文件 +
--log-file string
+ + 如果此值非空,使用所给字符串作为日志文件名 +
--log-file-max-size uint
+ + 定义日志文件的最大值。单位为兆字节(M)。如果值为 0,则最大文件大小表示无限制。(默认值为 1800) +
--log-flush-frequency duration
+ + 两次日志刷新之间的最大秒数(默认值为 5s) +
--logtostderr
+ + 日志输出到 stderr 而不是文件(默认值为 true) +
--machine-id-file string
+ + 以逗号分隔的文件列表,用于检查 machine-id。kubelet 使用存在的第一个 machine-id。(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--make-iptables-util-chains
+ + 设置为 true 表示 kubelet 将确保 Iptables 规则在主机上存在。(默认值为 true)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--manifest-url string
+ + 用于访问要运行的其他 Pod 规范的 URL(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--manifest-url-header --manifest-url-header 'a:hello,b:again,c:world' --manifest-url-header 'b:beautiful'
+ + 取值为由 HTTP 头部组成的逗号分隔列表,在访问 --manifest-url 所给出的 URL 时使用。名称相同的多个头部将按所列的顺序添加。该参数可以多次使用。例如:--manifest-url-header ‘a:hello,b:again,c:world’ --manifest-url-header ‘b:beautiful’(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--master-service-namespace string
+ + kubelet 向 Pod 注入 Kubernetes 主控服务信息时使用的命名空间(默认值为 “default”)(已弃用:此参数将在未来的版本中删除。) +
--max-open-files int
+ + kubelet 进程可以打开的最大文件数量(默认值为 1000000)。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--max-pods int32
+ + kubelet 能运行的 Pod 最大数量。(默认值为 110)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--maximum-dead-containers int32
+ + 设置全局可保留的已停止容器实例个数上限。每个实例会占用一些磁盘空间。要禁用,请设置为负数。(默认值为 -1)(已弃用:请改用 --eviction-hard 或者 --eviction-soft。此参数将在未来的版本中删除。) +
--maximum-dead-containers-per-container int32
+ + 可以保留的每个已停止容器的最大实例数量。每个容器占用一些磁盘空间。(默认值为 1)(已弃用:请改用 --eviction-hard 或者 --eviction-soft。此参数将在未来的版本中删除。) +
--minimum-container-ttl-duration duration
+ + 已结束的容器在被垃圾回收清理之前的最少存活时间。例如:‘300ms’、‘10s’ 或者 ‘2h45m’(已弃用:请改用 --eviction-hard 或者 --eviction-soft。此参数将在未来的版本中删除。) +
--minimum-image-ttl-duration duration
+ + 不再使用的镜像在被垃圾回收清理之前的最少存活时间。例如:‘300ms’、‘10s’ 或者 ‘2h45m’。(默认值为 2m0s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--network-plugin string
+ + <警告:alpha 功能> 设置 kubelet/pod 生命周期中各种事件调用的网络插件的名称。仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。 +
--network-plugin-mtu int32
+ + <警告:alpha 功能> 传递给网络插件的 MTU 值,将覆盖默认值。设置为 0 则使用默认的 1460 MTU。仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。 +
--node-ip string
+ + 节点的 IP 地址。如果设置,kubelet 将使用该 IP 地址作为节点的 IP 地址。 +
--node-labels mapStringString
+ + <警告:alpha 功能> kubelet 在集群中注册本节点时设置的标签。标签以 key=value 的格式表示,多个标签以逗号分隔。命名空间 ‘kubernetes.io’ 中的标签必须以 kubelet.kubernetes.io 或 node.kubernetes.io 为前缀,或者在以下明确允许范围内(beta.kubernetes.io/arch、beta.kubernetes.io/instance-type、beta.kubernetes.io/os、failure-domain.beta.kubernetes.io/region、 failure-domain.beta.kubernetes.io/zone、failure-domain.kubernetes.io/region、failure-domain.kubernetes.io/zone、kubernetes.io/arch、kubernetes.io/hostname、kubernetes.io/instance-type、kubernetes.io/os) +
--node-status-max-images int32
+ + <警告:alpha 功能> 在 Node.Status.Images 中可以报告的最大镜像数量。如果指定为 -1,则不设上限。(默认值为 50) +
--node-status-update-frequency duration
+ + 指定 kubelet 向主控节点汇报节点状态的时间间隔。注意:更改此常量时请务必谨慎,它必须与 nodecontroller 中的 nodeMonitorGracePeriod 一起使用。(默认值为 10s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--non-masquerade-cidr string
+ + kubelet 向该 IP 段之外的 IP 地址发送的流量将使用 IP 伪装技术。设置为 “0.0.0.0/0” 则不会使用伪装技术。(默认值为 “10.0.0.0/8”)(已弃用:该参数将在未来版本中删除。) +
--oom-score-adj int32
+ + kubelet 进程的 oom-score-adj 参数值。有效范围为 [-1000,1000](默认值为 -999)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--pod-cidr string
+ + 用于给 Pod 分配 IP 地址的 CIDR 地址池,仅在单机模式下使用。在集群模式下,CIDR 设置是从主服务器获取的。对于 IPv6,分配的 IP 的最大数量为 65536(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--pod-infra-container-image string
+ + 指定基础设施镜像,Pod 内所有容器与其共享网络和 IPC 命名空间。仅当容器运行环境设置为 docker 时,此特定于 docker 的参数才有效。(默认值为 “k8s.gcr.io/pause:3.1”) +
--pod-manifest-path string
+ + 设置包含要运行的静态 Pod 的文件的路径,或单个静态 Pod 文件的路径。以点(.)开头的文件将被忽略。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--pod-max-pids int
+ + 设置每个 Pod 中的最大进程数目。如果为 -1,则 kubelet 使用节点可分配的 PID 容量作为默认值。(默认值为 -1)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--pods-per-core int32
+ + kubelet 在每个处理器核上可运行的 Pod 数量。此 kubelet 上的 Pod 总数不能超过 max-pods 值。因此,如果此计算结果导致在 kubelet 上允许更多数量的 Pod,则使用 max-pods 值。值为 0 表示不做限制。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--port int32
+ + kubelet 服务监听的本机端口号。(默认值为 10250)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--protect-kernel-defaults
+ + 设置 kubelet 的默认内核调整行为。如果已设置该参数,当任何内核可调参数与 kubelet 默认值不同时,kubelet 都会出错。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--provider-id string
+ + 设置主机数据库中用来标识节点的唯一标识,即 cloudprovider +
--qos-reserved mapStringString
+ + <警告:alpha 功能> 设置在指定的 QoS 级别预留的 Pod 资源请求,以一组 “ResourceName=Percentage(资源名称=百分比)” 的形式进行设置,例如 memory=50%。当前仅支持内存(memory)。要求启用 QOSReserved 特性开关。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--read-only-port int32
+ + kubelet 可以在没有身份验证/鉴权的情况下提供只读服务的端口(设置为 0 表示禁用)(默认值为 10255)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--really-crash-for-testing
+ + 设置为 true 表示发生内核失效时崩溃。仅用于测试。 +
--redirect-container-streaming
+ + 启用容器流数据重定向。如果设置为 false,则 kubelet 将在 apiserver 和容器运行时之间转发容器流数据;如果设置为 true,则 kubelet 将返回指向 apiserver 的 HTTP 重定向指令,而 apiserver 将直接访问容器运行时。代理方法更安全,但会带来一些开销。重定向方法性能更高,但安全性较低,因为 apiserver 和容器运行时之间的连接可能未通过身份验证。 +
--register-node
+ + 将本节点注册到 apiserver。如果未提供 --kubeconfig 参数,则此参数无关紧要,因为 kubelet 将没有要注册的 apiserver。(默认值为 true) +
--register-schedulable
+ + 注册本节点为可调度的。register-node 为 false 时此设置无效。(默认值为 true)(已弃用:此参数将在未来的版本中删除。) +
--register-with-taints []api.Taint
+ + 设置本节点的污点标记,格式为 “<key>=<value>:<effect>” ,以逗号分隔。当 register-node 为 false 时此标志无效。 +
--registry-burst int32
+ + 设置突发性镜像拉取的个数上限,在不超过 registration-qps 设置值的前提下暂时允许此参数所给的镜像拉取个数。仅在 --registry-qps 大于 0(默认值为 10)时使用(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--registry-qps int32
+ + 如果 --registry-qps 大于 0,用来限制镜像仓库的 QPS 上限。设置为 0,表示不受限制。(默认值为 5)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--resolv-conf string
+ + 名字解析服务的配置文件名,用作容器 DNS 解析配置的基础。(默认值为 “/etc/resolv.conf”)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--root-dir string
+ + 设置用于管理 kubelet 文件的根目录(例如挂载卷的相关文件)(默认值为 “/var/lib/kubelet”) +
--rotate-certificates
+ + <警告:alpha 功能> 设置当客户端证书即将过期时 kubelet 自动从 kube-apiserver 请求新的证书进行轮换。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--rotate-server-certificates
+ + 当证书即将过期时自动从 kube-apiserver 请求新的证书进行轮换。要求启用 RotateKubeletServerCertificate 特性开关,以及对提交的 CertificateSigningRequest 对象进行批复(approve)操作。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--runonce
+ + 设置为 true 表示从本地清单或远程 URL 创建完 Pod 后立即退出 kubelet 进程,与 --enable-server 参数互斥 +
--runtime-cgroups string
+ + 设置用于创建和运行容器运行时的 cgroup 的绝对名称。 +
--runtime-request-timeout duration
+ + 除了长时间运行的请求(包括 pull、logs、exec 和 attach 等操作),设置其他请求的超时时间。到达超时时间时,请求会被取消,抛出一个错误并会等待重试。(默认值为 2m0s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--seccomp-profile-root string
+ + <警告:alpha 功能> seccomp 配置文件目录。(默认值为 “/var/lib/kubelet/seccomp”) +
--serialize-image-pulls
+ + 逐一拉取镜像。建议 *不要* 在 docker 守护进程版本低于 1.9 或启用了 Aufs 存储后端的节点上更改默认值。(默认值为 true)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--skip-headers
+ + 设置为 true,则在日志消息中去掉标头前缀 +
--skip-log-headers
+ + 设置为 true,打开日志文件时去掉标头 +
--stderrthreshold severity
+ + 设置严重程度达到或超过此阈值的日志输出到标准错误输出(默认值为 2) +
--storage-driver-buffer-duration duration
+ + 设置存储驱动程序中写操作的缓冲时长,超过时长的操作会作为单一事务提交到非内存后端。(默认值为 1m0s)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--storage-driver-db string
+ + 后端存储的数据库名称(默认值为 “cadvisor”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--storage-driver-host string
+ + 后端存储的数据库连接 URL 地址(默认值为 “localhost:8086”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--storage-driver-password string
+ + 后端存储的数据库密码(默认值为 “root”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--storage-driver-secure
+ + 后端存储的数据库是否用安全连接(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--storage-driver-table string
+ + 后端存储的数据库表名(默认值为 “stats”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--storage-driver-user string
+ + 后端存储的数据库用户名(默认值为 “root”)(已弃用:这是一个错误地在 kubelet 中注册的 cadvisor 参数。由于遗留问题,在删除之前,它将遵循标准的 CLI 弃用时间表。) +
--streaming-connection-idle-timeout duration
+ + 设置流连接在自动关闭之前可以空闲的最长时间。0 表示没有超时限制。例如:‘5m’(默认值为 4h0m0s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--sync-frequency duration
+ + 在运行中的容器与其配置之间执行同步操作的最长时间间隔(默认值为 1m0s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--system-cgroups /
+ + cgroup 的绝对名称,用于所有尚未放置在根目录下某 cgroup 内的非内核进程。空值表示不指定 cgroup。回滚该参数需要重启机器。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--system-reserved mapStringString
+ + 系统预留的资源配置,以一组 ”ResourceName=ResourceQuantity“ 的格式表示,(例如:cpu=200m,memory=500Mi,ephemeral-storage=1Gi)。目前仅支持 CPU 和内存(memory)的设置。请参考 http://kubernetes.io/docs/user-guide/compute-resources 获取更多信息。(默认值为 ”none“)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--system-reserved-cgroup string
+ + 给出一个顶层 cgroup 绝对名称,该 cgroup 用于管理非 kubernetes 组件,这些组件的计算资源通过 ‘--system-reserved’ 标志进行预留。例如 ‘/system-reserved’。(默认值为 ‘’)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--tls-cert-file string
+ + 包含 x509 证书的文件路径,用于 HTTPS 认证。如果有中间证书,则中间证书要串接在在服务器证书之后。如果未提供 --tls-cert-file 和 --tls-private-key-file,kubelet 会为公开地址生成自签名证书和密钥,并将其保存到通过 --cert-dir 指定的目录中。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--tls-cipher-suites stringSlice
+ + 服务器端加密算法列表,以逗号分隔,如果不设置,则使用 Go 语言加密包的默认算法列表。可选加密算法包括:TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_3DES_EDE_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_RC4_128_SHA (已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--tls-min-version string
+ + 设置支持的最小 TLS 版本号,可选的版本号包括:VersionTLS10、VersionTLS11、VersionTLS12 和 VersionTLS13 (已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--tls-private-key-file string
+ + 包含与 --tls-cert-file 对应的 x509 私钥文件路径。(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
--topology-manager-policy string
+ + 设置拓扑管理策略(Topology Manager policy)。可选值包括:‘none’、‘best-effort’、‘restricted’ 和 ‘single-numa-node’。(默认值为 “none”)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
-v, --v Level
+ + 设置 kubelet 日志级别详细程度的数值 +
--version version[=true]
+ + 打印 kubelet 版本信息并退出 +
--vmodule moduleSpec
+ + 以逗号分隔的 pattern=N 设置列表,用于文件过滤的日志记录 +
--volume-plugin-dir string
+ + <警告:alpha 功能> 用来搜索第三方存储卷插件的目录(默认值为 “/usr/libexec/kubernetes/kubelet-plugins/volume/exec/”) +
--volume-stats-agg-period duration
+ + 指定 kubelet 计算和缓存所有 Pod 和卷的磁盘用量总值的时间间隔。要禁用磁盘用量计算,请设置为 0。(默认值为 1m0s)(已弃用:在 --config 指定的配置文件中进行设置。有关更多信息,请参阅 https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/。) +
- - +{{% /capture %}} diff --git a/content/zh/docs/reference/glossary/admission-controller.md b/content/zh/docs/reference/glossary/admission-controller.md new file mode 100644 index 0000000000..4ce643553b --- /dev/null +++ b/content/zh/docs/reference/glossary/admission-controller.md @@ -0,0 +1,44 @@ +--- +title: 准入控制器 +id: admission-controller +date: 2019-06-28 +full_link: /docs/reference/access-authn-authz/admission-controllers/ +short_description: > + 在对象持久化之前拦截 Kubernetes Api 服务器请求的一段代码 +aka: +tags: +- extension +- security +--- + + + +在对象持久化之前拦截 Kubernetes Api 服务器请求的一段代码 + + + + +准入控制器可针对 Kubernetes Api 服务器进行配置,可以执行验证,变更或两者都执行。任何准入控制器都可以拒绝访问请求。 +变更(mutating)控制器可以修改其允许的对象,验证(validating)控制器则不可以。 + +* [Kubernetes 文档中的准入控制器](/docs/reference/access-authn-authz/admission-controllers/) \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/aggregation-layer.md b/content/zh/docs/reference/glossary/aggregation-layer.md new file mode 100644 index 0000000000..982c7ef3a2 --- /dev/null +++ b/content/zh/docs/reference/glossary/aggregation-layer.md @@ -0,0 +1,45 @@ +--- +title: 聚合层 +id: aggregation-layer +date: 2018-10-08 +full_link: /docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/ +short_description: > + 聚合层允许您在自己的集群上安装额外的 Kubernetes 风格的 API。 + +aka: +tags: +- architecture +- extension +- operation +--- + + + + + +聚合层允许您在自己的集群上安装额外的 Kubernetes 风格的 API。 + + + + + +当您配置了 {{< glossary_tooltip text="Kubernetes API Server" term_id="kube-apiserver" >}} 来 [支持额外的 API](/docs/tasks/access-kubernetes-api/configure-aggregation-layer/),您就可以在 Kubernetes API 中增加 `APIService` 对象来 "申领(Claim)" 一个 URL 路径。 diff --git a/content/zh/docs/reference/glossary/annotation.md b/content/zh/docs/reference/glossary/annotation.md new file mode 100644 index 0000000000..75705d9745 --- /dev/null +++ b/content/zh/docs/reference/glossary/annotation.md @@ -0,0 +1,42 @@ +--- +title: 注解 +id: annotation +date: 2018-04-12 +full_link: /docs/concepts/overview/working-with-objects/annotations +short_description: > + 注解是以键值对的形式给资源对象附加随机的无法标识的元数据。 + +aka: +tags: +- fundamental +--- + + + + + + 注解是以键值对的形式给资源对象附加随机的无法标识的元数据。 + + + + + +注解中的元数据可大可小,可以是结构化的也可以是非结构化的,并且能包含标签不允许使用的字符。像工具和软件库这样的客户端可以检索这些元数据。 + diff --git a/content/zh/docs/reference/glossary/app-container.md b/content/zh/docs/reference/glossary/app-container.md new file mode 100644 index 0000000000..a3238d65dd --- /dev/null +++ b/content/zh/docs/reference/glossary/app-container.md @@ -0,0 +1,41 @@ +--- +title: 应用程序容器 +id: app-container +date: 2019-02-12 +full_link: +short_description: > + 用于运行部分工作负载的容器。与初始化容器比较而言。 + +aka: +tags: +- workload +--- + 应用程序容器(或 app 容器){{< glossary_tooltip text="容器" term_id="container" >}} 在 {{< glossary_tooltip text="pod" term_id="pod" >}} 中,在 {{< glossary_tooltip text="初始化容器" term_id="init-container" >}} 启动完毕后才开始启动。 + + + + + + + +初始化容器使您可以分离对于 {{< glossary_tooltip text="工作负载" term_id="workload" >}} 整体而言很重要的初始化细节,并且一旦应用容器启动,它不需要继续运行。 +如果 pod 没有配置任何初始化容器,则该 pod 中的所有容器都是应用程序容器。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/application-architect.md b/content/zh/docs/reference/glossary/application-architect.md new file mode 100644 index 0000000000..849d1b7685 --- /dev/null +++ b/content/zh/docs/reference/glossary/application-architect.md @@ -0,0 +1,37 @@ +--- +title: 应用架构师 +id: application-architect +date: 2018-04-12 +full_link: +short_description: > + 应用架构师是负责应用高级设计的人。 + +aka: +tags: +- user-type +--- + 应用架构师是负责应用高级设计的人。 + + + + + + +应用架构师确保应用的实现允许它和周边组件进行可扩展的、可持续的交互。周边组件包括数据库、日志基础设施和其他微服务。 + diff --git a/content/zh/docs/reference/glossary/application-developer.md b/content/zh/docs/reference/glossary/application-developer.md new file mode 100644 index 0000000000..65650133da --- /dev/null +++ b/content/zh/docs/reference/glossary/application-developer.md @@ -0,0 +1,41 @@ +--- +title: 应用开发者 +id: application-developer +date: 2018-04-12 +full_link: +short_description: > + 编写可以在 Kubernetes 集群上运行的应用的人。 + +aka: +tags: +- user-type +--- + + + + + +编写可以在 Kubernetes 集群上运行的应用的人。 + + + + + +应用开发者专注于应用的某一部分。他们工作范围的大小有明显的差异。 diff --git a/content/zh/docs/reference/glossary/applications.md b/content/zh/docs/reference/glossary/applications.md new file mode 100644 index 0000000000..cd02a4ee14 --- /dev/null +++ b/content/zh/docs/reference/glossary/applications.md @@ -0,0 +1,26 @@ +--- +title: 应用 +id: applications +date: 2019-05-12 +full_link: +short_description: > + 各种容器化应用运行所在的层。 +aka: +tags: +- fundamental +--- + + + 各种容器化应用运行所在的层。 diff --git a/content/zh/docs/reference/glossary/approver.md b/content/zh/docs/reference/glossary/approver.md new file mode 100755 index 0000000000..879ef5e58b --- /dev/null +++ b/content/zh/docs/reference/glossary/approver.md @@ -0,0 +1,40 @@ +--- +title: 批准者 +id: approver +date: 2018-04-12 +full_link: +short_description: > + 可以审核并批准 Kubernetes 代码贡献的人。 + +aka: +tags: +- community +--- + + + + 可以审核并批准 Kubernetes 代码贡献的人。 + + + + + +代码审核的重点是代码质量和正确性,而批准的重点是对贡献的整体接受。 +整体接受包括向后/向前兼容性、遵守 API 和参数约定、细微的性能和正确性问题、与系统其他部分的交互等。 +批准者状态的作用域是代码库的一部分。 +审批者以前被称为维护者。 diff --git a/content/zh/docs/reference/glossary/certificate.md b/content/zh/docs/reference/glossary/certificate.md new file mode 100644 index 0000000000..238178c890 --- /dev/null +++ b/content/zh/docs/reference/glossary/certificate.md @@ -0,0 +1,42 @@ +--- +title: 证书 +id: certificate +date: 2018-04-12 +full_link: /docs/tasks/tls/managing-tls-in-a-cluster/ +short_description: > + 证书是个安全加密文件,用来确认对 Kubernetes 集群访问的合法性。 + +aka: +tags: +- security +--- + + + + + +证书是个安全加密文件,用来确认对 Kubernetes 集群访问的合法性。 + + + + + +证书可以让 Kubernetes 集群中运行的应用程序安全的访问 Kubernetes API。证书可以确认客户端是否被允许访问 API。 + diff --git a/content/zh/docs/reference/glossary/cgroup.md b/content/zh/docs/reference/glossary/cgroup.md new file mode 100644 index 0000000000..10d274a5e5 --- /dev/null +++ b/content/zh/docs/reference/glossary/cgroup.md @@ -0,0 +1,40 @@ +--- +title: cgroup (控制组) +id: cgroup +date: 2019-06-25 +full_link: +short_description: > + 一组具有可选资源隔离、审计和限制的 Linux 进程。 + +aka: +tags: +- fundamental +--- + + + + +一组具有可选资源隔离、审计和限制的 Linux 进程。 + + + + + +Cgroup 是一个 Linux 内核特性,对一组进程的资源使用(CPU、内存、磁盘 I/O 和网络等)进行限制、审计和隔离。 diff --git a/content/zh/docs/reference/glossary/cla.md b/content/zh/docs/reference/glossary/cla.md new file mode 100644 index 0000000000..dae58a89e6 --- /dev/null +++ b/content/zh/docs/reference/glossary/cla.md @@ -0,0 +1,38 @@ +--- +title: CLA (贡献者许可协议) +id: cla +date: 2018-04-12 +full_link: https://github.com/kubernetes/community/blob/master/CLA.md +short_description: > + 贡献者对他们在开源项目中所贡献的代码的授权许可条款。 + +aka: +tags: +- community +--- + + + + {{< glossary_tooltip text="贡献者" term_id="contributor" >}} 对他们在开源项目中所贡献的代码的授权许可条款。 + + + + + +CLA 对解决贡献者在开源社区所贡献的资料和智力资产(IP)导致的法律纠纷很有帮助。 + diff --git a/content/zh/docs/reference/glossary/cloud-controller-manager.md b/content/zh/docs/reference/glossary/cloud-controller-manager.md new file mode 100755 index 0000000000..b6254d7ce9 --- /dev/null +++ b/content/zh/docs/reference/glossary/cloud-controller-manager.md @@ -0,0 +1,47 @@ +--- +title: 云控制器管理器 +id: cloud-controller-manager +date: 2018-04-12 +full_link: /docs/tasks/administer-cluster/running-cloud-controller/ +short_description: > + 云控制器管理器是 1.8 的 alpha 特性。在未来发布的版本中,这是将 Kubernetes 与任何其他云集成的最佳方式。 + +aka: +tags: +- core-object +- architecture +- operation +--- + + + + + +云控制器管理器是 1.8 的 alpha 特性。在未来发布的版本中,这是将 Kubernetes 与任何其他云集成的最佳方式。 + + + + + +Kubernetes v1.6 包含一个新的可执行文件叫做 cloud-controller-manager。cloud-controller-manager 是一个守护进程,其中嵌入了特定于某云环境的控制环。 +这些特定于云环境的控制环最初位于 kube-controller-manager 中。 +由于云供应商的开发和发布节奏与 Kubernetes 项目不同步,将特定于供应商的代码抽象到 cloud-controller-manager 可执行文件可以允许云供应商独立于核心 Kubernetes 代码进行演进。 diff --git a/content/zh/docs/reference/glossary/cloud-provider.md b/content/zh/docs/reference/glossary/cloud-provider.md new file mode 100644 index 0000000000..16851569d6 --- /dev/null +++ b/content/zh/docs/reference/glossary/cloud-provider.md @@ -0,0 +1,38 @@ +--- +title: 云供应商 +id: cloud-provider +date: 2018-04-12 +full_link: /docs/concepts/cluster-administration/cloud-providers +short_description: > + 云供应商是提供可以用来运行 Kubernetes 集群的云计算平台的公司。 + +aka: +tags: +- community +--- + + + + 云供应商是提供可以用来运行 Kubernetes 集群的云计算平台的公司。 + + + + +云供应商也叫云服务供应商(CSPs),他们可以为用户提供云计算平台。他们提供的服务可以是基础设施即服务(IaaS)或者平台即服务(PaaS)。云供应商除了运行 Kubernetes 集群,还提供一些集群交互的服务,例如负载均衡(Load Balancers)、存储类别(Storage Classes)等。 diff --git a/content/zh/docs/reference/glossary/cluster-architect.md b/content/zh/docs/reference/glossary/cluster-architect.md new file mode 100644 index 0000000000..c45bcfbe34 --- /dev/null +++ b/content/zh/docs/reference/glossary/cluster-architect.md @@ -0,0 +1,37 @@ +--- +title: 集群架构师 +id: cluster-architect +date: 2018-04-12 +full_link: +short_description: > + 集群架构师负责设计集群的基础设施,可能包含一个或多个 Kubernetes 集群。 + +aka: +tags: +- user-type +--- + + + + 集群架构师负责设计集群的基础设施,可能包含一个或多个 Kubernetes 集群。 + + + + + +集群架构师要具备分布式系统的最佳实践经验,例如:高可用性和安全性。 diff --git a/content/zh/docs/reference/glossary/cluster-infrastructure.md b/content/zh/docs/reference/glossary/cluster-infrastructure.md new file mode 100644 index 0000000000..9d9eb4343d --- /dev/null +++ b/content/zh/docs/reference/glossary/cluster-infrastructure.md @@ -0,0 +1,31 @@ +--- +title: 集群基础设施 +id: cluster-infrastructure +date: 2019-05-12 +full_link: +short_description: > + 基础设施层提供并维护虚拟机、网络、安全组及其他资源。 + +aka: +tags: +- operations +--- + + + +基础设施层提供并维护虚拟机、网络、安全组及其他资源。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/cluster-operations.md b/content/zh/docs/reference/glossary/cluster-operations.md new file mode 100644 index 0000000000..98dcda6505 --- /dev/null +++ b/content/zh/docs/reference/glossary/cluster-operations.md @@ -0,0 +1,32 @@ +--- +title: 集群操作 +id: cluster-operations +date: 2019-05-12 +full_link: +short_description: > + 诸如升级集群、实现安全、存储、Ingress、网络、日志和监控之类的活动,以及管理 Kubernetes 集群所涉及的其他操作。 + +aka: +tags: +- operations +--- + + + + + 诸如升级集群、实现安全、存储、Ingress、网络、日志和监控之类的活动,以及管理 Kubernetes 集群所涉及的其他操作。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/cluster-operator.md b/content/zh/docs/reference/glossary/cluster-operator.md new file mode 100644 index 0000000000..8318dd46ed --- /dev/null +++ b/content/zh/docs/reference/glossary/cluster-operator.md @@ -0,0 +1,44 @@ +--- +title: 集群操作者 +id: cluster-operator +date: 2018-04-12 +full_link: +short_description: > + 配置、控制、监控集群的人。 + +aka: +tags: +- user-type +--- + + + + + 配置、控制、监控集群的人。 + + + + +他们的主要责任是保持集群正常运行,可能需要进行周期性的维护和升级活动。
+ +**注意:** 集群操作者不同于[操作者模式(Operator Pattern)](https://coreos.com/operators),操作者模式是用来扩展 Kubernetes API 的。 + diff --git a/content/zh/docs/reference/glossary/cluster.md b/content/zh/docs/reference/glossary/cluster.md new file mode 100644 index 0000000000..3b2f95566a --- /dev/null +++ b/content/zh/docs/reference/glossary/cluster.md @@ -0,0 +1,33 @@ +--- +title: 集群 +id: cluster +date: 2019-06-15 +full_link: +short_description: > + 集群由一组被称作节点的机器组成。这些节点上运行 Kubernetes 所管理的容器化应用。集群具有至少一个工作节点和至少一个主节点。 + +aka: +tags: +- fundamental +- operation +--- + + + +集群由一组被称作节点的机器组成。这些节点上运行 Kubernetes 所管理的容器化应用。集群具有至少一个工作节点和至少一个主节点。 + + + +工作节点托管作为应用程序组件的 Pod 。主节点管理集群中的工作节点和 Pod 。多个主节点用于为集群提供故障转移和高可用性。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/cncf.md b/content/zh/docs/reference/glossary/cncf.md new file mode 100644 index 0000000000..e6e857b6bc --- /dev/null +++ b/content/zh/docs/reference/glossary/cncf.md @@ -0,0 +1,43 @@ +--- +title: 云原生计算基金会 (CNCF) +id: cncf +date: 2019-05-26 +full_link: https://cncf.io/ +short_description: > + 云原生计算基金会 + +aka: +tags: +- community +--- + 云原生计算基金会(CNCF)建立了可持续的生态系统,并在围绕着 [项目](https://www.cncf.io/projects/) 建立一个社区,将容器编排微服务架构的一部分。 + +Kubernetes 是一个云原生计算基金会项目. + + + + + + +云原生计算基金会(CNCF)是 [Linux 基金会](https://www.linuxfoundation.org/) 的下属基金会。它的使命是让云原生计算无处不在。 diff --git a/content/zh/docs/reference/glossary/cni.md b/content/zh/docs/reference/glossary/cni.md new file mode 100644 index 0000000000..361a7f0911 --- /dev/null +++ b/content/zh/docs/reference/glossary/cni.md @@ -0,0 +1,44 @@ +--- +title: CNI (容器网络接口) +id: cni +date: 2018-05-25 +full_link: /docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/#cni +short_description: > + 容器网络接口 (CNI) 插件是遵循 appc/CNI 协议的一类网络插件。 + + +aka: +tags: +- networking +--- + + + + + + 容器网络接口 (CNI) 插件是遵循 appc/CNI 协议的一类网络插件。 + + + + + +* 想了解 Kubernetes 和 CNI 请参考 ["网络插件"](/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/#cni)。 diff --git a/content/zh/docs/reference/glossary/code-contributor.md b/content/zh/docs/reference/glossary/code-contributor.md new file mode 100644 index 0000000000..8d24d7f72f --- /dev/null +++ b/content/zh/docs/reference/glossary/code-contributor.md @@ -0,0 +1,43 @@ +--- +title: 代码贡献者 +id: code-contributor +date: 2018-04-12 +full_link: /docs/community/devel/ +short_description: > + 为 Kubernetes 开源代码库开发并贡献代码的人。 + +aka: +tags: +- community +- user-type +--- + + + + + + 为 Kubernetes 开源代码库开发并贡献代码的人。 + + + + + +代码贡献者也是加入一个或多个 {{< glossary_tooltip text="特别兴趣小组 (SIGs)" term_id="sig" >}} 的活跃的 {{< glossary_tooltip text="社区成员" term_id="member" >}}。 diff --git a/content/zh/docs/reference/glossary/configmap.md b/content/zh/docs/reference/glossary/configmap.md new file mode 100644 index 0000000000..d3d0945cdc --- /dev/null +++ b/content/zh/docs/reference/glossary/configmap.md @@ -0,0 +1,41 @@ +--- +title: ConfigMap +id: configmap +date: 2018-04-12 +full_link: /docs/tasks/configure-pod-container/configure-pod-configmap/ +short_description: > + ConfigMap 是一种 API 对象,用来将非机密性的数据保存到健值对中。使用时可以用作环境变量、命令行参数或者存储卷中的配置文件。 + +aka: +tags: +- core-object +--- + + + + + + ConfigMap 是一种 API 对象,用来将非机密性的数据保存到健值对中。使用时可以用作环境变量、命令行参数或者存储卷中的配置文件。 + + + + + +ConfigMap 将您的环境配置信息和 {{< glossary_tooltip text="容器镜像" term_id="container" >}} 解耦,便于应用配置的修改。当您需要储存机密信息时可以使用 [Secret](/docs/concepts/configuration/secret/) 对象。 diff --git a/content/zh/docs/reference/glossary/container-env-variables.md b/content/zh/docs/reference/glossary/container-env-variables.md new file mode 100644 index 0000000000..d851c14c92 --- /dev/null +++ b/content/zh/docs/reference/glossary/container-env-variables.md @@ -0,0 +1,40 @@ +--- +title: 容器环境变量 +id: container-env-variables +date: 2018-04-12 +full_link: /docs/concepts/containers/container-environment-variables.md +short_description: > + 容器环境变量提供了运行容器化应用所必须的一些重要信息。 + +aka: +tags: +- fundamental +--- + + + + + + 容器环境变量提供了运行容器化应用所必须的一些重要信息。 + + + + + 容器环境变量为运行中的容器化应用提供必要的信息,同时还提供与 {{< glossary_tooltip text="容器" term_id="container" >}} 重要资源相关的其他信息,例如:文件系统信息、容器自身的信息以及其他像服务端点(Service endpoints)这样的集群资源信息。 diff --git a/content/zh/docs/reference/glossary/container-lifecycle-hooks.md b/content/zh/docs/reference/glossary/container-lifecycle-hooks.md new file mode 100644 index 0000000000..3d1b708fe0 --- /dev/null +++ b/content/zh/docs/reference/glossary/container-lifecycle-hooks.md @@ -0,0 +1,38 @@ +--- +title: 容器生命周期钩子 +id: container-lifecycle-hooks +date: 2018-10-08 +full_link: /docs/concepts/containers/container-lifecycle-hooks/ +short_description: > + 生命周期钩子暴露容器管理生命周期中的事件,允许用户在事件发生时运行代码。 + +aka: +tags: +- extension +--- + + + 生命周期钩子暴露{{< glossary_tooltip text="容器" term_id="container" >}}管理生命周期中的事件,允许用户在事件发生时运行代码。 + + + + +针对容器暴露了两个钩子:PostStart 在容器创建之后立即执行,PreStop 在容器停止之前立即阻塞并被调用。 + diff --git a/content/zh/docs/reference/glossary/container-runtime.md b/content/zh/docs/reference/glossary/container-runtime.md new file mode 100644 index 0000000000..d5568e7fb8 --- /dev/null +++ b/content/zh/docs/reference/glossary/container-runtime.md @@ -0,0 +1,45 @@ +--- +title: 容器运行环境(Container Runtime) +id: container-runtime +date: 2019-06-05 +full_link: /docs/reference/generated/container-runtime +short_description: > + 容器运行环境是负责运行容器的软件。 + +aka: +tags: +- fundamental +- workload +--- + + + +容器运行环境是负责运行容器的软件。 + + + + +Kubernetes 支持多个容器运行环境: [Docker](http://www.docker.com)、 +[containerd](https://containerd.io)、[cri-o](https://cri-o.io/)、 +[rktlet](https://github.com/kubernetes-incubator/rktlet) 以及任何实现 [Kubernetes CRI (容器运行环境接口)](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/container-runtime-interface.md)。 diff --git a/content/zh/docs/reference/glossary/container.md b/content/zh/docs/reference/glossary/container.md new file mode 100644 index 0000000000..16d99f4e30 --- /dev/null +++ b/content/zh/docs/reference/glossary/container.md @@ -0,0 +1,44 @@ +--- +title: 容器 +id: container +date: 2018-04-12 +full_link: /docs/concepts/overview/what-is-kubernetes/#why-containers +short_description: > + 容器是可移植、可执行的轻量级的镜像,镜像中包含软件及其相关依赖。 + +aka: +tags: +- fundamental +- workload +--- + + + + + + 容器是可移植、可执行的轻量级的镜像,镜像中包含软件及其相关依赖。 + + + + + +容器使应用和底层的主机基础设施解耦,降低了应用在不同云环境或者操作系统上的部署难度,便于应用扩展。 + diff --git a/content/zh/docs/reference/glossary/containerd.md b/content/zh/docs/reference/glossary/containerd.md new file mode 100644 index 0000000000..e764362cc6 --- /dev/null +++ b/content/zh/docs/reference/glossary/containerd.md @@ -0,0 +1,39 @@ +--- +title: containerd +id: containerd +date: 2019-05-14 +full_link: https://containerd.io/docs/ +short_description: > + 强调简单性、健壮性和可移植性的一种容器运行时 +aka: +tags: +- tool +--- + + + + 强调简单性、健壮性和可移植性的一种容器运行时 + + + + + +containerd 是一种 {{< glossary_tooltip text="容器" term_id="container" >}} 运行时,能在 Linux 或者 Windows 后台运行。 +containerd 能取回、存储容器镜像,执行容器实例,提供网络访问等。 diff --git a/content/zh/docs/reference/glossary/contributor.md b/content/zh/docs/reference/glossary/contributor.md new file mode 100755 index 0000000000..32f21a5e54 --- /dev/null +++ b/content/zh/docs/reference/glossary/contributor.md @@ -0,0 +1,39 @@ +--- +title: 贡献者 +id: contributor +date: 2018-04-12 +full_link: +short_description: > + 通过贡献代码、文档或者投入时间等方式来帮助 Kubernetes 项目或社区的人。 + +aka: +tags: +- community +--- + + + + + +通过贡献代码、文档或者投入时间等方式来帮助 Kubernetes 项目或社区的人。 + + + + +贡献形式包括提交拉取请求(PRs)、问题报告(Issues)、反馈、参与{{< glossary_tooltip text="特别兴趣小组(SIG)" term_id="sig" >}}或者组织社区活动等等。 + diff --git a/content/zh/docs/reference/glossary/control-plane.md b/content/zh/docs/reference/glossary/control-plane.md new file mode 100644 index 0000000000..1916feac7f --- /dev/null +++ b/content/zh/docs/reference/glossary/control-plane.md @@ -0,0 +1,31 @@ +--- +title: 控制平面 +id: control-plane +date: 2019-05-12 +full_link: +short_description: > + 容器编排层,它暴露 API 和接口来定义、部署容器和管理容器的生命周期。 + +aka: +tags: +- fundamental +--- + + + + 容器编排层,它暴露 API 和接口来定义、部署容器和管理容器的生命周期。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/controller.md b/content/zh/docs/reference/glossary/controller.md new file mode 100644 index 0000000000..2b523c8b76 --- /dev/null +++ b/content/zh/docs/reference/glossary/controller.md @@ -0,0 +1,40 @@ +--- +title: 控制器 +id: controller +date: 2018-04-12 +full_link: /docs/admin/kube-controller-manager/ +short_description: > + 控制器通过 apiserver 监控集群的公共状态,并致力于将当前状态转变为期望的状态。 + +aka: +tags: +- architecture +- fundamental +--- + + + + 控制器通过 {{< glossary_tooltip text="apiserver" term_id="kube-apiserver" >}} 监控集群的公共状态,并致力于将当前状态转变为期望的状态。 + + + + + +Kubernetes 当前提供的部分控制器例子包括:副本控制器(replication controller)、端点控制器(endpoints controller)、命名空间控制器(namespace controller)、服务账号控制器(serviceaccounts controller)。 + diff --git a/content/zh/docs/reference/glossary/cri-o.md b/content/zh/docs/reference/glossary/cri-o.md new file mode 100644 index 0000000000..8eb19ddbbb --- /dev/null +++ b/content/zh/docs/reference/glossary/cri-o.md @@ -0,0 +1,40 @@ +--- +title: CRI-O +id: cri-o +date: 2019-05-14 +full_link: https://cri-o.io/docs/ +short_description: > + 专用于 Kubernetes 的轻量级容器运行环境 + +aka: +tags: +- tool +--- + + + +该工具可让您通过 Kubernetes CRI 使用 OCI 容器运行环境。 + + + + +CRI-O 是 {{< glossary_tooltip term_id="cri" >}} 的实现,可启用与开放容器倡议 Open Container Initiative(OCI)兼容的 {{< glossary_tooltip text="container" term_id="container" >}} 运行环境[运行时规范](http://www.github.com/opencontainers/runtime-spec)。 + + +部署 CRI-O 允许 Kubernetes 使用任何符合 OCI 运行环境,作为容器运行环境去运行 {{< glossary_tooltip text="Pods" term_id="pod" >}},并从远程注册表获取 OCI 容器镜像。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/cri.md b/content/zh/docs/reference/glossary/cri.md new file mode 100644 index 0000000000..42c6d4a76a --- /dev/null +++ b/content/zh/docs/reference/glossary/cri.md @@ -0,0 +1,40 @@ +--- +title: 容器运行时接口 (CRI) +id: cri +date: 2019-03-07 +full_link: /docs/concepts/overview/components/#container-runtime +short_description: > + 一组与 kubelet 集成的容器运行时 API + + +aka: +tags: +- fundamental +--- + 容器运行时接口 (CRI) 是一组与节点上 kubelet 集成的容器运行时 API + + + + + + + +更多信息, 请参考 [容器运行时接口](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/container-runtime-interface.md) API 与规格。 diff --git a/content/zh/docs/reference/glossary/cronjob.md b/content/zh/docs/reference/glossary/cronjob.md new file mode 100644 index 0000000000..5af7746647 --- /dev/null +++ b/content/zh/docs/reference/glossary/cronjob.md @@ -0,0 +1,43 @@ +--- +title: CronJob +id: cronjob +date: 2018-04-12 +full_link: /docs/concepts/workloads/controllers/cron-jobs/ +short_description: > + 管理定期运行的 [Job](/docs/concepts/workloads/controllers/jobs-run-to-completion/)。 + +aka: +tags: +- core-object +- workload +--- + + + + + + 管理定期运行的 [Job](/docs/concepts/workloads/controllers/jobs-run-to-completion/)。 + + + + + +Cronjob 对象类似 *crontab* 文件中的一行命令,它声明了一个遵循 [Cron](https://en.wikipedia.org/wiki/Cron) 格式的调度任务。 diff --git a/content/zh/docs/reference/glossary/csi.md b/content/zh/docs/reference/glossary/csi.md new file mode 100644 index 0000000000..afacbf8f1d --- /dev/null +++ b/content/zh/docs/reference/glossary/csi.md @@ -0,0 +1,48 @@ +--- +title: 容器存储接口 (CSI) +id: csi +date: 2018-06-25 +full_link: /docs/concepts/storage/volumes/#csi +short_description: > + 容器存储接口 (CSI)定义了存储系统暴露给容器的标准接口。 + + +aka: +tags: +- storage +--- + + + + + 容器存储接口 (CSI)定义了存储系统暴露给容器的标准接口。 + + + + + +CSI 允许存储驱动提供商为 Kubernetes 创建定制化的存储插件,而无需将这些插件的代码添加到 Kubernetes 代码仓库(外部插件)。要使用某个存储提供商的 CSI 驱动,你首先要[将它部署到你的集群上](https://kubernetes-csi.github.io/docs/Setup.html)。然后你才能创建使用该 CSI 驱动的 {{< glossary_tooltip text="Storage Class" term_id="storage-class" >}} 。 + +* [Kubernetes 文档中关于 CSI 的描述](/docs/concepts/storage/volumes/#csi) +* [可用的 CSI 驱动列表](https://kubernetes-csi.github.io/docs/Drivers.html) diff --git a/content/zh/docs/reference/glossary/customresourcedefinition.md b/content/zh/docs/reference/glossary/customresourcedefinition.md new file mode 100644 index 0000000000..510d26d3bc --- /dev/null +++ b/content/zh/docs/reference/glossary/customresourcedefinition.md @@ -0,0 +1,46 @@ +--- +title: CustomResourceDefinition +id: CustomResourceDefinition +date: 2018-04-12 +full_link: docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/ +short_description: > + 通过定制化的代码给您的 Kubernetes API 服务器增加资源对象,而无需编译完整的定制 API 服务器。 + +aka: +tags: +- fundamental +- operation +- extension +--- + + + + + + 通过定制化的代码给您的 Kubernetes API 服务器增加资源对象,而无需编译完整的定制 API 服务器。 + + + + + +当 Kubernetes 公开支持的 API 资源不能满足您的需要时,定制资源对象(Custom Resource Definitions)让您可以在您的环境上扩展 Kubernetes API。 + diff --git a/content/zh/docs/reference/glossary/daemonset.md b/content/zh/docs/reference/glossary/daemonset.md new file mode 100644 index 0000000000..f0ec7e9cda --- /dev/null +++ b/content/zh/docs/reference/glossary/daemonset.md @@ -0,0 +1,43 @@ +--- +title: DaemonSet +id: daemonset +date: 2018-04-12 +full_link: /docs/concepts/workloads/controllers/daemonset +short_description: > + 确保 Pod 的副本在集群中的一组节点上运行。 + +aka: +tags: +- fundamental +- core-object +- workload +--- + + + + 确保 {{< glossary_tooltip text="Pod" term_id="pod" >}} 的副本在{{< glossary_tooltip text="集群" term_id="cluster" >}}中的一组节点上运行。 + + + + +用来部署系统守护进程,例如日志搜集和监控代理,这些进程通常必须运行在每个{{< glossary_tooltip text="节点" term_id="node" >}}上。 + diff --git a/content/zh/docs/reference/glossary/data-plane.md b/content/zh/docs/reference/glossary/data-plane.md new file mode 100644 index 0000000000..addd1b032b --- /dev/null +++ b/content/zh/docs/reference/glossary/data-plane.md @@ -0,0 +1,30 @@ +--- +title: 数据平面 +id: data-plane +date: 2019-05-12 +full_link: +short_description: > + 提供诸如 CPU,内存,网络和存储的能力,以便容器可以运行并连接到网络。 +aka: +tags: +- fundamental +--- + 提供诸如 CPU,内存,网络和存储的能力,以便容器可以运行并连接到网络。 + + + + diff --git a/content/zh/docs/reference/glossary/deployment.md b/content/zh/docs/reference/glossary/deployment.md new file mode 100644 index 0000000000..08abdc60c8 --- /dev/null +++ b/content/zh/docs/reference/glossary/deployment.md @@ -0,0 +1,45 @@ +--- +title: Deployment +id: deployment +date: 2018-04-12 +full_link: /docs/concepts/workloads/controllers/deployment/ +short_description: > + Deployment 是管理应用副本的 API 对象。 + +aka: +tags: +- fundamental +- core-object +- workload +--- + + + + + + Deployment 是管理应用副本的 API 对象。 + + + + + +应用的每个副本就是一个 {{< glossary_tooltip term_id="pod" >}},并且这些 Pod 会分散运行在集群的节点上。 diff --git a/content/zh/docs/reference/glossary/developer.md b/content/zh/docs/reference/glossary/developer.md new file mode 100755 index 0000000000..2efbeea6e2 --- /dev/null +++ b/content/zh/docs/reference/glossary/developer.md @@ -0,0 +1,42 @@ +--- +title: 开发者 (释疑) +id: developer +date: 2018-04-12 +full_link: +short_description: > + 指的是:应用开发者、代码贡献者、或平台开发者。 + +aka: +tags: +- community +- user-type +--- + + + + 指的是: {{< glossary_tooltip text="应用开发者" term_id="application-developer" >}}、 {{< glossary_tooltip text="代码贡献者" term_id="code-contributor" >}}、或 {{< glossary_tooltip text="平台开发者" term_id="platform-developer" >}}。 + + + + + +根据上下文的不同,“开发者”这个被多处使用的词条会有不同的含义。 + + + diff --git a/content/zh/docs/reference/glossary/device-plugin.md b/content/zh/docs/reference/glossary/device-plugin.md new file mode 100644 index 0000000000..e6bc32b572 --- /dev/null +++ b/content/zh/docs/reference/glossary/device-plugin.md @@ -0,0 +1,32 @@ +--- +title: 驱动插件 +id: device-plugin +date: 2019-02-02 +full_link: /docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/ +short_description: > + 在 Kubernetes 中运行的容器提供对供应商特定资源的访问权限。 +aka: +tags: +- fundamental +- extension +--- + + + +设备插件是在 Kubernetes 中运行的容器,可用于访问供应商特定资源。 + + + + +[驱动插件](/docs/concepts/extend-kubernetes/compute-storage-net/device-plugins/) 是运行在 Kubernetes 中的容器,它提供对供应商特定资源的访问。驱动插件将这些资源发布到 {{< glossary_tooltip term_id="kubelet" >}}。并且可以手动部署或做为 {{< glossary_tooltip term_id="daemonset" >}},而不用编写定制的 Kubernetes 代码。 diff --git a/content/zh/docs/reference/glossary/docker.md b/content/zh/docs/reference/glossary/docker.md new file mode 100755 index 0000000000..1d7c9a8511 --- /dev/null +++ b/content/zh/docs/reference/glossary/docker.md @@ -0,0 +1,41 @@ +--- +title: docker +id: docker +date: 2018-04-12 +full_link: /docs/reference/kubectl/docker-cli-to-kubectl/ +short_description: > + Docker 是一种可以提供操作系统级别虚拟化(也称作容器)的软件技术。 + +aka: +tags: +- fundamental +--- + + + + + + Docker 是一种可以提供操作系统级别虚拟化(也称作容器)的软件技术 + + + + + +Docker 使用了 Linux 内核中的资源隔离特性(如 cgroup 和内核命名空间)以及支持联合文件系统(如 OverlayFS 和其他),允许多个相互独立的“容器”一起运行在同一 Linux 实例上,从而避免启动和维护虚拟机(VMs)的开销。 diff --git a/content/zh/docs/reference/glossary/downstream.md b/content/zh/docs/reference/glossary/downstream.md new file mode 100755 index 0000000000..575d9c74e0 --- /dev/null +++ b/content/zh/docs/reference/glossary/downstream.md @@ -0,0 +1,44 @@ +--- +title: 下游(消除歧义) +id: downstream +date: 2018-04-12 +full_link: +short_description: > + 可以指:Kubernetes 生态系统中依赖于核心 Kubernetes 代码库或分支代码库的代码。 + +aka: +tags: +- community +--- + + + + + +可以指:Kubernetes 生态系统中依赖于核心 Kubernetes 代码库或分支代码库的代码。 + + + + + +* 在 **Kubernetes 社区**中:*下游(downstream)* 在人们交流中常用来表示那些依赖核心 Kubernetes 代码库的生态系统、代码或者第三方工具。例如,Kubernete 的一个新特性可以被*下游(downstream)* 应用采用,以提升它们的功能性。 +* 在 **GitHub** 或 **git** 中:约定用*下游(downstream)* 表示分支代码库,源代码库被认为是*上游(upstream)*。 + diff --git a/content/zh/docs/reference/glossary/dynamic-volume-provisioning.md b/content/zh/docs/reference/glossary/dynamic-volume-provisioning.md new file mode 100755 index 0000000000..4f53bbef9d --- /dev/null +++ b/content/zh/docs/reference/glossary/dynamic-volume-provisioning.md @@ -0,0 +1,44 @@ +--- +title: 动态卷供应 +id: dynamicvolumeprovisioning +date: 2018-04-12 +full_link: /docs/concepts/storage/dynamic-provisioning +short_description: > + 允许用户请求自动创建存储卷。 + +aka: +tags: +- core-object +- storage +--- + + + + + + 允许用户请求自动创建存储 {{< glossary_tooltip text="卷" term_id="volume" >}}。 + + + + + +动态供应让集群管理员无需再预先供应存储。相反,它通过用户请求自动地供应存储。 +动态卷供应是基于 API 对象 {{< glossary_tooltip text="StorageClass" term_id="storage-class" >}} 的,StorageClass 可以引用 {{< glossary_tooltip text="卷插件(Volume Plugin)" term_id="volume-plugin" >}} 提供的 {{< glossary_tooltip text="卷(Volume)" term_id="volume" >}} ,也可以引用传递给卷插件(Volume Plugin)的参数集。 diff --git a/content/zh/docs/reference/glossary/endpoint-slice.md b/content/zh/docs/reference/glossary/endpoint-slice.md new file mode 100644 index 0000000000..d59366f7cd --- /dev/null +++ b/content/zh/docs/reference/glossary/endpoint-slice.md @@ -0,0 +1,40 @@ +--- +title: 端点切片 +id: endpoint-slice +date: 2018-04-12 +full_link: /docs/concepts/services-networking/endpoint-slices/ +short_description: > + 一种将网络端点与 Kubernetes 资源组合在一起的方法。 + +aka: +tags: +- networking +--- + 一种将网络端点与 Kubernetes 资源组合在一起的方法。 + + + + + + + + +一种将网络端点组合在一起的可扩缩、可扩展方式。它们将被 {{< glossary_tooltip text="kube-proxy" term_id="kube-proxy" >}} 用于在每个 {{< glossary_tooltip text="节点" term_id="node">}} 上建立网络路由。 diff --git a/content/zh/docs/reference/glossary/ephemeral-container.md b/content/zh/docs/reference/glossary/ephemeral-container.md new file mode 100644 index 0000000000..c7426f6a6f --- /dev/null +++ b/content/zh/docs/reference/glossary/ephemeral-container.md @@ -0,0 +1,36 @@ +--- +title: 临时容器 +id: ephemeral-container +date: 2019-08-26 +full_link: /docs/concepts/workloads/pods/ephemeral-containers/ +short_description: > + 您可以在 Pod 中临时运行的一种容器类型 +aka: +tags: +- fundamental +--- + 您可以在 {{< glossary_tooltip term_id="pod" >}} 中临时运行的一种 {{< glossary_tooltip term_id="container" >}} 类型 + + + + + + + +如果想要调查运行中有问题的 Pod,可以向该 Pod 添加一个临时容器并进行诊断。临时容器没有资源或调度保证,因此不应该使用它们来运行任何部分的工作负荷本身。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/etcd.md b/content/zh/docs/reference/glossary/etcd.md new file mode 100644 index 0000000000..916fa44122 --- /dev/null +++ b/content/zh/docs/reference/glossary/etcd.md @@ -0,0 +1,43 @@ +--- +title: etcd +id: etcd +date: 2018-04-12 +full_link: /docs/tasks/administer-cluster/configure-upgrade-etcd/ +short_description: > + etcd 是兼具一致性和高可用性的键值数据库,用作保存 Kubernetes 所有集群数据的后台数据库。 + +aka: +tags: +- architecture +- storage +--- + + + + + +etcd 是兼具一致性和高可用性的键值数据库,可以作为保存 Kubernetes 所有集群数据的后台数据库。 + + + + + +您的 Kubernetes 集群的 etcd 数据库通常需要有个备份计划。要了解 etcd 更深层次的信息,请参考 [etcd 文档](https://github.com/coreos/etcd/blob/master/Documentation/docs.md)。 diff --git a/content/zh/docs/reference/glossary/extensions.md b/content/zh/docs/reference/glossary/extensions.md new file mode 100644 index 0000000000..345342affe --- /dev/null +++ b/content/zh/docs/reference/glossary/extensions.md @@ -0,0 +1,38 @@ +--- +title: 扩展组件 +id: Extensions +date: 2019-02-01 +full_link: /docs/concepts/extend-kubernetes/extend-cluster/#extensions +short_description: > + 扩展组件是扩展并与 Kubernetes 深度集成以支持新型硬件的软件组件。 +aka: +tags: +- fundamental +- extension +--- + 扩展组件是扩展并与 Kubernetes 深度集成以支持新型硬件的软件组件。 + + + + + + + +大多数集群管理员会使用托管的 Kubernetes 或其某种发行包。因此,大多数 Kubernetes 用户将需要安装 [扩展组件](/docs/concepts/extend-kubernetes/extend-cluster/#extensions),较少用户会需要编写新的扩展组件。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/flexvolume.md b/content/zh/docs/reference/glossary/flexvolume.md new file mode 100644 index 0000000000..fdb0becda9 --- /dev/null +++ b/content/zh/docs/reference/glossary/flexvolume.md @@ -0,0 +1,41 @@ +--- +title: FlexVolume +id: flexvolume +date: 2018-06-25 +full_link: /docs/concepts/storage/volumes/#flexvolume +short_description: > + Flexvolume 是创建 out-of-tree 卷插件的一种接口。 {{< glossary_tooltip text="容器存储接口(CSI)" term_id="csi" >}} 是比 Flexvolume 更新的接口,它解决了 Flexvolumes 的一些问题。 + + +aka: +tags: +- storage +--- + + + + Flexvolume 是创建 out-of-tree 卷插件的一种接口。 {{< glossary_tooltip text="容器存储接口(CSI)" term_id="csi" >}} 是比 Flexvolume 更新的接口,它解决了 Flexvolume 的一些问题。 + + + + +Flexvolume 允许用户编写自己的驱动程序,并在 Kubernetes 中加入对用户自己的数据卷的支持。FlexVolume 驱动程序的二进制文件和依赖项必须安装在主机上。这需要 root 权限。如果可能的话,SIG Storage 建议实现 {{< glossary_tooltip text="CSI" term_id="csi" >}} 驱动程序,因为它解决了 Flexvolumes 的限制。 + + +* [Kubernetes 文档中的 Flexvolume](/docs/concepts/storage/volumes/#flexvolume) +* [更多关于 Flexvolumes 的信息](https://github.com/kubernetes/community/blob/master/contributors/devel/flexvolume.md) +* [存储供应商的卷插件 FAQ](https://github.com/kubernetes/community/blob/master/sig-storage/volume-plugin-faq.md) \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/helm-chart.md b/content/zh/docs/reference/glossary/helm-chart.md new file mode 100755 index 0000000000..d76c6a7906 --- /dev/null +++ b/content/zh/docs/reference/glossary/helm-chart.md @@ -0,0 +1,43 @@ +--- +title: Helm Chart +id: helm-chart +date: 2018-04-12 +full_link: https://github.com/kubernetes/helm/blob/master/docs/charts.md +short_description: > + Helm Chart 是一组预先配置的 Kubernetes 资源所构成的包,可以使用 Helm 工具对其进行管理。 + +aka: +tags: +- tool +--- + + + + + +Helm Chart 是一组预先配置的 Kubernetes 资源所构成的包,可以使用 Helm 工具对其进行管理。 + + + + + +Chart 提供了一种可重现的用来创建和共享 Kubernetes 应用的方法。 +单个 Chart 可用来部署简单的系统(例如一个 memcached Pod),也可以用来部署复杂的系统(例如包含 HTTP 服务器、数据库、缓存等组件的完整 Web 应用堆栈)。 diff --git a/content/zh/docs/reference/glossary/horizontal-pod-autoscaler.md b/content/zh/docs/reference/glossary/horizontal-pod-autoscaler.md new file mode 100755 index 0000000000..663ebd26c8 --- /dev/null +++ b/content/zh/docs/reference/glossary/horizontal-pod-autoscaler.md @@ -0,0 +1,37 @@ +--- +title: Pod 水平自动扩缩器 +id: horizontal-pod-autoscaler +date: 2018-04-12 +full_link: /docs/tasks/run-application/horizontal-pod-autoscale/ +short_description: > + Pod 水平自动扩缩器(Horizontal Pod Autoscaler)是一种 API 资源,它根据目标 CPU 利用率或自定义度量目标扩缩 Pod 副本的数量。 + +aka: +tags: +- operation +--- + + + + Pod 水平自动扩缩器(Horizontal Pod Autoscaler)是一种 API 资源,它根据目标 CPU 利用率或自定义度量目标扩缩 Pod 副本的数量。 + + + + + +HPA 通常用于 {{< glossary_tooltip text="Replication Controllers" term_id="replication-controller" >}}、{{< glossary_tooltip text="Deployments" term_id="deployment" >}} 或者 Replica Sets 上。HPA 不能用于不支持扩缩的对象,例如 {{< glossary_tooltip text="DaemonSets" term_id="daemonset" >}}。 diff --git a/content/zh/docs/reference/glossary/image.md b/content/zh/docs/reference/glossary/image.md new file mode 100755 index 0000000000..1fc7db55e5 --- /dev/null +++ b/content/zh/docs/reference/glossary/image.md @@ -0,0 +1,42 @@ +--- +title: 镜像 +id: image +date: 2018-04-12 +full_link: +short_description: > + 镜像是保存的容器实例,它打包了应用运行所需的一组软件。 + +aka: +tags: +- fundamental +--- + + + + + +镜像是保存的容器实例,它打包了应用运行所需的一组软件。 + + + + + +镜像是软件打包的一种方式,可以将镜像存储在容器镜像仓库、拉取到本地系统并作为应用来运行。 +镜像中包含的元数据指明了运行什么可执行程序、是由谁构建的以及其他信息。 diff --git a/content/zh/docs/reference/glossary/index.md b/content/zh/docs/reference/glossary/index.md index ecd4541c0b..0c13697ff9 100755 --- a/content/zh/docs/reference/glossary/index.md +++ b/content/zh/docs/reference/glossary/index.md @@ -1,4 +1,7 @@ --- +approvers: +- chenopis +- abiogenesis-now title: 标准化词汇表 layout: glossary noedit: true diff --git a/content/zh/docs/reference/glossary/ingress.md b/content/zh/docs/reference/glossary/ingress.md old mode 100755 new mode 100644 index c06726c68f..806dec752d --- a/content/zh/docs/reference/glossary/ingress.md +++ b/content/zh/docs/reference/glossary/ingress.md @@ -3,22 +3,44 @@ title: Ingress id: ingress date: 2018-04-12 full_link: /docs/concepts/services-networking/ingress/ +short_description: > + Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。 + +aka: +tags: +- networking +- architecture +- extension +--- + + + -一个 API 对象,用于管理对集群中服务的外部访问,通常是 HTTP。 - + Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。 + + + -Ingress 可以提供负载平衡,SSL 终端和基于名称的虚拟主机。 + +Ingress 可以提供负载均衡、SSL 终结和基于名称的虚拟托管。 + diff --git a/content/zh/docs/reference/glossary/init-container.md b/content/zh/docs/reference/glossary/init-container.md new file mode 100755 index 0000000000..cf8cead312 --- /dev/null +++ b/content/zh/docs/reference/glossary/init-container.md @@ -0,0 +1,41 @@ +--- +title: 初始化容器 +id: init-container +date: 2018-04-12 +full_link: +short_description: > + 应用容器运行前必须先运行完成的一个或多个初始化容器。 + +aka: +tags: +- fundamental +--- + + + + + + 应用容器运行前必须先运行完成的一个或多个初始化容器。 + + + + + +初始化(init)容器像常规应用容器一样,只有一点不同:初始化(init)容器必须在应用容器启动前运行完成。Init 容器的运行顺序:一个初始化(init)容器必须在下一个初始化(init)容器开始前运行完成。 diff --git a/content/zh/docs/reference/glossary/istio.md b/content/zh/docs/reference/glossary/istio.md new file mode 100755 index 0000000000..58c4cfffcc --- /dev/null +++ b/content/zh/docs/reference/glossary/istio.md @@ -0,0 +1,45 @@ +--- +title: Istio +id: istio +date: 2018-04-12 +full_link: https://istio.io/docs/concepts/what-is-istio/overview.html +short_description: > + Istio 是个开放平台(非 Kubernetes 特有),提供了一种统一的方式来集成微服务、管理流量、实施策略和汇总度量数据。 +aka: +tags: +- networking +- architecture +- extension +--- + + + + + +Istio 是个开放平台(非 Kubernetes 特有),提供了一种统一的方式来集成微服务、管理流量、实施策略和汇总度量数据。 + + + + + +添加 Istio 时不需要修改应用代码。它是基础设施的一层,介于服务和网络之间。当它和服务的 Deployment 相结合时,就构成了通常所谓的服务网格(Service Mesh)。Istio 的控制面抽象掉了底层的集群管理平台,这一集群管理平台可以是 Kubernetes、Mesosphere 等。 + diff --git a/content/zh/docs/reference/glossary/job.md b/content/zh/docs/reference/glossary/job.md new file mode 100755 index 0000000000..8ce421f280 --- /dev/null +++ b/content/zh/docs/reference/glossary/job.md @@ -0,0 +1,45 @@ +--- +title: Job +id: job +date: 2018-04-12 +full_link: /docs/concepts/workloads/controllers/jobs-run-to-completion +short_description: > + Job 是需要运行完成的确定性的或批量的任务。 + +aka: +tags: +- fundamental +- core-object +- workload +--- + + + + + + Job 是需要运行完成的确定性的或批量的任务。 + + + + + +Job 创建一个或多个 {{< glossary_tooltip term_id="Pod" >}} 对象,并确保指定数量的 Pod 成功终止。随着各 Pod 成功结束,Job 会跟踪记录成功完成的个数。 diff --git a/content/zh/docs/reference/glossary/kops.md b/content/zh/docs/reference/glossary/kops.md new file mode 100755 index 0000000000..c1024390e7 --- /dev/null +++ b/content/zh/docs/reference/glossary/kops.md @@ -0,0 +1,63 @@ +--- +title: Kops +id: kops +date: 2018-04-12 +full_link: /docs/getting-started-guides/kops/ +short_description: > + kops 是一个命令行工具,可以帮助您创建、销毁、升级和维护生产级,高可用性的 Kubernetes 集群。注意:官方仅支持 AWS,GCE 和 VMware vSphere 的支持还处于 alpha* 阶段。 + +aka: +tags: +- tool +- operation +--- + + + + + +kops 是一个命令行工具,可以帮助您创建、销毁、升级和维护生产级,高可用性的 Kubernetes 集群。*注意:官方仅支持 AWS,GCE 和 VMware vSphere 的支持还处于 alpha 阶段*。 + + + + + +`kops` 为您的集群提供了: + + * 全自动化安装 + * 基于 DNS 的集群标识 + * 自愈功能:所有组件都在自动伸缩组(Auto-Scaling Groups)中运行 + * 有限的操作系统支持 (推荐使用 Debian,支持 Ubuntu 16.04,试验性支持 CentOS & RHEL) + * 高可用 (HA) 支持 + * 直接提供或者生成 Terraform 清单文件的能力 + + + +您也可以将自己的集群作为一个构造块,使用 {{< glossary_tooltip term_id="kubeadm" >}} 构造集群。`kops` 是建立在 kubeadm 之上的。 diff --git a/content/zh/docs/reference/glossary/kube-apiserver.md b/content/zh/docs/reference/glossary/kube-apiserver.md new file mode 100755 index 0000000000..c2d0e8a9eb --- /dev/null +++ b/content/zh/docs/reference/glossary/kube-apiserver.md @@ -0,0 +1,44 @@ +--- +title: kube-apiserver +id: kube-apiserver +date: 2018-04-12 +full_link: /docs/reference/generated/kube-apiserver/ +short_description: > + 主节点上负责提供 Kubernetes API 服务的组件;它是 Kubernetes 控制面的前端。 + +aka: +tags: +- architecture +- fundamental +--- + + + + + +主节点上负责提供 Kubernetes API 服务的组件;它是 Kubernetes 控制面的前端。 + + + + + +kube-apiserver 在设计上考虑了水平扩缩的需要。 +换言之,通过部署多个实例可以实现扩缩。 +参见[构造高可用集群](/docs/admin/high-availability/)。 + diff --git a/content/zh/docs/reference/glossary/kube-controller-manager.md b/content/zh/docs/reference/glossary/kube-controller-manager.md new file mode 100755 index 0000000000..c24234e501 --- /dev/null +++ b/content/zh/docs/reference/glossary/kube-controller-manager.md @@ -0,0 +1,39 @@ +--- +title: kube-controller-manager +id: kube-controller-manager +date: 2018-04-12 +full_link: /docs/reference/generated/kube-controller-manager/ +short_description: > + 主节点上运行控制器的组件。 + +aka: +tags: +- architecture +- fundamental +--- + + + + +在主节点上运行{{< glossary_tooltip text="控制器" term_id="controller" >}}的组件。 + + + +从逻辑上讲,每个{{< glossary_tooltip text="控制器" term_id="controller" >}}都是一个单独的进程,但是为了降低复杂性,它们都被编译到同一个可执行文件,并在一个进程中运行。 + diff --git a/content/zh/docs/reference/glossary/kube-proxy.md b/content/zh/docs/reference/glossary/kube-proxy.md new file mode 100755 index 0000000000..84b95e228f --- /dev/null +++ b/content/zh/docs/reference/glossary/kube-proxy.md @@ -0,0 +1,41 @@ +--- +title: kube-proxy +id: kube-proxy +date: 2018-04-12 +full_link: /docs/reference/command-line-tools-reference/kube-proxy/ +short_description: > + `kube-proxy` 是集群中每个节点上运行的网络代理。 + +aka: +tags: +- fundamental +- networking +--- + + + [kube-proxy](/docs/reference/command-line-tools-reference/kube-proxy/) 是集群中每个节点上运行的网络代理,实现 Kubernetes {{< glossary_tooltip term_id="service">}} 概念的一部分。 + + + + +kube-proxy 维护节点上的网络规则。这些网络规则允许从集群内部或外部的网络会话与 Pod 进行网络通信。 + + +如果有 kube-proxy 可用,它将使用操作系统数据包过滤层。否则,kube-proxy 会转发流量本身。 diff --git a/content/zh/docs/reference/glossary/kube-scheduler.md b/content/zh/docs/reference/glossary/kube-scheduler.md new file mode 100755 index 0000000000..67d82d98d7 --- /dev/null +++ b/content/zh/docs/reference/glossary/kube-scheduler.md @@ -0,0 +1,42 @@ +--- +title: kube-scheduler +id: kube-scheduler +date: 2018-04-12 +full_link: /docs/reference/generated/kube-scheduler/ +short_description: > + 主节点上的组件,该组件监视那些新创建的未指定运行节点的 Pod,并选择节点让 Pod 在上面运行。 + +aka: +tags: +- architecture +- scheduler +--- + + + + + +主节点上的组件,该组件监视那些新创建的未指定运行节点的 Pod,并选择节点让 Pod 在上面运行。 + + + + + +调度决策考虑的因素包括单个 Pod 和 Pod 集合的资源需求、硬件/软件/策略约束、亲和性和反亲和性规范、数据位置、工作负载间的干扰和最后时限。 diff --git a/content/zh/docs/reference/glossary/kubeadm.md b/content/zh/docs/reference/glossary/kubeadm.md new file mode 100644 index 0000000000..3d7ce11b59 --- /dev/null +++ b/content/zh/docs/reference/glossary/kubeadm.md @@ -0,0 +1,43 @@ +--- +title: Kubeadm +id: kubeadm +date: 2018-04-12 +full_link: /docs/admin/kubeadm/ +short_description: > + 用来快速安装 Kubernetes 并搭建安全稳定的集群的工具。 + +aka: +tags: +- tool +- operation +--- + + + + + + 用来快速安装 Kubernetes 并搭建安全稳定的集群的工具。 + + + + + +您可以使用 kubeadm 安装控制面和工作节点组件。 diff --git a/content/zh/docs/reference/glossary/kubectl.md b/content/zh/docs/reference/glossary/kubectl.md new file mode 100755 index 0000000000..2c8bde22eb --- /dev/null +++ b/content/zh/docs/reference/glossary/kubectl.md @@ -0,0 +1,43 @@ +--- +title: Kubectl +id: kubectl +date: 2018-04-12 +full_link: /docs/user-guide/kubectl-overview/ +short_description: > + kubectl 是用来和 Kubernetes API 服务器进行通信的命令行工具。 + +aka: +tags: +- tool +- fundamental +--- + + + + + + kubectl 是用来和 {{< glossary_tooltip text="Kubernetes API" term_id="kubernetes-api" >}} 服务器进行通信的命令行工具。 + + + + + +您可以使用 kubectl 创建、检查、更新和删除 Kubernetes 对象。 diff --git a/content/zh/docs/reference/glossary/kubelet.md b/content/zh/docs/reference/glossary/kubelet.md new file mode 100755 index 0000000000..c561109b6e --- /dev/null +++ b/content/zh/docs/reference/glossary/kubelet.md @@ -0,0 +1,40 @@ +--- +title: Kubelet +id: kubelet +date: 2018-04-12 +full_link: /docs/reference/generated/kubelet +short_description: > + 一个在集群中每个节点上运行的代理。它保证容器都运行在 Pod 中。 + +aka: +tags: +- fundamental +- core-object +--- + + +一个在集群中每个节点上运行的代理。它保证容器都运行在 Pod 中。 + + + + + +kubelet 接收一组通过各类机制提供给它的 PodSpecs,确保这些 PodSpecs 中描述的容器处于运行状态且健康。kubelet 不会管理不是由 Kubernetes 创建的容器。 diff --git a/content/zh/docs/reference/glossary/kubernetes-api.md b/content/zh/docs/reference/glossary/kubernetes-api.md new file mode 100755 index 0000000000..fc1dbeac6a --- /dev/null +++ b/content/zh/docs/reference/glossary/kubernetes-api.md @@ -0,0 +1,47 @@ +--- +title: Kubernetes API +id: kubernetes-api +date: 2018-04-12 +full_link: /docs/concepts/overview/kubernetes-api/ +short_description: > + Kubernetes API 是通过 RESTful 接口提供 Kubernetes 功能服务并负责集群状态存储的应用程序。 + +aka: +tags: +- fundamental +- architecture +--- + + + + + +Kubernetes API 是通过 RESTful 接口提供 Kubernetes 功能服务并负责集群状态存储的应用程序。 + + + + + +Kubernetes 资源和"意向记录"都是作为 API 对象储存的,并可以通过对 API 的 RESTful 调用进行修改。 +API 允许以声明方式管理配置。 +用户可以直接和 Kubernetes API 交互,也可以通过 `kubectl` 这样的工具进行交互。 +核心的 Kubernetes API 是很灵活的,可以扩展以支持定制资源。 + diff --git a/content/zh/docs/reference/glossary/label.md b/content/zh/docs/reference/glossary/label.md new file mode 100755 index 0000000000..6201aaeb29 --- /dev/null +++ b/content/zh/docs/reference/glossary/label.md @@ -0,0 +1,41 @@ +--- +title: 标签 +id: label +date: 2018-04-12 +full_link: /docs/concepts/overview/working-with-objects/labels +short_description: > + 用来为对象设置可标识的属性标记;这些标记对用户而言是有意义且重要的。 + +aka: +tags: +- fundamental +--- + + + + + +用来为对象设置可标识的属性标记;这些标记对用户而言是有意义且重要的。 + + + + + +标签是一些关联到 {{< glossary_tooltip text="Pods" term_id="pod" >}} 这类对象上的键值对。 +它们通常用来组织和选择对象子集。 + diff --git a/content/zh/docs/reference/glossary/limitrange.md b/content/zh/docs/reference/glossary/limitrange.md new file mode 100644 index 0000000000..b2bf02639f --- /dev/null +++ b/content/zh/docs/reference/glossary/limitrange.md @@ -0,0 +1,51 @@ +--- +title: LimitRange +id: limitrange +date: 2019-04-15 +full_link: /docs/concepts/policy/limit-range/ +short_description: > + 提供约束来限制命名空间中每个容器或 Pod 的资源消耗。 + +aka: +tags: +- core-object +- fundamental +- architecture +related: + - pod + - container + +--- + + + + + 提供约束来限制命名空间中每个 {{< glossary_tooltip text="容器" term_id="container" >}} 或 {{< glossary_tooltip text="Pod" term_id="pod" >}} 的资源消耗。 + + + +LimitRange 按照类型来限制命名空间中对象能够创建的数量,以及单个 {{< glossary_tooltip text="容器" term_id="container" >}} 或 {{< glossary_tooltip text="Pod" term_id="pod" >}} 可以请求/使用的计算资源量。 diff --git a/content/zh/docs/reference/glossary/logging.md b/content/zh/docs/reference/glossary/logging.md new file mode 100644 index 0000000000..980555c79a --- /dev/null +++ b/content/zh/docs/reference/glossary/logging.md @@ -0,0 +1,39 @@ +--- +title: 日志 +id: logging +date: 2019-04-04 +full_link: /docs/concepts/cluster-administration/logging/ +short_description: > + 日志是集群或应用程序记录的事件列表。 + +aka: +tags: +- architecture +- fundamental +--- + 日志是 {{< glossary_tooltip text="集群" term_id="cluster" >}} 或应用程序记录的事件列表。 + + + + + + + +应用程序和系统日志可以帮助您了解集群内部发生的情况。日志对于调试问题和监视集群活动非常有用。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/managed-service.md b/content/zh/docs/reference/glossary/managed-service.md new file mode 100755 index 0000000000..fb7d5440c9 --- /dev/null +++ b/content/zh/docs/reference/glossary/managed-service.md @@ -0,0 +1,42 @@ +--- +title: 托管服务 +id: managed-service +date: 2018-04-12 +full_link: +short_description: > + 由第三方供应商负责维护的一种软件产品。 + +aka: +tags: +- extension +--- + + + + + +由第三方供应商负责维护的一种软件产品。 + + + + + +托管服务的一些例子有 AWS EC2、Azure SQL 数据库和 GCP Pub/Sub 等, +不过它们也可以是可以被某应用使用的任何软件交付件。 +[服务目录](/docs/concepts/service-catalog/)提供了一种方法用来列举、供应和绑定到 +{{< glossary_tooltip text="服务代理商" term_id="service-broker" >}}所提供的托管服务。 diff --git a/content/zh/docs/reference/glossary/member.md b/content/zh/docs/reference/glossary/member.md new file mode 100644 index 0000000000..57e7cac386 --- /dev/null +++ b/content/zh/docs/reference/glossary/member.md @@ -0,0 +1,42 @@ +--- +title: 成员 +id: member +date: 2018-04-12 +full_link: +short_description: > + K8s 社区中持续活跃的贡献者。 + +aka: +tags: +- community +--- + + + + + + K8s 社区中持续活跃的贡献者。 + + + + + +可以将问题单(issue)和 PR 指派给成员,成员也可以通过 GitHub 小组加入 {{< glossary_tooltip text="特别兴趣小组 (SIGs)" term_id="sig" >}}。针对成员所提交的 PR,系统自动运行提交前测试。成员应该是持续活跃的社区贡献者。 + diff --git a/content/zh/docs/reference/glossary/minikube.md b/content/zh/docs/reference/glossary/minikube.md new file mode 100755 index 0000000000..e88e513ba4 --- /dev/null +++ b/content/zh/docs/reference/glossary/minikube.md @@ -0,0 +1,43 @@ +--- +title: Minikube +id: minikube +date: 2018-04-12 +full_link: /docs/getting-started-guides/minikube/ +short_description: > + Minikube 是用来在本地运行 Kubernetes 的一种工具。 + +aka: +tags: +- fundamental +- tool +--- + + + + + +Minikube 是用来在本地运行 Kubernetes 的一种工具。 + + + + + +Minikube 在用户计算机上的一个虚拟机内运行单节点 Kubernetes 集群。 diff --git a/content/zh/docs/reference/glossary/mirror-pod.md b/content/zh/docs/reference/glossary/mirror-pod.md new file mode 100755 index 0000000000..a8aca1fb94 --- /dev/null +++ b/content/zh/docs/reference/glossary/mirror-pod.md @@ -0,0 +1,46 @@ +--- +title: 静态 Pod +id: 静态-pod +date: 2019-08-06 +short_description: > + API 服务器中的一个对象,用于跟踪 kubelet 上的静态容器。 + +aka: +tags: +- 基本的 +--- + + + + kubelet 使用一个对象 {{< glossary_tooltip text="pod" term_id="pod" >}} 来代表 {{< glossary_tooltip text="static pod" term_id="static-pod" >}} + + + + + +当 kubelet 在其配置中发现一个静态容器时, +它会自动地尝试在 Kubernetes API 服务器上为它创建 Pod 对象。 +这意味着 pod 在 API 服务器上将是可见的,但不能在其上进行控制。 + +(例如,删除静态 pod 将不会停止 kubelet 守护程序的运行)。 diff --git a/content/zh/docs/reference/glossary/name.md b/content/zh/docs/reference/glossary/name.md index 161082e052..dcc6028b3d 100755 --- a/content/zh/docs/reference/glossary/name.md +++ b/content/zh/docs/reference/glossary/name.md @@ -1,4 +1,18 @@ --- +title: 名称 +id: name +date: 2018-04-12 +full_link: /docs/concepts/overview/working-with-objects/names +short_description: > + 客户端提供的字符串,用来指代资源 URL 中的对象,如 `/api/v1/pods/some-name`。 + +aka: +tags: +- fundamental +--- + + + diff --git a/content/zh/docs/reference/glossary/namespace.md b/content/zh/docs/reference/glossary/namespace.md new file mode 100644 index 0000000000..42019215cf --- /dev/null +++ b/content/zh/docs/reference/glossary/namespace.md @@ -0,0 +1,41 @@ +--- +title: 命名空间 +id: namespace +date: 2018-04-12 +full_link: /docs/concepts/overview/working-with-objects/namespaces +short_description: > + 命名空间是 Kubernetes 为了在同一物理集群上支持多个虚拟集群而使用的一种抽象。 + +aka: +tags: +- fundamental +--- + + + + + +命名空间是 Kubernetes 为了在同一物理集群上支持多个虚拟集群而使用的一种抽象。 + + + + + +命名空间用来组织集群中对象,并为集群资源划分提供了一种方法。同一命名空间内的资源名称必须唯一,但跨命名空间时不作要求。 diff --git a/content/zh/docs/reference/glossary/network-policy.md b/content/zh/docs/reference/glossary/network-policy.md new file mode 100755 index 0000000000..25269bcc05 --- /dev/null +++ b/content/zh/docs/reference/glossary/network-policy.md @@ -0,0 +1,44 @@ +--- +title: 网络策略 +id: network-policy +date: 2018-04-12 +full_link: /docs/concepts/services-networking/network-policies/ +short_description: > + 网络策略是一种规范,规定了允许 Pod 组之间、Pod 与其他网络端点之间以怎样的方式进行通信。 + +aka: +tags: +- networking +- architecture +- extension +--- + + + +网络策略是一种规范,规定了允许 Pod 组之间、Pod 与其他网络端点之间以怎样的方式进行通信。 + + + + + +网络策略帮助您声明式地配置允许哪些 Pod 之间接、哪些命名空间之间允许进行通信,并具体配置了哪些端口号来执行各个策略。`NetworkPolicy` 资源使用标签来选择 Pod,并定义了所选 Pod 可以接受什么样的流量。网络策略由网络提供商提供的并被 Kubernetes 支持的网络插件实现。请注意,当没有控制器实现网络资源时,创建网络资源将不会生效。 diff --git a/content/zh/docs/reference/glossary/node.md b/content/zh/docs/reference/glossary/node.md new file mode 100755 index 0000000000..d1756799b7 --- /dev/null +++ b/content/zh/docs/reference/glossary/node.md @@ -0,0 +1,43 @@ +--- +title: 节点 +id: node +date: 2018-04-12 +full_link: /docs/concepts/architecture/nodes/ +short_description: > + Kubernetes 中的工作机器称作节点。 + +aka: +tags: +- fundamental +--- + + + + + +Kubernetes 中的工作机器称作节点。 + + + + + +工作机器可以是虚拟机也可以是物理机,取决于集群的配置。 +其上部署了运行 {{< glossary_tooltip text="Pods" term_id="pod" >}} 所必需的{{< glossary_tooltip text="服务" term_id="service" >}}, +并由主控组件来管理。 +节点上的{{< glossary_tooltip text="服务" term_id="service" >}}包括 Docker、kubelet 和 kube-proxy。 + diff --git a/content/zh/docs/reference/glossary/operator-pattern.md b/content/zh/docs/reference/glossary/operator-pattern.md new file mode 100644 index 0000000000..6e7235fb89 --- /dev/null +++ b/content/zh/docs/reference/glossary/operator-pattern.md @@ -0,0 +1,46 @@ +--- +title: Operator 模式 +id: operator-pattern +date: 2019-05-21 +full_link: /docs/concepts/extend-kubernetes/operator/ +short_description: > + 一种用于管理自定义资源的专用控制器 + +aka: +tags: +- architecture +--- + [operator 模式](/docs/concepts/extend-kubernetes/operator/) 是一个系统设计, 将 {{< glossary_tooltip term_id="controller" >}} 关联到一个或多个自定义资源。 + + + + + + + +除了使用作为 Kubernetes 自身一部分的内置控制器之外,您还可以通过将控制器添加到集群中来扩展 Kubernetes。 + +如果正在运行的应用程序能够充当控制器并通过 API 访问的方式来执行任务操控那些在控制平面中定义的自定义资源,这就是一个 operator 模式的示例。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/persistent-volume-claim.md b/content/zh/docs/reference/glossary/persistent-volume-claim.md new file mode 100755 index 0000000000..00fc0c563f --- /dev/null +++ b/content/zh/docs/reference/glossary/persistent-volume-claim.md @@ -0,0 +1,39 @@ +--- +title: 持久卷申领 +id: persistent-volume-claim +date: 2018-04-12 +full_link: /docs/concepts/storage/persistent-volumes/ +short_description: > + 声明在持久卷中定义的存储资源,以便可以将其挂载为容器中的卷。 + +aka: +tags: +- core-object +- storage +--- + + + + +申领持久卷中定义的存储资源,以便可以将其挂载为容器中的卷。 + + + + +指定存储的数量,如何访问存储(只读、读写或独占)以及如何回收存储(保留、回收或删除)。存储本身的详细信息在 PersistentVolume 规范中。 diff --git a/content/zh/docs/reference/glossary/persistent-volume.md b/content/zh/docs/reference/glossary/persistent-volume.md new file mode 100644 index 0000000000..d2364a6f8a --- /dev/null +++ b/content/zh/docs/reference/glossary/persistent-volume.md @@ -0,0 +1,48 @@ +--- +title: 持久卷 +id: persistent-volume +date: 2018-04-12 +full_link: /docs/concepts/storage/persistent-volumes/ +short_description: > + 持久卷是代表集群中一块存储空间的 API 对象。 它是通用的、可插拔的、并且不受单个 Pod 生命周期约束的持久化资源。 + +aka: +tags: +- core-object +- storage +--- + + + + + +持久卷是代表集群中一块存储空间的 API 对象。 它是通用的、可插拔的、并且不受单个 Pod 生命周期约束的持久化资源。 + + + + + +持久卷(PersistentVolumes,PV)提供了一个 API,该 API 对存储的供应方式细节进行抽象,令其与使用方式相分离。 +在提前创建存储(静态供应)的场景中,PV 可以直接使用。 +在按需提供存储(动态供应)的场景中,需要使用 PersistentVolumeClaims (PVCs)。 + diff --git a/content/zh/docs/reference/glossary/platform-developer.md b/content/zh/docs/reference/glossary/platform-developer.md new file mode 100755 index 0000000000..0cc10ac633 --- /dev/null +++ b/content/zh/docs/reference/glossary/platform-developer.md @@ -0,0 +1,42 @@ +--- +title: 平台开发者 +id: platform-developer +date: 2018-04-12 +full_link: +short_description: > + 定制 Kubernetes 平台以满足自己的项目需求的人。 + +aka: +tags: +- user-type +--- + + + + + + 定制 Kubernetes 平台以满足自己的项目需求的人。 + + + + + +例如,平台开发人员可以使用[定制资源](/docs/concepts/api-extension/custom-resources/)或[使用汇聚层扩展 Kubernetes API](/docs/concepts/api-extension/apiserver-aggregation/) 来为其 Kubernetes 实例增加功能,特别是为其应用程序添加功能。一些平台开发人员也是 Kubrenetes {{< glossary_tooltip text="贡献者" term_id="contributor" >}},他们会开发贡献给 Kubernetes 社区的扩展;另一些则开发封闭源代码的商业扩展或用于特定功能的扩展。 + diff --git a/content/zh/docs/reference/glossary/pod-disruption-budget.md b/content/zh/docs/reference/glossary/pod-disruption-budget.md new file mode 100644 index 0000000000..3c04a0cc95 --- /dev/null +++ b/content/zh/docs/reference/glossary/pod-disruption-budget.md @@ -0,0 +1,40 @@ +--- +id: pod-disruption-budget +title: Pod Disruption Budget +full-link: /docs/concepts/workloads/pods/disruptions/ +date: 2019-02-12 +short_description: > + Pod Disruption Budget 是这样一种对象:它保证在主动中断( voluntary disruptions)时,多实例应用的 {{< glossary_tooltip text="Pod" term_id="pod" >}} 不会少于一定的数量。 + +aka: + - PDB +related: + - pod + - container +tags: + - operation +--- + + + + + [Pod Disruption Budget](/docs/concepts/workloads/pods/disruptions/) 使应用所有者能够为多实例应用创建一个对象,来确保一定数量的具有指定标签的 Pod 在任何时候都不会被主动驱逐。 PDB 无法防止非主动的中断,但是会计入预算(budget)。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/pod-lifecycle.md b/content/zh/docs/reference/glossary/pod-lifecycle.md new file mode 100644 index 0000000000..67376a475c --- /dev/null +++ b/content/zh/docs/reference/glossary/pod-lifecycle.md @@ -0,0 +1,40 @@ + +--> +--- +title: Pod 生命周期 +id: pod-lifecycle +date: 2019-02-17 +full-link: /docs/concepts/workloads/pods/pod-lifecycle/ +related: + - pod + - container +tags: + - fundamental +short_description: > + 关于 Pod 在其生命周期中处于哪个阶段的更高层次概述。 + +--- + 关于 Pod 在其生命周期中处于哪个阶段的更高层次概述。 + + + +[Pod 生命周期](/docs/concepts/workloads/pods/pod-lifecycle/) 是关于 Pod 在其生命周期中处于哪个阶段的更高层次概述。Pod 的`status` 字段是 [PodStatus](/docs/reference/generated/kubernetes-api/v1.13/#podstatus-v1-core) 对象, 该对象的 `phase` 字段包含了下面的状态: Running、Pending、Succeeded、Failed、Unknown、Completed 或 CrashLoopBackOff。 diff --git a/content/zh/docs/reference/glossary/pod-priority.md b/content/zh/docs/reference/glossary/pod-priority.md new file mode 100644 index 0000000000..d66561d9d7 --- /dev/null +++ b/content/zh/docs/reference/glossary/pod-priority.md @@ -0,0 +1,39 @@ +--- +title: Pod 优先级 +id: pod-priority +date: 2019-01-31 +full_link: /docs/concepts/configuration/pod-priority-preemption/#pod-priority +short_description: > + Pod 优先级表示一个 Pod 相对于其他 Pod 的重要性。 + +aka: +tags: +- operation +--- + + + + + Pod 优先级表示一个 Pod 相对于其他 Pod 的重要性。 + + + + +[Pod 优先级](/docs/concepts/configuration/pod-priority-preemption/#pod-priority) 允许为一个 Pod 设置高于或低于其他 Pod 的优先级 -- 这对于生产集群工作负载而言是一个重要的特性。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/pod-security-policy.md b/content/zh/docs/reference/glossary/pod-security-policy.md new file mode 100644 index 0000000000..e9937009cd --- /dev/null +++ b/content/zh/docs/reference/glossary/pod-security-policy.md @@ -0,0 +1,46 @@ +--- +title: Pod 安全策略 +id: pod-security-policy +date: 2018-04-12 +full_link: /docs/concepts/policy/pod-security-policy/ +short_description: > + 为 Pod 的创建和更新操作启用细粒度的授权。 + +aka: +tags: +- core-object +- fundamental +--- + + + + + +为 Pod 的创建和更新操作启用细粒度的授权。 + + + + + +Pod 安全策略是集群级别的资源,它控制着 Pod 规约中的安全性敏感的内容。 +`PodSecurityPolicy`对象定义了一组条件以及相关字段的默认值,Pod 运行时必须满足这些条件。Pod 安全策略控制实现上体现为一个可选的准入控制器。 + + diff --git a/content/zh/docs/reference/glossary/pod.md b/content/zh/docs/reference/glossary/pod.md new file mode 100755 index 0000000000..d8fcbb4cee --- /dev/null +++ b/content/zh/docs/reference/glossary/pod.md @@ -0,0 +1,43 @@ +--- +title: Pod +id: pod +date: 2018-04-12 +full_link: /docs/concepts/workloads/pods/pod-overview/ +short_description: > + Pod 是 Kubernetes 的原子对象。Pod 表示您的集群上一组正在运行的容器。 + +aka: +tags: +- core-object +- fundamental +--- + + + + + + Pod 是 Kubernetes 的原子对象。Pod 表示您的集群上一组正在运行的{{< glossary_tooltip text="容器" term_id="container" >}}。 + + + + + +通常创建 Pod 是为了运行单个主容器。Pod 还可以运行可选的挂斗(sidecar)容器,以添加诸如日志记录之类的补充特性。通常用 {{< glossary_tooltip term_id="deployment" >}} 来管理 Pod。 diff --git a/content/zh/docs/reference/glossary/podpreset.md b/content/zh/docs/reference/glossary/podpreset.md new file mode 100755 index 0000000000..3c5789de6d --- /dev/null +++ b/content/zh/docs/reference/glossary/podpreset.md @@ -0,0 +1,40 @@ +--- +title: PodPreset +id: podpreset +date: 2018-04-12 +full_link: +short_description: > + PodPreset 是一种 API 对象,在创建 Pod 时将诸如 Secret、卷挂载和环境变量之类的信息注入到该 Pod 中。 + +aka: +tags: +- operation +--- + + + + +PodPreset 是一种 API 对象,在创建 Pod 时将诸如 Secret、卷挂载和环境变量之类的信息注入到该 Pod 中。 + + + + + +此 API 对象使用标准选择器选择 Pod 并向其中注入信息。这允许 podspec 定义是非特定的,从而将 podspec 与环境特定的配置解耦。 diff --git a/content/zh/docs/reference/glossary/preemption.md b/content/zh/docs/reference/glossary/preemption.md new file mode 100644 index 0000000000..575b329065 --- /dev/null +++ b/content/zh/docs/reference/glossary/preemption.md @@ -0,0 +1,38 @@ +--- +title: 抢占 +id: preemption +date: 2019-01-31 +full_link: /docs/concepts/configuration/pod-priority-preemption/#preemption +short_description: > + Kubernetes 中的抢占逻辑通过驱逐节点上的低优先级 Pod 来帮助挂起的 Pod 找到合适的节点。 + +aka: +tags: +- operation +--- + + + + Kubernetes 中的抢占逻辑通过驱逐节点上的低优先级 Pod 来帮助挂起的 Pod 找到合适的节点。 + + + + +如果一个 Pod 无法调度,调度器会尝试[抢占](/docs/concepts/configuration/pod-priority-preemption/#preemption)较低优先级的 Pod,以使得挂起的 Pod 可能被调度。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/qos-class.md b/content/zh/docs/reference/glossary/qos-class.md new file mode 100644 index 0000000000..82b18bfe38 --- /dev/null +++ b/content/zh/docs/reference/glossary/qos-class.md @@ -0,0 +1,46 @@ +--- +title: QoS 类 +id: qos-class +date: 2019-04-15 +full_link: +short_description: > + QoS 类(Quality of Service Class)为 Kubernetes 提供了一种将集群中的 Pod 分为几个类并做出有关调度和驱逐决策的方法。 + +aka: +tags: +- core-object +- fundamental +- architecture +related: + - pod + +--- + + + QoS Class(Quality of Service Class)为 Kubernetes 提供了一种将集群中的 Pod 分为几个类型并做出有关调度和驱逐决策的方法。 + + + + +Pod 的 QoS 类是基于 Pod 在创建时配置的计算资源请求和限制。QoS 类用于制定有关 Pod 调度和逐出的决策。 +Kubernetes 可以为 Pod 分配以下 QoS 类:`Guaranteed`,`Burstable` 或者 `BestEffort`。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/quantity.md b/content/zh/docs/reference/glossary/quantity.md new file mode 100644 index 0000000000..70d5a95ffa --- /dev/null +++ b/content/zh/docs/reference/glossary/quantity.md @@ -0,0 +1,60 @@ +--- +title: 数量 +id: quantity +date: 2018-08-07 +full_link: +short_description: > + 使用 SI 后缀的小数或大数的整数表示。 + +aka: +tags: +- core-object +--- + + + + +数量是使用紧凑的整数表示法的小数或大数的表示,并带有国际计量单位制(SI)后缀。 +小数用 milli 单位表示,而大数用 kilo、mega 或 giga 单位表示。 + +例如,数字 `1.5` 表示为`1500m`, +而数字`1000`表示为`1k`,`1000000`表示为`1M`。 +您还可以指定二进制表示法后缀; 数字 2048 可以写成`2Ki`。 + +公认的十进制(10的幂)单位是 `m`(milli)、`k`(kilo, +有意小写)、`M`(mega),`G`(giga)、`T`(terra)、`P`(peta)、 +`E`(exa)。 + +公认的二进制(2的幂)单位是 `Ki` (kibi)、 `Mi` (mebi)、`Gi` (gibi)、 +`Ti` (tebi)、 `Pi` (pebi)、 `Ei` (exbi)。 + + diff --git a/content/zh/docs/reference/glossary/rbac.md b/content/zh/docs/reference/glossary/rbac.md new file mode 100755 index 0000000000..6f045ed9d0 --- /dev/null +++ b/content/zh/docs/reference/glossary/rbac.md @@ -0,0 +1,43 @@ +--- +title: RBAC(基于角色的访问控制) +id: rbac +date: 2018-04-12 +full_link: /docs/reference/access-authn-authz/rbac/ +short_description: > + 管理授权决策,允许管理员通过 Kubernetes API 动态配置访问策略。 + +aka: +tags: +- security +- fundamental +--- + + + + +管理授权决策,允许管理员通过 {{< glossary_tooltip text="Kubernetes API" term_id="kubernetes-api" >}} 动态配置访问策略。 + + + + +RBAC 使用 *角色* (包含权限规则)和 *角色绑定* (将角色中定义的权限授予一组用户)。 + + diff --git a/content/zh/docs/reference/glossary/replica-set.md b/content/zh/docs/reference/glossary/replica-set.md new file mode 100755 index 0000000000..5f394133b6 --- /dev/null +++ b/content/zh/docs/reference/glossary/replica-set.md @@ -0,0 +1,45 @@ +--- +title: ReplicaSet +id: replica-set +date: 2018-04-12 +full_link: /docs/concepts/workloads/controllers/replicaset/ +short_description: > + ReplicaSet 是下一代副本控制器。 + +aka: +tags: +- fundamental +- core-object +- workload +--- + + + + + +ReplicaSet 是下一代副本控制器。 + + + + + +ReplicaSet 就像 ReplicationController 那样,确保一次运行指定数量的 Pod 副本。ReplicaSet 支持新的基于集合的选择器需求(在标签的用户指南中有相关描述),而副本控制器只支持基于等值的选择器需求。 diff --git a/content/zh/docs/reference/glossary/replication-controller.md b/content/zh/docs/reference/glossary/replication-controller.md new file mode 100644 index 0000000000..8fd910e799 --- /dev/null +++ b/content/zh/docs/reference/glossary/replication-controller.md @@ -0,0 +1,43 @@ +--- +title: Replication Controller +id: replication-controller +date: 2018-04-12 +full_link: +short_description: > + Replication Controller 是 Kubernetes 的一种服务,用来确保给定个数的 Pod 一直处于运行状态。 + +aka: +tags: +- workload +- core-object +--- + + + + + +Replication Controller 是 Kubernetes 的一种服务,用来确保给定个数的 Pod 一直处于运行状态。 + + + + + +Replication Controller 会基于设定值自动增删 Pod 的实例。如果 Pod 被误删除或者启动实例过多,Replication Controller 允许 Pod 的实例个数恢复到设定值。 diff --git a/content/zh/docs/reference/glossary/resource-quota.md b/content/zh/docs/reference/glossary/resource-quota.md new file mode 100755 index 0000000000..c0f40f3234 --- /dev/null +++ b/content/zh/docs/reference/glossary/resource-quota.md @@ -0,0 +1,47 @@ +--- +title: 资源配额 +id: resource-quota +date: 2018-04-12 +full_link: /docs/concepts/policy/resource-quotas/ +short_description: > + 资源配额提供了限制每个命名空间的资源消耗总和的约束。 + +aka: +tags: +- fundamental +- operation +- architecture +--- + + + + + +资源配额提供了限制每个 {{< glossary_tooltip text="命名空间" term_id="namespace">}} 的资源消耗总和的约束。 + + + + + +限制了命名空间中每种对象可以创建的数量,也限制了项目中可被资源对象利用的计算资源总数。 + + diff --git a/content/zh/docs/reference/glossary/reviewer.md b/content/zh/docs/reference/glossary/reviewer.md new file mode 100644 index 0000000000..a181122927 --- /dev/null +++ b/content/zh/docs/reference/glossary/reviewer.md @@ -0,0 +1,41 @@ +--- +title: 评审者 +id: reviewer +date: 2018-04-12 +full_link: +short_description: > + 评审者是负责评审项目的某部分代码以便提高代码质量和正确性的人。 + +aka: +tags: +- community +--- + + + + + + 评审者是负责评审项目的某部分代码以便提高代码质量和正确性的人。 + + + + + +评审者既要了解代码库又要了解软件工程规范。评审者状态是基于代码库的组成部分来设定的。 diff --git a/content/zh/docs/reference/glossary/secret.md b/content/zh/docs/reference/glossary/secret.md new file mode 100755 index 0000000000..a43dbb6ece --- /dev/null +++ b/content/zh/docs/reference/glossary/secret.md @@ -0,0 +1,45 @@ +--- +title: Secret +id: secret +date: 2018-04-12 +full_link: /docs/concepts/configuration/secret/ +short_description: > + Secret 用于存储敏感信息,如密码、OAuth 令牌和 SSH 密钥。 + +aka: +tags: +- core-object +- security +--- + + + + + + Secret 用于存储敏感信息,如密码、OAuth 令牌和 SSH 密钥。 + + + + + +Secret 允许用户对如何使用敏感信息进行更多的控制,并减少信息意外暴露的风险,包括静态[加密](/docs/tasks/administer-cluster/encrypt-data/#ensure-all-secrets-are-encrypted)。 +{{< glossary_tooltip text="Pod" term_id="pod" >}} 通过挂载卷中的文件的方式引用 Secret,或者通过 kubelet 为 pod 拉取镜像时引用。 +Secret 非常适合机密数据使用,而 [ConfigMaps](/docs/tasks/configure-pod-container/configure-pod-configmap/) 适用于非机密数据。 diff --git a/content/zh/docs/reference/glossary/security-context.md b/content/zh/docs/reference/glossary/security-context.md new file mode 100755 index 0000000000..31b99c635c --- /dev/null +++ b/content/zh/docs/reference/glossary/security-context.md @@ -0,0 +1,43 @@ +--- +title: 安全上下文(Security Context) +id: security-context +date: 2018-04-12 +full_link: /docs/tasks/configure-pod-container/security-context/ +short_description: > + securityContext 字段定义 Pod 或容器的特权和访问控制设置,包括运行时 UID 和 GID。 + +aka: +tags: +- security +--- + + + + +securityContext 字段定义 Pod 或容器的特权和访问控制设置,包括运行时 UID 和 GID。 + + + + +{{< glossary_tooltip term_id="pod" >}} 或者容器中的 securityContext 字段(应用于所有容器)用于设置容器进程使用的用户(runAsUser)和组 (fsGroup)、权能字、特权设置和安全策略(SELinux/AppArmor/Seccomp)。 + + + + diff --git a/content/zh/docs/reference/glossary/selector.md b/content/zh/docs/reference/glossary/selector.md new file mode 100644 index 0000000000..5a3e83ef0d --- /dev/null +++ b/content/zh/docs/reference/glossary/selector.md @@ -0,0 +1,42 @@ +--- +title: 选择算符 +id: selector +date: 2018-04-12 +full_link: /docs/concepts/overview/working-with-objects/labels/ +short_description: > + 选择算符允许用户通过标签对一组资源对象进行筛选过滤。 + +aka: +tags: +- fundamental +--- + + + + + +选择算符允许用户通过标签对一组资源对象进行筛选过滤。 + + + + + +在查询资源列表时,选择算符可以通过 {{< glossary_tooltip text="标签" term_id="label" >}} 对资源进行过滤筛选。 + diff --git a/content/zh/docs/reference/glossary/service-account.md b/content/zh/docs/reference/glossary/service-account.md new file mode 100755 index 0000000000..4dd29b301b --- /dev/null +++ b/content/zh/docs/reference/glossary/service-account.md @@ -0,0 +1,43 @@ +--- +title: 服务账户 +id: service-account +date: 2018-04-12 +full_link: /docs/tasks/configure-pod-container/configure-service-account/ +short_description: > + 为在 Pod 中运行的进程提供标识。 + +aka: +tags: +- fundamental +- core-object +--- + + + + +为在 {{< glossary_tooltip text="Pod" term_id="pod" >}} 中运行的进程提供标识。 + + + + +当 Pod 中的进程访问集群时,API 服务器将它们作为特定的服务帐户进行身份验证,例如 `default`。当您创建 Pod 时,如果您没有指定服务帐户,它将在相同的命名空间 {{< glossary_tooltip text="命名空间" term_id="namespace" >}} 中自动分配 default 服务账户。 + + diff --git a/content/zh/docs/reference/glossary/service-broker.md b/content/zh/docs/reference/glossary/service-broker.md new file mode 100755 index 0000000000..8a017d127b --- /dev/null +++ b/content/zh/docs/reference/glossary/service-broker.md @@ -0,0 +1,42 @@ +--- +title: 服务代理(Service Broker) +id: service-broker +date: 2018-04-12 +full_link: +short_description: > + 由第三方提供并维护的一组托管服务的访问端点。 + +aka: +tags: +- extension +--- + + + + + +由第三方提供并维护的一组{{< glossary_tooltip text="托管服务" term_id="managed-service">}} 的访问端点。 + + + + + +{{< glossary_tooltip text="服务代理" term_id="service-broker">}}会实现 +[开放服务代理 API 规范](https://github.com/openservicebrokerapi/servicebroker/blob/v2.13/spec.md) +并为应用提供使用其托管服务的标准接口。 +[服务目录(Service Catalog)](/docs/concepts/service-catalog/)则提供一种方法,用来列举、供应和绑定服务代理商所提供的托管服务。 diff --git a/content/zh/docs/reference/glossary/service-catalog.md b/content/zh/docs/reference/glossary/service-catalog.md new file mode 100644 index 0000000000..726aff57c2 --- /dev/null +++ b/content/zh/docs/reference/glossary/service-catalog.md @@ -0,0 +1,43 @@ +--- +title: 服务目录 +id: service-catalog +date: 2018-04-12 +full_link: +short_description: > + 服务目录是一种扩展 API,它能让 Kubernetes 集群中运行的应用易于使用外部托管的软件服务,例如云供应商提供的数据仓库服务。 + + An extension API that enables applications running in Kubernetes clusters to easily use external managed software offerings, such as a datastore service offered by a cloud provider. +aka: +tags: +- extension +--- + + + + + +服务目录(Service Catalog)是一种扩展 API,它能让 Kubernetes 集群中运行的应用易于使用外部托管的的软件服务,例如云供应商提供的数据仓库服务。 + + + + + +服务目录可以检索、供应、和绑定由 {{< glossary_tooltip text="服务代理人(Service Brokers)" term_id="service-broker" >}} 提供的外部 {{< glossary_tooltip text="托管服务" term_id="managed-service" >}},而无需知道那些服务具体是怎样创建和托管的。 + diff --git a/content/zh/docs/reference/glossary/service.md b/content/zh/docs/reference/glossary/service.md index 657db3aa06..67a1ba8404 100755 --- a/content/zh/docs/reference/glossary/service.md +++ b/content/zh/docs/reference/glossary/service.md @@ -22,4 +22,4 @@ An abstract way to expose an application running on a set of {{< glossary_toolti -服务所针对的Pod集(通常)由 {{< glossary_tooltip text="selector" term_id="selector" >}} 确定。 如果添加或删除了更多Pod,则与选择器匹配的Pod集将发生变化。 该服务确保可以将网络流量定向到该工作负载的当前Pod集。 \ No newline at end of file +服务所针对的Pod集(通常)由 {{< glossary_tooltip text="selector" term_id="selector" >}} 确定。 如果添加或删除了更多Pod,则与选择器匹配的Pod集将发生变化。 该服务确保可以将网络流量定向到该工作负载的当前Pod集。 diff --git a/content/zh/docs/reference/glossary/sig.md b/content/zh/docs/reference/glossary/sig.md new file mode 100755 index 0000000000..a42a15b0b1 --- /dev/null +++ b/content/zh/docs/reference/glossary/sig.md @@ -0,0 +1,48 @@ +--- +title: SIG (特别兴趣小组) +id: sig +date: 2018-04-12 +full_link: https://github.com/kubernetes/community/blob/master/sig-list.md#master-sig-list +short_description: > + 共同管理大范畴 Kubernetes 开源项目中某组件或方面的一组社区成员。 + +aka: +tags: +- community +--- + + + + + +共同管理大范畴 Kubernetes 开源项目中某组件或方面的一组{{< glossary_tooltip text="社区成员" term_id="member" >}}。 + + + + + +SIG 中的成员对推进某个领域(如体系结构、API 机制构件或者文档)具有相同的兴趣。 +SIGs 必须遵从 [SIG Governance](https://github.com/kubernetes/community/blob/master/sig-governance.md) 的规定, +不过可以有自己的贡献策略以及通信渠道(方式)。 + +更多的详细信息可参阅 [kubernetes/community](https://github.com/kubernetes/community) 仓库以及 +[SIGs 和工作组(Working Groups)](https://github.com/kubernetes/community/blob/master/sig-list.md)的最新列表。 + diff --git a/content/zh/docs/reference/glossary/statefulset.md b/content/zh/docs/reference/glossary/statefulset.md new file mode 100644 index 0000000000..ff63c63ce1 --- /dev/null +++ b/content/zh/docs/reference/glossary/statefulset.md @@ -0,0 +1,49 @@ +--- +title: StatefulSet +id: statefulset +date: 2018-04-12 +full_link: /docs/concepts/workloads/controllers/statefulset/ +short_description: > + StatefulSet 用来管理 Deployment 和伸缩一组 Pod,并且能为这些 Pod 提供*序号和唯一性保证*。 +aka: +tags: +- fundamental +- core-object +- workload +- storage +--- + + + + StatefulSet 用来管理 Deployment 和扩展一组 Pod,并且能为这些 Pod 提供*序号和唯一性保证*。 + + + + + +和 {{< glossary_tooltip term_id="Deployment" >}} 相同的是,StatefulSet 管理了基于相同容器定义的一组 Pod。但和 Deployment 不同的是,StatefulSet 为它们的每个 Pod 维护了一个固定的 ID。这些 Pod 是基于相同的声明来创建的,但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。 + + + +StatefulSet 和其他控制器使用相同的工作模式。你在 StatefulSet *对象* 中定义你期望的状态,然后 StatefulSet 的 *控制器* 就会通过各种更新来达到那种你想要的状态。 + diff --git a/content/zh/docs/reference/glossary/static-pod.md b/content/zh/docs/reference/glossary/static-pod.md new file mode 100644 index 0000000000..83659846fd --- /dev/null +++ b/content/zh/docs/reference/glossary/static-pod.md @@ -0,0 +1,39 @@ +--- +title: 静态 Pod +id: static-pod +date: 2019-02-12 +full_link: /docs/tasks/configure-pod-container/static-pod/ +short_description: > + 由特定节点上的 kubelet 守护进程直接管理的 pod。 + +aka: +tags: +- fundamental +--- + + + + +由特定节点上的 kubelet 守护进程直接管理的 {{< glossary_tooltip text="pod" term_id="pod" >}}, + + + +API 服务器不了解它的存在。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/storage-class.md b/content/zh/docs/reference/glossary/storage-class.md new file mode 100644 index 0000000000..52886478eb --- /dev/null +++ b/content/zh/docs/reference/glossary/storage-class.md @@ -0,0 +1,40 @@ + + +--- +title: 存储类别 +id: storageclass +date: 2018-04-12 +full_link: /docs/concepts/storage/storage-classes +short_description: > + StorageClass 是管理员用来描述不同的可用存储类型的一种方法。 + +aka: +tags: +- core-object +- storage +--- + + StorageClass 是管理员用来描述不同的可用存储类型的一种方法。 + + + + +StorageClass 可以映射到服务质量等级(QoS)、备份策略、或者管理员随机定义的策略。每个 StorageClass 对象包含的域有 `provisioner`、 `parameters` 和 `reclaimPolicy`,属于该存储类别的 {{< glossary_tooltip text="永久卷" term_id="persistent-volume" >}} 需要动态分配时就要用到这些域参数。通过 StorageClass 对象的名称,用户可以请求他们需要的特定存储类别。 + diff --git a/content/zh/docs/reference/glossary/sysctl.md b/content/zh/docs/reference/glossary/sysctl.md new file mode 100644 index 0000000000..46a6dd98f3 --- /dev/null +++ b/content/zh/docs/reference/glossary/sysctl.md @@ -0,0 +1,51 @@ +--- +title: sysctl +id: sysctl +date: 2019-02-12 +full_link: /docs/tasks/administer-cluster/sysctl-cluster/ +short_description: > + 用于获取和设置 Unix 内核参数的接口 + +aka: +tags: +- 工具 +--- + + + + + + `sysctl` 是一个半标准化的接口,用于读取或更改正在运行的 Unix 内核的属性。 + + + + + +在类 Unix 系统上, `sysctl` 既是管理员用于查看和修改这些设置的工具的名称,也是该工具所调用的系统调用的名称。 + + + +{{< glossary_tooltip text="容器" term_id="container" >}} 运行时和网络插件可能对 `sysctl` 的取值有一定的要求。 diff --git a/content/zh/docs/reference/glossary/taint.md b/content/zh/docs/reference/glossary/taint.md new file mode 100644 index 0000000000..24b54fc16e --- /dev/null +++ b/content/zh/docs/reference/glossary/taint.md @@ -0,0 +1,39 @@ +--- +title: 污点 +id: taint +date: 2019-01-11 +full_link: /docs/concepts/configuration/taint-and-toleration/ +short_description: > + 一个核心对象,由三个必需的属性组成:键,值和效果。污点会阻止在节点或节点组上调度 Pod。 + +aka: +tags: +- core-object +- fundamental +--- + 一个核心对象,由三个必需的属性组成:键,值和效果。污点会阻止在节点或节点组上调度 Pod。 + + + + + + + +污点和 {{< glossary_tooltip text="容忍度" term_id="toleration" >}} 一起工作,以确保不会将 Pod 调度到不适合的节点上。一个或多个污点应用于 {{< glossary_tooltip text="节点" term_id="node" >}}。节点应该仅能调度那些带着能与污点相匹配容忍度的 pod。 \ No newline at end of file diff --git a/content/zh/docs/reference/glossary/toleration.md b/content/zh/docs/reference/glossary/toleration.md new file mode 100644 index 0000000000..ba59aed099 --- /dev/null +++ b/content/zh/docs/reference/glossary/toleration.md @@ -0,0 +1,38 @@ +--- +title: 容忍度 +id: toleration +date: 2019-01-11 +full_link: /docs/concepts/configuration/taint-and-toleration/ +short_description: > + 一个核心对象,由三个必需的属性组成:key、value 和 effect。容忍度允许将 Pod 调度到具有对应污点的节点或节点组上。 +aka: +tags: +- core-object +- fundamental +--- + 一个核心对象,由三个必需的属性组成:key、value 和 effect。 + 容忍度允许将 Pod 调度到具有匹配 {{< glossary_tooltip text="污点" term_id="taint" >}} 的节点或节点组上。 + + + + + + + 容忍度 和 {{< glossary_tooltip text="污点" term_id="taint" >}} 共同作用以确保不会将 Pod 调度在不适合的节点上。在同一 {{< glossary_tooltip text="pod" term_id="pod" >}} 上可以设置一个或者多个容忍度。容忍度表示在匹配节点或节点组上的 {{< glossary_tooltip text="污点" term_id="taint" >}} 调度 {{< glossary_tooltip text="pod" term_id="pod" >}} 是允许的(但不必要)。 diff --git a/content/zh/docs/reference/glossary/uid.md b/content/zh/docs/reference/glossary/uid.md index a8f61a0449..5990d46d1d 100755 --- a/content/zh/docs/reference/glossary/uid.md +++ b/content/zh/docs/reference/glossary/uid.md @@ -3,6 +3,20 @@ title: UID id: uid date: 2018-04-12 full_link: /docs/concepts/overview/working-with-objects/names +short_description: > + 由 Kubernetes 系统生成、用来唯一标识对象的字符串。 + +aka: +tags: +- fundamental +--- + + + diff --git a/content/zh/docs/reference/glossary/upstream.md b/content/zh/docs/reference/glossary/upstream.md new file mode 100644 index 0000000000..7f2c7ded3e --- /dev/null +++ b/content/zh/docs/reference/glossary/upstream.md @@ -0,0 +1,27 @@ +--- +title: Upstream (disambiguation) +id: upstream +date: 2018-04-12 +full_link: +short_description: > + May refer to: core Kubernetes or the source repo from which a repo was forked. + +aka: +tags: +- community +--- + + + + +可以参考:核心 Kubernetes 仓库或作为当前仓库派生来源的来源仓库。 + + + +* 在 **Kubernetes社区**:对话中通常使用 *upstream* 来表示核心 Kubernetes 代码库,也就是更广泛的 kubernetes 生态系统、其他代码或第三方工具所依赖的仓库。 例如,[社区成员](#term-member)可能会建议将某个功能特性贡献到 upstream,使其位于核心代码库中,而不是维护于插件或第三方工具中。 +* 在 **GitHub** 或 **git** 中:约定是将源仓库称为 *upstream*,而派生的仓库则被视为 *downstream*。 diff --git a/content/zh/docs/reference/glossary/volume-plugin.md b/content/zh/docs/reference/glossary/volume-plugin.md new file mode 100755 index 0000000000..ca4318d4ad --- /dev/null +++ b/content/zh/docs/reference/glossary/volume-plugin.md @@ -0,0 +1,44 @@ +--- +title: 卷(Volume)插件 +id: volumeplugin +date: 2018-04-12 +full_link: +short_description: > + 卷(Volume)插件可以让 Pod 集成存储。 + +aka: +tags: +- core-object +- storage +--- + + + + + +卷插件可以让 {{< glossary_tooltip text="Pod" term_id="pod" >}} 集成存储。 + + + + + +卷插件让您能给 {{< glossary_tooltip text="Pod" term_id="pod" >}} 附加和挂载存储卷。卷插件既可以是 _in tree_ 也可以是 _out of tree_ 。_in tree_ 插件是 Kubernetes 代码库的一部分,并遵循其发布周期。而 _Out of tree_ 插件则是独立开发的。 + diff --git a/content/zh/docs/reference/glossary/volume.md b/content/zh/docs/reference/glossary/volume.md new file mode 100755 index 0000000000..279626861d --- /dev/null +++ b/content/zh/docs/reference/glossary/volume.md @@ -0,0 +1,43 @@ +--- +title: 卷 +id: volume +date: 2018-04-12 +full_link: /docs/concepts/storage/volumes/ +short_description: > + 包含可被 Pod 中容器访问的数据的目录。 + +aka: +tags: +- core-object +- fundamental +--- + + + + + +包含可被 {{< glossary_tooltip text="pod" term_id="pod" >}} 中容器访问的数据的目录。 + + + + +每个 Kubernetes 卷在所处的{{< glossary_tooltip text="pod" term_id="pod" >}} 存在期间保持存在状态。 +因此,卷的生命期会超出 {{< glossary_tooltip text="pod" term_id="pod" >}} 中运行的{{< glossary_tooltip text="容器" term_id="container" >}}, +并且保证{{< glossary_tooltip text="容器" term_id="container" >}}重启之后仍保留数据。 + diff --git a/content/zh/docs/reference/glossary/wg.md b/content/zh/docs/reference/glossary/wg.md new file mode 100644 index 0000000000..9a42e77ab0 --- /dev/null +++ b/content/zh/docs/reference/glossary/wg.md @@ -0,0 +1,45 @@ +--- +title: WG (工作组) +id: wg +date: 2018-04-12 +full_link: https://github.com/kubernetes/community/blob/master/sig-list.md#master-working-group-list +short_description: > + 工作组是为了方便讨论和(或)推进执行一些短周期、窄范围、或者从委员会和 SIG 分离出来的项目、以及跨 SIG 的活动。 + +aka: +tags: +- community +--- + + + + + +工作组是为了方便讨论和(或)推进执行一些短周期、窄范围、或者从委员会和 SIG 分离出来的项目、以及跨 SIG 的活动。 + + + + + +工作组可以将人们组织起来,一起完成一项分散的任务。它组建简单,完成任务即可解散。 + +更多信息请参考 [kubernetes/community](https://github.com/kubernetes/community) 代码库和当前的 [SIGs 和工作组](https://github.com/kubernetes/community/blob/master/sig-list.md) 列表。 diff --git a/content/zh/docs/reference/glossary/workload.md b/content/zh/docs/reference/glossary/workload.md new file mode 100644 index 0000000000..1fb3586d86 --- /dev/null +++ b/content/zh/docs/reference/glossary/workload.md @@ -0,0 +1,39 @@ +--- +title: 工作负载 +id: workloads +date: 2019-02-13 +full_link: /docs/concepts/workloads/ +short_description: > + 工作负载是在 Kubernetes 上运行的应用程序。 + +aka: +tags: +- fundamental +--- + + + + 工作负载是在 Kubernetes 上运行的应用程序。 + + + + +代表不同类型或部分工作负载的各种核心对象包括 DaemonSet, Deployment, Job, ReplicaSet, and StatefulSet。 + +例如,具有 Web 服务器和数据库的工作负载可能在一个 {{< glossary_tooltip term_id="StatefulSet" >}} 中运行数据库,而 Web 服务器运行在 {{< glossary_tooltip term_id="Deployment" >}}。 \ No newline at end of file diff --git a/content/zh/docs/reference/issues-security/_index.md b/content/zh/docs/reference/issues-security/_index.md index 382a4ed66d..b4f4e0c193 100644 --- a/content/zh/docs/reference/issues-security/_index.md +++ b/content/zh/docs/reference/issues-security/_index.md @@ -2,4 +2,12 @@ title: Kubernetes 问题和安全 weight: 10 toc-hide: true ---- \ No newline at end of file +--- + + diff --git a/content/zh/docs/reference/issues-security/issues.md b/content/zh/docs/reference/issues-security/issues.md new file mode 100644 index 0000000000..7976be7684 --- /dev/null +++ b/content/zh/docs/reference/issues-security/issues.md @@ -0,0 +1,16 @@ +--- +title: Kubernetes 问题追踪 +weight: 10 +--- + + + + +Kubernetes 代码的问题追踪基于 [GitHub Issues](https://github.com/kubernetes/kubernetes/issues/) 进行。 diff --git a/content/zh/docs/reference/issues-security/security.md b/content/zh/docs/reference/issues-security/security.md new file mode 100644 index 0000000000..a0fe43786a --- /dev/null +++ b/content/zh/docs/reference/issues-security/security.md @@ -0,0 +1,129 @@ +--- +title: Kubernetes 安全和信息披露 +aliases: [/security/] +content_template: templates/concept +weight: 20 +--- + + + +{{% capture overview %}} + +本页面介绍 Kubernetes 安全和信息披露相关的内容。 +{{% /capture %}} + +{{% capture body %}} + +## 安全公告 + + +加入 [kubernets-announce](https://groups.google.com/forum/#!forum/kubernetes-announce) 组,以获取关于安全性和主要 API 公告的电子邮件。 + + +## 报告一个漏洞 + + +我们非常感谢向 Kubernetes 开源社区报告漏洞的安全研究人员和用户。 +所有的报告都由社区志愿者进行彻底调查。 + + +如需报告,请连同安全细节以及预期的[所有 Kubernetes bug 报告](https://git.k8s.io/kubernetes/.github/ISSUE_TEMPLATE/bug-report.md)详细信息电邮到[security@kubernetes.io](mailto:security@kubernetes.io) 列表。 + + +您可以使用[产品安全团队成员](https://git.k8s.io/sig-release/security-release-process-documentation/security-release-process.md#product-security-team-pst)的 GPG 密钥加密您的电子邮件到此列表。 +使用 GPG 加密不需要公开。 + + +### 我应该在什么时候报告漏洞? + + +- 您认为在 Kubernetes 中发现了一个潜在的安全漏洞 +- 您不确定漏洞如何影响 Kubernetes +- 您认为您在 Kubernetes 依赖的另一个项目中发现了一个漏洞(例如 docker、rkt、etcd) + + +### 我什么时候不应该报告漏洞? + + +- 您需要帮助调整 Kubernetes 组件的安全性 +- 您需要帮助应用与安全相关的更新 +- 您的问题与安全无关 + + +## 安全漏洞响应 + + +每个报告在 3 个工作日内由产品安全团队成员确认和分析。这将启动[安全发布过程](https://git.k8s.io/sig-release/security-release-process-documentation/security-release-process.md#disclosures)。 + + +与产品安全团队共享的任何漏洞信息都保留在 Kubernetes 项目中,除非有必要修复该问题,否则不会传播到其他项目。 + + +随着安全问题从分类、识别修复、发布计划等方面的进展,我们将不断更新报告。 + + +## 公开披露时间 + + +公开披露日期由 Kubernetes 产品安全团队和 bug 提交者协商。我们倾向于在用户缓解措施可用时尽快完全披露该 bug。 + + +当 bug 或其修复还没有被完全理解,解决方案没有经过良好的测试,或者为了处理供应商协调问题时,延迟披露是合理的。 + + +信息披露的时间范围从即时(尤其是已经公开的)到几周。作为一个基本的约定,我们希望报告日期到披露日期的间隔是 7 天。在设置披露日期时,Kubernetes 产品安全团队拥有最终决定权。 +{{% /capture %}} diff --git a/content/zh/docs/reference/kubectl/_index.md b/content/zh/docs/reference/kubectl/_index.md index 7b6c2d720b..fb61e32478 100755 --- a/content/zh/docs/reference/kubectl/_index.md +++ b/content/zh/docs/reference/kubectl/_index.md @@ -1,5 +1,11 @@ --- +title: "kubectl 命令行界面" +weight: 60 +--- + + diff --git a/content/zh/docs/reference/kubectl/cheatsheet.md b/content/zh/docs/reference/kubectl/cheatsheet.md new file mode 100644 index 0000000000..75b7c2f7be --- /dev/null +++ b/content/zh/docs/reference/kubectl/cheatsheet.md @@ -0,0 +1,679 @@ +--- +title: kubectl 备忘单 +reviewers: +- erictune +- krousey +- clove +content_template: templates/concept +card: + name: reference + weight: 30 +--- + + +{{% capture overview %}} + + +也可以看下: [Kubectl 概述](/docs/reference/kubectl/overview/) 和 [JsonPath 指南](/docs/reference/kubectl/jsonpath)。 + + +本页面是 `kubectl` 命令的概述。 + +{{% /capture %}} + +{{% capture body %}} + + +## kubectl - 备忘单 + + +## Kubectl 自动补全 + +### BASH + + +```bash +source <(kubectl completion bash) # 在 bash 中设置当前 shell 的自动补全,要先安装 bash-completion 包。 +echo "source <(kubectl completion bash)" >> ~/.bashrc # 在您的 bash shell 中永久的添加自动补全 +``` + + +您还可以为 `kubectl` 使用一个速记别名,该别名也可以与 completion 一起使用: + +```bash +alias k=kubectl +complete -F __start_kubectl k +``` + +### ZSH + + +```bash +source <(kubectl completion zsh) # 在 zsh 中设置当前 shell 的自动补全 +echo "if [ $commands[kubectl] ]; then source <(kubectl completion zsh); fi" >> ~/.zshrc # 在您的 zsh shell 中永久的添加自动补全 +``` + + +## Kubectl 上下文和配置 + +设置 `kubectl` 与哪个 Kubernetes 集群进行通信并修改配置信息。查看 [使用 kubeconfig 跨集群授权访问](/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) 文档获取详情配置文件信息。 + + +```bash +kubectl config view # 显示合并的 kubeconfig 配置。 + +# 同时使用多个 kubeconfig 文件并查看合并的配置 +KUBECONFIG=~/.kube/config:~/.kube/kubconfig2 kubectl config view + +# 获取 e2e 用户的密码 +kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}' + +kubectl config current-context # 展示当前所处的上下文 +kubectl config use-context my-cluster-name # 设置默认的上下文为 my-cluster-name + +# 添加新的集群配置到 kubeconf 中,使用 basic auth 进行鉴权 +kubectl config set-credentials kubeuser/foo.kubernetes.com --username=kubeuser --password=kubepassword + +# 使用特定的用户名和命名空间设置上下文。 +kubectl config set-context gce --user=cluster-admin --namespace=foo \ + && kubectl config use-context gce +``` + + +## Apply +`apply` 通过定义 Kubernetes 资源的文件管理应用程序。它通过运行 `kubectl apply` 在集群中创建和更新资源。这是在生产中管理 Kubernetes 应用程序的推荐方法。查阅 [Kubectl 文档](https://kubectl.docs.kubernetes.io)。 + + +## 创建对象 + + +Kubernetes 配置可以用 json 或 yaml 定义。可以使用的文件扩展名有 `.yaml`,`.yml` 和 `.json`。 + + +```bash +kubectl apply -f ./my-manifest.yaml # 创建资源 +kubectl apply -f ./my1.yaml -f ./my2.yaml # 使用多个文件创建 +kubectl apply -f ./dir # 从目录下的全部配置文件创建资源 +kubectl apply -f https://git.io/vPieo # 从 url 中创建资源 +kubectl create deployment nginx --image=nginx # 启动单实例 nginx +kubectl explain pods,svc # 获取 pod,svc 配置的文档说明 + +# 从标准输入中的多个 YAML 对象中创建 +cat < +## 获取和查找资源 + + +```bash +# 使用 get 命令获取基本输出 +kubectl get services # 列出当前命名空间下的所有 services +kubectl get pods --all-namespaces # 列出所有命名空间下的全部的 pods +kubectl get pods -o wide # 列出当前命名空间下的全部 pods,有更多的详细信息 +kubectl get deployment my-dep # 列出某个特定的 deployment +kubectl get pods --include-uninitialized # 列出当前命名空间下的全部 pods,包含未初始化的 +kubectl get pod my-pod -o yaml # 获取一个 pod 的 YAML +kubectl get pod my-pod -o yaml --export # 获取一个没有集群特定信息的 YAML + +# 使用 describe 命令获取详细输出 +kubectl describe nodes my-node +kubectl describe pods my-pod + +kubectl get services --sort-by=.metadata.name # 列出当前命名空间下所有 services,按照名称排序 + +# 列出 pods 按照重启次数进行排序 +kubectl get pods --sort-by='.status.containerStatuses[0].restartCount' + +# 列出测试命名空间中的 Pod,按容量排序 +kubectl get pods -n test --sort-by=.spec.capacity.storage + +# 获取包含 app=cassandra 标签全部 pods 的 version 标签 +kubectl get pods --selector=app=cassandra -o \ + jsonpath='{.items[*].metadata.labels.version}' + +# 获取所有工作节点(使用选择器以排除标签名称为 'node-role.kubernetes.io/master' 的结果) +kubectl get node --selector='!node-role.kubernetes.io/master' + +# 获取当前命名空间中正在运行的 pods +kubectl get pods --field-selector=status.phase=Running + +# 获取全部 node 的 ExternalIP 地址 +kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}' + +# 列出属于某个特定 RC 的 pods 的名称 +# "jq" 命令对于 jsonpath 过于复杂的转换非常有用,可以在 https://stedolan.github.io/jq/ 找到它。 +sel=${$(kubectl get rc my-rc --output=json | jq -j '.spec.selector | to_entries | .[] | "\(.key)=\(.value),"')%?} +echo $(kubectl get pods --selector=$sel --output=jsonpath={.items..metadata.name}) + +# 显示所有 Pod 的标签(或任何其他支持标签的 Kubernetes 对象) +# 也可以使用 "jq" +for item in $( kubectl get pod --output=name); do printf "Labels for %s\n" "$item" | grep --color -E '[^/]+$' && kubectl get "$item" --output=json | jq -r -S '.metadata.labels | to_entries | .[] | " \(.key)=\(.value)"' 2>/dev/null; printf "\n"; done + +# 或也可以使用此命令来获取与容器关联的所有标签 +kubectl get pods --show-labels + +# 检查哪些节点处于 ready +JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}' \ + && kubectl get nodes -o jsonpath="$JSONPATH" | grep "Ready=True" + +# 列出被一个 pod 使用的全部 secret +kubectl get pods -o json | jq '.items[].spec.containers[].env[]?.valueFrom.secretKeyRef.name' | grep -v null | sort | uniq + +# 列出 events,按照创建时间排序 +kubectl get events --sort-by=.metadata.creationTimestamp +``` + + +## 更新资源 + + +从版本 1.11 开始,`rolling-update` 已被弃用(参见 [CHANGELOG-1.11.md](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.11.md)),请使用 `rollout` 代替。 + + +```bash +kubectl set image deployment/frontend www=image:v2 # 滚动更新 "frontend" deployment 的 "www" 容器镜像 +kubectl rollout history deployment/frontend # 检查部署的历史记录,包括版本 +kubectl rollout undo deployment/frontend # 回滚到上次部署版本 +kubectl rollout undo deployment/frontend --to-revision=2 # 回滚到特定部署版本 +kubectl rollout status -w deployment/frontend # Watch "frontend" deployment 的滚动升级状态直到完成 + +# 从 1.11 版本开始弃用 +kubectl rolling-update frontend-v1 -f frontend-v2.json # (弃用) 滚动升级 frontend-v1 的 pods +kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2 # (弃用) 修改资源的名称并更新镜像 +kubectl rolling-update frontend --image=image:v2 # (弃用) 更新 frontend 的 pods 的镜像 +kubectl rolling-update frontend-v1 frontend-v2 --rollback # (弃用) 终止已经进行中的 rollout + +cat pod.json | kubectl replace -f - # 通过传入到标准输入的 JSON 来替换 pod + +# 强制进行替换,会删除然后再创建资源,会导致服务不可用。 +kubectl replace --force -f ./pod.json + +# 为多副本的 nginx 创建服务,使用 80 端口提供服务,连接到容器的 8000 端口。 +kubectl expose rc nginx --port=80 --target-port=8000 + +# 更新单容器 pod 的镜像标签到 v4 +kubectl get pod mypod -o yaml | sed 's/\(image: myimage\):.*$/\1:v4/' | kubectl replace -f - + +kubectl label pods my-pod new-label=awesome # 添加标签 +kubectl annotate pods my-pod icon-url=http://goo.gl/XXBTWq # 添加注解 +kubectl autoscale deployment foo --min=2 --max=10 # 使 "foo" deployment 自动伸缩容 +``` + + +## 局部更新资源 + + +```bash +kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}' # 部分更新 node + +#更新容器的镜像;spec.containers[*].name 是必须的。因为它是一个合并 key。 +kubectl patch pod valid-pod -p '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}' + +# 使用带位置数组的 json patch 更新容器的镜像 +kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]' + +# 使用带位置数组的 json patch 禁用 deployment 的 livenessProbe +kubectl patch deployment valid-deployment --type json -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/livenessProbe"}]' + +# 在带位置数组中添加元素 +kubectl patch sa default --type='json' -p='[{"op": "add", "path": "/secrets/1", "value": {"name": "whatever" } }]' +``` + + +## 编辑资源 + +在编辑器中编辑任何 API 资源 + + +```bash +kubectl edit svc/docker-registry # 编辑名为 docker-registry 的 service +KUBE_EDITOR="nano" kubectl edit svc/docker-registry # 使用其他编辑器 +``` + + +## 对资源进行伸缩 + + +```bash +kubectl scale --replicas=3 rs/foo # 将名为 'foo' 的副本集伸缩到 3 副本 +kubectl scale --replicas=3 -f foo.yaml # 将在 "foo.yaml" 中的特定资源伸缩到 3 个副本 +kubectl scale --current-replicas=2 --replicas=3 deployment/mysql # 如果名为 mysql 的 deployment 的副本当前是 2,那么将它伸缩到 3 +kubectl scale --replicas=5 rc/foo rc/bar rc/baz # 伸缩多个 replication controllers +``` + + +## 删除资源 + + +```bash +kubectl delete -f ./pod.json # 删除在 pod.json 中指定的类型和名称的 pod +kubectl delete pod,service baz foo # 删除名称为 "baz" 和 "foo" 的 pod 和 service +kubectl delete pods,services -l name=myLabel # 删除包含 name=myLabel 标签的 pods 和 services +kubectl delete pods,services -l name=myLabel --include-uninitialized # 删除包含 label name=myLabel 标签的 pods 和 services,包括未初始化的 +kubectl -n my-ns delete po,svc --all # 删除在 my-ns 命名空间中全部的 pods 和 services ,包括未初始化的 +# 删除所有与 pattern1 或 pattern2 匹配的 pod +kubectl get pods -n mynamespace --no-headers=true | awk '/pattern1|pattern2/{print $1}' | xargs kubectl delete -n mynamespace pod +``` + + +## 与运行中的 Pods 进行交互 + + +```bash +kubectl logs my-pod # 获取 pod 日志(标准输出) +kubectl logs -l name=myLabel # 获取 pod label name=myLabel 日志(标准输出) +kubectl logs my-pod --previous # 获取上个容器实例的 pod 日志(标准输出) +kubectl logs my-pod -c my-container # 获取 pod 的容器日志 (标准输出, 多容器的场景) +kubectl logs -l name=myLabel -c my-container # 获取 label name=myLabel pod 的容器日志 (标准输出, 多容器的场景) +kubectl logs my-pod -c my-container --previous # 获取 pod 的上个容器实例日志 (标准输出, 多容器的场景) +kubectl logs -f my-pod # 流式输出 pod 的日志 (标准输出) +kubectl logs -f my-pod -c my-container # 流式输出 pod 容器的日志 (标准输出, 多容器的场景) +kubectl logs -f -l name=myLabel --all-containers # 流式输出 label name=myLabel pod 的日志 (标准输出) +kubectl run -i --tty busybox --image=busybox -- sh # 以交互式 shell 运行 pod +kubectl attach my-pod -i # 进入到一个运行中的容器中 +kubectl port-forward my-pod 5000:6000 # 在本地计算机上侦听端口 5000 并转发到 my-pod 上的端口 6000 +kubectl exec my-pod -- ls / # 在已有的 pod 中运行命令(单容器的场景) +kubectl exec my-pod -c my-container -- ls / # 在已有的 pod 中运行命令(多容器的场景) +kubectl top pod POD_NAME --containers # 显示给定 pod 和容器的监控数据 +``` + + +## 与节点和集群进行交互 + + +```bash +kubectl cordon my-node # 设置 my-node 节点为不可调度 +kubectl drain my-node # 对 my-node 节点进行驱逐操作,为节点维护做准备 +kubectl uncordon my-node # 设置 my-node 节点为可以调度 +kubectl top node my-node # 显示给定 node 的指标 +kubectl cluster-info # 显示 master 和 services 的地址 +kubectl cluster-info dump # 将当前集群状态输出到标准输出 +kubectl cluster-info dump --output-directory=/path/to/cluster-state # 将当前集群状态输出到 /path/to/cluster-state + +# 如果已存在具有该键和效果的污点,则其值将按指定替换 +kubectl taint nodes foo dedicated=special-user:NoSchedule +``` + + +### 资源类型 + + +列出全部支持的资源类型和它们的简称, [API group](/docs/concepts/overview/kubernetes-api/#api-groups), 无论它们是否是 [namespaced](/docs/concepts/overview/working-with-objects/namespaces), [Kind](/docs/concepts/overview/working-with-objects/kubernetes-objects)。 + +```bash +kubectl api-resources +``` + + +用于探索 API 资源的其他操作: + + +```bash +kubectl api-resources --namespaced=true # 所有在命名空间中的资源 +kubectl api-resources --namespaced=false # 所有不在命名空间中的资源 +kubectl api-resources -o name # 输出简单的所有资源(只是资源名称) +kubectl api-resources -o wide # 具有扩展(又称 "wide")输出的所有资源 +kubectl api-resources --verbs=list,get # 支持 "list" 和 "get" 请求动词的所有资源 +kubectl api-resources --api-group=extensions # "extensions" API 组中的所有资源 +``` + + +### 格式化输出 + + +要以特定格式将详细信息输出到终端窗口,可以将 `-o` 或 `--output` 参数添加到支持的 `kubectl` 命令。 + + +输出格式 | 描述 +--------------| ----------- +`-o=custom-columns=` | 使用逗号分隔的自定义列列表打印表格 +`-o=custom-columns-file=` | 使用 `` 文件中的自定义列模板打印表格 +`-o=json` | 输出 JSON 格式的 API 对象 +`-o=jsonpath=
+
+
+

挑战

+ +
Workiva提供了一个基于云的平台,用于管理和报告业务数据。此 SaaS 产品 Wdesk 被 70% 以上的财富 500 强企业使用。随着公司从单体系统向更分散的基于微服务的系统转变,“我们有许多人在研究这个问题,他们都在不同的团队中,所以我们需要确定问题是什么,瓶颈在哪里,”高级软件架构师 MacLeod Broad 说。随着后端代码在 Google App Engine,Google Compute Engine,以及 Amazon Web Services 上运行,Workiva 需要一个还未被开发的跟踪系统。在准备公司首批使用 AWS 的产品时,Broad 的团队将新应用程序中构建的电子表格数据与 Workiva 现有系统上的旧应用程序中创建的文档相关联,该功能涉及“同步和链接”功能,从而发现了一个理想的跟踪用例:存在循环依赖关系,而优化通常证明是不影响整体速度的微优化。 + +
+ +
+ +
+

解决方案

+ +Broad 的团队推出了与平台无关的分布式跟踪系统 OpenTracing,帮助他们找出瓶颈。 +
+

影响

+ +现在在整个公司使用,OpenTracing 产生了立竿见影的效果。软件工程师 Michael Davis 报告说:“跟踪让我们能够立即了解如何改进我们的服务。通过查看每个调用的花费时间以及最常使用哪些调用的组合,我们能够在单个修复中将平均响应时间减少 95%(从 600ms 到 30ms)。” + +
+ +
+