From aec8c4bcf5cdd9ce315fbb860705d9d6631d5bc5 Mon Sep 17 00:00:00 2001 From: Yushiro FURUKAWA Date: Fri, 14 Feb 2020 04:58:36 +0900 Subject: [PATCH 01/38] Remove trailing spaces from it documents (#16790) --- content/it/community/code-of-conduct.md | 10 +- .../it/docs/concepts/architecture/nodes.md | 6 +- .../cluster-administration/cloud-providers.md | 60 ++++---- .../cluster-administration-overview.md | 4 +- .../controller-metrics.md | 10 +- .../kubelet-garbage-collection.md | 26 ++-- .../manage-deployment.md | 90 +++++------ .../cluster-administration/networking.md | 144 +++++++++--------- .../federation-deprecation-warning-note.md | 4 +- 9 files changed, 177 insertions(+), 177 deletions(-) diff --git a/content/it/community/code-of-conduct.md b/content/it/community/code-of-conduct.md index 2d0b6959ca..7c64183ece 100644 --- a/content/it/community/code-of-conduct.md +++ b/content/it/community/code-of-conduct.md @@ -8,16 +8,16 @@ css: /css/community.css

Codice di condotta della comunità di Kubernetes

-Kubernetes segue il +Kubernetes segue il codice di condotta CNCF. -Il testo del CNC CoC è replicato di seguito a partire dal +Il testo del CNC CoC è replicato di seguito a partire dal commit 0ce4694. Se noti che questo non è aggiornato, ti preghiamo di far presente questo problema. file an issue. -Se noti una violazione del Codice di condotta in occasione di un evento o una riunione, in Slack o in un altro meccanismo di comunicazione, -contatta il Comitato per -il codice di condotta di Kubernetes/a>. +Se noti una violazione del Codice di condotta in occasione di un evento o una riunione, in Slack o in un altro meccanismo di comunicazione, +contatta il Comitato per +il codice di condotta di Kubernetes/a>. Potete raggiungerci via email all'indirizzo conduct@kubernetes.io. Il tuo anonimato sarà protetto. diff --git a/content/it/docs/concepts/architecture/nodes.md b/content/it/docs/concepts/architecture/nodes.md index c7ca78917b..4ad016b327 100644 --- a/content/it/docs/concepts/architecture/nodes.md +++ b/content/it/docs/concepts/architecture/nodes.md @@ -97,7 +97,7 @@ numero di pod che possono essere programmati sul nodo. Informazioni generali sul nodo, come la versione del kernel, la versione di Kubernetes (versione kubelet e kube-proxy), versione Docker (se utilizzata), nome del sistema operativo. -Le informazioni sono raccolte da Kubelet dal nodo. +Le informazioni sono raccolte da Kubelet dal nodo. ## Management @@ -211,7 +211,7 @@ NodeController è responsabile per l'aggiunta di taints corrispondenti ai proble nodo irraggiungibile o non pronto. Vedi [questa documentazione](/docs/concepts/configuration/taint-and-toleration/) per i dettagli su `NoExecute` taints e la funzione alpha. -partire dalla versione 1.8, il controller del nodo può essere reso responsabile della creazione di taints che rappresentano le condizioni del nodo. +partire dalla versione 1.8, il controller del nodo può essere reso responsabile della creazione di taints che rappresentano le condizioni del nodo. Questa è una caratteristica alfa della versione 1.8. ### Self-Registration of Nodes @@ -229,7 +229,7 @@ Per l'autoregistrazione, il kubelet viene avviato con le seguenti opzioni: - `--node-labels` - Etichette da aggiungere quando si registra il nodo nel cluster (vedere le restrizioni dell'etichetta applicate dal [plugin di accesso NodeRestriction](/docs/reference/access-authn-authz/admission-controller/#noderestriction) in 1.13+). - `--node-status-update-frequency` - Specifica la frequenza con cui kubelet invia lo stato del nodo al master -Quando [Node authorization mode](/docs/reference/access-authn-authz/node/) e +Quando [Node authorization mode](/docs/reference/access-authn-authz/node/) e [NodeRestriction admission plugin](/docs/reference/access-authn-authz/admission-controllers/#noderestriction) sono abilitati, kubelets è autorizzato solo a creare / modificare la propria risorsa nodo. diff --git a/content/it/docs/concepts/cluster-administration/cloud-providers.md b/content/it/docs/concepts/cluster-administration/cloud-providers.md index ea2c49533a..5ea917a9c5 100644 --- a/content/it/docs/concepts/cluster-administration/cloud-providers.md +++ b/content/it/docs/concepts/cluster-administration/cloud-providers.md @@ -14,7 +14,7 @@ fornitore di servizi cloud. ### kubeadm [kubeadm](/docs/reference/setup-tools/kubeadm/kubeadm/) è un'opzione popolare per la creazione di cluster di kuberneti. -kubeadm ha opzioni di configurazione per specificare le informazioni di configurazione per i provider cloud. Ad esempio +kubeadm ha opzioni di configurazione per specificare le informazioni di configurazione per i provider cloud. Ad esempio un tipico il provider cloud in-tree può essere configurato utilizzando kubeadm come mostrato di seguito: ```yaml @@ -46,15 +46,15 @@ controllerManager: mountPath: "/etc/kubernetes/cloud.conf" ``` -I provider cloud in-tree in genere richiedono sia `--cloud-provider` e` --cloud-config` specificati nelle righe di +I provider cloud in-tree in genere richiedono sia `--cloud-provider` e` --cloud-config` specificati nelle righe di comando per [kube-apiserver](/docs/admin/kube-apiserver/), [kube-controller-manager](/docs/admin/kube-controller-manager/) -e il [Kubelet](/docs/admin/kubelet/). Anche il contenuto del file specificato in `--cloud-config` per ciascun provider +e il [Kubelet](/docs/admin/kubelet/). Anche il contenuto del file specificato in `--cloud-config` per ciascun provider è documentato di seguito. Per tutti i fornitori di servizi cloud esterni, seguire le istruzioni sui singoli repository. ## AWS -Questa sezione descrive tutte le possibili configurazioni che possono essere utilizzato durante l'esecuzione di +Questa sezione descrive tutte le possibili configurazioni che possono essere utilizzato durante l'esecuzione di Kubernetes su Amazon Web Services. ### Node Name @@ -107,23 +107,23 @@ Le informazioni per le annotazioni per AWS sono tratte dai commenti su [aws.go]( ## Azure ### Node Name -Il provider cloud di Azure utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto -con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve +Il provider cloud di Azure utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto +con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve corrispondere al nome VM di Azure. ## CloudStack ### Node Name -Il provider cloud CloudStack utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto -con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve +Il provider cloud CloudStack utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto +con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve corrispondere al nome VM di CloudStack. ## GCE ### Node Name -Il provider cloud GCE utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto +Il provider cloud GCE utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il primo segmento del nome del nodo -Kubernetes deve corrispondere al nome dell'istanza GCE (ad esempio, un nodo denominato `kubernetes-node-2.c.my-proj.internal` +Kubernetes deve corrispondere al nome dell'istanza GCE (ad esempio, un nodo denominato `kubernetes-node-2.c.my-proj.internal` deve corrispondere a un'istanza denominata` kubernetes-node-2`) . ## OpenStack @@ -135,7 +135,7 @@ Il provider cloud OpenStack utilizza il nome dell'istanza (come determinato dai Si noti che il nome dell'istanza deve essere un nome nodo Kubernetes valido affinché kubelet registri correttamente il suo oggetto Node. ### Services -Il provider cloud OpenStack implementazione per Kubernetes supporta l'uso di questi servizi OpenStack da la nuvola +Il provider cloud OpenStack implementazione per Kubernetes supporta l'uso di questi servizi OpenStack da la nuvola sottostante, ove disponibile: | Servizio | Versioni API | Richiesto | @@ -252,7 +252,7 @@ file:   L'impostazione predefinita è `false`. Quando è specificato `true` quindi` monitor-delay`,   `monitor-timeout`, e` monitor-max-retries` deve essere impostato. * `monitor-delay` (Opzionale): il tempo tra l'invio delle sonde a -  membri del servizio di bilanciamento del carico. Assicurati di specificare un'unità di tempo valida. Le unità di tempo +  membri del servizio di bilanciamento del carico. Assicurati di specificare un'unità di tempo valida. Le unità di tempo valide sono "ns", "us" (o "μs"), "ms", "s", "m", "h" * `monitor-timeout` (Opzionale): tempo massimo di attesa per un monitor   per una risposta ping prima che scada. Il valore deve essere inferiore al ritardo @@ -346,22 +346,22 @@ File `cloud.conf`: ## OVirt ### Node Name -Il provider di cloud OVirt utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto -con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve +Il provider di cloud OVirt utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto +con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve corrispondere al FQDN del VM (riportato da OVirt in ` ... `) ## Photon ### Node Name -Il provider cloud Photon utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto -con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve -corrispondere al nome VM Photon (o se "overrideIP` è impostato su true in` --cloud-config`, il nome del nodo Kubernetes +Il provider cloud Photon utilizza il nome host del nodo (come determinato dal kubelet o sovrascritto +con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve +corrispondere al nome VM Photon (o se "overrideIP` è impostato su true in` --cloud-config`, il nome del nodo Kubernetes deve corrispondere all'indirizzo IP della macchina virtuale Photon). ## VSphere ### Node Name -Il provider cloud VSphere utilizza il nome host rilevato del nodo (come determinato dal kubelet) come nome dell'oggetto +Il provider cloud VSphere utilizza il nome host rilevato del nodo (come determinato dal kubelet) come nome dell'oggetto Nodo Kubernetes. Il parametro `--hostname-override` viene ignorato dal fornitore di cloud VSphere. @@ -369,31 +369,31 @@ Il parametro `--hostname-override` viene ignorato dal fornitore di cloud VSphere ## IBM Cloud Kubernetes Service ### Compute nodes -Utilizzando il provider di servizi IBM Cloud Kubernetes, è possibile creare cluster con una combinazione di nodi -virtuali e fisici (bare metal) in una singola zona o su più zone in una regione. Per ulteriori informazioni, +Utilizzando il provider di servizi IBM Cloud Kubernetes, è possibile creare cluster con una combinazione di nodi +virtuali e fisici (bare metal) in una singola zona o su più zone in una regione. Per ulteriori informazioni, consultare [Pianificazione dell'installazione di cluster e nodo di lavoro](https://cloud.ibm.com/docs/containers?topic=containers-plan_clusters#plan_clusters). Il nome dell'oggetto Nodo Kubernetes è l'indirizzo IP privato dell'istanza del nodo di lavoro IBM Cloud Kubernetes Service. ### Networking -Il fornitore di servizi IBM Cloud Kubernetes fornisce VLAN per le prestazioni di rete di qualità e l'isolamento della -rete per i nodi. È possibile configurare firewall personalizzati e criteri di rete Calico per aggiungere un ulteriore -livello di sicurezza per il cluster o per connettere il cluster al data center on-prem tramite VPN. Per ulteriori +Il fornitore di servizi IBM Cloud Kubernetes fornisce VLAN per le prestazioni di rete di qualità e l'isolamento della +rete per i nodi. È possibile configurare firewall personalizzati e criteri di rete Calico per aggiungere un ulteriore +livello di sicurezza per il cluster o per connettere il cluster al data center on-prem tramite VPN. Per ulteriori informazioni, vedere [Pianificazione in-cluster e rete privata](https://cloud.ibm.com/docs/containers?topic=containers-cs_network_cluster#cs_network_cluster). -Per esporre le app al pubblico o all'interno del cluster, è possibile sfruttare i servizi NodePort, LoadBalancer o -Ingress. È anche possibile personalizzare il bilanciamento del carico dell'applicazione Ingress con le annotazioni. +Per esporre le app al pubblico o all'interno del cluster, è possibile sfruttare i servizi NodePort, LoadBalancer o +Ingress. È anche possibile personalizzare il bilanciamento del carico dell'applicazione Ingress con le annotazioni. Per ulteriori informazioni, vedere [Pianificazione per esporre le app con reti esterne](https://cloud.ibm.com/docs/containers?topic=containers-cs_network_planning#cs_network_planning). ### Storage -Il fornitore di servizi IBM Cloud Kubernetes sfrutta i volumi persistenti nativi di Kubernetes per consentire agli -utenti di montare archiviazione di file, blocchi e oggetti cloud nelle loro app. È inoltre possibile utilizzare il -componente aggiuntivo database-as-a-service e di terze parti per la memorizzazione permanente dei dati. Per ulteriori +Il fornitore di servizi IBM Cloud Kubernetes sfrutta i volumi persistenti nativi di Kubernetes per consentire agli +utenti di montare archiviazione di file, blocchi e oggetti cloud nelle loro app. È inoltre possibile utilizzare il +componente aggiuntivo database-as-a-service e di terze parti per la memorizzazione permanente dei dati. Per ulteriori informazioni, vedere [Pianificazione dell'archiviazione persistente altamente disponibile](https://cloud.ibm.com/docs/containers?topic=containers-storage_planning#storage_planning). ## Baidu Cloud Container Engine ### Node Name -Il provider di cloud Baidu utilizza l'indirizzo IP privato del nodo (come determinato dal kubelet o sovrascritto -con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve +Il provider di cloud Baidu utilizza l'indirizzo IP privato del nodo (come determinato dal kubelet o sovrascritto +con `--hostname-override`) come nome dell'oggetto Nodo Kubernetes. Si noti che il nome del nodo Kubernetes deve corrispondere all'IP privato VM di Baidu. diff --git a/content/it/docs/concepts/cluster-administration/cluster-administration-overview.md b/content/it/docs/concepts/cluster-administration/cluster-administration-overview.md index c2654fcf45..cd160cbdcc 100644 --- a/content/it/docs/concepts/cluster-administration/cluster-administration-overview.md +++ b/content/it/docs/concepts/cluster-administration/cluster-administration-overview.md @@ -20,9 +20,9 @@ Prima di scegliere una guida, ecco alcune considerazioni: - **Se si sta progettando per l'alta disponibilità**, impara a configurare [cluster in più zone](/docs/concepts/cluster-administration/federation/). - Utilizzerai **un cluster di Kubernetes ospitato**, come [Motore di Google Kubernetes](https://cloud.google.com/kubernetes-engine/) o **che ospita il tuo cluster**? - Il tuo cluster sarà **on-premises** o **nel cloud (IaaS)**? Kubernetes non supporta direttamente i cluster ibridi. Invece, puoi impostare più cluster. - - **Se stai configurando Kubernetes on-premises**, considera quale [modello di rete](/docs/concepts/cluster-administration/networking/) si adatti meglio. + - **Se stai configurando Kubernetes on-premises**, considera quale [modello di rete](/docs/concepts/cluster-administration/networking/) si adatti meglio. - Eseguirai Kubernetes su **hardware "bare metal"** o su **macchine virtuali (VM)**? - - Vuoi **solo eseguire un cluster**, oppure ti aspetti di fare **lo sviluppo attivo del codice del progetto di Kubernetes**? + - Vuoi **solo eseguire un cluster**, oppure ti aspetti di fare **lo sviluppo attivo del codice del progetto di Kubernetes**? In quest'ultimo caso, scegli una distribuzione sviluppata attivamente. Alcune distribuzioni utilizzano solo versioni binarie, ma offrono una maggiore varietà di scelte - Familiarizzare con i [componenti](/docs/admin/cluster-components/) necessari per eseguire un cluster. diff --git a/content/it/docs/concepts/cluster-administration/controller-metrics.md b/content/it/docs/concepts/cluster-administration/controller-metrics.md index c38d0840cd..666b6023de 100644 --- a/content/it/docs/concepts/cluster-administration/controller-metrics.md +++ b/content/it/docs/concepts/cluster-administration/controller-metrics.md @@ -13,13 +13,13 @@ il responsabile del controller. ## Cosa sono le metriche del controller -Le metriche del controller forniscono informazioni importanti sulle prestazioni del controller. Queste metriche -includono le comuni metriche di runtime del linguaggio Go, come il conteggio go_routine e le metriche specifiche del -controller come latenze delle richieste etcd o latenze API Cloudprovider (AWS, GCE, OpenStack) che possono essere +Le metriche del controller forniscono informazioni importanti sulle prestazioni del controller. Queste metriche +includono le comuni metriche di runtime del linguaggio Go, come il conteggio go_routine e le metriche specifiche del +controller come latenze delle richieste etcd o latenze API Cloudprovider (AWS, GCE, OpenStack) che possono essere utilizzate per valutare la salute di un cluster. -A partire da Kubernetes 1.7, le metriche dettagliate di Cloudprovider sono disponibili per le operazioni di archiviazione -per GCE, AWS, Vsphere e OpenStack. Queste metriche possono essere utilizzate per monitorare lo stato delle operazioni +A partire da Kubernetes 1.7, le metriche dettagliate di Cloudprovider sono disponibili per le operazioni di archiviazione +per GCE, AWS, Vsphere e OpenStack. Queste metriche possono essere utilizzate per monitorare lo stato delle operazioni di volume persistenti. Ad esempio, per GCE queste metriche sono chiamate: diff --git a/content/it/docs/concepts/cluster-administration/kubelet-garbage-collection.md b/content/it/docs/concepts/cluster-administration/kubelet-garbage-collection.md index f787519141..976e64cc95 100644 --- a/content/it/docs/concepts/cluster-administration/kubelet-garbage-collection.md +++ b/content/it/docs/concepts/cluster-administration/kubelet-garbage-collection.md @@ -6,11 +6,11 @@ weight: 70 --- {{% capture overview %}} -La garbage collection è una funzione utile di kubelet che pulisce le immagini inutilizzate e i contenitori inutilizzati. -Kubelet eseguirà la raccolta dei rifiuti per i contenitori ogni minuto e la raccolta dei dati inutili per le immagini +La garbage collection è una funzione utile di kubelet che pulisce le immagini inutilizzate e i contenitori inutilizzati. +Kubelet eseguirà la raccolta dei rifiuti per i contenitori ogni minuto e la raccolta dei dati inutili per le immagini ogni cinque minuti. -Gli strumenti di garbage collection esterni non sono raccomandati in quanto questi strumenti possono potenzialmente +Gli strumenti di garbage collection esterni non sono raccomandati in quanto questi strumenti possono potenzialmente interrompere il comportamento di kubelet rimuovendo i contenitori che si prevede esistano. {{% /capture %}} @@ -34,18 +34,18 @@ soglia è stata soddisfatta. ## Container Collection -La politica per i contenitori di garbage collection considera tre variabili definite dall'utente. `MinAge` è l'età minima -in cui un contenitore può essere raccolto dalla spazzatura. `MaxPerPodContainer` è il numero massimo di contenitori morti -ogni singolo la coppia pod (UID, nome contenitore) può avere. `MaxContainers` è il numero massimo di contenitori morti -totali. Queste variabili possono essere disabilitate individualmente impostando `MinAge` a zero e impostando `MaxPerPodContainer` +La politica per i contenitori di garbage collection considera tre variabili definite dall'utente. `MinAge` è l'età minima +in cui un contenitore può essere raccolto dalla spazzatura. `MaxPerPodContainer` è il numero massimo di contenitori morti +ogni singolo la coppia pod (UID, nome contenitore) può avere. `MaxContainers` è il numero massimo di contenitori morti +totali. Queste variabili possono essere disabilitate individualmente impostando `MinAge` a zero e impostando `MaxPerPodContainer` e `MaxContainers` rispettivamente a meno di zero. -Kubelet agirà su contenitori non identificati, cancellati o al di fuori dei limiti impostati dalle bandiere -precedentemente menzionate. I contenitori più vecchi saranno generalmente rimossi per primi. `MaxPerPodContainer` -e `MaxContainer` possono potenzialmente entrare in conflitto l'uno con l'altro in situazioni in cui il mantenimento del -numero massimo di contenitori per pod (`MaxPerPodContainer`) non rientra nell'intervallo consentito di contenitori morti -globali (` MaxContainers`). `MaxPerPodContainer` verrebbe regolato in questa situazione: uno scenario peggiore sarebbe -quello di eseguire il downgrade di` MaxPerPodContainer` su 1 e rimuovere i contenitori più vecchi. Inoltre, i +Kubelet agirà su contenitori non identificati, cancellati o al di fuori dei limiti impostati dalle bandiere +precedentemente menzionate. I contenitori più vecchi saranno generalmente rimossi per primi. `MaxPerPodContainer` +e `MaxContainer` possono potenzialmente entrare in conflitto l'uno con l'altro in situazioni in cui il mantenimento del +numero massimo di contenitori per pod (`MaxPerPodContainer`) non rientra nell'intervallo consentito di contenitori morti +globali (` MaxContainers`). `MaxPerPodContainer` verrebbe regolato in questa situazione: uno scenario peggiore sarebbe +quello di eseguire il downgrade di` MaxPerPodContainer` su 1 e rimuovere i contenitori più vecchi. Inoltre, i contenitori di proprietà dei pod che sono stati cancellati vengono rimossi una volta che sono più vecchi di "MinAge". I contenitori che non sono gestiti da Kubelet non sono soggetti alla garbage collection del contenitore. diff --git a/content/it/docs/concepts/cluster-administration/manage-deployment.md b/content/it/docs/concepts/cluster-administration/manage-deployment.md index 33f3cb7ec2..4f4d3dae50 100644 --- a/content/it/docs/concepts/cluster-administration/manage-deployment.md +++ b/content/it/docs/concepts/cluster-administration/manage-deployment.md @@ -6,9 +6,9 @@ weight: 40 {{% capture overview %}} -Hai distribuito la tua applicazione e l'hai esposta tramite un servizio. Ora cosa? Kubernetes fornisce una serie di -strumenti per aiutarti a gestire la distribuzione delle applicazioni, compreso il ridimensionamento e l'aggiornamento. -Tra le caratteristiche che discuteremo in modo più approfondito ci sono [file di configurazione](/docs/concepts/configuration/overview/) +Hai distribuito la tua applicazione e l'hai esposta tramite un servizio. Ora cosa? Kubernetes fornisce una serie di +strumenti per aiutarti a gestire la distribuzione delle applicazioni, compreso il ridimensionamento e l'aggiornamento. +Tra le caratteristiche che discuteremo in modo più approfondito ci sono [file di configurazione](/docs/concepts/configuration/overview/) e [labels](/docs/concepts/overview/working-with-objects/labels/). {{% /capture %}} @@ -187,9 +187,9 @@ guestbook-redis-slave-qgazl 1/1 Running 0 3m ## Distribuzioni canarie -Un altro scenario in cui sono necessarie più etichette è quello di distinguere distribuzioni di diverse versioni o -configurazioni dello stesso componente. È prassi comune distribuire un * canarino * di una nuova versione -dell'applicazione (specificata tramite il tag immagine nel modello pod) parallelamente alla versione precedente in +Un altro scenario in cui sono necessarie più etichette è quello di distinguere distribuzioni di diverse versioni o +configurazioni dello stesso componente. È prassi comune distribuire un * canarino * di una nuova versione +dell'applicazione (specificata tramite il tag immagine nel modello pod) parallelamente alla versione precedente in modo che la nuova versione possa ricevere il traffico di produzione in tempo reale prima di distribuirlo completamente. Ad esempio, puoi usare un'etichetta `track` per differenziare le diverse versioni. @@ -208,7 +208,7 @@ La versione stabile e primaria avrebbe un'etichetta `track` con valore come` sta image: gb-frontend:v3 ``` -e quindi puoi creare una nuova versione del frontend del guestbook che porta l'etichetta `track` con un valore diverso +e quindi puoi creare una nuova versione del frontend del guestbook che porta l'etichetta `track` con un valore diverso (ad esempio` canary`), in modo che due gruppi di pod non si sovrappongano: ```yaml @@ -223,8 +223,8 @@ e quindi puoi creare una nuova versione del frontend del guestbook che porta l'e image: gb-frontend:v4 ``` -Il servizio di frontend coprirebbe entrambe le serie di repliche selezionando il sottoinsieme comune delle loro -etichette (ad esempio omettendo l'etichetta `track`), in modo che il traffico venga reindirizzato ad entrambe le +Il servizio di frontend coprirebbe entrambe le serie di repliche selezionando il sottoinsieme comune delle loro +etichette (ad esempio omettendo l'etichetta `track`), in modo che il traffico venga reindirizzato ad entrambe le applicazioni: ```yaml @@ -234,16 +234,16 @@ applicazioni: ``` 452/5000 -È possibile modificare il numero di repliche delle versioni stable e canary per determinare il rapporto tra ciascuna -versione che riceverà il traffico di produzione live (in questo caso, 3: 1). Una volta che sei sicuro, puoi aggiornare +È possibile modificare il numero di repliche delle versioni stable e canary per determinare il rapporto tra ciascuna +versione che riceverà il traffico di produzione live (in questo caso, 3: 1). Una volta che sei sicuro, puoi aggiornare la traccia stabile alla nuova versione dell'applicazione e rimuovere quella canarino. Per un esempio più concreto, controlla il [tutorial di distribuzione di Ghost](https://github.com/kelseyhightower/talks/tree/master/kubecon-eu-2016/demo#deploy-a-canary). ## Updating labels -A volte i pod esistenti e altre risorse devono essere rinominati prima di creare nuove risorse. Questo può essere fatto -con l'etichetta `kubectl`. Ad esempio, se desideri etichettare tutti i tuoi pod nginx come livello frontend, esegui +A volte i pod esistenti e altre risorse devono essere rinominati prima di creare nuove risorse. Questo può essere fatto +con l'etichetta `kubectl`. Ad esempio, se desideri etichettare tutti i tuoi pod nginx come livello frontend, esegui semplicemente: ```shell @@ -253,7 +253,7 @@ pod/my-nginx-2035384211-u2c7e labeled pod/my-nginx-2035384211-u3t6x labeled ``` -Questo prima filtra tutti i pod con l'etichetta "app = nginx", quindi li etichetta con il "tier = fe". Per vedere i pod +Questo prima filtra tutti i pod con l'etichetta "app = nginx", quindi li etichetta con il "tier = fe". Per vedere i pod appena etichettati, esegui: ```shell @@ -267,13 +267,13 @@ my-nginx-2035384211-u3t6x 1/1 Running 0 23m fe questo produce tutti i pod "app = nginx", con un'ulteriore colonna di etichette del livello dei pod (specificata con `-L` o` --label-columns`). -Per ulteriori informazioni, consultare [labels](/docs/concepts/overview/working-with-objects/labels/) e +Per ulteriori informazioni, consultare [labels](/docs/concepts/overview/working-with-objects/labels/) e [kubectl label](/docs/reference/generated/kubectl/kubectl-commands/#label). ## Aggiornare annotazioni -A volte vorresti allegare annotazioni alle risorse. Le annotazioni sono metadati arbitrari non identificativi per il -recupero da parte di client API come strumenti, librerie, ecc. Questo può essere fatto con `kubectl annotate`. Per +A volte vorresti allegare annotazioni alle risorse. Le annotazioni sono metadati arbitrari non identificativi per il +recupero da parte di client API come strumenti, librerie, ecc. Questo può essere fatto con `kubectl annotate`. Per esempio: ```shell @@ -287,12 +287,12 @@ metadata: ... ``` -Per ulteriori informazioni, consultare il documento [annotazioni](/docs/concepts/overview/working-with-objects/annotations/) +Per ulteriori informazioni, consultare il documento [annotazioni](/docs/concepts/overview/working-with-objects/annotations/) e [kubectl annotate](/docs/reference/generated/kubectl/kubectl-commands/#annotate). ## Ridimensionamento dell'applicazione -Quando si carica o si riduce la richiesta, è facile ridimensionare con `kubectl`. Ad esempio, per ridurre il numero di +Quando si carica o si riduce la richiesta, è facile ridimensionare con `kubectl`. Ad esempio, per ridurre il numero di repliche nginx da 3 a 1, fare: ```shell @@ -318,7 +318,7 @@ horizontalpodautoscaler.autoscaling/my-nginx autoscaled Ora le repliche di nginx verranno ridimensionate automaticamente in base alle esigenze. Per maggiori informazioni, vedi [scala kubectl](/docs/reference/generated/kubectl/kubectl-commands/#scale), -[kubectl autoscale](/docs/reference/generated/kubectl/kubectl-commands/#autoscale) e documento +[kubectl autoscale](/docs/reference/generated/kubectl/kubectl-commands/#autoscale) e documento [orizzontale pod autoscaler](/docs/tasks/run-application/horizontal-pod-autoscale/). ## Aggiornamenti sul posto delle risorse @@ -327,13 +327,13 @@ A volte è necessario apportare aggiornamenti stretti e senza interruzioni alle ### kubectl apply -Si consiglia di mantenere un set di file di configurazione nel controllo del codice sorgente (vedere -[configurazione come codice](http://martinfowler.com/bliki/InfrastructureAsCode.html)), in modo che possano essere -mantenuti e versionati insieme al codice per le risorse che configurano. Quindi, puoi usare +Si consiglia di mantenere un set di file di configurazione nel controllo del codice sorgente (vedere +[configurazione come codice](http://martinfowler.com/bliki/InfrastructureAsCode.html)), in modo che possano essere +mantenuti e versionati insieme al codice per le risorse che configurano. Quindi, puoi usare [`kubectl apply`](/docs/reference/generated/kubectl/kubectl-commands/#apply) per inviare le modifiche alla configurazione nel cluster. -Questo comando confronterà la versione della configurazione che stai spingendo con la versione precedente e applicherà +Questo comando confronterà la versione della configurazione che stai spingendo con la versione precedente e applicherà le modifiche che hai apportato, senza sovrascrivere le modifiche automatiche alle proprietà che non hai specificato. ```shell @@ -341,18 +341,18 @@ $ kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.ya deployment.apps/my-nginx configured ``` -Si noti che `kubectl apply` allega un'annotazione alla risorsa per determinare le modifiche alla configurazione -dall'invocazione precedente. Quando viene invocato, `kubectl apply` fa una differenza a tre tra la configurazione -precedente, l'input fornito e la configurazione corrente della risorsa, al fine di determinare come modificare la +Si noti che `kubectl apply` allega un'annotazione alla risorsa per determinare le modifiche alla configurazione +dall'invocazione precedente. Quando viene invocato, `kubectl apply` fa una differenza a tre tra la configurazione +precedente, l'input fornito e la configurazione corrente della risorsa, al fine di determinare come modificare la risorsa. -Attualmente, le risorse vengono create senza questa annotazione, quindi la prima chiamata di `kubectl apply` ricadrà su -una differenza a due vie tra l'input fornito e la configurazione corrente della risorsa. Durante questa prima chiamata, -non è in grado di rilevare l'eliminazione delle proprietà impostate al momento della creazione della risorsa. Per questo +Attualmente, le risorse vengono create senza questa annotazione, quindi la prima chiamata di `kubectl apply` ricadrà su +una differenza a due vie tra l'input fornito e la configurazione corrente della risorsa. Durante questa prima chiamata, +non è in grado di rilevare l'eliminazione delle proprietà impostate al momento della creazione della risorsa. Per questo motivo, non li rimuoverà. -Tutte le chiamate successive a `kubectl apply`, e altri comandi che modificano la configurazione, come `kubectl replace` -e `kubectl edit`, aggiorneranno l'annotazione, consentendo le successive chiamate a` kubectl apply` per rilevare ed +Tutte le chiamate successive a `kubectl apply`, e altri comandi che modificano la configurazione, come `kubectl replace` +e `kubectl edit`, aggiorneranno l'annotazione, consentendo le successive chiamate a` kubectl apply` per rilevare ed eseguire cancellazioni usando un tre via diff. {{< note >}} @@ -367,7 +367,7 @@ In alternativa, puoi anche aggiornare le risorse con `kubectl edit`: $ kubectl edit deployment/my-nginx ``` -Questo equivale a prima "get` la risorsa, modificarla nell'editor di testo e quindi" applicare "la risorsa con la +Questo equivale a prima "get` la risorsa, modificarla nell'editor di testo e quindi" applicare "la risorsa con la versione aggiornata: ```shell @@ -379,7 +379,7 @@ deployment.apps/my-nginx configured $ rm /tmp/nginx.yaml ``` -Questo ti permette di fare più cambiamenti significativi più facilmente. Nota che puoi specificare l'editor con le +Questo ti permette di fare più cambiamenti significativi più facilmente. Nota che puoi specificare l'editor con le variabili di ambiente `EDITOR` o` KUBE_EDITOR`. Per ulteriori informazioni, consultare il documento [kubectl edit](/docs/reference/generated/kubectl/kubectl-commands/#edit). @@ -396,9 +396,9 @@ and ## Disruptive updates 375/5000 -In alcuni casi, potrebbe essere necessario aggiornare i campi di risorse che non possono essere aggiornati una volta -inizializzati, oppure si può semplicemente voler fare immediatamente una modifica ricorsiva, come per esempio correggere -i pod spezzati creati da una distribuzione. Per cambiare tali campi, usa `replace --force`, che elimina e ricrea la +In alcuni casi, potrebbe essere necessario aggiornare i campi di risorse che non possono essere aggiornati una volta +inizializzati, oppure si può semplicemente voler fare immediatamente una modifica ricorsiva, come per esempio correggere +i pod spezzati creati da una distribuzione. Per cambiare tali campi, usa `replace --force`, che elimina e ricrea la risorsa. In questo caso, puoi semplicemente modificare il tuo file di configurazione originale: ```shell @@ -409,12 +409,12 @@ deployment.apps/my-nginx replaced ## Aggiornamento dell'applicazione senza un'interruzione del servizio -A un certo punto, alla fine sarà necessario aggiornare l'applicazione distribuita, in genere specificando una nuova -immagine o un tag immagine, come nello scenario di distribuzione canarino precedente. `kubectl` supporta diverse +A un certo punto, alla fine sarà necessario aggiornare l'applicazione distribuita, in genere specificando una nuova +immagine o un tag immagine, come nello scenario di distribuzione canarino precedente. `kubectl` supporta diverse operazioni di aggiornamento, ognuna delle quali è applicabile a diversi scenari. -Ti guideremo attraverso come creare e aggiornare le applicazioni con le distribuzioni. Se l'applicazione distribuita è -gestita dai controller di replica, dovresti leggere +Ti guideremo attraverso come creare e aggiornare le applicazioni con le distribuzioni. Se l'applicazione distribuita è +gestita dai controller di replica, dovresti leggere [come usare `kubectl rolling-update`](/docs/tasks/run-application/rolling-update-replication-controller/). Diciamo che stavi usando la versione 1.7.9 di nginx: @@ -424,16 +424,16 @@ $ kubectl run my-nginx --image=nginx:1.7.9 --replicas=3 deployment.apps/my-nginx created ``` -Per aggiornare alla versione 1.9.1, cambia semplicemente `.spec.template.spec.containers [0] .image` da `nginx: 1.7.9` +Per aggiornare alla versione 1.9.1, cambia semplicemente `.spec.template.spec.containers [0] .image` da `nginx: 1.7.9` a `nginx: 1.9.1`, con i comandi kubectl che abbiamo imparato sopra. ```shell $ kubectl edit deployment/my-nginx ``` -Questo è tutto! La distribuzione aggiornerà in modo dichiarativo l'applicazione nginx distribuita progressivamente -dietro la scena. Garantisce che solo un certo numero di vecchie repliche potrebbe essere inattivo mentre vengono -aggiornate e solo un certo numero di nuove repliche può essere creato sopra il numero desiderato di pod. Per ulteriori +Questo è tutto! La distribuzione aggiornerà in modo dichiarativo l'applicazione nginx distribuita progressivamente +dietro la scena. Garantisce che solo un certo numero di vecchie repliche potrebbe essere inattivo mentre vengono +aggiornate e solo un certo numero di nuove repliche può essere creato sopra il numero desiderato di pod. Per ulteriori informazioni su di esso, visitare [Pagina di distribuzione](/docs/concepts/workloads/controller/deployment/). {{% /capture %}} diff --git a/content/it/docs/concepts/cluster-administration/networking.md b/content/it/docs/concepts/cluster-administration/networking.md index 697328535f..2888511489 100644 --- a/content/it/docs/concepts/cluster-administration/networking.md +++ b/content/it/docs/concepts/cluster-administration/networking.md @@ -5,7 +5,7 @@ weight: 50 --- {{% capture overview %}} -Il networking è una parte centrale di Kubernetes, ma può essere difficile capire esattamente come dovrebbe funzionare. +Il networking è una parte centrale di Kubernetes, ma può essere difficile capire esattamente come dovrebbe funzionare. Ci sono 4 reti distinte problemi da affrontare: 1. Comunicazioni container-to-container altamente accoppiate: questo è risolto da @@ -71,35 +71,35 @@ cieco all'esistenza o alla non esistenza dei porti di accoglienza. ## Come implementare il modello di rete di Kubernetes -Ci sono diversi modi in cui questo modello di rete può essere implementato. Questo il documento non è uno studio +Ci sono diversi modi in cui questo modello di rete può essere implementato. Questo il documento non è uno studio esaustivo dei vari metodi, ma si spera che serva come introduzione a varie tecnologie e serve da punto di partenza. Le seguenti opzioni di networking sono ordinate alfabeticamente - l'ordine no implica uno stato preferenziale. ### ACI -[Cisco Application Centric Infrastructure](https://www.cisco.com/c/en/us/solutions/data-center-virtualization/application-centric-infrastructure/index.html) +[Cisco Application Centric Infrastructure](https://www.cisco.com/c/en/us/solutions/data-center-virtualization/application-centric-infrastructure/index.html) offers an integrated overlay and underlay SDN solution that supports containers, virtual machines, and bare metal -servers. [ACI](https://www.github.com/noironetworks/aci-containers) provides container networking integration for ACI. +servers. [ACI](https://www.github.com/noironetworks/aci-containers) provides container networking integration for ACI. An overview of the integration is provided [here](https://www.cisco.com/c/dam/en/us/solutions/collateral/data-center-virtualization/application-centric-infrastructure/solution-overview-c22-739493.pdf). ### AOS da Apstra -[AOS](http://www.apstra.com/products/aos/) è un sistema di rete basato sull'intento che crea e gestisce ambienti di -data center complessi da una semplice piattaforma integrata. AOS sfrutta un design distribuito altamente scalabile per +[AOS](http://www.apstra.com/products/aos/) è un sistema di rete basato sull'intento che crea e gestisce ambienti di +data center complessi da una semplice piattaforma integrata. AOS sfrutta un design distribuito altamente scalabile per eliminare le interruzioni di rete riducendo al minimo i costi. -Il progetto di riferimento AOS attualmente supporta gli host connessi Layer-3 che eliminano i problemi di commutazione -Layer-2 legacy. Questi host Layer-3 possono essere server Linux (Debian, Ubuntu, CentOS) che creano relazioni vicine -BGP direttamente con gli switch top of rack (TOR). AOS automatizza le adiacenze di routing e quindi fornisce un +Il progetto di riferimento AOS attualmente supporta gli host connessi Layer-3 che eliminano i problemi di commutazione +Layer-2 legacy. Questi host Layer-3 possono essere server Linux (Debian, Ubuntu, CentOS) che creano relazioni vicine +BGP direttamente con gli switch top of rack (TOR). AOS automatizza le adiacenze di routing e quindi fornisce un controllo a grana fine sulle iniezioni di integrità del percorso (RHI) comuni in una distribuzione di Kubernetes. -AOS dispone di un ricco set di endpoint REST API che consentono a Kubernetes di modificare rapidamente i criteri di -rete in base ai requisiti dell'applicazione. Ulteriori miglioramenti integreranno il modello AOS Graph utilizzato per -la progettazione della rete con il provisioning del carico di lavoro, consentendo un sistema di gestione end-to-end per +AOS dispone di un ricco set di endpoint REST API che consentono a Kubernetes di modificare rapidamente i criteri di +rete in base ai requisiti dell'applicazione. Ulteriori miglioramenti integreranno il modello AOS Graph utilizzato per +la progettazione della rete con il provisioning del carico di lavoro, consentendo un sistema di gestione end-to-end per cloud privati ​​e pubblici. -AOS supporta l'utilizzo di apparecchiature di produttori comuni di produttori quali Cisco, Arista, Dell, Mellanox, HPE +AOS supporta l'utilizzo di apparecchiature di produttori comuni di produttori quali Cisco, Arista, Dell, Mellanox, HPE e un gran numero di sistemi white-box e sistemi operativi di rete aperti come Microsoft SONiC, Dell OPX e Cumulus Linux. I dettagli su come funziona il sistema AOS sono disponibili qui: http://www.apstra.com/products/how-it-works/ @@ -121,11 +121,11 @@ indirizzamento. ### CNI-Genie from Huawei -[CNI-Genie](https://github.com/Huawei-PaaS/CNI-Genie) è un plugin CNI che consente a Kubernetes -di [avere simultaneamente accesso a diverse implementazioni](https://github.com/Huawei-PaaS/CNI-Genie/blob/master/docs/multiple-cni-plugins/README.md#what-cni-genie-feature-1-multiple-cni-plugins-enables) -del [modello di rete Kubernetes](https://git.k8s.io/website/docs/concepts/cluster-administration/networking.md#kubernetes-model) in runtime. -Ciò include qualsiasi implementazione che funziona come un [plugin CNI](https://github.com/containernetworking/cni#3rd-party-plugins), -come [Flannel](https://github.com/coreos/flannel#flanella), [Calico](http://docs.projectcalico.org/), +[CNI-Genie](https://github.com/Huawei-PaaS/CNI-Genie) è un plugin CNI che consente a Kubernetes +di [avere simultaneamente accesso a diverse implementazioni](https://github.com/Huawei-PaaS/CNI-Genie/blob/master/docs/multiple-cni-plugins/README.md#what-cni-genie-feature-1-multiple-cni-plugins-enables) +del [modello di rete Kubernetes](https://git.k8s.io/website/docs/concepts/cluster-administration/networking.md#kubernetes-model) in runtime. +Ciò include qualsiasi implementazione che funziona come un [plugin CNI](https://github.com/containernetworking/cni#3rd-party-plugins), +come [Flannel](https://github.com/coreos/flannel#flanella), [Calico](http://docs.projectcalico.org/), [Romana](http://romana.io), [Weave-net](https://www.weave.works/products/tessere-net/). CNI-Genie supporta anche [assegnando più indirizzi IP a un pod](https://github.com/Huawei-PaaS/CNI-Genie/blob/master/docs/multiple-ips/README.md#feature-2-extension-cni-genie-multiple-ip-indirizzi-per-pod), ciascuno da un diverso plugin CNI. @@ -151,15 +151,15 @@ complessità della rete richiesta per implementare Kubernetes su larga scala all 226/5000 -[Contiv](https://github.com/contiv/netplugin) fornisce un networking configurabile (nativo l3 usando BGP, +[Contiv](https://github.com/contiv/netplugin) fornisce un networking configurabile (nativo l3 usando BGP, overlay usando vxlan, classic l2 o Cisco-SDN / ACI) per vari casi d'uso. [Contiv](http://contiv.io) è tutto aperto. ### Contrail / Tungsten Fabric -[Contrail](http://www.juniper.net/us/en/products-services/sdn/contrail/contrail-networking/), basato su -[Tungsten Fabric](https://tungsten.io), è un virtualizzazione della rete e piattaforma di gestione delle -policy realmente aperte e multi-cloud. Contrail e Tungsten Fabric sono integrati con vari sistemi di -orchestrazione come Kubernetes, OpenShift, OpenStack e Mesos e forniscono diverse modalità di isolamento +[Contrail](http://www.juniper.net/us/en/products-services/sdn/contrail/contrail-networking/), basato su +[Tungsten Fabric](https://tungsten.io), è un virtualizzazione della rete e piattaforma di gestione delle +policy realmente aperte e multi-cloud. Contrail e Tungsten Fabric sono integrati con vari sistemi di +orchestrazione come Kubernetes, OpenShift, OpenStack e Mesos e forniscono diverse modalità di isolamento per macchine virtuali, contenitori / pod e carichi di lavoro bare metal. ### DANM @@ -176,14 +176,14 @@ Con questo set di strumenti DANM è in grado di fornire più interfacce di rete ### Flannel -[Flannel](https://github.com/coreos/flannel#flannel) è un overlay molto semplice rete che soddisfa i requisiti di +[Flannel](https://github.com/coreos/flannel#flannel) è un overlay molto semplice rete che soddisfa i requisiti di Kubernetes. Molti le persone hanno riportato il successo con Flannel e Kubernetes. ### Google Compute Engine (GCE) -Per gli script di configurazione del cluster di Google Compute Engine, -[avanzato routing](https://cloud.google.com/vpc/docs/routes) è usato per assegna a ciascuna VM una sottorete -(l'impostazione predefinita è `/ 24` - 254 IP). Qualsiasi traffico vincolato per questo la sottorete verrà instradata +Per gli script di configurazione del cluster di Google Compute Engine, +[avanzato routing](https://cloud.google.com/vpc/docs/routes) è usato per assegna a ciascuna VM una sottorete +(l'impostazione predefinita è `/ 24` - 254 IP). Qualsiasi traffico vincolato per questo la sottorete verrà instradata direttamente alla VM dal fabric di rete GCE. Questo è dentro aggiunta all'indirizzo IP "principale" assegnato alla VM, a cui è stato assegnato NAT accesso a Internet in uscita. Un bridge linux (chiamato `cbr0`) è configurato per esistere su quella sottorete, e viene passato al flag `--bridge` della finestra mobile. @@ -196,11 +196,11 @@ DOCKER_OPTS="--bridge=cbr0 --iptables=false --ip-masq=false" Questo bridge è creato da Kubelet (controllato da `--network-plugin = kubenet` flag) in base al `Nodo` .spec.podCIDR`. -Docker ora assegna gli IP dal blocco `cbr-cidr`. I contenitori possono raggiungere l'un l'altro e `Nodi` sul +Docker ora assegna gli IP dal blocco `cbr-cidr`. I contenitori possono raggiungere l'un l'altro e `Nodi` sul ponte` cbr0`. Questi IP sono tutti instradabili all'interno della rete del progetto GCE. -GCE non sa nulla di questi IP, quindi non lo farà loro per il traffico internet in uscita. Per ottenere ciò viene -utilizzata una regola iptables masquerade (aka SNAT - per far sembrare che i pacchetti provengano dal `Node` stesso) +GCE non sa nulla di questi IP, quindi non lo farà loro per il traffico internet in uscita. Per ottenere ciò viene +utilizzata una regola iptables masquerade (aka SNAT - per far sembrare che i pacchetti provengano dal `Node` stesso) traffico che è vincolato per IP al di fuori della rete del progetto GCE (10.0.0.0/8). ```shell @@ -219,25 +219,25 @@ traffico verso internet. ### Jaguar -[Jaguar](https://gitlab.com/sdnlab/jaguar) è una soluzione open source per la rete di Kubernetes basata -su OpenDaylight. Jaguar fornisce una rete overlay utilizzando vxlan e Jaguar. CNIPlugin fornisce un indirizzo +[Jaguar](https://gitlab.com/sdnlab/jaguar) è una soluzione open source per la rete di Kubernetes basata +su OpenDaylight. Jaguar fornisce una rete overlay utilizzando vxlan e Jaguar. CNIPlugin fornisce un indirizzo IP per pod. ### Knitter 363/5000 -[Knitter](https://github.com/ZTE/Knitter/) è una soluzione di rete che supporta più reti in Kubernetes. -Fornisce la capacità di gestione dei titolari e gestione della rete. Knitter include una serie di soluzioni -di rete container NFV end-to-end oltre a più piani di rete, come mantenere l'indirizzo IP per le applicazioni, +[Knitter](https://github.com/ZTE/Knitter/) è una soluzione di rete che supporta più reti in Kubernetes. +Fornisce la capacità di gestione dei titolari e gestione della rete. Knitter include una serie di soluzioni +di rete container NFV end-to-end oltre a più piani di rete, come mantenere l'indirizzo IP per le applicazioni, la migrazione degli indirizzi IP, ecc. ### Kube-router 430/5000 -[Kube-router](https://github.com/cloudnativelabs/kube-router) è una soluzione di rete sviluppata appositamente -per Kubernetes che mira a fornire alte prestazioni e semplicità operativa. Kube-router fornisce un proxy di -servizio basato su Linux [LVS / IPVS](http://www.linuxvirtualserver.org/software/ipvs.html), una soluzione di -rete pod-to-pod basata sul kernel di inoltro del kernel Linux senza sovrapposizioni, e il sistema di sicurezza +[Kube-router](https://github.com/cloudnativelabs/kube-router) è una soluzione di rete sviluppata appositamente +per Kubernetes che mira a fornire alte prestazioni e semplicità operativa. Kube-router fornisce un proxy di +servizio basato su Linux [LVS / IPVS](http://www.linuxvirtualserver.org/software/ipvs.html), una soluzione di +rete pod-to-pod basata sul kernel di inoltro del kernel Linux senza sovrapposizioni, e il sistema di sicurezza della politica di rete basato su iptables / ipset. ### L2 networks and linux bridging @@ -254,41 +254,41 @@ Lars Kellogg-Stedman. ### Multus (a Multi Network plugin) -[Multus](https://github.com/Intel-Corp/multus-cni) è un plugin Multi CNI per supportare la funzionalità Multi +[Multus](https://github.com/Intel-Corp/multus-cni) è un plugin Multi CNI per supportare la funzionalità Multi Networking in Kubernetes utilizzando oggetti di rete basati su CRD in Kubernetes. -Multus supporta tutti i [plug-in di riferimento](https://github.com/containernetworking/plugins) -(ad esempio [Flannel](https://github.com/containernetworking/plugins/tree/master/plugins/meta/flannel), -[DHCP](https://github.com/containernetworking/plugins/tree/master/plugins/ipam/dhcp), -[Macvlan](https://github.com/containernetworking/plugins/tree/master/plugins/main/macvlan)) che implementano -le specifiche CNI e i plugin di terze parti (ad esempio [Calico](https://github.com/projectcalico/cni-plugin), -[Weave](https://github.com/weaveworks/weave) ), [Cilium](https://github.com/cilium/cilium), -[Contiv](https://github.com/contiv/netplugin)). Oltre a ciò, Multus supporta -[SRIOV](https://github.com/hustcat/sriov-cni), [DPDK](https://github.com/Intel-Corp/sriov-cni), -[OVS- DPDK e VPP](https://github.com/intel/vhost-user-net-plugin) carichi di lavoro in Kubernetes con applicazioni +Multus supporta tutti i [plug-in di riferimento](https://github.com/containernetworking/plugins) +(ad esempio [Flannel](https://github.com/containernetworking/plugins/tree/master/plugins/meta/flannel), +[DHCP](https://github.com/containernetworking/plugins/tree/master/plugins/ipam/dhcp), +[Macvlan](https://github.com/containernetworking/plugins/tree/master/plugins/main/macvlan)) che implementano +le specifiche CNI e i plugin di terze parti (ad esempio [Calico](https://github.com/projectcalico/cni-plugin), +[Weave](https://github.com/weaveworks/weave) ), [Cilium](https://github.com/cilium/cilium), +[Contiv](https://github.com/contiv/netplugin)). Oltre a ciò, Multus supporta +[SRIOV](https://github.com/hustcat/sriov-cni), [DPDK](https://github.com/Intel-Corp/sriov-cni), +[OVS- DPDK e VPP](https://github.com/intel/vhost-user-net-plugin) carichi di lavoro in Kubernetes con applicazioni cloud native e basate su NFV in Kubernetes. ### NSX-T -[VMware NSX-T](https://docs.vmware.com/en/VMware-NSX-T/index.html) è una piattaforma di virtualizzazione e sicurezza -della rete. NSX-T può fornire la virtualizzazione di rete per un ambiente multi-cloud e multi-hypervisor ed è -focalizzato su architetture applicative emergenti e architetture con endpoint eterogenei e stack tecnologici. Oltre +[VMware NSX-T](https://docs.vmware.com/en/VMware-NSX-T/index.html) è una piattaforma di virtualizzazione e sicurezza +della rete. NSX-T può fornire la virtualizzazione di rete per un ambiente multi-cloud e multi-hypervisor ed è +focalizzato su architetture applicative emergenti e architetture con endpoint eterogenei e stack tecnologici. Oltre agli hypervisor vSphere, questi ambienti includono altri hypervisor come KVM, container e bare metal. -[Plug-in contenitore NSX-T (NCP)](https://docs.vmware.com/en/VMware-NSX-T/2.0/nsxt_20_ncp_kubernetes.pdf) fornisce -integrazione tra NSX-T e orchestratori di contenitori come Kubernetes, così come l'integrazione tra NSX-T e piattaforme +[Plug-in contenitore NSX-T (NCP)](https://docs.vmware.com/en/VMware-NSX-T/2.0/nsxt_20_ncp_kubernetes.pdf) fornisce +integrazione tra NSX-T e orchestratori di contenitori come Kubernetes, così come l'integrazione tra NSX-T e piattaforme CaaS / PaaS basate su container come Pivotal Container Service (PKS) e OpenShift. ### Nuage Networks VCS (Servizi cloud virtualizzati) -[Nuage](http://www.nuagenetworks.net) fornisce una piattaforma Software-Defined Networking (SDN) altamente scalabile -basata su policy. Nuage utilizza open source Open vSwitch per il piano dati insieme a un controller SDN ricco di +[Nuage](http://www.nuagenetworks.net) fornisce una piattaforma Software-Defined Networking (SDN) altamente scalabile +basata su policy. Nuage utilizza open source Open vSwitch per il piano dati insieme a un controller SDN ricco di funzionalità basato su standard aperti. -La piattaforma Nuage utilizza gli overlay per fornire una rete basata su policy senza soluzione di continuità tra i -Pod di Kubernetes e gli ambienti non Kubernetes (VM e server bare metal). Il modello di astrazione delle policy di -Nuage è stato progettato pensando alle applicazioni e semplifica la dichiarazione di policy a grana fine per le -applicazioni. Il motore di analisi in tempo reale della piattaforma consente la visibilità e il monitoraggio della +La piattaforma Nuage utilizza gli overlay per fornire una rete basata su policy senza soluzione di continuità tra i +Pod di Kubernetes e gli ambienti non Kubernetes (VM e server bare metal). Il modello di astrazione delle policy di +Nuage è stato progettato pensando alle applicazioni e semplifica la dichiarazione di policy a grana fine per le +applicazioni. Il motore di analisi in tempo reale della piattaforma consente la visibilità e il monitoraggio della sicurezza per le applicazioni Kubernetes. ### OpenVSwitch @@ -307,37 +307,37 @@ a [ovn-kubernetes](https://github.com/openvswitch/ovn-kubernetes). ### Progetto Calico -[Project Calico](http://docs.projectcalico.org/) è un provider di rete contenitore open source e +[Project Calico](http://docs.projectcalico.org/) è un provider di rete contenitore open source e motore di criteri di rete. -Calico offre una soluzione di rete e di rete altamente scalabile per il collegamento di pod Kubernetes basati sugli -stessi principi di rete IP di Internet, sia per Linux (open source) che per Windows (proprietario - disponibile da -[Tigera](https://www.tigera.io/essenziali/)). Calico può essere distribuito senza incapsulamento o sovrapposizioni per -fornire reti di data center ad alte prestazioni e su vasta scala. Calico fornisce inoltre una politica di sicurezza di +Calico offre una soluzione di rete e di rete altamente scalabile per il collegamento di pod Kubernetes basati sugli +stessi principi di rete IP di Internet, sia per Linux (open source) che per Windows (proprietario - disponibile da +[Tigera](https://www.tigera.io/essenziali/)). Calico può essere distribuito senza incapsulamento o sovrapposizioni per +fornire reti di data center ad alte prestazioni e su vasta scala. Calico fornisce inoltre una politica di sicurezza di rete basata su intere grane per i pod Kubernetes tramite il firewall distribuito. -Calico può anche essere eseguito in modalità di applicazione della policy insieme ad altre soluzioni di rete come +Calico può anche essere eseguito in modalità di applicazione della policy insieme ad altre soluzioni di rete come Flannel, alias [canal](https://github.com/tigera/canal) o native GCE, AWS o networking Azure. ### Romana -[Romana](http://romana.io) è una soluzione di automazione della sicurezza e della rete open source che consente di -distribuire Kubernetes senza una rete di overlay. Romana supporta Kubernetes -[Politica di rete](/docs/concepts/services-networking/network-policies/) per fornire isolamento tra gli spazi dei nomi +[Romana](http://romana.io) è una soluzione di automazione della sicurezza e della rete open source che consente di +distribuire Kubernetes senza una rete di overlay. Romana supporta Kubernetes +[Politica di rete](/docs/concepts/services-networking/network-policies/) per fornire isolamento tra gli spazi dei nomi di rete. ### Weave Net di Weaveworks -[Weave Net](https://www.weave.works/products/weave-net/) è un rete resiliente e semplice da usare per Kubernetes e le +[Weave Net](https://www.weave.works/products/weave-net/) è un rete resiliente e semplice da usare per Kubernetes e le sue applicazioni in hosting. Weave Net funziona come un plug-in [CNI](https://www.weave.works/docs/net/latest/cni-plugin/) -o stand-alone. In entrambe le versioni, non richiede alcuna configurazione o codice aggiuntivo per eseguire, e in +o stand-alone. In entrambe le versioni, non richiede alcuna configurazione o codice aggiuntivo per eseguire, e in entrambi i casi, la rete fornisce un indirizzo IP per pod, come è standard per Kubernetes. {{% /capture %}} {{% capture whatsnext %}} -Il progetto iniziale del modello di rete e la sua logica, e un po 'di futuro i piani sono descritti in maggior +Il progetto iniziale del modello di rete e la sua logica, e un po 'di futuro i piani sono descritti in maggior dettaglio nella [progettazione della rete documento](https://git.k8s.io/community/contributors/design-proposals/network/networking.md). {{% /capture %}} diff --git a/content/it/includes/federation-deprecation-warning-note.md b/content/it/includes/federation-deprecation-warning-note.md index 2d53cdaaf1..27c525642c 100644 --- a/content/it/includes/federation-deprecation-warning-note.md +++ b/content/it/includes/federation-deprecation-warning-note.md @@ -1,5 +1,5 @@ -L'uso di `Federation v1` è fortemente sconsigliato. `Federation V1` ha ormai raggiunto lo stato GA e non è più in +L'uso di `Federation v1` è fortemente sconsigliato. `Federation V1` ha ormai raggiunto lo stato GA e non è più in fase di sviluppo attivo. La documentazione è solo per scopi storici. -Per ulteriori informazioni, il seguente link +Per ulteriori informazioni, il seguente link [Kubernetes Federation v2](https://github.com/kubernetes-sigs/federation-v2). From 37137dadaf2acd80c9355bacb1597ffff4731956 Mon Sep 17 00:00:00 2001 From: xieyanker Date: Fri, 14 Feb 2020 10:22:17 +0800 Subject: [PATCH 02/38] fix format error (#19118) --- content/zh/docs/tasks/administer-cluster/out-of-resource.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/zh/docs/tasks/administer-cluster/out-of-resource.md b/content/zh/docs/tasks/administer-cluster/out-of-resource.md index ad792d4522..ba6a50cc7e 100644 --- a/content/zh/docs/tasks/administer-cluster/out-of-resource.md +++ b/content/zh/docs/tasks/administer-cluster/out-of-resource.md @@ -117,7 +117,7 @@ support in favor of eviction in response to disk pressure. `memory.available` 的值从 cgroupfs 获取,而不是通过类似 `free -m` 的工具。这很重要,因为 `free -m` 不能在容器中工作,并且如果用户使用了 [可分配节点](/docs/tasks/administer-cluster/reserve-compute-resources/#node-allocatable)特性,资源不足的判定将同时在本地 cgroup 层次结构的终端用户 pod 部分和根节点做出。这个 [脚本](/docs/tasks/administer-cluster/out-of-resource/memory-available.sh)复现了与 `kubelet` 计算 `memory.available` 相同的步骤。`kubelet`将`inactive_file`(意即活动 LRU 列表上基于文件后端的内存字节数)从计算中排除,因为它假设内存在出现压力时将被回收。 -`kub`elet` 只支持两种文件系统分区。 +`kubelet` 只支持两种文件系统分区。 1. `nodefs` 文件系统,kubelet 将其用于卷和守护程序日志等。 2. `imagefs` 文件系统,容器运行时用于保存镜像和容器可写层。 From 207c65404292e913f3146b01a2f139e57f468977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20L=C3=A9one?= Date: Sat, 15 Feb 2020 01:33:27 +0100 Subject: [PATCH 03/38] Add a theme-color (#18976) --- layouts/partials/head.html | 1 + 1 file changed, 1 insertion(+) diff --git a/layouts/partials/head.html b/layouts/partials/head.html index da38d8550e..e710c60af7 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -12,6 +12,7 @@ {{ if .Title }}{{ .Title }} - {{ end }}{{ site.Title }} + {{ partial "css.html" . }} From 3f6dfb1ee394ee60400de239eff615bef536be3a Mon Sep 17 00:00:00 2001 From: June Yi Date: Sat, 15 Feb 2020 10:59:27 +0900 Subject: [PATCH 04/38] Fourth Korean L10n Work For Release 1.17 (#19127) * translate assign-pod-node.md (#18955) * correct the misspelling (#19063) * Update to Outdated files in dev-1.17-ko.4 branch. (#19002) Co-Authored-By: KimMJ Co-Authored-By: forybm Co-Authored-By: Yuk, Yongsu Co-authored-by: KimMJ Co-authored-by: forybm Co-authored-by: Yuk, Yongsu --- .../concepts/architecture/cloud-controller.md | 2 + .../concepts/configuration/assign-pod-node.md | 399 ++++++++++++++++++ content/ko/docs/concepts/containers/images.md | 27 +- .../docs/concepts/containers/runtime-class.md | 13 +- .../ko/docs/concepts/overview/components.md | 11 +- .../docs/concepts/overview/kubernetes-api.md | 2 +- .../connect-applications-service.md | 2 +- .../services-networking/endpoint-slices.md | 119 +++++- .../ingress-controllers.md | 1 + .../concepts/services-networking/service.md | 27 +- .../workloads/controllers/replicaset.md | 8 +- .../workloads/pods/ephemeral-containers.md | 3 +- .../concepts/workloads/pods/pod-lifecycle.md | 2 +- .../docs/contribute/style/write-new-topic.md | 5 +- content/ko/docs/reference/glossary/cluster.md | 6 +- .../reference/glossary/container-runtime.md | 8 +- .../glossary/kube-controller-manager.md | 2 +- .../docs/reference/glossary/kube-scheduler.md | 4 +- .../docs/reference/glossary/pod-lifecycle.md | 6 +- .../reference/issues-security/security.md | 2 +- .../ko/docs/reference/kubectl/cheatsheet.md | 3 + content/ko/docs/setup/_index.md | 2 +- .../setup/best-practices/node-conformance.md | 2 +- .../setup/learning-environment/minikube.md | 9 +- .../container-runtimes.md | 18 +- .../production-environment/tools/kops.md | 106 +++-- .../cilium-network-policy.md | 44 +- .../resource-metrics-pipeline.md | 10 + .../declarative-config.md | 4 +- .../imperative-config.md | 4 +- .../horizontal-pod-autoscale-walkthrough.md | 2 +- .../horizontal-pod-autoscale.md | 203 ++++++++- content/ko/docs/tutorials/hello-minikube.md | 19 +- .../create-cluster/cluster-intro.html | 2 +- .../expose/expose-intro.html | 2 +- .../mysql-wordpress-persistent-volume.md | 14 +- content/ko/examples/minikube/Dockerfile | 2 +- content/ko/examples/pods/pod-nginx.yaml | 13 + .../examples/pods/pod-with-node-affinity.yaml | 26 ++ .../examples/pods/pod-with-pod-affinity.yaml | 29 ++ content/ko/includes/task-tutorial-prereqs.md | 6 +- 41 files changed, 967 insertions(+), 202 deletions(-) create mode 100644 content/ko/docs/concepts/configuration/assign-pod-node.md create mode 100644 content/ko/examples/pods/pod-nginx.yaml create mode 100644 content/ko/examples/pods/pod-with-node-affinity.yaml create mode 100644 content/ko/examples/pods/pod-with-pod-affinity.yaml diff --git a/content/ko/docs/concepts/architecture/cloud-controller.md b/content/ko/docs/concepts/architecture/cloud-controller.md index e21ff73c49..5c872bf06a 100644 --- a/content/ko/docs/concepts/architecture/cloud-controller.md +++ b/content/ko/docs/concepts/architecture/cloud-controller.md @@ -223,11 +223,13 @@ rules: 다음은 클라우드 제공사업자들이 구현한 CCM들이다. +* [Alibaba Cloud](https://github.com/kubernetes/cloud-provider-alibaba-cloud) * [AWS](https://github.com/kubernetes/cloud-provider-aws) * [Azure](https://github.com/kubernetes/cloud-provider-azure) * [BaiduCloud](https://github.com/baidu/cloud-provider-baiducloud) * [DigitalOcean](https://github.com/digitalocean/digitalocean-cloud-controller-manager) * [GCP](https://github.com/kubernetes/cloud-provider-gcp) +* [Hetzner](https://github.com/hetznercloud/hcloud-cloud-controller-manager) * [Linode](https://github.com/linode/linode-cloud-controller-manager) * [OpenStack](https://github.com/kubernetes/cloud-provider-openstack) * [Oracle](https://github.com/oracle/oci-cloud-controller-manager) diff --git a/content/ko/docs/concepts/configuration/assign-pod-node.md b/content/ko/docs/concepts/configuration/assign-pod-node.md new file mode 100644 index 0000000000..1c818457cb --- /dev/null +++ b/content/ko/docs/concepts/configuration/assign-pod-node.md @@ -0,0 +1,399 @@ +--- +title: 노드에 파드 할당하기 +content_template: templates/concept +weight: 30 +--- + + +{{% capture overview %}} + +{{< glossary_tooltip text="파드" term_id="pod" >}}를 특정한 {{< glossary_tooltip text="노드(들)" term_id="node" >}}에서만 동작하도록 하거나, +특정 노드들을 선호하도록 제한할 수 있다. +이를 수행하는 방법에는 여러 가지가 있으며, 권장되는 접근 방식은 모두 +[레이블 셀렉터](/ko/docs/concepts/overview/working-with-objects/labels/)를 사용하여 선택한다. +보통 스케줄러가 자동으로 합리적인 배치(예: 노드들에 걸쳐 파드를 분배하거나, +자원이 부족한 노드에 파드를 배치하지 않는 등)를 수행하기에 이런 제약 조건은 필요하지 않지만 +간혹 파드가 배치되는 노드에 대해 더 많은 제어를 원할 수 있는 상황이 있다. +예를 들어 SSD가 장착된 머신에 파드가 연결되도록 하거나 또는 동일한 가용성 영역(availability zone)에서 +많은 것을 통신하는 두 개의 서로 다른 서비스의 파드를 같이 배치할 수 있다. + +{{% /capture %}} + +{{% capture body %}} + +## 노드 셀렉터(nodeSelector) + +`nodeSelector` 는 가장 간단하고 권장되는 노드 선택 제약 조건의 형태이다. +`nodeSelector` 는 PodSpec의 필드이다. 이는 키-값 쌍의 매핑으로 지정한다. 파드가 노드에서 동작할 수 있으려면, +노드는 키-값의 쌍으로 표시되는 레이블을 각자 가지고 있어야 한다(이는 추가 레이블을 가지고 있을 수 있다). +일반적으로 하나의 키-값 쌍이 사용된다. + +`nodeSelector` 를 어떻게 사용하는지 예시를 통해 알아보도록 하자. + +### 0 단계: 사전 준비 + +이 예시는 쿠버네티스 파드에 대한 기본적인 이해를 하고 있고 [쿠버네티스 클러스터가 설정](/ko/docs/setup/)되어 있다고 가정한다. + +### 1 단계: 노드에 레이블 붙이기 + +`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 "노드 이름"` 을 사용해서 노드에 주어진 레이블의 전체 목록을 확인할 수 있다. + +### 2 단계: 파드 설정에 nodeSelector 필드 추가하기 + +실행하고자 하는 파드의 설정 파일을 가져오고, 이처럼 nodeSelector 섹션을 추가한다. 예를 들어 이것이 파드 설정이라면, + +```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` 을 +실행하면, 레이블이 붙여진 노드에 파드가 스케줄 된다. +`kubectl get pods -o wide` 를 실행해서 파드가 할당된 +"NODE" 를 보면 작동하는지 검증할 수 있다. + +## 넘어가기 전에: 내장 노드 레이블들 {#built-in-node-labels} + +[붙인](#1-단계-노드에-레이블-붙이기) 레이블뿐만 아니라, 노드에는 +표준 레이블 셋이 미리 채워져 있다. 이 레이블들은 다음과 같다. + +* [`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-domainbetakubernetesiozone) +* [`failure-domain.beta.kubernetes.io/region`](/docs/reference/kubernetes-api/labels-annotations-taints/#failure-domainbetakubernetesioregion) +* [`topology.kubernetes.io/zone`](/docs/reference/kubernetes-api/labels-annotations-taints/#topologykubernetesiozone) +* [`topology.kubernetes.io/region`](/docs/reference/kubernetes-api/labels-annotations-taints/#topologykubernetesiozone) +* [`beta.kubernetes.io/instance-type`](/docs/reference/kubernetes-api/labels-annotations-taints/#beta-kubernetes-io-instance-type) +* [`node.kubernetes.io/instance-type`](/docs/reference/kubernetes-api/labels-annotations-taints/#nodekubernetesioinstance-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 >}} + +## 노드 격리(isolation)/제한(restriction) + +노드 오브젝트에 레이블을 추가하면 파드가 특정 노드 또는 노드 그룹을 목표 대상으로 할 수 있게 된다. +이는 특정 파드가 어떤 격리, 보안, 또는 규제 속성이 있는 노드에서만 실행되도록 사용할 수 있다. +이 목적으로 레이블을 사용하는 경우, 노드에서 kubelet 프로세스로 수정할 수 없는 레이블 키를 선택하는 것을 권장한다. +이렇게 하면 손상된 노드가 해당 kubelet 자격 증명을 사용해서 해당 레이블을 자체 노드 오브젝트에 설정하고, +스케줄러가 손상된 노드로 워크로드를 스케줄 하는 것을 방지할 수 있다. + +`NodeRestriction` 어드미션 플러그인은 kubelet이 `node-restriction.kubernetes.io/` 접두사로 레이블을 설정 또는 수정하지 못하게 한다. +노드 격리에 해당 레이블 접두사를 사용하려면 다음과 같이 한다. + +1. [노드 권한부여자](/docs/reference/access-authn-authz/node/)를 사용하고 있고, [NodeRestriction 어드미션 플러그인](/docs/reference/access-authn-authz/admission-controllers/#noderestriction)을 _활성화_ 해야 한다. +2. 노드 오브젝트의 `node-restriction.kubernetes.io/` 접두사 아래에 레이블을 추가하고, 해당 레이블을 노드 셀렉터에서 사용한다. +예를 들어, `example.com.node-restriction.kubernetes.io/fips=true` 또는 `example.com.node-restriction.kubernetes.io/pci-dss=true` 이다. + +## 어피니티(affinity)와 안티-어피니티(anti-affinity) + +`nodeSelector` 는 파드를 특정 레이블이 있는 노드로 제한하는 매우 간단한 방법을 제공한다. +어피니티/안티-어피니티 기능은 표현할 수 있는 제약 종류를 크게 확장한다. 주요 개선 사항은 다음과 같다. + +1. 언어가 보다 표현적이다("AND 또는 정확한 일치" 만이 아니다). +2. 규칙이 엄격한 요구 사항이 아니라 "유연한(soft)"/"선호(preference)" 규칙을 나타낼 수 있기에 스케줄러가 규칙을 만족할 수 없더라도, + 파드가 계속 스케줄 되도록 한다. +3. 노드 자체에 레이블을 붙이기보다는 노드(또는 다른 토폴로지 도메인)에서 실행 중인 다른 파드의 레이블을 제한할 수 있다. + 이를 통해 어떤 파드가 함께 위치할 수 있는지와 없는지에 대한 규칙을 적용할 수 있다. + +어피니티 기능은 "노드 어피니티" 와 "파드 간 어피니티/안티-어피니티" 두 종류의 어피니티로 구성된다. +노드 어피니티는 기존 `nodeSelector` 와 비슷하지만(그러나 위에서 나열된 첫째와 두 번째 이점이 있다.), +파드 간 어피니티/안티-어피니티는 위에서 나열된 세번째 항목에 설명된 대로 +노드 레이블이 아닌 파드 레이블에 대해 제한되고 위에서 나열된 첫 번째와 두 번째 속성을 가진다. + +### 노드 어피니티 + +노드 어피니티는 개념적으로 `nodeSelector` 와 비슷하다 -- 이는 노드의 레이블을 기반으로 파드를 +스케줄할 수 있는 노드를 제한할 수 있다. + +여기에 현재 `requiredDuringSchedulingIgnoredDuringExecution` 와 `preferredDuringSchedulingIgnoredDuringExecution` 로 부르는 +두 가지 종류의 노드 어피니티가 있다. 전자는 파드가 노드에 스케줄 되도록 *반드시* +규칙을 만족해야 하는 것(`nodeSelector` 와 같으나 보다 표현적인 구문을 사용해서)을 지정하고, +후자는 스케줄러가 시도하려고는 하지만, 보증하지 않는 *선호(preferences)* 를 지정한다는 점에서 +이를 각각 "엄격함(hard)" 과 "유연함(soft)" 으로 생각할 수 있다. +이름의 "IgnoredDuringExecution" 부분은 `nodeSelector` 작동 방식과 유사하게 노드의 +레이블이 런타임 중에 변경되어 파드의 어피니티 규칙이 더 이상 충족되지 않으면 파드가 여전히 그 노드에서 +동작한다는 의미이다. 향후에는 파드의 노드 어피니티 요구 사항을 충족하지 않는 노드에서 파드를 제거한다는 +점을 제외하고는 `preferredDuringSchedulingIgnoredDuringExecution` 와 같은 `requiredDuringSchedulingIgnoredDuringExecution` 를 제공할 계획이다. + +따라서 `requiredDuringSchedulingIgnoredDuringExecution` 의 예로는 "인텔 CPU가 있는 노드에서만 파드 실행"이 +될 수 있고, `preferredDuringSchedulingIgnoredDuringExecution` 의 예로는 "장애 조치 영역 XYZ에 파드 집합을 실행하려고 +하지만, 불가능하다면 다른 곳에서 일부를 실행하도록 허용"이 있을 것이다. + +노드 어피니티는 PodSpec의 `affinity` 필드의 `nodeAffinity` 필드에서 지정된다. + +여기에 노드 어피니티를 사용하는 파드 예시가 있다. + +{{< codenew file="pods/pod-with-node-affinity.yaml" >}} + +이 노드 어피니티 규칙은 키가 `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` 를 사용해서 안티-어피니티를 수행하거나, +특정 노드에서 파드를 쫓아내는 [노드 테인트(taint)](/docs/concepts/configuration/taint-and-toleration/)를 설정할 수 있다. + +`nodeSelector` 와 `nodeAffinity` 를 모두 지정한다면 파드가 후보 노드에 스케줄 되기 위해서는 +*둘 다* 반드시 만족해야 한다. + +`nodeAffinity` 유형과 연관된 `nodeSelectorTerms` 를 지정하면, 파드를 `nodeSelectorTerms` 가 지정된 것 중 **한 가지**라도 만족하는 노드에 스케줄할 수 있다. + +`nodeSelectorTerms` 와 연관된 여러 `matchExpressions` 를 지정하면, 파드는 `matchExpressions` 를 **모두** 만족하는 노드에만 스케줄할 수 있다. + +파드가 스케줄 된 노드의 레이블을 지우거나 변경해도 파드는 제거되지 않는다. 다시 말해서 어피니티 선택은 파드를 스케줄링 하는 시점에만 작동한다. + +`preferredDuringSchedulingIgnoredDuringExecution` 의 `weight` 필드의 범위는 1-100이다. 모든 스케줄링 요구 사항 (리소스 요청, RequiredDuringScheduling 어피니티 표현식 등)을 만족하는 각 노드들에 대해 스케줄러는 이 필드의 요소들을 반복해서 합계를 계산하고 노드가 MatchExpressions 에 일치하는 경우 합계에 "가중치(weight)"를 추가한다. 이후에 이 점수는 노드에 대한 다른 우선순위 함수의 점수와 합쳐진다. 전체 점수가 가장 높은 노드를 가장 선호한다. + +### 파드간 어피니티와 안티-어피니티 + +파드간 어피니티와 안티-어피니티를 사용하면 노드의 레이블을 기반으로 하지 않고, *노드에서 이미 실행 중인 파드 레이블을 기반으로* +파드가 스케줄될 수 있는 노드를 제한할 수 있다. 규칙은 "X가 규칙 Y를 충족하는 하나 이상의 파드를 이미 실행중인 경우 +이 파드는 X에서 실행해야 한다(또는 안티-어피니티가 없는 경우에는 동작하면 안된다)"는 형태이다. Y는 +선택적으로 연관된 네임스페이스 목록을 가진 LabelSelector로 표현된다. 노드와는 다르게 파드는 네임스페이스이기에 +(그리고 따라서 파드의 레이블은 암암리에 네임스페이스이다) 파드 레이블위의 레이블 셀렉터는 반드시 +셀렉터가 적용될 네임스페이스를 지정해야만 한다. 개념적으로 X는 노드, 랙, +클라우드 공급자 영역, 클라우드 공급자 지역 등과 같은 토폴로지 도메인이다. 시스템이 이런 토폴로지 +도메인을 나타내는 데 사용하는 노드 레이블 키인 `topologyKey` 를 사용하여 이를 표현한다. +예: [넘어가기 전에: 빌트인 노드 레이블](#built-in-node-labels) 섹션 위에 나열된 레이블 키를 본다. + +{{< note >}} +파드간 어피니티와 안티-어피니티에는 상당한 양의 프로세싱이 필요하기에 +대규모 클러스터에서는 스케줄링 속도가 크게 느려질 수 있다. +수백 개의 노드를 넘어가는 클러스터에서 이를 사용하는 것은 추천하지 않는다. +{{< /note >}} + +{{< note >}} +파드 안티-어피니티에서는 노드에 일관된 레이블을 지정해야 한다. 즉, 클러스터의 모든 노드는 `topologyKey` 와 매칭되는 적절한 레이블을 가지고 있어야 한다. 일부 또는 모든 노드에 지정된 `topologyKey` 레이블이 없는 경우에는 의도하지 않은 동작이 발생할 수 있다. +{{< /note >}} + +노드 어피니티와 마찬가지로 현재 파드 어피니티와 안티-어피니티로 부르는 "엄격함" 대 "유연함"의 요구사항을 나타내는 `requiredDuringSchedulingIgnoredDuringExecution` 와 +`preferredDuringSchedulingIgnoredDuringExecution` 두 가지 종류가 있다. +앞의 노드 어피니티 섹션의 설명을 본다. +`requiredDuringSchedulingIgnoredDuringExecution` 어피니티의 예시는 +"서로 많은 통신을 하기 때문에 서비스 A와 서비스 B를 같은 영역에 함께 위치시키는 것"이고, +`preferredDuringSchedulingIgnoredDuringExecution` 안티-어피니티의 예시는 "서비스를 여러 영역에 걸쳐서 분배하는 것"이다 +(엄격한 요구사항은 영역보다 파드가 더 많을 수 있기 때문에 엄격한 요구사항은 의미가 없다). + +파드간 어피니티는 PodSpec에서 `affinity` 필드 중 `podAffinity` 필드로 지정한다. +그리고 파드간 안티-어피니티는 PodSpec에서 `affinity` 필드 중 `podAntiAffinity` 필드로 지정한다. + +#### 파드 어피니티를 사용하는 파드의 예시 + +{{< codenew file="pods/pod-with-pod-affinity.yaml" >}} + +이 파드의 어피니티는 하나의 파드 어피니티 규칙과 하나의 파드 안티-어피니티 규칙을 정의한다. +이 예시에서 `podAffinity` 는 `requiredDuringSchedulingIgnoredDuringExecution` 이고 `podAntiAffinity` 는 +`preferredDuringSchedulingIgnoredDuringExecution` 이다. 파드 어피니티 규칙에 의하면 키 "security" 와 값 +"S1"인 레이블이 있는 하나 이상의 이미 실행 중인 파드와 동일한 영역에 있는 경우에만 파드를 노드에 스케줄할 수 있다. +(보다 정확하게는, 클러스터에 키 "security"와 값 "S1"인 레이블을 가지고 있는 실행 중인 파드가 있는 키 +`failure-domain.beta.kubernetes.io/zone` 와 값 V인 노드가 최소 하나 이상 있고, 노드 N이 키 +`failure-domain.beta.kubernetes.io/zone` 와 일부 값이 V인 레이블을 가진다면 파드는 노드 N에서 실행할 수 있다.) +파드 안티-어피니티 규칙에 의하면 노드가 이미 키 "security"와 값 "S2"인 레이블을 가진 파드를 +실행하고 있는 파드는 노드에 스케줄되는 것을 선호하지 않는다. +(만약 `topologyKey` 가 `failure-domain.beta.kubernetes.io/zone` 라면 노드가 키 +"security"와 값 "S2"를 레이블로 가진 파드와 +동일한 영역에 있는 경우, 노드에 파드를 예약할 수 없음을 의미한다.) +[디자인 문서](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md)를 통해 +`requiredDuringSchedulingIgnoredDuringExecution` 와 `preferredDuringSchedulingIgnoredDuringExecution` 의 +파드 어피니티와 안티-어피니티에 대한 많은 예시를 맛볼 수 있다. + +파드 어피니티와 안티-어피니티의 적합한 연산자는 `In`, `NotIn`, `Exists`, `DoesNotExist` 이다. + +원칙적으로, `topologyKey` 는 적법한 어느 레이블-키도 될 수 있다. +하지만, 성능과 보안상의 이유로 topologyKey에는 몇 가지 제약조건이 있다. + +1. 어피니티와 `requiredDuringSchedulingIgnoredDuringExecution` 파드 안티-어피니티는 대해 +`topologyKey` 가 비어있는 것을 허용하지 않는다. +2. `requiredDuringSchedulingIgnoredDuringExecution` 파드 안티-어피니티에서 `topologyKey` 를 `kubernetes.io/hostname` 로 제한하기 위해 어드미션 컨트롤러 `LimitPodHardAntiAffinityTopology` 가 도입되었다. 사용자 지정 토폴로지를에 사용할 수 있도록 하려면, 어드미션 컨트롤러를 수정하거나 간단히 이를 비활성화 할 수 있다. +3. `preferredDuringSchedulingIgnoredDuringExecution` 파드 안티-어피니티의 경우 빈 `topologyKey` 는 "all topology"("all topology"는 현재 `kubernetes.io/hostname`, `failure-domain.beta.kubernetes.io/zone` 그리고 `failure-domain.beta.kubernetes.io/region` 의 조합으로 제한된다)로 해석한다. +4. 위의 경우를 제외하고, `topologyKey` 는 적법한 어느 레이블-키도 가능하다. + +`labelSelector` 와 `topologyKey` 외에도 `labelSelector` 와 일치해야 하는 네임스페이스 목록 `namespaces` 를 +선택적으로 지정할 수 있다(이것은 `labelSelector` 와 `topologyKey` 와 같은 수준의 정의이다). +생략되어있거나 비어있을 경우 어피니티/안티-어피니티 정의가 있는 파드의 네임스페이스가 기본 값이다. + +파드를 노드에 스케줄하려면 `requiredDuringSchedulingIgnoredDuringExecution` 어피니티와 안티-어피니티와 +연관된 `matchExpressions` 가 모두 충족되어야 한다. + +#### 더 실용적인 유스케이스 + +파드간 어피니티와 안티-어피니티는 레플리카셋, 스테이트풀셋, 디플로이먼트 등과 같은 +상위 레벨 모음과 함께 사용할 때 더욱 유용할 수 있다. 워크로드 집합이 동일한 노드와 같이 +동일하게 정의된 토폴로지와 같은 위치에 배치되도록 쉽게 구성할 수 있다. + +##### 항상 같은 노드에 위치시키기 + +세 개의 노드가 있는 클러스터에서 웹 애플리케이션에는 redis와 같은 인-메모리 캐시가 있다. 웹 서버가 가능한 캐시와 함께 위치하기를 원한다. + +다음은 세 개의 레플리카와 셀렉터 레이블이 `app=store` 가 있는 간단한 redis 디플로이먼트의 yaml 스니펫이다. 디플로이먼트에는 스케줄러가 단일 노드에서 레플리카를 함께 배치하지 않도록 `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 +``` + +아래 yaml 스니펫의 웹서버 디플로이먼트는 `podAntiAffinity` 와 `podAffinity` 설정을 가지고 있다. 이렇게 하면 스케줄러에 모든 레플리카는 셀렉터 레이블이 `app=store` 인 파드와 함께 위치해야 한다. 또한 각 웹 서버 레플리카가 단일 노드의 같은 위치에 있지 않도록 한다. + +```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 +``` + +만약 위의 두 디플로이먼트를 생성하면 세 개의 노드가 있는 클러스터는 다음과 같아야 한다. + +| 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 +``` + +##### 절대 동일한 노드에 위치시키지 않게 하기 + +위의 예시에서 `topologyKey:"kubernetes.io/hostname"` 과 함께 `PodAntiAffinity` 규칙을 사용해서 +두 개의 인스터스가 동일한 호스트에 있지 않도록 redis 클러스터를 배포한다. +같은 기술을 사용해서 고 가용성을 위해 안티-어피니티로 구성된 스테이트풀셋의 예시는 +[ZooKeeper 튜토리얼](/docs/tutorials/stateful-application/zookeeper/#tolerating-node-failure)을 본다. + +## nodeName + +`nodeName` 은 가장 간단한 형태의 노트 선택 제약 조건이지만, +한계로 인해 일반적으로는 사용하지 않는다. +`nodeName` 은 PodSpec의 필드이다. 만약 비어있지 않으면, 스케줄러는 +파드를 무시하고 명명된 노드에서 실행 중인 kubelet이 +파드를 실행하려고 한다. 따라서 만약 PodSpec에 `nodeName` 가 +제공된 경우, 노드 선텍을 위해 위의 방법보다 우선한다. + +`nodeName` 을 사용해서 노드를 선택할 때의 몇 가지 제한은 다음과 같다. + +- 만약 명명된 노드가 없으면, 파드가 실행되지 않고 + 따라서 자동으로 삭제될 수 있다. +- 만약 명명된 노드에 파드를 수용할 수 있는 + 리소스가 없는 경우 파드가 실패하고, 그 이유는 다음과 같이 표시된다. + 예: OutOfmemory 또는 OutOfcpu. +- 클라우드 환경의 노드 이름은 항상 예측 가능하거나 + 안정적인 것은 아니다. + +여기에 `nodeName` 필드를 사용하는 파드 설정 파일 예시가 있다. + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: nginx +spec: + containers: + - name: nginx + image: nginx + nodeName: kube-01 +``` + +위 파드는 kube-01 노드에서 실행될 것이다. + +{{% /capture %}} + +{{% capture whatsnext %}} + +[테인트](/docs/concepts/configuration/taint-and-toleration/)는 노드가 특정 파드들을 *쫓아내게* 할 수 있다. + +[노드 어피니티](https://git.k8s.io/community/contributors/design-proposals/scheduling/nodeaffinity.md)와 +[파드간 어피니티/안티-어피니티](https://git.k8s.io/community/contributors/design-proposals/scheduling/podaffinity.md)에 대한 디자인 문서에는 +이러한 기능에 대한 추가 배경 정보가 있다. + +파드가 노드에 할당되면 kubelet은 파드를 실행하고 노드의 로컬 리소스를 할당한다. +[토폴로지 매니저](/docs/tasks/administer-cluster/topology-manager/)는 +노드 수준의 리소스 할당 결정에 참여할 수 있다. + +{{% /capture %}} diff --git a/content/ko/docs/concepts/containers/images.md b/content/ko/docs/concepts/containers/images.md index c0d4fe4b0b..3bc71c53c8 100644 --- a/content/ko/docs/concepts/containers/images.md +++ b/content/ko/docs/concepts/containers/images.md @@ -120,9 +120,9 @@ kubelet은 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` +- kubelet 로그 수준을 최소 3 이상으로 늘리고 kubelet 로그에서 (예: `journalctl -u kubelet`) 다음과 같은 로그 라인을 확인한다. + - `aws_credentials.go:109] unable to get ECR credentials from cache, checking ECR API` + - `aws_credentials.go:116] Got ECR credentials from ECR API for .dkr.ecr..amazonaws.com` ### Azure 컨테이너 레지스트리(ACR) 사용 [Azure 컨테이너 레지스트리](https://azure.microsoft.com/en-us/services/container-registry/)를 사용하는 경우 @@ -202,7 +202,7 @@ Docker는 프라이빗 레지스트리를 위한 키를 `$HOME/.dockercfg` 또 프라이빗 이미지를 사용하는 파드를 생성하여 검증한다. 예를 들면 다음과 같다. -```yaml +```shell kubectl apply -f - <}} 런타임 핸들러는 containerd의 구성 파일인 `/etc/containerd/config.toml` 통해 설정한다. 유효한 핸들러는 runtimes 단락 아래에서 설정한다. @@ -129,10 +129,10 @@ CRI 런타임 설치에 대한 자세한 내용은 [CRI 설치](/docs/setup/prod 더 자세한 containerd의 구성 문서를 살펴본다. https://github.com/containerd/cri/blob/master/docs/config.md -#### [cri-o](https://cri-o.io/) +#### {{< glossary_tooltip term_id="cri-o" >}} -런타임 핸들러는 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`을 통해 설정한다. +[crio.runtime 테이블](https://github.com/cri-o/cri-o/blob/master/docs/crio.conf.5.md#crioruntime-table) 아래에 유효한 핸들러를 설정한다. ``` @@ -140,8 +140,9 @@ https://github.com/containerd/cri/blob/master/docs/config.md runtime_path = "${PATH_TO_BINARY}" ``` -더 자세한 cri-o의 구성 문서를 살펴본다. -https://github.com/kubernetes-sigs/cri-o/blob/master/cmd/crio/config.go +더 자세한 것은 CRI-O의 [설정 문서][100]를 본다. + +[100]: https://raw.githubusercontent.com/cri-o/cri-o/9f11d1d/docs/crio.conf.5.md ### 스케줄 diff --git a/content/ko/docs/concepts/overview/components.md b/content/ko/docs/concepts/overview/components.md index 541e4f164c..dae6876343 100644 --- a/content/ko/docs/concepts/overview/components.md +++ b/content/ko/docs/concepts/overview/components.md @@ -9,7 +9,7 @@ card: {{% capture overview %}} 쿠버네티스를 배포하면 클러스터를 얻는다. -{{< glossary_definition term_id="cluster" length="all" prepend="클러스터는">}} +{{< glossary_definition term_id="cluster" length="all" prepend="쿠버네티스 클러스터는">}} 이 문서는 완전히 작동하는 쿠버네티스 클러스터를 갖기 위해 필요한 다양한 컴포넌트들에 대해 요약하고 정리한다. @@ -21,13 +21,12 @@ card: {{% /capture %}} {{% capture body %}} -## 마스터 컴포넌트 +## 컨트롤 플래인 컴포넌트 -마스터 컴포넌트는 클러스터의 컨트롤 플레인을 제공한다. 마스터 컴포넌트는 클러스터에 관한 전반적인 결정 -(예를 들어, 스케줄링)을 수행하고 클러스터 이벤트(예를 들어, 디플로이먼트의 `replicas` 필드가 요구조건을 충족되지 않을 경우 새로운 {{< glossary_tooltip text="파드" term_id="pod">}}를 구동시키는 것)를 감지하고 반응한다. +컨트롤 플래인 컴포넌트는 클러스터에 관한 전반적인 결정(예를 들어, 스케줄링)을 수행하고 클러스터 이벤트(예를 들어, 디플로이먼트의 `replicas` 필드에 대한 요구조건을 충족되지 않을 경우 새로운 {{< glossary_tooltip text="파드" term_id="pod">}}를 구동시키는 것)를 감지하고 반응한다. -마스터 컴포넌트는 클러스터 내 어떠한 머신에서든지 동작 될 수 있다. 그러나 -간결성을 위하여, 구성 스크립트는 보통 동일 머신 상에 모든 마스터 컴포넌트를 구동시키고, +컨트롤 플래인 컴포넌트는 클러스터 내 어떠한 머신에서든지 동작 될 수 있다. 그러나 +간결성을 위하여, 구성 스크립트는 보통 동일 머신 상에 모든 컨트롤 플래인 컴포넌트를 구동시키고, 사용자 컨테이너는 해당 머신 상에 동작시키지 않는다. 다중-마스터-VM 설치 예제를 보려면 [고가용성 클러스터 구성하기](/docs/admin/high-availability/)를 확인해본다. diff --git a/content/ko/docs/concepts/overview/kubernetes-api.md b/content/ko/docs/concepts/overview/kubernetes-api.md index e3d9981a3a..bc38340964 100644 --- a/content/ko/docs/concepts/overview/kubernetes-api.md +++ b/content/ko/docs/concepts/overview/kubernetes-api.md @@ -59,7 +59,7 @@ GET /swagger-2.0.0.pb-v1.gz | GET /openapi/v2 **Accept**: application/com.github 1.14 이전 버전에서 쿠버네티스 apiserver는 `/swaggerapi`에서 [Swagger v1.2](http://swagger.io/) 쿠버네티스 API 스펙을 검색하는데 사용할 수 있는 API도 제공한다. -이러한 엔드포인트는 사용 중단되었으며, 쿠버네티스 1.14에서 제거될 예정이다. +이러한 엔드포인트는 사용 중단되었으며, 쿠버네티스 1.14에서 제거되었다. ## API 버전 규칙 diff --git a/content/ko/docs/concepts/services-networking/connect-applications-service.md b/content/ko/docs/concepts/services-networking/connect-applications-service.md index fce55dbf8e..361660a119 100644 --- a/content/ko/docs/concepts/services-networking/connect-applications-service.md +++ b/content/ko/docs/concepts/services-networking/connect-applications-service.md @@ -13,7 +13,7 @@ weight: 30 기본적으로 도커는 호스트-프라이빗 네트워킹을 사용하기에 컨테이너는 동일한 머신에 있는 경우에만 다른 컨테이너와 통신 할 수 있다. 도커 컨테이너가 노드를 통해 통신하려면 머신 포트에 IP 주소가 할당되어야 컨테이너에 전달되거나 프록시된다. 이것은 컨테이너가 사용하는 포트를 매우 신중하게 조정하거나 포트를 동적으로 할당해야 한다는 의미이다. -여러 개발자에 걸쳐있는 포트를 조정하는 것은 규모면에서 매우 어려우며, 사용자가 제어할 수 없는 클러스터 수준의 문제에 노출된다. 쿠버네티스는 파드가 배치된 호스트와는 무관하게 다른 파드와 통신할 수 있다고 가정한다. 모든 파드에게 자체 클러스터-프라이빗-IP 주소를 제공하기 때문에 파드간에 명시적으로 링크를 만들거나 컨테이너 포트를 호스트 포트에 매핑 할 필요가 없다. 이것은 파드 내의 컨테이너는 모두 로컬호스트에서 서로의 포트에 도달할 수 있으며 클러스터의 모든 파드는 NAT 없이 서로를 볼 수 있다는 의미이다. 이 문서의 나머지 부분에서는 이러한 네트워킹 모델에서 신뢰할 수 있는 서비스를 실행하는 방법에 대해 자세히 설명할 것이다. +컨테이너를 제공하는 여러 개발자 또는 팀에서 포트를 조정하는 것은 규모면에서 매우 어려우며, 사용자가 제어할 수 없는 클러스터 수준의 문제에 노출된다. 쿠버네티스는 파드가 배치된 호스트와는 무관하게 다른 파드와 통신할 수 있다고 가정한다. 쿠버네티스는 모든 파드에게 자체 클러스터-프라이빗 IP 주소를 제공하기 때문에 파드간에 명시적으로 링크를 만들거나 컨테이너 포트를 호스트 포트에 매핑 할 필요가 없다. 이것은 파드 내의 컨테이너는 모두 로컬호스트에서 서로의 포트에 도달할 수 있으며 클러스터의 모든 파드는 NAT 없이 서로를 볼 수 있다는 의미이다. 이 문서의 나머지 부분에서는 이러한 네트워킹 모델에서 신뢰할 수 있는 서비스를 실행하는 방법에 대해 자세히 설명할 것이다. 이 가이드는 간단한 nginx 서버를 사용해서 개념증명을 보여준다. 동일한 원칙이 보다 완전한 [Jenkins CI 애플리케이션](https://kubernetes.io/blog/2015/07/strong-simple-ssl-for-kubernetes)에서 구현된다. diff --git a/content/ko/docs/concepts/services-networking/endpoint-slices.md b/content/ko/docs/concepts/services-networking/endpoint-slices.md index b8f154c152..f40ff87993 100644 --- a/content/ko/docs/concepts/services-networking/endpoint-slices.md +++ b/content/ko/docs/concepts/services-networking/endpoint-slices.md @@ -1,7 +1,7 @@ --- -title: 엔드포인트 슬라이스 +title: 엔드포인트슬라이스 feature: - title: 엔드포인트 슬라이스 + title: 엔드포인트슬라이스 description: > 쿠버네티스 클러스터에서 확장 가능한 네트워크 엔드포인트 추적. @@ -14,7 +14,7 @@ weight: 10 {{< feature-state for_k8s_version="v1.17" state="beta" >}} -_엔드포인트 슬라이스_ 는 쿠버네티스 클러스터 내의 네트워크 엔드포인트를 +_엔드포인트슬라이스_ 는 쿠버네티스 클러스터 내의 네트워크 엔드포인트를 추적하는 간단한 방법을 제공한다. 이것은 엔드포인트를 더 확장하고, 확장 가능한 대안을 제안한다. @@ -22,13 +22,14 @@ _엔드포인트 슬라이스_ 는 쿠버네티스 클러스터 내의 네트워 {{% capture body %}} -## 엔드포인트 슬라이스 리소스 {#endpointslice-resource} +## 엔드포인트슬라이스 리소스 {#endpointslice-resource} 쿠버네티스에서 EndpointSlice는 일련의 네트워크 엔드 포인트에 대한 -참조를 포함한다. 쿠버네티스 서비스에 셀렉터가 지정되면 EndpointSlice -컨트롤러는 자동으로 엔드포인트 슬라이스를 생성한다. 이 엔드포인트 슬라이스는 -서비스 셀렉터와 매치되는 모든 파드들을 포함하고 참조한다. 엔드포인트 -슬라이스는 고유한 서비스와 포트 조합을 통해 네트워크 엔드포인트를 그룹화 한다. +참조를 포함한다. 쿠버네티스 서비스에 {{< glossary_tooltip text="셀렉터" +term_id="selector" >}} 가 지정되면 EndpointSlice +컨트롤러는 자동으로 엔드포인트슬라이스를 생성한다. 이 엔드포인트슬라이스는 +서비스 셀렉터와 매치되는 모든 파드들을 포함하고 참조한다. 엔드포인트슬라이스는 +고유한 서비스와 포트 조합을 통해 네트워크 엔드포인트를 그룹화 한다. 예를 들어, 여기에 `example` 쿠버네티스 서비스를 위한 EndpointSlice 리소스 샘플이 있다. @@ -47,7 +48,7 @@ ports: port: 80 endpoints: - addresses: - - "10.1.2.3" + - "10.1.2.3" conditions: ready: true hostname: pod-1 @@ -56,15 +57,15 @@ endpoints: topology.kubernetes.io/zone: us-west2-a ``` -기본적으로, EndpointSlice 컨트롤러가 관리하는 엔드포인트 슬라이스에는 -각각 100개 이하의 엔드포인트를 가지고 있다. 이 스케일 아래에서 엔드포인트 슬라이스는 +기본적으로, EndpointSlice 컨트롤러가 관리하는 엔드포인트슬라이스에는 +각각 100개 이하의 엔드포인트를 가지고 있다. 이 스케일 아래에서 엔드포인트슬라이스는 엔드포인트 및 서비스와 1:1로 매핑해야하며, 유사한 성능을 가져야 한다. -엔드포인트 슬라이스는 내부 트래픽을 라우트하는 방법에 대해 kube-proxy에 +엔드포인트슬라이스는 내부 트래픽을 라우트하는 방법에 대해 kube-proxy에 신뢰할 수 있는 소스로 역할을 할 수 있다. 이를 활성화 하면, 많은 수의 엔드포인트를 가지는 서비스에 대해 성능 향상을 제공해야 한다. -## 주소 유형 +### 주소 유형 EndpointSlice는 다음 주소 유형을 지원한다. @@ -72,6 +73,94 @@ EndpointSlice는 다음 주소 유형을 지원한다. * IPv6 * FQDN (Fully Qualified Domain Name) +### 토폴로지 + +엔드포인트슬라이스 내 각 엔드포인트는 연관된 토폴로지 정보를 포함할 수 있다. +이는 해당 노드, 영역 그리고 지역에 대한 정보가 포함된 +엔드포인트가 있는 위치를 나타나는데 사용 한다. 값을 사용할 수 있으면 +다음의 토폴로지 레이블이 엔드포인트슬라이스 컨트롤러에 의해 설정된다. + +* `kubernetes.io/hostname` - 이 엔드포인트가 있는 노드의 이름. +* `topology.kubernetes.io/zone` - 이 엔드포인트가 있는 영역의 이름. +* `topology.kubernetes.io/region` - 이 엔드포인트가 있는 지역의 이름. + +이런 레이블 값은 슬라이스의 각 엔드포인트와 연관된 리소스에서 +파생된다. 호스트 이름 레이블은 해당 파드의 +NodeName 필드 값을 나타낸다. 영역 및 지역 레이블은 해당 +노드에서 이름이 같은 값을 나타낸다. + +### 관리 + +기본적으로 엔드포인트슬라이스는 엔드포인트슬라이스 컨트롤러에의해 +생성되고 관리된다. 서비스 메시 구현과 같은 다른 엔드포인트슬라이스 +유스 케이스는 다른 엔터티나 컨트롤러가 추가 엔드포인트슬라이스 +집합을 관리할 수 있게 할 수 있다. 여러 엔티티가 서로 간섭하지 않고 +엔드포인트슬라이스를 관리할 수 있도록 엔드포인트슬라이스를 관리하는 +엔티티를 나타내는데 `endpointslice.kubernetes.io/managed-by` 레이블이 사용된다. +엔드포인트슬라이스 컨트롤러는 관리하는 모든 엔드포인트 +슬라이스에 레이블의 값으로 `endpointslice-controller.k8s.io` 를 설정한다. +엔드포인트슬라이스를 관리하는 다른 엔티티도 이 레이블에 +고유한 값을 설정해야 한다. + +### 소유권 + +대부분의 유스 케이스에서 엔드포인트를 추적하는 서비스가 엔드포인트슬라이스를 +소유한다. 이는 각 엔드포인트슬라이스의 참조와 서비스에 속하는 모든 +엔드포인트슬라이스를 간단하게 조회할 수 있는 `kubernetes.io/service-name` +레이블로 표시된다. + +## 엔드포인트슬라이스 컨트롤러 + +엔드포인트슬라이스 컨트롤러는 해당 엔드포인트슬라이스가 최신 상태인지 +확인하기 위해 서비스와 파드를 감시한다. 컨트롤러가 셀렉터로 지정한 모든 +서비스에 대해 엔드포인트슬라이스를 관리한다. 이는 서비스 셀렉터와 +일치하는 파드의 IP를 나타내게 된다. + +### 엔드포인트슬라이스의 크기 + +기본적으로 엔드포인트슬라이스는 각각 100개의 엔드포인트 크기로 제한된다. +최대 1000개까지 `--max-endpoints-per-slice` {{< glossary_tooltip +text="kube-controller-manager" term_id="kube-controller-manager" >}} 플래그를 +사용해서 구성할 수 있다. + +### 엔드포인트슬라이스의 배포 + +각 엔드포인트슬라이스에는 리소스 내에 모든 엔드포인트가 적용되는 +포트 집합이 있다. 서비스에 알려진 포트를 사용하는 경우 파드는 +동일하게 알려진 포트에 대해 다른 대상 포트 번호로 끝날 수 있으며 다른 +엔드포인트슬라이스가 필요하다. 이는 하위 집합이 엔드포인트와 그룹화하는 +방식의 논리와 유사하다. + +컨트롤러는 엔드포인트슬라이스를 최대한 채우려고 노력하지만, +적극적으로 재조정하지는 않는다. 컨트롤러의 동작은 매우 직관적이다. + +1. 기존 엔드포인트슬라이스에 대해 반복적으로, 더 이상 필요하지 않는 엔드포인트를 + 제거하고 변경에 의해 일치하는 엔드포인트를 업데이트 한다. +2. 첫 번째 단계에서 수정된 엔드포인트슬라이스를 반복해서 + 필요한 새 엔드포인트로 채운다. +3. 추가할 새 엔드포인트가 여전히 남아있으면, 이전에 변경되지 않은 + 슬라이스에 엔드포인트를 맞추거나 새로운 것을 생성한다. + +중요한 것은, 세 번째 단계는 엔드포인트슬라이스를 완벽하게 전부 배포하는 것보다 +엔드포인트슬라이스 업데이트 제한을 우선시한다. 예를 들어, 추가할 새 엔드포인트가 +10개이고 각각 5개의 공간을 사용할 수 있는 엔드포인트 공간이 있는 2개의 +엔드포인트슬라이스가 있는 경우, 이 방법은 기존 엔드포인트슬라이스 +2개를 채우는 대신에 새 엔드포인트슬라이스를 생성한다. 다른 말로, 단일 +엔드포인트슬라이스를 생성하는 것이 여러 엔드포인트슬라이스를 업데이트하는 것 보다 더 선호된다. + +각 노드에서 kube-proxy를 실행하고 엔드포인트슬라이스를 관찰하면, +엔드포인트슬라이스에 대한 모든 변경 사항이 클러스터의 모든 노드로 전송되기 +때문에 상대적으로 비용이 많이 소요된다. 이 방법은 여러 엔드포인트슬라이스가 +가득 차지 않은 결과가 발생할지라도, 모든 노드에 전송해야 하는 +변경 횟수를 의도적으로 제한하기 위한 것이다. + +실제로는, 이러한 이상적이지 않은 분배는 드물 것이다. 엔드포인트슬라이스 +컨트롤러에서 처리하는 대부분의 변경 내용은 기존 엔드포인트슬라이스에 +적합할 정도로 적고, 그렇지 않은 경우 새 엔드포인트슬라이스가 +필요할 수 있다. 디플로이먼트의 롤링 업데이트도 모든 파드와 해당 +교체되는 엔드포인트에 대해서 엔드포인트슬라이스를 +자연스럽게 재포장한다. + ## 사용동기 엔드포인트 API는 쿠버네티스에서 네트워크 엔드포인트를 추적하는 @@ -84,14 +173,14 @@ EndpointSlice는 다음 주소 유형을 지원한다. 리소스에 저장되기 때문에 엔드포인트 리소스가 상당히 커질 수 있다. 이것은 쿠버네티스 구성요소 (특히 마스터 컨트롤 플레인)의 성능에 영향을 미쳤고 엔드포인트가 변경될 때 상당한 양의 네트워크 트래픽과 처리를 초래했다. -엔드포인트 슬라이스는 이러한 문제를 완화하고 토폴로지 라우팅과 +엔드포인트슬라이스는 이러한 문제를 완화하고 토폴로지 라우팅과 같은 추가 기능을 위한 확장 가능한 플랫폼을 제공한다. {{% /capture %}} {{% capture whatsnext %}} -* [엔드포인트 슬라이스 활성화하기](/docs/tasks/administer-cluster/enabling-endpointslices) +* [엔드포인트슬라이스 활성화하기](/docs/tasks/administer-cluster/enabling-endpointslices) * [애플리케이션을 서비스와 함께 연결하기](/ko/docs/concepts/services-networking/connect-applications-service/) 를 읽는다. {{% /capture %}} diff --git a/content/ko/docs/concepts/services-networking/ingress-controllers.md b/content/ko/docs/concepts/services-networking/ingress-controllers.md index cd8337ef0a..92a2387f5d 100644 --- a/content/ko/docs/concepts/services-networking/ingress-controllers.md +++ b/content/ko/docs/concepts/services-networking/ingress-controllers.md @@ -21,6 +21,7 @@ kube-controller-manager 바이너리의 일부로 실행되는 컨트롤러의 ## 추가 컨트롤러 +* [AKS Application Gateway Ingress Controller](https://github.com/Azure/application-gateway-kubernetes-ingress) is an ingress controller that enables ingress to [AKS clusters](https://docs.microsoft.com/azure/aks/kubernetes-walkthrough-portal) using the [Azure Application Gateway](https://docs.microsoft.com/azure/application-gateway/overview). * [Ambassador](https://www.getambassador.io/) API 게이트웨이는 [Datawire](https://www.datawire.io/)의 [커뮤니티](https://www.getambassador.io/docs) 혹은 [상업적](https://www.getambassador.io/pro/) 지원을 제공하는 [Envoy](https://www.envoyproxy.io) 기반 인그레스 컨트롤러다. diff --git a/content/ko/docs/concepts/services-networking/service.md b/content/ko/docs/concepts/services-networking/service.md index ba0d78cf2f..b6a8448f06 100644 --- a/content/ko/docs/concepts/services-networking/service.md +++ b/content/ko/docs/concepts/services-networking/service.md @@ -184,17 +184,17 @@ ExternalName 서비스는 셀렉터가 없고 DNS명을 대신 사용하는 특수한 상황의 서비스이다. 자세한 내용은 이 문서 뒷부분의 [ExternalName](#externalname) 섹션을 참조한다. -### 엔드포인트 슬라이스 +### 엔드포인트슬라이스 {{< feature-state for_k8s_version="v1.17" state="beta" >}} -엔드포인트 슬라이스는 엔드포인트에 보다 확장 가능한 대안을 제공할 수 있는 -API 리소스이다. 개념적으로 엔드포인트와 매우 유사하지만, 엔드포인트 슬라이스를 +엔드포인트슬라이스는 엔드포인트에 보다 확장 가능한 대안을 제공할 수 있는 +API 리소스이다. 개념적으로 엔드포인트와 매우 유사하지만, 엔드포인트슬라이스를 사용하면 여러 리소스에 네트워크 엔드포인트를 분산시킬 수 있다. 기본적으로, -엔드포인트 슬라이스는 100개의 엔드포인트에 도달하면 "가득찬 것"로 간주되며, -추가 엔드포인트를 저장하기 위해서는 추가 엔드포인트 슬라이스가 +엔드포인트슬라이스는 100개의 엔드포인트에 도달하면 "가득찬 것"로 간주되며, +추가 엔드포인트를 저장하기 위해서는 추가 엔드포인트슬라이스가 생성된다. -엔드포인트 슬라이스는 [엔드포인트 슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)에서 +엔드포인트슬라이스는 [엔드포인트슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)에서 자세하게 설명된 추가적인 속성 및 기능을 제공한다. ## 가상 IP와 서비스 프록시 @@ -484,7 +484,7 @@ API에서 `엔드포인트` 레코드를 생성하고, DNS 구성을 수정하 `externalName` 필드의 컨텐츠 (예:`foo.bar.example.com`)에 맵핑한다. 어떤 종류의 프록시도 설정되어 있지 않다. {{< note >}} - `ExternalName` 유형을 사용하려면 CoreDNS 버전 1.7 이상이 필요하다. + `ExternalName` 유형을 사용하려면 kube-dns 버전 1.7 또는 CoreDNS 버전 1.7 이상이 필요하다. {{< /note >}} [인그레스](/ko/docs/concepts/services-networking/ingress/)를 사용하여 서비스를 노출시킬 수도 있다. 인그레스는 서비스 유형이 아니지만, 클러스터의 진입점 역할을 한다. 동일한 IP 주소로 여러 서비스를 노출시킬 수 있기 때문에 라우팅 규칙을 단일 리소스로 통합할 수 있다. @@ -548,6 +548,9 @@ status: 외부 로드 밸런서의 트래픽은 백엔드 파드로 전달된다. 클라우드 공급자는 로드 밸런싱 방식을 결정한다. +로드 밸런서 서비스 유형의 경우 두 개 이상의 포트가 정의된 경우, +모든 포트의 프로토콜이 동일해야 하고, 프로토콜은 `TCP`, `UDP` 그리고 +`SCTP` 중 하나여야 한다. 일부 클라우드 공급자는 `loadBalancerIP`를 지정할 수 있도록 허용한다. 이 경우, 로드 밸런서는 사용자 지정 `loadBalancerIP`로 생성된다. `loadBalancerIP` 필드가 지정되지 않으면, @@ -1100,21 +1103,15 @@ IPVS는 로드 밸런싱을 위해 설계되었고 커널-내부 해시 테이 ### TCP -{{< feature-state for_k8s_version="v1.0" state="stable" >}} - 모든 종류의 서비스에 TCP를 사용할 수 있으며, 이는 기본 네트워크 프로토콜이다. ### UDP -{{< feature-state for_k8s_version="v1.0" state="stable" >}} - 대부분의 서비스에 UDP를 사용할 수 있다. type=LoadBalancer 서비스의 경우, UDP 지원은 이 기능을 제공하는 클라우드 공급자에 따라 다르다. ### HTTP -{{< feature-state for_k8s_version="v1.1" state="stable" >}} - 클라우드 공급자가 이를 지원하는 경우, LoadBalancer 모드의 서비스를 사용하여 서비스의 엔드포인트로 전달하는 외부 HTTP / HTTPS 리버스 프록시를 설정할 수 있다. @@ -1126,8 +1123,6 @@ HTTP / HTTPS 서비스를 노출할 수도 있다. ### PROXY 프로토콜 -{{< feature-state for_k8s_version="v1.1" state="stable" >}} - 클라우드 공급자가 지원하는 경우에 (예: [AWS](/docs/concepts/cluster-administration/cloud-providers/#aws)), LoadBalancer 모드의 서비스를 사용하여 쿠버네티스 자체 외부에 로드 밸런서를 구성할 수 있으며, 이때 접두사가 @@ -1196,6 +1191,6 @@ kube-proxy는 유저스페이스 모드에 있을 때 SCTP 연결 관리를 지 * [서비스와 애플리케이션 연결](/docs/concepts/services-networking/connect-applications-service/) 알아보기 * [인그레스](/ko/docs/concepts/services-networking/ingress/)에 대해 알아보기 -* [엔드포인트 슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)에 대해 알아보기 +* [엔드포인트슬라이스](/ko/docs/concepts/services-networking/endpoint-slices/)에 대해 알아보기 {{% /capture %}} diff --git a/content/ko/docs/concepts/workloads/controllers/replicaset.md b/content/ko/docs/concepts/workloads/controllers/replicaset.md index 27f2dd359c..aedb0d03ef 100644 --- a/content/ko/docs/concepts/workloads/controllers/replicaset.md +++ b/content/ko/docs/concepts/workloads/controllers/replicaset.md @@ -73,7 +73,7 @@ kubectl describe rs/frontend ```shell Name: frontend Namespace: default -Selector: tier=frontend,tier in (frontend) +Selector: tier=frontend Labels: app=guestbook tier=frontend Annotations: @@ -132,7 +132,7 @@ metadata: name: frontend-9si5l namespace: default ownerReferences: - - apiVersion: extensions/v1beta1 + - apiVersion: apps/v1 blockOwnerDeletion: true controller: true kind: ReplicaSet @@ -257,7 +257,7 @@ REST API또는 `client-go` 라이브러리를 이용할 때는 -d 옵션으로 ` 예시: ```shell kubectl proxy --port=8080 -curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \ +curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \ > -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \ > -H "Content-Type: application/json" ``` @@ -269,7 +269,7 @@ REST API 또는 `client-go` 라이브러리를 이용할 때는 `propagationPoli 예시: ```shell kubectl proxy --port=8080 -curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \ +curl -X DELETE 'localhost:8080/apis/apps/v1/namespaces/default/replicasets/frontend' \ > -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \ > -H "Content-Type: application/json" ``` diff --git a/content/ko/docs/concepts/workloads/pods/ephemeral-containers.md b/content/ko/docs/concepts/workloads/pods/ephemeral-containers.md index 6e831326c6..c394c58ab7 100644 --- a/content/ko/docs/concepts/workloads/pods/ephemeral-containers.md +++ b/content/ko/docs/concepts/workloads/pods/ephemeral-containers.md @@ -6,7 +6,7 @@ weight: 80 {{% capture overview %}} -{{< feature-state state="alpha" >}} +{{< feature-state state="alpha" for_k8s_version="v1.16" >}} 이 페이지는 임시 컨테이너에 대한 개요를 제공한다: 이 특별한 유형의 컨테이너는 트러블 슈팅과 같은 사용자가 시작한 작업을 완료하기위해 기존 {{< glossary_tooltip term_id="pod" >}} 에서 @@ -187,6 +187,7 @@ kubectl attach -it example-pod -c debugger 예를 들어, 임시 컨테이너에 붙은 이후에 디버거 컨테이너에서 `ps` 를 실행한다. ```shell +# "디버거" 임시 컨테이너 내부 쉘에서 이것을 실행한다. ps auxww ``` 다음과 유사하게 출력된다. diff --git a/content/ko/docs/concepts/workloads/pods/pod-lifecycle.md b/content/ko/docs/concepts/workloads/pods/pod-lifecycle.md index 3c8f9af995..813c111163 100644 --- a/content/ko/docs/concepts/workloads/pods/pod-lifecycle.md +++ b/content/ko/docs/concepts/workloads/pods/pod-lifecycle.md @@ -186,7 +186,7 @@ kubelet은 실행 중인 컨테이너들에 대해서 선택적으로 세 가지 ... ``` -* `Running`: 컨테이너가 이슈 없이 구동된다는 뜻이다. 컨테이너가 Running 상태가 되면, `postStart` 훅이 (존재한다면) 실행된다. 이 상태는 컨테이너가 언제 Running 상태에 돌입한 시간도 함께 출력된다. +* `Running`: 컨테이너가 이슈 없이 구동된다는 뜻이다. `postStart` 훅(있는 경우)은 컨테이너가 Running 상태가 되기 전에 실행된다. 이 상태는 컨테이너가 언제 Running 상태에 돌입한 시간도 함께 출력된다. ```yaml ... diff --git a/content/ko/docs/contribute/style/write-new-topic.md b/content/ko/docs/contribute/style/write-new-topic.md index 00cfa2db6c..d6c21c7bc9 100644 --- a/content/ko/docs/contribute/style/write-new-topic.md +++ b/content/ko/docs/contribute/style/write-new-topic.md @@ -115,8 +115,9 @@ YAML 파일과 같은 새로운 독립형 샘플 파일을 추가할 때 `/examples/` 의 하위 디렉토리 중 하나에 코드를 배치하자. 여기서 ``은 주제에 관한 언어이다. 문서 파일에서 `codenew` 단축 코드(shortcode)를 사용하자. -
{{< codenew file="<RELPATH>/my-example-yaml>" >}}
- +```none +{{/my-example-yaml>" */>}} +``` 여기서 `` 는 `examples` 디렉토리와 관련하여 포함될 파일의 경로이다. 다음 Hugo 단축 코드(shortcode)는 `/content/en/examples/pods/storage/gce-volume.yaml` 에 있는 YAML 파일을 참조한다. diff --git a/content/ko/docs/reference/glossary/cluster.md b/content/ko/docs/reference/glossary/cluster.md index 92f8eabd37..a4a42b32aa 100755 --- a/content/ko/docs/reference/glossary/cluster.md +++ b/content/ko/docs/reference/glossary/cluster.md @@ -4,14 +4,14 @@ id: cluster date: 2019-06-15 full_link: short_description: > - 쿠버네티스에서 관리하는 컨테이너화된 애플리케이션을 실행하는 노드라고 하는 기계의 집합. 클러스터는 최소 1개의 워커 노드와 최소 1개의 마스터 노드를 가진다. + 컨테이너화된 애플리케이션을 실행하는 노드라고 하는 워커 머신의 집합. 모든 클러스터는 최소 한 개의 워커 노드를 가진다. aka: tags: - fundamental - operation --- -쿠버네티스에서 관리하는 컨테이너화된 애플리케이션을 실행하는 노드라고 하는 기계의 집합. 클러스터는 최소 1개의 워커 노드와 최소 1개의 마스터 노드를 가진다. +컨테이너화된 애플리케이션을 실행하는 노드라고 하는 워커 머신의 집합. 모든 클러스터는 최소 한 개의 워커 노드를 가진다. -워커 노드는 애플리케이션의 구성요소인 파드를 호스트한다. 마스터 노드는 워커 노드와 클러스터 내 파드를 관리한다. 다수의 마스터 노드는 장애극복(failover)과 고가용성의 클러스터에서 사용한다. +워커 노드는 애플리케이션의 구성요소인 파드를 호스트한다. 컨트롤 플레인은 워커 노드와 클러스터 내 파드를 관리한다. 프로덕션 환경에서는 일반적으로 컨트롤 플레인이 여러 컴퓨터에 걸쳐 실행되고, 클러스터는 일반적으로 여러 노드를 실행하므로 내결함성과 고가용성이 제공된다. diff --git a/content/ko/docs/reference/glossary/container-runtime.md b/content/ko/docs/reference/glossary/container-runtime.md index 112282e178..47fd7031b1 100644 --- a/content/ko/docs/reference/glossary/container-runtime.md +++ b/content/ko/docs/reference/glossary/container-runtime.md @@ -15,7 +15,7 @@ tags: -쿠버네티스는 여러 컨테이너 런타임을 지원한다. [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)를 구현한 모든 소프트웨어. +쿠버네티스는 여러 컨테이너 런타임을 지원한다. {{< glossary_tooltip term_id="docker">}}, +{{< glossary_tooltip term_id="containerd" >}}, {{< glossary_tooltip term_id="cri-o" >}} +그리고 [Kubernetes CRI (컨테이너 런타임 +인터페이스)](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/container-runtime-interface.md)를 구현한 모든 소프트웨어. diff --git a/content/ko/docs/reference/glossary/kube-controller-manager.md b/content/ko/docs/reference/glossary/kube-controller-manager.md index 41751f92f5..e327a6c285 100644 --- a/content/ko/docs/reference/glossary/kube-controller-manager.md +++ b/content/ko/docs/reference/glossary/kube-controller-manager.md @@ -4,7 +4,7 @@ id: kube-controller-manager date: 2018-04-12 full_link: /docs/reference/command-line-tools-reference/kube-controller-manager/ short_description: > - 컨트롤러를 구동하는 마스터 상의 컴포넌트. + {{< glossary_tooltip text="컨트롤러" term_id="controller" >}} 프로세스를 실행하는 컨트롤 플레인 컴포넌트. aka: tags: diff --git a/content/ko/docs/reference/glossary/kube-scheduler.md b/content/ko/docs/reference/glossary/kube-scheduler.md index d93c40bea7..a560832ef5 100644 --- a/content/ko/docs/reference/glossary/kube-scheduler.md +++ b/content/ko/docs/reference/glossary/kube-scheduler.md @@ -4,13 +4,13 @@ id: kube-scheduler date: 2018-04-12 full_link: /docs/reference/generated/kube-scheduler/ short_description: > - 노드가 배정되지 않은 새로 생성된 파드를 감지하고 그것이 구동될 노드를 선택하는 마스터 상의 컴포넌트. + 노드가 배정되지 않은 새로 생성된 파드를 감지하고, 실행할 노드를 선택하는 컨트롤 플레인 컴포넌트. aka: tags: - architecture --- - 노드가 배정되지 않은 새로 생성된 파드를 감지하고 그것이 구동될 노드를 선택하는 마스터 상의 컴포넌트. + 노드가 배정되지 않은 새로 생성된 파드를 감지하고, 실행할 노드를 선택하는 컨트롤 플레인 컴포넌트. diff --git a/content/ko/docs/reference/glossary/pod-lifecycle.md b/content/ko/docs/reference/glossary/pod-lifecycle.md index a435551e88..52f107ecb9 100644 --- a/content/ko/docs/reference/glossary/pod-lifecycle.md +++ b/content/ko/docs/reference/glossary/pod-lifecycle.md @@ -9,11 +9,11 @@ related: tags: - fundamental short-description: > - 파드가 라이프사이클 중 어느 단계(phase)에 있는지 표현하는 고수준의 요약이다. + 파드가 수명(lifetime) 동안 통과하는 상태의 순서이다. --- - 파드가 라이프사이클 중 어느 단계(phase)에 있는지 표현하는 고수준의 요약이다. + 파드가 수명(lifetime) 동안 통과하는 상태의 순서이다. -[파드 라이프사이클](/ko/docs/concepts/workloads/pods/pod-lifecycle/)은 파드가 라이프사이클 중 어느 단계에 있는지 표현하는 고수준의 요약이다. 파드의 `status` 필드는 [파드 스테이터스](/docs/reference/generated/kubernetes-api/v1.13/#podstatus-v1-core) 오브젝트이다. 그것은 `phase` 필드를 가지며, Running, Pending, Succeeded, Failed, Unknown, Completed, CrashLoopBackOff 중 하나의 단계(phase)를 보여준다. +[파드 라이프사이클](/ko/docs/concepts/workloads/pods/pod-lifecycle/)은 파드의 라이프사이클에 대한 고수준의 요약이다. 다섯 가지 파드 단계가 있다: Pending, Running, Succeeded, Failed, 그리고 Unknown. [파드 스테이터스](/docs/reference/generated/kubernetes-api/v1.13/#podstatus-v1-core)의 `phase` 필드에 파드 상태에 대한 자세한 설명이 요약되어 있다. diff --git a/content/ko/docs/reference/issues-security/security.md b/content/ko/docs/reference/issues-security/security.md index b52356cb18..234ec3c018 100644 --- a/content/ko/docs/reference/issues-security/security.md +++ b/content/ko/docs/reference/issues-security/security.md @@ -19,7 +19,7 @@ weight: 20 우리는 쿠버네티스 오픈소스 커뮤니티에 취약점을 보고하는 보안 연구원들과 사용자들에게 매우 감사하고 있다. 모든 보고서는 커뮤니티 자원 봉사자들에 의해 철저히 조사된다. -보고서를 작성하기 위해서는 보안 세부 내용과 [모든 쿠버네티스 버그 보고서](https://git.k8s.io/kubernetes/.github/ISSUE_TEMPLATE/bug-report.md)로부터 예상되는 세부 사항을 [security@kubernetes.io](mailto:security@kubernetes.io)로 이메일을 보낸다. +보고서를 작성하려면, [쿠버네티스 버그 현상금 프로그램](https://hackerone.com/kubernetes)에 취약점을 제출한다. 이를 통해 표준화된 응답시간으로 취약점을 분류하고 처리할 수 있다. 또한, 보안 세부 내용과 [모든 쿠버네티스 버그 보고서](https://git.k8s.io/kubernetes/.github/ISSUE_TEMPLATE/bug-report.md)로 부터 예상되는 세부사항을 [security@kubernetes.io](mailto:security@kubernetes.io)로 이메일을 보낸다. [제품 보안 위원회 구성원](https://git.k8s.io/security/security-release-process.md#product-security-committee-psc)의 GPG 키를 사용하여 이 목록으로 이메일을 암호화할 수 있다. GPG를 사용한 암호화는 공개할 필요가 없다. diff --git a/content/ko/docs/reference/kubectl/cheatsheet.md b/content/ko/docs/reference/kubectl/cheatsheet.md index 8c6e54aabb..3ea2a1e60b 100644 --- a/content/ko/docs/reference/kubectl/cheatsheet.md +++ b/content/ko/docs/reference/kubectl/cheatsheet.md @@ -191,6 +191,9 @@ kubectl get pods -o json | jq '.items[].spec.containers[].env[]?.valueFrom.secre # 타임스탬프로 정렬된 이벤트 목록 조회 kubectl get events --sort-by=.metadata.creationTimestamp + +# 매니페스트가 적용된 경우 클러스터의 현재 상태와 클러스터의 상태를 비교한다. +kubectl diff -f ./my-manifest.yaml ``` ## 리소스 업데이트 diff --git a/content/ko/docs/setup/_index.md b/content/ko/docs/setup/_index.md index 8e6bc5e668..668684fa03 100644 --- a/content/ko/docs/setup/_index.md +++ b/content/ko/docs/setup/_index.md @@ -79,7 +79,7 @@ card: | [Gardener](https://gardener.cloud/) | ✔ | ✔ | ✔ | ✔ | ✔ | [사용자 정의 확장](https://github.com/gardener/gardener/blob/master/docs/extensions/overview.md) | | [Giant Swarm](https://www.giantswarm.io/) | ✔ | ✔ | ✔ | | | [Google](https://cloud.google.com/) | [Google Kubernetes Engine (GKE)](https://cloud.google.com/kubernetes-engine/) | [Google Compute Engine (GCE)](https://cloud.google.com/compute/)|[GKE On-Prem](https://cloud.google.com/gke-on-prem/) | | | | | | | | -| [Hidora](https:/hidora.com/) | ✔ | ✔| ✔ | | | | | | | | +| [Hidora](https://hidora.com/) | ✔ | ✔| ✔ | | | | | | | | | [IBM](https://www.ibm.com/in-en/cloud) | [IBM Cloud Kubernetes Service](https://cloud.ibm.com/kubernetes/catalog/cluster)| |[IBM Cloud Private](https://www.ibm.com/in-en/cloud/private) | | | [Ionos](https://www.ionos.com/enterprise-cloud) | [Ionos Managed Kubernetes](https://www.ionos.com/enterprise-cloud/managed-kubernetes) | [Ionos Enterprise Cloud](https://www.ionos.com/enterprise-cloud) | | | [Kontena Pharos](https://www.kontena.io/pharos/) | |✔| ✔ | | | diff --git a/content/ko/docs/setup/best-practices/node-conformance.md b/content/ko/docs/setup/best-practices/node-conformance.md index 399e7f13a5..3aa27d96ea 100644 --- a/content/ko/docs/setup/best-practices/node-conformance.md +++ b/content/ko/docs/setup/best-practices/node-conformance.md @@ -73,7 +73,7 @@ sudo docker run -it --rm --privileged --net=host \ k8s.gcr.io/node-test:0.2 ``` -노드 적합성 테스트는 [노드 e2e 테스트](https://github.com/kubernetes/community/blob/{{< param "githubbranch" >}}/contributors/devel/sig-node/e2e-node-tests.md)를 컨테이너화한 버전이다. +노드 적합성 테스트는 [노드 e2e 테스트](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/e2e-node-tests.md)를 컨테이너화한 버전이다. 기본적으로, 모든 적합성 테스트를 실행한다. 이론적으로, 컨테이너와 필요한 볼륨을 적절히 설정했다면 어떤 노드 e2e 테스트도 수행할 수 있다. diff --git a/content/ko/docs/setup/learning-environment/minikube.md b/content/ko/docs/setup/learning-environment/minikube.md index 4c8df0c805..d66ada6ea8 100644 --- a/content/ko/docs/setup/learning-environment/minikube.md +++ b/content/ko/docs/setup/learning-environment/minikube.md @@ -1,5 +1,6 @@ --- title: Minikube로 쿠버네티스 설치 +weight: 30 content_template: templates/concept --- @@ -257,11 +258,7 @@ minikube start \ Docker 이미지를 'latest'가 아닌 다른 태그로 태그했는지 확인하고 이미지를 풀링할 때에는 그 태그를 이용한다. 혹시 이미지 태그 버전을 지정하지 않았다면, 기본값은 `:latest`이고 이미지 풀링 정책은 `Always`가 가정하나, 만약 기본 Docker 레지스트리(보통 DockerHub)에 해당 Docker 이미지 버전이 없다면 `ErrImagePull`의 결과가 나타날 것이다. {{< /note >}} -맥이나 리눅스 호스트에서 해당 Docker 데몬을 사용하려면 `docker-env command`를 쉘에서 사용해야 한다. - -```shell -eval $(minikube docker-env) -``` +맥이나 리눅스 호스트에서 해당 Docker 데몬을 사용하려면 `minikube docker-env` 에서 마지막 줄을 실행한다. 이제 개인의 맥/리눅스 머신 내 커멘드 라인에서 도커를 사용해서 Minikube VM 안의 도커 데몬과 통신할 수 있다. @@ -404,7 +401,7 @@ spec: | VirtualBox | Linux | /home | /hosthome | | VirtualBox | macOS | /Users | /Users | | VirtualBox | Windows | C://Users | /c/Users | -| VMware Fusion | macOS | /Users | /Users | +| VMware Fusion | macOS | /Users | /mnt/hgfs/Users | | Xhyve | macOS | /Users | /Users | ## 프라이빗 컨테이너 레지스트리 diff --git a/content/ko/docs/setup/production-environment/container-runtimes.md b/content/ko/docs/setup/production-environment/container-runtimes.md index b5758996af..c83a13327a 100644 --- a/content/ko/docs/setup/production-environment/container-runtimes.md +++ b/content/ko/docs/setup/production-environment/container-runtimes.md @@ -72,7 +72,7 @@ kubelet을 재시작 하는 것은 에러를 해결할 수 없을 것이다. # Docker CE 설치 ## 리포지터리 설정 ### apt가 HTTPS 리포지터리를 사용할 수 있도록 해주는 패키지 설치 -apt-get update && apt-get install \ +apt-get update && apt-get install -y \ apt-transport-https ca-certificates curl software-properties-common ### Docker의 공식 GPG 키 추가 @@ -85,7 +85,7 @@ add-apt-repository \ stable" ## Docker CE 설치. -apt-get update && apt-get install \ +apt-get update && apt-get install -y \ containerd.io=1.2.10-3 \ docker-ce=5:19.03.4~3-0~ubuntu-$(lsb_release -cs) \ docker-ce-cli=5:19.03.4~3-0~ubuntu-$(lsb_release -cs) @@ -113,14 +113,14 @@ systemctl restart docker # Docker CE 설치 ## 리포지터리 설정 ### 필요한 패키지 설치. -yum install yum-utils device-mapper-persistent-data lvm2 +yum install -y yum-utils device-mapper-persistent-data lvm2 ### Docker 리포지터리 추가 yum-config-manager --add-repo \ https://download.docker.com/linux/centos/docker-ce.repo ## Docker CE 설치. -yum update && yum install \ +yum update -y && yum install -y \ containerd.io-1.2.10 \ docker-ce-19.03.4 \ docker-ce-cli-19.03.4 @@ -181,13 +181,13 @@ sysctl --system # 선행 조건 설치 apt-get update -apt-get install software-properties-common +apt-get install -y software-properties-common add-apt-repository ppa:projectatomic/ppa apt-get update # CRI-O 설치 -apt-get install cri-o-1.15 +apt-get install -y cri-o-1.15 {{< /tab >}} {{< tab name="CentOS/RHEL 7.4+" codelang="bash" >}} @@ -196,7 +196,7 @@ apt-get install cri-o-1.15 yum-config-manager --add-repo=https://cbs.centos.org/repos/paas7-crio-115-release/x86_64/os/ # CRI-O 설치 -yum install --nogpgcheck cri-o +yum install --nogpgcheck -y cri-o {{< /tab >}} {{< /tabs >}} @@ -270,7 +270,7 @@ systemctl restart containerd # containerd 설치 ## 리포지터리 설정 ### 필요한 패키지 설치 -yum install yum-utils device-mapper-persistent-data lvm2 +yum install -y yum-utils device-mapper-persistent-data lvm2 ### Docker 리포지터리 추가리 yum-config-manager \ @@ -278,7 +278,7 @@ yum-config-manager \ https://download.docker.com/linux/centos/docker-ce.repo ## containerd 설치 -yum update && yum install containerd.io +yum update -y && yum install -y containerd.io # containerd 설정 mkdir -p /etc/containerd diff --git a/content/ko/docs/setup/production-environment/tools/kops.md b/content/ko/docs/setup/production-environment/tools/kops.md index d4d801a406..f1c1ed4d2d 100644 --- a/content/ko/docs/setup/production-environment/tools/kops.md +++ b/content/ko/docs/setup/production-environment/tools/kops.md @@ -1,6 +1,6 @@ --- title: Kops로 쿠버네티스 설치하기 -content_template: templates/concept +content_template: templates/task weight: 20 --- @@ -9,7 +9,7 @@ weight: 20 이곳 빠른 시작에서는 사용자가 얼마나 쉽게 AWS에 쿠버네티스 클러스터를 설치할 수 있는지 보여준다. [`kops`](https://github.com/kubernetes/kops)라는 이름의 툴을 이용할 것이다. -kops는 강력한 프로비저닝 시스템인데, +kops는 자동화된 프로비저닝 시스템인데, * 완전 자동화된 설치 * DNS를 통해 클러스터들의 신원 확인 @@ -18,26 +18,30 @@ kops는 강력한 프로비저닝 시스템인데, * 고가용성 지원 - [high_availability.md](https://github.com/kubernetes/kops/blob/master/docs/operations/high_availability.md) 보기 * 직접 프로비저닝 하거나 또는 할 수 있도록 terraform 매니페스트를 생성 - [terraform.md](https://github.com/kubernetes/kops/blob/master/docs/terraform.md) 보기 -만약 클러스터를 구축하는데 있어 이런 방법이 사용자의 생각과 다르다면 일종의 블록처럼 [kubeadm](/docs/admin/kubeadm/)를 이용할 수도 있다. -kops는 kubeadmin 위에서도 잘 동작한다. +{{% /capture %}} + +{{% capture prerequisites %}} + +* [kubectl](/docs/tasks/tools/install-kubectl/)을 반드시 설치해야 한다. + +* 반드시 64-bit (AMD64 그리고 Intel 64)디바이스 아키텍쳐 위에서 `kops` 를 [설치](https://github.com/kubernetes/kops#installing) 한다. + +* [AWS 계정](https://docs.aws.amazon.com/polly/latest/dg/setting-up.html)이 있고 [IAM 키](https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html#access-keys-and-secret-access-keys)를 생성하고 [구성](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html#cli-quick-configuration) 해야 한다. {{% /capture %}} -{{% capture body %}} +{{% capture steps %}} ## 클러스터 구축 ### (1/5) kops 설치 -#### 요구사항 - -kops를 이용하기 위해서는 [kubectl](/docs/tasks/tools/install-kubectl/)이 설치되어 있어야 한다. - #### 설치 [releases page](https://github.com/kubernetes/kops/releases)에서 kops를 다운로드 한다(소스코드로부터 빌드하는것도 역시 어렵지 않다). -MacOS에서: +{{< tabs name="kops_installation" >}} +{{% tab name="macOS" %}} 최신 버전의 릴리즈를 다운받는 명령어: @@ -78,19 +82,19 @@ sudo mv kops-darwin-amd64 /usr/local/bin/kops brew update && brew install kops ``` -Linux에서: +{{% /tab %}} +{{% tab name="Linux" %}} + 최신 릴리즈를 다운로드 받는 명령어: ```shell curl -LO https://github.com/kubernetes/kops/releases/download/$(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4)/kops-linux-amd64 ``` -특정 버전을 다운로드 받는다면 다음을 변경한다. +특정 버전의 kops를 다운로드하려면 명령의 다음 부분을 특정 kops 버전으로 변경한다. ```shell $(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4) ``` -특정 버전의 명령 부분이다. - 예를 들어 kops 버전을 v1.15.0을 다운로드 하려면 다음을 입력한다. ```shell @@ -115,38 +119,58 @@ sudo mv kops-linux-amd64 /usr/local/bin/kops brew update && brew install kops ``` +{{% /tab %}} +{{< /tabs >}} + + ### (2/5) 클러스터에 사용할 route53 domain 생성 -kops는 디스커버리를 위해 클러스터 내외부에서 DNS를 이용하고 이를 통해 사용자는 쿠버네티스 API서버에 도달할 수 있다. + +kops는 클러스터 내부와 외부 모두에서 검색을 위해 DNS을 사용하기에 클라이언트에서 쿠버네티스 API 서버에 연결할 +수 있다. 이런 클러스터 이름에 kops는 명확한 견해을 가지는데: 반드시 유효한 DNS 이름이어야 한다. 이렇게 함으로써 -사용자는 클러스터를 헷갈리지 않을것이고, 동료들과 혼선없이 공유할 수 있으며, IP를 기억할 필요없이 접근할 수 있다. +사용자는 클러스터를 헷갈리지 않을것이고, 동료들과 혼선없이 공유할 수 있으며, +IP를 기억할 필요없이 접근할 수 있다. -그렇게 하고 있겠지만, 클러스터를 구분하기 위해 서브도메인을 활용할 수 있다. 예를 들어 `useast1.dev.example.com`을 이용한다면, API 서버 엔드포인트는 `api.useast1.dev.example.com`가 될 것이다. +그렇게 하고 있겠지만, 클러스터를 구분하기 위해 서브도메인을 활용할 수 있다. 예를 들어 +`useast1.dev.example.com`을 이용한다면, API 서버 엔드포인트는 `api.useast1.dev.example.com`가 될 것이다. -Route53 hosted zone은 서브도메인도 지원한다. 여러분의 hosted zone은 `useast1.dev.example.com`, `dev.example.com` 그리고 `example.com` 같은 것도 될 수 있다. -kops는 이것들 모두와 잘 동작하며, 사용자는 보통 조직적인 부분을 고려해 결정한다(예를 들어, 사용자가 `dev.example.com`하위에 레코드를 생성하는것은 허용되지만, +Route53 hosted zone은 서브도메인도 지원한다. 여러분의 hosted zone은 `useast1.dev.example.com`, +`dev.example.com` 그리고 `example.com` 같은 것도 될 수 있다. kops는 이것들 모두와 잘 동작하며, +사용자는 보통 조직적인 부분을 고려해 결정한다(예를 들어, 사용자가 `dev.example.com`하위에 레코드를 생성하는것은 허용되지만, `example.com`하위에는 그렇지 않을 수 있다). `dev.example.com`을 hosted zone으로 사용하고 있다고 가정해보자. 보통 사용자는 [일반적인 방법](http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/CreatingNewSubdomain.html) 에 따라 생성하거나 `aws route53 create-hosted-zone --name dev.example.com --caller-reference 1` 와 같은 커맨드를 이용한다. -그 후 도메인 내 레코드들을 확인할 수 있도록 상위 도메인내에 NS 레코드를 생성해야 한다. 여기서는, `dev` NS 레코드를 `example.com`에 생성한다. 만약 이것이 루트 도메인 네임이라면 이 NS 레코드들은 도메인 등록기관을 통해서 생성해야 한다(예를 들어, `example.com`는 `example.com`를 구매한 곳에서 설정 할 수 있다). -이 단계에서 문제가 되기 쉽다.(문제를 만드는 가장 큰 이유이다!) dig 툴을 실행해서 클러스터 설정이 정확한지 한번 더 확인 한다. +그 후 도메인 내 레코드들을 확인할 수 있도록 상위 도메인내에 NS 레코드를 생성해야 한다. 여기서는, +`dev` NS 레코드를 `example.com`에 생성한다. 만약 이것이 루트 도메인 네임이라면 이 NS 레코드들은 +도메인 등록기관을 통해서 생성해야 한다(예를 들어, `example.com`는 `example.com`를 구매한 곳에서 설정 할 수 있다). + +이 단계에서 문제가 되기 쉽다.(문제를 만드는 가장 큰 이유이다!) dig 툴을 실행해서 +클러스터 설정이 정확한지 한번 더 확인 한다. `dig NS dev.example.com` 당신의 hosted zone용으로 할당된 3~4개의 NS 레코드를 Route53에서 확인할 수 있어야 한다. ### (3/5) 클러스터 상태 저장용 S3 버킷 생성 -kops는 설치 이후에도 클러스터를 관리할 수 있다. 이를 위해 사용자가 생성한 클러스터의 상태나 사용하는 키 정보들을 지속적으로 추적해야 한다. 이 정보가 S3에 저장된다. + +kops는 설치 이후에도 클러스터를 관리할 수 있다. 이를 위해 사용자가 생성한 클러스터의 상태나 +사용하는 키 정보들을 지속적으로 추적해야 한다. 이 정보가 S3에 저장된다. 이 버킷의 접근은 S3 권한으로 제어한다. -다수의 클러스터는 동일한 S3 버킷을 이용할 수 있고, 사용자는 이 S3 버킷을 같은 클러스트를 운영하는 동료에게 공유할 수 있다. 하지만 이 S3 버킷에 접근 가능한 사람은 사용자의 모든 클러스터에 관리자 접근이 가능하게 되니, 운영팀 이외로 공유되지 않도록 해야 한다. +다수의 클러스터는 동일한 S3 버킷을 이용할 수 있고, 사용자는 이 S3 버킷을 같은 클러스트를 +운영하는 동료에게 공유할 수 있다. 하지만 이 S3 버킷에 접근 가능한 사람은 사용자의 +모든 클러스터에 관리자 접근이 가능하게 되니, 운영팀 이외로 +공유되지 않도록 해야 한다. -그래서 보통 한 운영팀 당 하나의 S3 버킷을 가지도록 하기도 한다.(그리고 종종 운영팀 이름은 위에서 언급한 hosted zone과 동일하게 짓기도 한다!) +그래서 보통 한 운영팀 당 하나의 S3 버킷을 가지도록 하기도 한다.(그리고 종종 운영팀 +이름은 위에서 언급한 hosted zone과 동일하게 짓기도 한다!) -우리 예제에서는, `dev.example.com`를 hosted zone으로 했으니 `clusters.dev.example.com`를 S3 버킷 이름으로 정하자. +우리 예제에서는, `dev.example.com`를 hosted zone으로 했으니 `clusters.dev.example.com`를 +S3 버킷 이름으로 정하자. * `AWS_PROFILE`를 선언한다. (AWS CLI 동작을 위해 다른 profile을 선택해야 할 경우) @@ -155,12 +179,16 @@ kops는 설치 이후에도 클러스터를 관리할 수 있다. 이를 위해 * `export KOPS_STATE_STORE=s3://clusters.dev.example.com` 하면, kops는 이 위치를 기본값으로 인식할 것이다. 이 부분을 bash profile등에 넣어두는것을 권장한다. + ### (4/5) 클러스터 설정 구성 + 클러스터 설정하려면, `kops create cluster` 를 실행한다: `kops create cluster --zones=us-east-1c useast1.dev.example.com` -kops는 클러스터에 사용될 설정을 생성할것이다. 여기서 주의할 점은 실제 클러스트 리소스가 아닌 _설정_ 만을 생성한다는 것에 주의하자 - 이 부분은 다음 단계에서 `kops update cluster` 으로 구성해볼 것이다. 그 때 만들어진 설정을 점검하거나 변경할 수 있다. +kops는 클러스터에 사용될 설정을 생성할것이다. 여기서 주의할 점은 실제 클러스트 리소스가 아닌 _설정_ +만을 생성한다는 것에 주의하자 - 이 부분은 다음 단계에서 `kops update cluster` 으로 +구성해볼 것이다. 그 때 만들어진 설정을 점검하거나 변경할 수 있다. 더 자세한 내용을 알아보기 위한 커맨드가 출력된다. @@ -169,7 +197,10 @@ kops는 클러스터에 사용될 설정을 생성할것이다. 여기서 주의 * 인스턴스 그룹 수정: `kops edit ig --name=useast1.dev.example.com nodes` * 마스터 인스턴스 그룹 수정: `kops edit ig --name=useast1.dev.example.com master-us-east-1c` -만약 kops사용이 처음이라면, 얼마 걸리지 않으니 이들을 시험해 본다. 인스턴스 그룹은 쿠버네티스 노드로 등록된 인스턴스의 집합을 말한다. AWS상에서는 auto-scaling-groups를 통해 만들어진다. 사용자는 여러개의 인스턴스 그룹을 관리할 수 있는데, 예를 들어, spot과 on-demand 인스턴스 조합 또는 GPU 와 non-GPU 인스턴스의 조합으로 구성할 수 있다. +만약 kops사용이 처음이라면, 얼마 걸리지 않으니 이들을 시험해 본다. 인스턴스 그룹은 +쿠버네티스 노드로 등록된 인스턴스의 집합을 말한다. AWS상에서는 auto-scaling-groups를 +통해 만들어진다. 사용자는 여러개의 인스턴스 그룹을 관리할 수 있는데, +예를 들어, spot과 on-demand 인스턴스 조합 또는 GPU 와 non-GPU 인스턴스의 조합으로 구성할 수 있다. ### (5/5) AWS에 클러스터 생성 @@ -179,31 +210,30 @@ kops는 클러스터에 사용될 설정을 생성할것이다. 여기서 주의 `kops update cluster useast1.dev.example.com --yes` 실행은 수 초 만에 되지만, 실제로 클러스터가 준비되기 전까지 수 분이 걸릴 수 있다. -언제든 `kops update cluster`로 클러스트 설정을 변경할 수 있다. 사용자가 변경한 클러스트 설정을 그대로 반영해 줄 것이며, 필요다하면 AWS 나 쿠버네티스를 재설정 해 줄것이다. +언제든 `kops update cluster`로 클러스터 설정을 변경할 수 있다. 사용자가 +변경한 클러스터 설정을 그대로 반영해 줄 것이며, 필요다하면 AWS 나 쿠버네티스를 재설정 해 줄것이다. -예를 들면, `kops edit ig nodes` 뒤에 `kops update cluster --yes`를 실행해 설정을 반영한다. 그리고 `kops rolling-update cluster`로 설정을 즉시 원복시킬 수 있다. - -`--yes`를 명시하지 않으면 `kops update cluster` 커맨드 후 어떤 설정이 변경될지가 표시된다. 운영계 클러스터 관리할 때 사용하기 좋다! +예를 들면, `kops edit ig nodes` 뒤에 `kops update cluster --yes`를 실행해 설정을 반영한다. +그리고 `kops rolling-update cluster`로 설정을 즉시 원복시킬 수 있다. +`--yes`를 명시하지 않으면 `kops update cluster` 커맨드 후 어떤 설정이 변경될지가 표시된다. +운영계 클러스터 관리할 때 사용하기 좋다! ### 다른 애드온 탐험 + [애드온 리스트](/docs/concepts/cluster-administration/addons/) 에서 쿠버네티스 클러스터용 로깅, 모니터링, 네트워크 정책, 시각화 & 제어 등을 포함한 다른 애드온을 확인해본다. ## 정리하기 * `kops delete cluster useast1.dev.example.com --yes` 로 클러스터를 삭제한다. -## Feedback - -* Slack Channel: [#kops-users](https://kubernetes.slack.com/messages/kops-users/) -* [GitHub Issues](https://github.com/kubernetes/kops/issues) - {{% /capture %}} {{% capture whatsnext %}} * 쿠버네티스 [개념](/docs/concepts/) 과 [`kubectl`](/docs/user-guide/kubectl-overview/)에 대해 더 알아보기. -* `kops` [고급 사용법](https://github.com/kubernetes/kops) 알아보기. -* 튜토리얼, 모범사례, 고급 설정 옵션을 위해 `kops` [문서](https://github.com/kubernetes/kops) 부분 보기. +* 튜토리얼, 모범사례 및 고급 구성 옵션에 대한 `kops` [고급 사용법](https://kops.sigs.k8s.io/)에 대해 더 자세히 알아본다. +* 슬랙(Slack)에서 `kops` 커뮤니티 토론을 할 수 있다: [커뮤니티 토론](https://github.com/kubernetes/kops#other-ways-to-communicate-with-the-contributors) +* 문제를 해결하거나 이슈를 제기하여 `kops` 에 기여한다. [깃헙 이슈](https://github.com/kubernetes/kops/issues) {{% /capture %}} diff --git a/content/ko/docs/tasks/administer-cluster/network-policy-provider/cilium-network-policy.md b/content/ko/docs/tasks/administer-cluster/network-policy-provider/cilium-network-policy.md index b0cba9681e..1b0c866d18 100644 --- a/content/ko/docs/tasks/administer-cluster/network-policy-provider/cilium-network-policy.md +++ b/content/ko/docs/tasks/administer-cluster/network-policy-provider/cilium-network-policy.md @@ -1,5 +1,4 @@ --- -reviewers: title: 네트워크 폴리시로 실리움(Cilium) 사용하기 content_template: templates/task weight: 20 @@ -8,7 +7,7 @@ weight: 20 {{% capture overview %}} 이 페이지는 어떻게 네트워크 폴리시(NetworkPolicy)로 실리움(Cilium)를 사용하는지 살펴본다. -실리움의 배경에 대해서는 [실리움 소개](https://cilium.readthedocs.io/en/stable/intro)를 읽어보자. +실리움의 배경에 대해서는 [실리움 소개](https://docs.cilium.io/en/stable/intro)를 읽어보자. {{% /capture %}} {{% capture prerequisites %}} @@ -22,35 +21,44 @@ weight: 20 실리움에 쉽게 친숙해지기 위해 Minikube에 실리움을 기본적인 데몬셋으로 설치를 수행하는 -[실리움 쿠버네티스 시작하기 안내](https://cilium.readthedocs.io/en/stable/gettingstarted/minikube/)를 따라 해볼 수 있다. +[실리움 쿠버네티스 시작하기 안내](https://docs.cilium.io/en/stable/gettingstarted/minikube/)를 따라 해볼 수 있다. -Minikube를 시작하려면 최소 버전으로 >= v0.33.1 이 필요하고, +Minikube를 시작하려면 최소 버전으로 >= v1.3.1 이 필요하고, 다음의 실행 파라미터로 실행한다. ```shell minikube version ``` ``` -minikube version: v0.33.1 +minikube version: v1.3.1 ``` ```shell minikube start --network-plugin=cni --memory=4096 ``` -Minikube에서 실리움의 데몬셋 구성과 Minikube에 배포된 etcd 인스턴스로 접속하는데 필요한 구성 뿐만 아니라 -RBAC 설정을 포함하는 필요한 구성을 -이 간단한 ``올인원`` YAML 파일로 배포할 수 있다. +BPF 파일시스템을 마운트한다 ```shell -kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.5/examples/kubernetes/1.14/cilium-minikube.yaml +minikube ssh -- sudo mount bpffs -t bpf /sys/fs/bpf +``` + +Minikube에서 실리움의 데몬셋 구성과 적절한 RBAC 설정을 포함하는 필요한 구성을 +간단한 ``올인원`` YAML 파일로 배포할 수 있다. + +```shell +kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.6/install/kubernetes/quick-install.yaml ``` ``` configmap/cilium-config created -daemonset.apps/cilium created -clusterrolebinding.rbac.authorization.k8s.io/cilium created -clusterrole.rbac.authorization.k8s.io/cilium created serviceaccount/cilium created +serviceaccount/cilium-operator created +clusterrole.rbac.authorization.k8s.io/cilium created +clusterrole.rbac.authorization.k8s.io/cilium-operator created +clusterrolebinding.rbac.authorization.k8s.io/cilium created +clusterrolebinding.rbac.authorization.k8s.io/cilium-operator created +daemonset.apps/cilium create +deployment.apps/cilium-operator created ``` 시작하기 안내서의 나머지 부분은 예제 애플리케이션을 이용하여 @@ -60,7 +68,7 @@ L3/L4(예, IP 주소 + 포트) 모두의 보안 정책 뿐만 아니라 L7(예, ## 실리움을 실 서비스 용도로 배포하기 실리움을 실 서비스 용도의 배포에 관련한 자세한 방법은 -[실리움 쿠버네티스 설치 안내](https://cilium.readthedocs.io/en/stable/kubernetes/intro/)를 살펴본다. +[실리움 쿠버네티스 설치 안내](https://docs.cilium.io/en/stable/kubernetes/intro/)를 살펴본다. 이 문서는 자세한 요구사항, 방법과 실제 데몬셋 예시를 포함한다. @@ -84,14 +92,8 @@ cilium-6rxbd 1/1 Running 0 1m ... ``` -알고 있어야 할 두 가지 주요 구성요소는 다음과 같다. - -- 먼저는 `cilium` 파드가 클러스터의 각 노드에서 운영되고, -노드의 파드로 보내고/받는 트래픽을 리눅스 BPF를 이용하여 네트워크 폴리시를 적용한다. -- 실 서비스에 배포하는 경우 실리움은 키-값 저장소(예, etcd)를 활용해야 한다. -[실리움 쿠버네티스 설치 안내](https://cilium.readthedocs.io/en/stable/kubernetes/intro/)에서 -키-값 저장소를 설치하는 방법과 실리움에서 이를 구성하는 필수 단계를 -제공할 것이다. +`cilium` 파드는 클러스터 각 노드에서 실행되며, 리눅스 BPF를 사용해서 +해당 노드의 파드에 대한 트래픽 네트워크 폴리시를 적용한다. {{% /capture %}} diff --git a/content/ko/docs/tasks/debug-application-cluster/resource-metrics-pipeline.md b/content/ko/docs/tasks/debug-application-cluster/resource-metrics-pipeline.md index 05b08113e7..9bddc81234 100644 --- a/content/ko/docs/tasks/debug-application-cluster/resource-metrics-pipeline.md +++ b/content/ko/docs/tasks/debug-application-cluster/resource-metrics-pipeline.md @@ -34,6 +34,16 @@ Horizontal Pod Autoscaler 같은 클러스터의 컨트롤러에서 결정을 이 API를 사용하려면 메트릭 서버를 클러스터에 배포해야 한다. 그렇지 않으면 사용할 수 없다. {{< /note >}} +## 리소스 사용량 측정 + +### CPU + +CPU는 일정 기간 동안 [CPU 코어](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#meaning-of-cpu)에서 평균 사용량으로 리포트된다. 이 값은 커널(리눅스와 윈도우 커널 모두)에서 제공하는 누적 CPU 카운터보다 높은 비율을 적용해서 얻는다. kubelet은 비율 계산에 사용할 윈도우를 선택한다. + +### 메모리 + +메모리는 메트릭이 수집된 순간 작업 집합으로 리포트 된다. 이상적인 환경에서 "작업 집합(working set)"은 압박(memory pressure)에서 풀려날 수 없는 사용 중인(in-use) 메모리의 양이다. 그러나 작업 집합의 계산은 호스트 OS에 따라 다르며, 일반적으로 휴리스틱스를 사용해서 평가한다. 쿠버네티스는 스왑(swap)을 지원하지 않기 때문에 모든 익명(파일로 백업되지 않은) 메모리를 포함한다. 호스트 OS가 항상 이러한 페이지를 회수할 수 없기 때문에 메트릭에는 일반적으로 일부 캐시된(파일 백업) 메모리도 포함된다. + ## 메트릭 서버 [메트릭 서버](https://github.com/kubernetes-incubator/metrics-server)는 클러스터 전역에서 리소스 사용량 데이터를 집계한다. diff --git a/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md b/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md index 83f787b152..d47b6e7f31 100644 --- a/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md +++ b/content/ko/docs/tasks/manage-kubernetes-objects/declarative-config.md @@ -983,11 +983,11 @@ TODO(pwittrock): Why doesn't export remove the status field? Seems like it shou ```yaml selector: matchLabels: - controller-selector: "extensions/v1beta1/deployment/nginx" + controller-selector: "apps/v1/deployment/nginx" template: metadata: labels: - controller-selector: "extensions/v1beta1/deployment/nginx" + controller-selector: "apps/v1/deployment/nginx" ``` {{% capture whatsnext %}} diff --git a/content/ko/docs/tasks/manage-kubernetes-objects/imperative-config.md b/content/ko/docs/tasks/manage-kubernetes-objects/imperative-config.md index 1080064ff1..3fdd8ad12d 100644 --- a/content/ko/docs/tasks/manage-kubernetes-objects/imperative-config.md +++ b/content/ko/docs/tasks/manage-kubernetes-objects/imperative-config.md @@ -135,11 +135,11 @@ kubectl create -f --edit ```yaml selector: matchLabels: - controller-selector: "extensions/v1beta1/deployment/nginx" + controller-selector: "apps/v1/deployment/nginx" template: metadata: labels: - controller-selector: "extensions/v1beta1/deployment/nginx" + controller-selector: "apps/v1/deployment/nginx" ``` {{% /capture %}} diff --git a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md index 27ae2c2f52..418ebb17dc 100644 --- a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md +++ b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough.md @@ -74,7 +74,7 @@ deployment.apps/php-apache created 다음 명령어는 첫 번째 단계에서 만든 php-apache 디플로이먼트 파드의 개수를 1부터 10 사이로 유지하는 Horizontal Pod Autoscaler를 생성한다. 간단히 얘기하면, HPA는 (디플로이먼트를 통한) 평균 CPU 사용량을 50%로 유지하기 위하여 레플리카의 개수를 늘리고 줄인다. -[kubectl run](https://github.com/kubernetes/kubernetes/blob/{{< param "githubbranch" >}}/docs/user-guide/kubectl/kubectl_run.md)으로 각 파드는 200 밀리코어까지 요청할 수 있고, +(kubectl run으로 각 파드는 200 밀리코어까지 요청할 수 있고, 따라서 여기서 말하는 평균 CPU 사용은 100 밀리코어를 말한다). 이에 대한 자세한 알고리즘은 [여기](/docs/tasks/run-application/horizontal-pod-autoscale/#algorithm-details)를 참고하기 바란다. diff --git a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md index e3ba3cf282..3f40a1b22b 100644 --- a/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md +++ b/content/ko/docs/tasks/run-application/horizontal-pod-autoscale.md @@ -41,28 +41,28 @@ Horizontal Pod Autoscaler는 컨트롤러 또는 사용자 지정 메트릭 API(다른 모든 메트릭 용)에서 메트릭을 가져온다. * 파드 단위 리소스 메트릭(예 : CPU)의 경우 컨트롤러는 HorizontalPodAutoscaler가 -대상으로하는 각 파드에 대한 리소스 메트릭 API에서 메트릭을 가져온다. -그런 다음, 목표 사용률 값이 설정되면, 컨트롤러는 각 파드의 -컨테이너에 대한 동등한 자원 요청을 퍼센트 단위로 하여 사용률 값을 -계산한다. 대상 원시 값이 설정된 경우 원시 메트릭 값이 직접 사용된다. -그리고, 컨트롤러는 모든 대상 파드에서 사용된 사용률의 평균 또는 원시 값(지정된 -대상 유형에 따라 다름)을 가져와서 원하는 레플리카의 개수를 스케일하는데 -사용되는 비율을 생성한다. + 대상으로하는 각 파드에 대한 리소스 메트릭 API에서 메트릭을 가져온다. + 그런 다음, 목표 사용률 값이 설정되면, 컨트롤러는 각 파드의 + 컨테이너에 대한 동등한 자원 요청을 퍼센트 단위로 하여 사용률 값을 + 계산한다. 대상 원시 값이 설정된 경우 원시 메트릭 값이 직접 사용된다. + 그리고, 컨트롤러는 모든 대상 파드에서 사용된 사용률의 평균 또는 원시 값(지정된 + 대상 유형에 따라 다름)을 가져와서 원하는 레플리카의 개수를 스케일하는데 + 사용되는 비율을 생성한다. -파드의 컨테이너 중 일부에 적절한 리소스 요청이 설정되지 않은 경우, -파드의 CPU 사용률은 정의되지 않으며, 따라서 오토스케일러는 -해당 메트릭에 대해 아무런 조치도 취하지 않는다. 오토스케일링 -알고리즘의 작동 방식에 대한 자세한 내용은 아래 [알고리즘 세부 정보](#알고리즘-세부-정보) -섹션을 참조하기 바란다. + 파드의 컨테이너 중 일부에 적절한 리소스 요청이 설정되지 않은 경우, + 파드의 CPU 사용률은 정의되지 않으며, 따라서 오토스케일러는 + 해당 메트릭에 대해 아무런 조치도 취하지 않는다. 오토스케일링 + 알고리즘의 작동 방식에 대한 자세한 내용은 아래 [알고리즘 세부 정보](#알고리즘-세부-정보) + 섹션을 참조하기 바란다. * 파드 단위 사용자 정의 메트릭의 경우, 컨트롤러는 사용률 값이 아닌 원시 값을 사용한다는 점을 -제외하고는 파드 단위 리소스 메트릭과 유사하게 작동한다. + 제외하고는 파드 단위 리소스 메트릭과 유사하게 작동한다. * 오브젝트 메트릭 및 외부 메트릭의 경우, 문제의 오브젝트를 표현하는 -단일 메트릭을 가져온다. 이 메트릭은 목표 값과 -비교되어 위와 같은 비율을 생성한다. `autoscaling/v2beta2` API -버전에서는, 비교가 이루어지기 전에 해당 값을 파드의 개수로 -선택적으로 나눌 수 있다. + 단일 메트릭을 가져온다. 이 메트릭은 목표 값과 + 비교되어 위와 같은 비율을 생성한다. `autoscaling/v2beta2` API + 버전에서는, 비교가 이루어지기 전에 해당 값을 파드의 개수로 + 선택적으로 나눌 수 있다. HorizontalPodAutoscaler는 보통 일련의 API 집합(`metrics.k8s.io`, `custom.metrics.k8s.io`, `external.metrics.k8s.io`)에서 메트릭을 가져온다. `metrics.k8s.io` API는 대개 별도로 @@ -154,10 +154,17 @@ HorizontalPodAutoscaler에 여러 메트릭이 지정된 경우, 이 계산은 큰 값이 선택된다. 이러한 메트릭 중 어떠한 것도 원하는 레플리카 수로 변환할 수 없는 경우(예 : 메트릭 API에서 메트릭을 가져오는 중 오류 발생) 스케일을 건너뛴다. +이는 하나 이상의 메트릭이 +현재 값보다 높은 `desiredReplicas` 을 제공하는 경우 +HPA가 여전히 확장할 수 있음을 의미한다. -마지막으로, HPA가 목표를 스케일하기 직전에 스케일 권장 사항이 기록된다. 컨트롤러는 -구성 가능한 창(window) 내에서 가장 높은 권장 사항을 선택하도록 해당 창 내의 -모든 권장 사항을 고려한다. 이 값은 `--horizontal-pod-autoscaler-downscale-stabilization` 플래그를 사용하여 설정할 수 있고, 기본 값은 5분이다. +마지막으로, HPA가 목표를 스케일하기 직전에 스케일 권장 사항이 +기록된다. 컨트롤러는 구성 가능한 창(window) 내에서 가장 높은 권장 +사항을 선택하도록 해당 창 내의 모든 권장 사항을 고려한다. 이 값은 +`--horizontal-pod-autoscaler-downscale-stabilization` 플래그 또는 HPA 오브젝트 +동작 `behavior.scaleDown.stabilizationWindowSeconds` ([구성가능한 +스케일링 동작 지원](#구성가능한-스케일링-동작-지원)을 본다)을 +사용하여 설정할 수 있고, 기본 값은 5분이다. 즉, 스케일 다운이 점진적으로 발생하여 급격히 변동하는 메트릭 값의 영향을 완만하게 한다. @@ -206,9 +213,6 @@ Horizontal Pod Autoscaler를 사용하여 레플리카 그룹의 스케일을 평가된 메트릭의 동적인 특징 때문에 레플리카 수가 자주 변동할 수 있다. 이것은 때로는 *스래싱 (thrashing)* 이라고도 한다. -v1.6부터 클러스터 운영자는 `kube-controller-manager` 구성 -요소의 플래그로 노출된 글로벌 HPA 설정을 조정하여 이 문제를 완화할 수 있다. - v1.12부터는 새로운 알고리즘 업데이트가 업스케일 지연에 대한 필요성을 제거하였다. @@ -225,6 +229,11 @@ v1.12부터는 새로운 알고리즘 업데이트가 업스케일 지연에 대 있다. {{< /note >}} +v1.17 부터 v2beta2 API 필드에서 `behavior.scaleDown.stabilizationWindowSeconds` +를 설정하여 다운스케일 안정화 창을 HPA별로 설정할 수 있다. +[구성가능한 스케일링 +동작 지원](#구성가능한-스케일링-동작-지원)을 본다. + ## 멀티 메트릭을 위한 지원 Kubernetes 1.6은 멀티 메트릭을 기반으로 스케일링을 지원한다. `autoscaling/v2beta2` API @@ -275,6 +284,154 @@ API에 접속하려면 클러스터 관리자는 다음을 확인해야 한다. 어떻게 사용하는지에 대한 예시는 [커스텀 메트릭 사용하는 작업 과정](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-multiple-metrics-and-custom-metrics)과 [외부 메트릭스 사용하는 작업 과정](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#autoscaling-on-metrics-not-related-to-kubernetes-objects)을 참조한다. +## 구성가능한 스케일링 동작 지원 + +[v1.17](https://github.com/kubernetes/enhancements/blob/master/keps/sig-autoscaling/20190307-configurable-scale-velocity-for-hpa.md) +부터 `v2beta2` API는 HPA `behavior` 필드를 통해 +스케일링 동작을 구성할 수 있다. +동작은 `behavior` 필드 아래의 `scaleUp` 또는 `scaleDown` +섹션에서 스케일링 업과 다운을 위해 별도로 지정된다. 안정화 윈도우는 +스케일링 대상에서 레플리카 수의 플래핑(flapping)을 방지하는 +양방향에 대해 지정할 수 있다. 마찬가지로 스케일링 정책을 지정하면 +스케일링 중 레플리카 변경 속도를 제어할 수 있다. + +### 스케일링 정책 + +스펙의 `behavior` 섹션에 하나 이상의 스케일링 폴리시를 지정할 수 있다. +폴리시가 여러 개 지정된 경우 가장 많은 양의 변경을 +허용하는 정책이 기본적으로 선택된 폴리시이다. 다음 예시는 스케일 다운 중 이 +동작을 보여준다. + +```yaml +behavior: + scaleDown: + policies: + - type: Pods + value: 4 + periodSeconds: 60 + - type: Percent + value: 10 + periodSeconds: 60 +``` + +파드 수가 40개를 초과하면 두 번째 폴리시가 스케일링 다운에 사용된다. +예를 들어 80개의 레플리카가 있고 대상을 10개의 레플리카로 축소해야 하는 +경우 첫 번째 단계에서 8개의 레플리카가 스케일 다운 된다. 레플리카의 수가 72개일 때 +다음 반복에서 파드의 10%는 7.2 이지만, 숫자는 8로 올림된다. 오토스케일러 컨트롤러의 +각 루프에서 변경될 파드의 수는 현재 레플리카의 수에 따라 재계산된다. 레플리카의 수가 40 +미만으로 떨어지면 첫 번째 폴리시 _(파드들)_ 가 적용되고 한번에 +4개의 레플리카가 줄어든다. + +`periodSeconds` 는 폴리시가 참(true)으로 유지되어야 하는 기간을 나타낸다. +첫 번째 정책은 1분 내에 최대 4개의 레플리카를 스케일 다운할 수 있도록 허용한다. +두 번째 정책은 현재 레플리카의 최대 10%를 1분 내에 스케일 다운할 수 있도록 허용한다. + +확장 방향에 대해 `selectPolicy` 필드를 확인하여 폴리시 선택을 변경할 수 있다. +레플리카의 수를 최소로 변경할 수 있는 폴리시를 선택하는 `최소(Min)`로 값을 설정한다. +값을 `Disabled` 로 설정하면 해당 방향으로 스케일링이 완전히 +비활성화 된다. + +### 안정화 윈도우 + +안정화 윈도우는 스케일링에 사용되는 메트릭이 계속 변동할 때 레플리카의 플래핑을 +다시 제한하기 위해 사용된다. 안정화 윈도우는 스케일링을 방지하기 위해 과거부터 +계산된 의도한 상태를 고려하는 오토스케일링 알고리즘에 의해 사용된다. +다음의 예시에서 `scaleDown` 에 대해 안정화 윈도우가 지정되어있다. + +```yaml +scaleDown: + stabilizationWindowSeconds: 300 +``` + +메트릭이 대상을 축소해야하는 것을 나타내는 경우 알고리즘은 +이전에 계산된 의도한 상태를 살펴보고 지정된 간격의 최고 값을 사용한다. +위의 예시에서 지난 5분 동안 모든 의도한 상태가 고려된다. + +### 기본 동작 + +사용자 지정 스케일링을 사용하려면 일부 필드를 지정해야 한다. 사용자 정의해야 +하는 값만 지정할 수 있다. 이러한 사용자 지정 값은 기본값과 병합된다. 기본값은 HPA +알고리즘의 기존 동작과 일치한다. + +```yaml +behavior: + scaleDown: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 100 + periodSeconds: 15 + scaleUp: + stabilizationWindowSeconds: 0 + policies: + - type: Percent + value: 100 + periodSeconds: 15 + - type: Pods + value: 4 + periodSeconds: 15 + selectPolicy: Max +``` +안정화 윈도우의 스케일링 다운의 경우 _300_ 초(또는 제공된 +경우`--horizontal-pod-autoscaler-downscale-stabilization` 플래그의 값)이다. 스케일링 다운에서는 현재 +실행 중인 레플리카의 100%를 제거할 수 있는 단일 정책만 있으며, 이는 스케일링 +대상을 최소 허용 레플리카로 축소할 수 있음을 의미한다. +스케일링 업에는 안정화 윈도우가 없다. 메트릭이 대상을 스케일 업해야 한다고 표시된다면 대상이 즉시 스케일 업된다. +두 가지 폴리시가 있다. HPA가 정상 상태에 도달 할 때까지 15초 마다 +4개의 파드 또는 현재 실행 중인 레플리카의 100% 가 추가된다. + +### 예시: 다운스케일 안정화 윈도우 변경 + +사용자 지정 다운스케일 안정화 윈도우를 1분 동안 제공하기 위해 +다음 동작이 HPA에 추가된다. + +```yaml +behavior: + scaleDown: + stabilizationWindowSeconds: 60 +``` + +### 예시: 스케일 다운 비율 제한 + +HPA에 의해 파드가 제거되는 속도를 분당 10%로 제한하기 위해 +다음 동작이 HPA에 추가된다. + +```yaml +behavior: + scaleDown: + policies: + - type: Percent + value: 10 + periodSeconds: 60 +``` + +마지막으로 5개의 파드를 드롭하기 위해 다른 폴리시를 추가하고, 최소 선택 +전략을 추가할 수 있다. + +```yaml +behavior: + scaleDown: + policies: + - type: Percent + value: 10 + periodSeconds: 60 + - type: Pods + value: 5 + periodSeconds: 60 + selectPolicy: Max +``` + +### 예시: 스케일 다운 비활성화 + +`selectPolicy` 의 `Disabled` 값은 주어진 방향으로의 스케일링을 끈다. +따라서 다운 스케일링을 방지하기 위해 다음 폴리시가 사용된다. + +```yaml +behavior: + scaleDown: + selectPolicy: Disabled +``` + {{% /capture %}} {{% capture whatsnext %}} diff --git a/content/ko/docs/tutorials/hello-minikube.md b/content/ko/docs/tutorials/hello-minikube.md index 5c7470ef63..e24b887509 100644 --- a/content/ko/docs/tutorials/hello-minikube.md +++ b/content/ko/docs/tutorials/hello-minikube.md @@ -169,7 +169,7 @@ Katacode는 무료로 브라우저에서 쿠버네티스 환경을 제공한다. ## 애드온 사용하기 -Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네티스 환경에서 접속해 볼 수 있는 내장 애드온 셋이 있다. +Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네티스 환경에서 접속해 볼 수 있는 내장 {{< glossary_tooltip text="애드온" term_id="addons" >}} 셋이 있다. 1. 현재 지원하는 애드온 목록을 확인한다. @@ -186,7 +186,6 @@ Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네 efk: disabled freshpod: disabled gvisor: disabled - heapster: disabled helm-tiller: disabled ingress: disabled ingress-dns: disabled @@ -200,16 +199,16 @@ Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네 storage-provisioner-gluster: disabled ``` -2. 한 애드온을 활성화 한다. 예를 들어 `heapster` +2. 한 애드온을 활성화 한다. 예를 들어 `metrics-server` ```shell - minikube addons enable heapster + minikube addons enable metrics-server ``` 다음과 유사하게 출력된다. ``` - heapster was successfully enabled + metrics-server was successfully enabled ``` 3. 방금 생성한 파드와 서비스를 확인한다. @@ -224,7 +223,7 @@ Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네 NAME READY STATUS RESTARTS AGE pod/coredns-5644d7b6d9-mh9ll 1/1 Running 0 34m pod/coredns-5644d7b6d9-pqd2t 1/1 Running 0 34m - pod/heapster-9jttx 1/1 Running 0 26s + pod/metrics-server-67fb648c5 1/1 Running 0 26s pod/etcd-minikube 1/1 Running 0 34m pod/influxdb-grafana-b29w8 2/2 Running 0 26s pod/kube-addon-manager-minikube 1/1 Running 0 34m @@ -235,22 +234,22 @@ Minikube에는 활성화하거나 비활성화 할 수 있고 로컬 쿠버네 pod/storage-provisioner 1/1 Running 0 34m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE - service/heapster ClusterIP 10.96.241.45 80/TCP 26s + service/metrics-server ClusterIP 10.96.241.45 80/TCP 26s service/kube-dns ClusterIP 10.96.0.10 53/UDP,53/TCP 34m service/monitoring-grafana NodePort 10.99.24.54 80:30002/TCP 26s service/monitoring-influxdb ClusterIP 10.111.169.94 8083/TCP,8086/TCP 26s ``` -4. `heapster` 비활성화 +4. `metrics-server` 비활성화 ```shell - minikube addons disable heapster + minikube addons disable metrics-server ``` 다음과 유사하게 출력된다. ``` - heapster was successfully disabled + metrics-server was successfully disabled ``` ## 제거하기 diff --git a/content/ko/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html b/content/ko/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html index 5c285b65ef..95c22577fd 100644 --- a/content/ko/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html +++ b/content/ko/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro.html @@ -99,7 +99,7 @@ weight: 10

애플리케이션을 쿠버네티스에 배포한다는 것은, 마스터에 애플리케이션 컨테이너를 구동하라고 지시하는 것이다. 마스터는 컨테이너를 클러스터의 어느 노드에 구동시킬지를 스케줄한다. 노드는 마스터가 - 제공하는 쿠버네티스 API를 통해서 마스터와 통신한다. 최종 사용자도 쿠버네티스 API를 직접 + 제공하는 쿠버네티스 API를 통해서 마스터와 통신한다. 최종 사용자도 쿠버네티스 API를 직접 사용해서 클러스터와 상호작용할 수 있다.

쿠버네티스 클러스터는 물리 및 가상 머신 모두에 설치될 수 있다. 쿠버네티스 개발을 시작하려면 diff --git a/content/ko/docs/tutorials/kubernetes-basics/expose/expose-intro.html b/content/ko/docs/tutorials/kubernetes-basics/expose/expose-intro.html index 1c763fbd70..f8cf20216d 100644 --- a/content/ko/docs/tutorials/kubernetes-basics/expose/expose-intro.html +++ b/content/ko/docs/tutorials/kubernetes-basics/expose/expose-intro.html @@ -35,7 +35,7 @@ weight: 10

비록 각 파드들이 고유의 IP를 갖고 있기는 하지만, 그 IP들은 서비스의 도움없이 클러스터 외부로 노출되어질 수 없다. 서비스들은 여러분의 애플리케이션들에게 트래픽이 실릴 수 있도록 허용해준다. 서비스들은 ServiceSpec에서 type을 지정함으로써 다양한 방식들로 노출시킬 수 있다:

  • ClusterIP (기본값) - 클러스터 내에서 내부 IP 에 대해 서비스를 노출해준다. 이 방식은 오직 클러스터 내에서만 서비스가 접근될 수 있도록 해준다.
  • -
  • NodePort - NAT가 이용되는 클러스터 내에서 각각 선택된 노드들의 동일한 포트에 서비스를 노출시켜준다. <NodeIP>:<NodePort>를 이용하여 클러스터 외부로부터 서비스가 접근할 수 있도록 해준다. CluserIP의 상위 집합이다.
  • +
  • NodePort - NAT가 이용되는 클러스터 내에서 각각 선택된 노드들의 동일한 포트에 서비스를 노출시켜준다. <NodeIP>:<NodePort>를 이용하여 클러스터 외부로부터 서비스가 접근할 수 있도록 해준다. ClusterIP의 상위 집합이다.
  • LoadBalancer - (지원 가능한 경우) 기존 클라우드에서 외부용 로드밸런서를 생성하고 서비스에 고정된 공인 IP를 할당해준다. NodePort의 상위 집합이다.
  • ExternalName - 이름으로 CNAME 레코드를 반환함으로써 임의의 이름(스펙에서 externalName으로 명시)을 이용하여 서비스를 노출시켜준다. 프록시는 사용되지 않는다. 이 방식은 kube-dns 버전 1.7 이상에서 지원 가능하다.
diff --git a/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md b/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md index 71919aad75..1f419fdaf3 100644 --- a/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md +++ b/content/ko/docs/tutorials/stateful-application/mysql-wordpress-persistent-volume.md @@ -113,13 +113,13 @@ EOF 3. 두 파일을 `kustomization.yaml`에 추가하자. - ```shell - cat <>./kustomization.yaml - resources: - - mysql-deployment.yaml - - wordpress-deployment.yaml - EOF - ``` +```shell +cat <>./kustomization.yaml +resources: + - mysql-deployment.yaml + - wordpress-deployment.yaml +EOF +``` ## 적용하고 확인하기 `kustomization.yaml`은 WordPress 사이트와 MySQL 데이터베이스를 배포하는 모든 리소스를 포함한다. diff --git a/content/ko/examples/minikube/Dockerfile b/content/ko/examples/minikube/Dockerfile index 1fe745295a..dd58cb7e75 100644 --- a/content/ko/examples/minikube/Dockerfile +++ b/content/ko/examples/minikube/Dockerfile @@ -1,4 +1,4 @@ FROM node:6.14.2 EXPOSE 8080 COPY server.js . -CMD node server.js +CMD [ "node", "server.js" ] diff --git a/content/ko/examples/pods/pod-nginx.yaml b/content/ko/examples/pods/pod-nginx.yaml new file mode 100644 index 0000000000..134ddae2aa --- /dev/null +++ b/content/ko/examples/pods/pod-nginx.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Pod +metadata: + name: nginx + labels: + env: test +spec: + containers: + - name: nginx + image: nginx + imagePullPolicy: IfNotPresent + nodeSelector: + disktype: ssd diff --git a/content/ko/examples/pods/pod-with-node-affinity.yaml b/content/ko/examples/pods/pod-with-node-affinity.yaml new file mode 100644 index 0000000000..253d2b21ea --- /dev/null +++ b/content/ko/examples/pods/pod-with-node-affinity.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: with-node-affinity +spec: + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/e2e-az-name + operator: In + values: + - e2e-az1 + - e2e-az2 + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: another-node-label-key + operator: In + values: + - another-node-label-value + containers: + - name: with-node-affinity + image: k8s.gcr.io/pause:2.0 \ No newline at end of file diff --git a/content/ko/examples/pods/pod-with-pod-affinity.yaml b/content/ko/examples/pods/pod-with-pod-affinity.yaml new file mode 100644 index 0000000000..35e645ef1f --- /dev/null +++ b/content/ko/examples/pods/pod-with-pod-affinity.yaml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: Pod +metadata: + name: with-pod-affinity +spec: + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: security + operator: In + values: + - S1 + topologyKey: failure-domain.beta.kubernetes.io/zone + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: security + operator: In + values: + - S2 + topologyKey: failure-domain.beta.kubernetes.io/zone + containers: + - name: with-pod-affinity + image: k8s.gcr.io/pause:2.0 diff --git a/content/ko/includes/task-tutorial-prereqs.md b/content/ko/includes/task-tutorial-prereqs.md index 762d3210d7..70d2196773 100644 --- a/content/ko/includes/task-tutorial-prereqs.md +++ b/content/ko/includes/task-tutorial-prereqs.md @@ -1,5 +1,7 @@ -쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 통신할 수 있도록 설정되어 있어야 합니다. -만약, 클러스터를 이미 가지고 있지 않다면, [Minikube](/docs/setup/minikube)를 사용해서 만들거나, +쿠버네티스 클러스터가 필요하고, kubectl 커맨드-라인 툴이 클러스터와 +통신할 수 있도록 설정되어 있어야 합니다. +만약, 아직 클러스터를 가지고 있지 않다면, +[Minikube](/docs/setup/learning-environment/minikube/)를 사용해서 만들거나, 다음의 쿠버네티스 플레이그라운드 중 하나를 사용할 수 있습니다: * [Katacoda](https://www.katacoda.com/courses/kubernetes/playground) From 57cdc4cbabee2dd710a606c23c4115394359ee49 Mon Sep 17 00:00:00 2001 From: xieyanker Date: Sat, 15 Feb 2020 14:31:27 +0800 Subject: [PATCH 05/38] hidden original annotation (#19126) --- content/zh/docs/concepts/containers/images.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/content/zh/docs/concepts/containers/images.md b/content/zh/docs/concepts/containers/images.md index 654512ad45..d0cf178b3e 100644 --- a/content/zh/docs/concepts/containers/images.md +++ b/content/zh/docs/concepts/containers/images.md @@ -618,6 +618,7 @@ common use cases and suggested solutions. - 使用 Docker hub 上的公有镜像 - 无需配置 - 在 GCE/GKE 上会自动使用高稳定性和高速的 Docker hub 的本地 mirror + -上述例子使用到的 `effect` 的一个值 `NoSchedule`,您也可以使用另外一个值 `PreferNoSchedule`。这是“优化”或“软”版本的 `NoSchedule` ——系统会*尽量*避免将 pod 调度到存在其不能容忍 taint 的节点上,但这不是强制的。`effect` 的值还可以设置为 `NoExecute` ,下文会详细描述这个值。 +上述例子使用到的 `effect` 的一个值 `NoSchedule`,您也可以使用另外一个值 `PreferNoSchedule`。这是“优化”或“软”版本的 `NoSchedule` ——系统会 *尽量* 避免将 pod 调度到存在其不能容忍 taint 的节点上,但这不是强制的。`effect` 的值还可以设置为 `NoExecute` ,下文会详细描述这个值。 * 如果未被过滤的 taint 中存在一个以上 effect 值为 `NoSchedule` 的 taint,则 Kubernetes 不会将 pod 分配到该节点。 -* 如果未被过滤的 taint 中不存在 effect 值为 `NoSchedule` 的 taint,但是存在 effect 值为 `PreferNoSchedule` 的 taint,则 Kubernetes 会*尝试*将 pod 分配到该节点。 +* 如果未被过滤的 taint 中不存在 effect 值为 `NoSchedule` 的 taint,但是存在 effect 值为 `PreferNoSchedule` 的 taint,则 Kubernetes 会 *尝试* 将 pod 分配到该节点。 * 如果未被过滤的 taint 中存在一个以上 effect 值为 `NoExecute` 的 taint,则 Kubernetes 不会将 pod 分配到该节点(如果 pod 还未在节点上运行),或者将 pod 从该节点驱逐(如果 pod 已经在节点上运行)。 -通过 taint 和 toleration ,可以灵活地让 pod *避开*某些节点或者将 pod 从某些节点驱逐。下面是几个使用例子: +通过 taint 和 toleration ,可以灵活地让 pod *避开* 某些节点或者将 pod 从某些节点驱逐。下面是几个使用例子: 前文我们提到过 taint 的 effect 值 `NoExecute` ,它会影响已经在节点上运行的 pod + * 如果 pod 不能忍受effect 值为 `NoExecute` 的 taint,那么 pod 将马上被驱逐 * 如果 pod 能够忍受effect 值为 `NoExecute` 的 taint,但是在 toleration 定义中没有指定 `tolerationSeconds`,则 pod 还会一直在这个节点上运行。 * 如果 pod 能够忍受effect 值为 `NoExecute` 的 taint,而且指定了 `tolerationSeconds`,则 pod 还能在这个节点上继续运行这个指定的时间长度。 @@ -350,7 +351,7 @@ behavior of pod evictions due to node problems, the system actually adds the tai in a rate-limited way. This prevents massive pod evictions in scenarios such as the master becoming partitioned from the nodes. --> -注意:为了保证由于节点问题引起的 pod 驱逐[rate limiting](/docs/concepts/architecture/nodes/)行为正常,系统实际上会以 rate-limited 的方式添加 taint。在像 master 和 node 通讯中断等场景下,这避免了 pod 被大量驱逐。 +为了保证由于节点问题引起的 pod 驱逐[rate limiting](/docs/concepts/architecture/nodes/)行为正常,系统实际上会以 rate-limited 的方式添加 taint。在像 master 和 node 通讯中断等场景下,这避免了 pod 被大量驱逐。 {{< /note >}} +### 标签页演示:内联 Markdown 和 HTML ```go-html-template {{}} {{% tab name="Markdown" %}} -This is **some markdown.** -{{< note >}}**Note:** It can even contain shortcodes.{{< /note >}} +这是 **一些 markdown 。** +{{< note >}}它甚至可以包含短代码。{{< /note >}} {{% /tab %}} {{< tab name="HTML" >}}
-

Plain HTML

-

This is some plain HTML.

+

纯 HTML

+

这是一些 HTML 。

{{< /tab >}} {{< /tabs */>}} @@ -223,13 +224,13 @@ This is **some markdown.** {{< tabs name="tab_with_md" >}} {{% tab name="Markdown" %}} -This is **some markdown.** -{{< note >}}**Note:** It can even contain shortcodes.{{< /note >}} +这是 **一些 markdown 。** +{{< note >}}它甚至可以包含短代码。{{< /note >}} {{% /tab %}} {{< tab name="HTML" >}}
-

Plain HTML

-

This is some plain HTML.

+

纯 HTML

+

这是一些 HTML 。

{{< /tab >}} {{< /tabs >}} From 044abec93e385ffa7dcb40a8f3a8eb70e4163e49 Mon Sep 17 00:00:00 2001 From: chentanjun <2799194073@qq.com> Date: Mon, 17 Feb 2020 13:13:28 +0800 Subject: [PATCH 14/38] update zh-trans content/zh/docs/concepts/policy/resource-quotas.md (#19037) --- .../docs/concepts/policy/resource-quotas.md | 851 ++++++++++++++++-- 1 file changed, 760 insertions(+), 91 deletions(-) diff --git a/content/zh/docs/concepts/policy/resource-quotas.md b/content/zh/docs/concepts/policy/resource-quotas.md index 08e6a07f83..1e00115344 100644 --- a/content/zh/docs/concepts/policy/resource-quotas.md +++ b/content/zh/docs/concepts/policy/resource-quotas.md @@ -4,115 +4,362 @@ approvers: title: 资源配额 --- -当多个用户或团队共享具有固定数目节点的集群时,人们会担心有人使用的资源超出应有的份额。 + +{{% capture overview %}} + + +当多个用户或团队共享具有固定节点数目的集群时,人们会担心有人使用超过其基于公平原则所分配到的资源量。 + + 资源配额是帮助管理员解决这一问题的工具。 -资源配额, 通过 `ResourceQuota` 对象来定义, 对每个namespace的资源消耗总量提供限制。 它可以按类型限制namespace下可以创建的对象的数量,也可以限制可被该项目以资源形式消耗的计算资源的总量。 +{{% /capture %}} + +{{% capture body %}} + + +资源配额,通过 `ResourceQuota` 对象来定义,对每个命名空间的资源消耗总量提供限制。它可以限制命名空间中某种类型的对象的总数目上限,也可以限制命令空间中的 Pod 可以使用的计算资源的总上限。 + + 资源配额的工作方式如下: -- 不同的团队在不同的namespace下工作。 目前这是自愿的, 但计划通过ACL (Access Control List 访问控制列表) - 使其变为强制性的。 -- 管理员为每个namespace创建一个或多个资源配额对象。 -- 用户在namespace下创建资源 (pods、 services等),同时配额系统会跟踪使用情况,来确保其不超过 - 资源配额中定义的硬性资源限额。 -- 如果资源的创建或更新违反了配额约束,则请求会失败,并返回 HTTP状态码 `403 FORBIDDEN` ,以及说明违反配额 - 约束的信息。 -- 如果namespace下的计算资源 (如 `cpu` 和 `memory`)的配额被启用,则用户必须为这些资源设定请求值(request) - 和约束值(limit),否则配额系统将拒绝Pod的创建。 - 提示: 可使用 LimitRange 准入控制器来为没有设置计算资源需求的Pod设置默认值。 - 作为示例,请参考 [演练](/docs/tasks/administer-cluster/quota-memory-cpu-namespace/) 来避免这个问题。 + +- 不同的团队可以在不同的命名空间下工作,目前这是非约束性的,在未来的版本中可能会通过 ACL (Access Control List 访问控制列表) 来实现强制性约束。 +- 集群管理员可以为每个命名空间创建一个或多个资源配额对象。 +- 当用户在命名空间下创建资源(如 Pod、Service 等)时,Kubernetes 的配额系统会跟踪集群的资源使用情况,以确保使用的资源用量不超过资源配额中定义的硬性资源限额。 +- 如果资源创建或者更新请求违反了配额约束,那么该请求会报错(HTTP 403 FORBIDDEN),并在消息中给出有可能违反的约束。 +- 如果命名空间下的计算资源 (如 `cpu` 和 `memory`)的配额被启用,则用户必须为这些资源设定请求值(request)和约束值(limit),否则配额系统将拒绝 Pod 的创建。 + 提示: 可使用 `LimitRanger` 准入控制器来为没有设置计算资源需求的 Pod 设置默认值。 + 若想避免这类问题,请参考[演练](/docs/tasks/administer-cluster/quota-memory-cpu-namespace/)中的示例。 -下面是使用namespace和配额构建策略的示例: + +下面是使用命名空间和配额构建策略的示例: -- 在具有 32 GiB 内存 和 16 核CPU资源的集群中, 允许A团队使用 20 GiB 内存 和 10 核的CPU资源, - 允许B团队使用 10GiB 内存和 4 核的CPU资源, 并且预留 2GiB 内存和 2 核的CPU资源供将来分配。 -- 限制 "testing" namespace使用 1 核CPU资源和 1GiB 内存。 允许 "production" namespace使用任意数量。 + +- 在具有 32 GiB 内存和 16 核 CPU 资源的集群中,允许 A 团队使用 20 GiB 内存 和 10 核的 CPU 资源,允许 B 团队使用 10 GiB 内存和 4 核的 CPU 资源,并且预留 2 GiB 内存和 2 核的 CPU 资源供将来分配。 +- 限制 "testing" 命名空间使用 1 核 CPU 资源和 1GiB 内存。允许 "production" 命名空间使用任意数量。 -在集群容量小于各namespace配额总和的情况下,可能存在资源竞争。 Kubernetes采用先到先服务的方式处理这类问题。 + +在集群容量小于各命名空间配额总和的情况下,可能存在资源竞争。资源竞争时,Kubernetes 系统会遵循先到先得的原则。 -无论是资源竞争还是配额的变更都不会影响已经创建的资源。 + +不管是资源竞争还是配额的修改,都不会影响已经创建的资源使用对象。 + ## 启用资源配额 -资源配额的支持在很多Kubernetes版本中是默认开启的。 当 apiserver 的 -`--admission-control=` 参数中包含 `ResourceQuota` 时,资源配额会被启用。 + +资源配额的支持在很多 Kubernetes 版本中是默认开启的。当 apiserver `--enable-admission-plugins=` 参数中包含 `ResourceQuota` 时,资源配额会被启用。 -当namespace中存在一个 `ResourceQuota` 对象时,该namespace即开始实施资源配额管理。 -一个namespace中最多只应存在一个 `ResourceQuota` 对象 + +当命名空间中存在一个 `ResourceQuota` 对象时,对于该命名空间而言,资源配额就是开启的。 + ## 计算资源配额 -用户可以对给定namespace下的 [计算资源](/docs/user-guide/compute-resources) 总量进行限制。 + +用户可以对给定命名空间下的可被请求的[计算资源](/docs/user-guide/compute-resources)总量进行限制。 + 配额机制所支持的资源类型: + | 资源名称 | 描述 | | --------------------- | ----------------------------------------------------------- | -| `cpu` | 所有非终止状态的Pod中,其CPU需求总量不能超过该值。 | -| `limits.cpu` | 所有非终止状态的Pod中,其CPU限额总量不能超过该值。 | -| `limits.memory` | 所有非终止状态的Pod中,其内存限额总量不能超过该值。 | -| `memory` | 所有非终止状态的Pod中,其内存需求总量不能超过该值。 | -| `requests.cpu` | 所有非终止状态的Pod中,其CPU需求总量不能超过该值。 | -| `requests.memory` | 所有非终止状态的Pod中,其内存需求总量不能超过该值。 | +| `limits.cpu` | 所有非终止状态的 Pod,其 CPU 限额总量不能超过该值。 | +| `limits.memory` | 所有非终止状态的 Pod,其内存限额总量不能超过该值。 | +| `requests.cpu` | 所有非终止状态的 Pod,其 CPU 需求总量不能超过该值。 | +| `requests.memory` | 所有非终止状态的 Pod,其内存需求总量不能超过该值。 | + +### 扩展资源的资源配额 + + +除上述资源外,在 Kubernetes 1.10 版本中,还添加了对[扩展资源](/docs/concepts/configuration/manage-compute-resources-container/#extended-resources)的支持。 + + +由于扩展资源不可超量分配,因此没有必要在配额中为同一扩展资源同时指定 `requests` 和 `limits`。对于扩展资源而言,目前仅允许使用前缀为 `requests.` 的配额项。 + + +以 GPU 拓展资源为例,如果资源名称为 `nvidia.com/gpu`,并且要将命名空间中请求的 GPU 资源总数限制为 4,则可以如下定义配额: + +* `requests.nvidia.com/gpu: 4` + + +有关更多详细信息,请参阅[查看和设置配额](#viewing-and-setting-quotas)。 + + ## 存储资源配额 -用户可以对给定namespace下的 [存储资源](/docs/user-guide/persistent-volumes) 总量进行限制。 + +用户可以对给定命名空间下的[存储资源](/docs/user-guide/persistent-volumes)总量进行限制。 + 此外,还可以根据相关的存储类(Storage Class)来限制存储资源的消耗。 + | 资源名称 | 描述 | | --------------------- | ----------------------------------------------------------- | -| `requests.storage` | 所有的PVC中,存储资源的需求不能超过该值。 | -| `persistentvolumeclaims` | namespace中所允许的 [PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims) 总量。 | -| `.storageclass.storage.k8s.io/requests.storage` | 所有该storage-class-name相关的PVC中, 存储资源的需求不能超过该值。 | -| `.storageclass.storage.k8s.io/persistentvolumeclaims` | namespace中所允许的该storage-class-name相关的[PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims)的总量。 | +| `requests.storage` | 所有 PVC,存储资源的需求总量不能超过该值。 | +| `persistentvolumeclaims` | 在该命名空间中所允许的 [PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims) 总量。 | +| `.storageclass.storage.k8s.io/requests.storage` | 在所有与 storage-class-name 相关的持久卷声明中,存储请求的总和不能超过该值。 | +| `.storageclass.storage.k8s.io/persistentvolumeclaims` | 在与 storage-class-name 相关的所有持久卷声明中,命名空间中可以存在的[持久卷声明](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims)总数。 | -例如,如果一个操作人员针对 "黄金" 存储类型与 "铜" 存储类型设置配额,操作员可以 -定义配额如下: + +例如,如果一个操作人员针对 `gold` 存储类型与 `bronze` 存储类型设置配额,操作人员可以定义如下配额: * `gold.storageclass.storage.k8s.io/requests.storage: 500Gi` * `bronze.storageclass.storage.k8s.io/requests.storage: 100Gi` + +在 Kubernetes 1.8 版本中,本地临时存储的配额支持已经是 Alpha 功能: + + +| 资源名称 | 描述 | +| ------------------------------- |----------------------------------------------------------- | +| `requests.ephemeral-storage` | 在命名空间的所有 Pod 中,本地临时存储请求的总和不能超过此值。 | +| `limits.ephemeral-storage` | 在命名空间的所有 Pod 中,本地临时存储限制值的总和不能超过此值。 | + + ## 对象数量配额 -给定类型的对象数量可以被限制。 支持以下类型: + +Kubernetes 1.9 版本增加了使用以下语法对所有标准的、命名空间域的资源类型进行配额设置的支持。 +* `count/.` + + +这是用户可能希望利用对象计数配额来管理的一组资源示例。 + +* `count/persistentvolumeclaims` +* `count/services` +* `count/secrets` +* `count/configmaps` +* `count/replicationcontrollers` +* `count/deployments.apps` +* `count/replicasets.apps` +* `count/statefulsets.apps` +* `count/jobs.batch` +* `count/cronjobs.batch` +* `count/deployments.extensions` + + +Kubernetes 1.15 版本增加了对使用相同语法来约束自定义资源的支持。 +例如,要对 `example.com` API 组中的自定义资源 `widgets` 设置配额,请使用 `count/widgets.example.com`。 + + + +当使用 `count/*` 资源配额时,如果对象存在于服务器存储中,则会根据配额管理资源。 +这些类型的配额有助于防止存储资源耗尽。例如,用户可能想根据服务器的存储能力来对服务器中 Secret 的数量进行配额限制。集群中存在过多的 Secret 实际上会导致服务器和控制器无法启动!用户可以选择对 Job 进行配额管理,以防止配置不当的 CronJob 在某命名空间中创建太多作业而导致集群拒绝服务。 + + + +在 Kubernetes 1.9 版本之前,可以在有限的一组资源上实施一般性的对象数量配额。 +此外,还可以进一步按资源的类型设置其配额。 + + +支持以下类型: + + | 资源名称 | 描述 | | ------------------------------- | ------------------------------------------------- | -| `configmaps` | namespace下允许存在的configmap的数量。 | -| `persistentvolumeclaims` | namespace下允许存在的[PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims)的数量。 | -| `pods` | namespace下允许存在的非终止状态的pod数量。 如果pod 的 `status.phase 为 Failed 或 Succeeded` , 那么其处于终止状态。 | -| `replicationcontrollers` | namespace下允许存在的replication controllers的数量。 | -| `resourcequotas` | namespace下允许存在的 [resource quotas](/docs/admin/admission-controllers/#resourcequota) 的数量。 | -| `services` | namespace下允许存在的service的数量。 | -| `services.loadbalancers` | namespace下允许存在的load balancer类型的service的数量。 | -| `services.nodeports` | namespace下允许存在的node port类型的service的数量。 | -| `secrets` | namespace下允许存在的secret的数量。 | +| `configmaps` | 在该命名空间中允许存在的 ConfigMap 总数上限。 | +| `persistentvolumeclaims` | 在该命名空间中允许存在的 [PVC](/docs/user-guide/persistent-volumes/#persistentvolumeclaims) 的总数上限。 | +| `pods` | 在该命名空间中允许存在的非终止状态的 pod 总数上限。Pod 终止状态等价于 Pod 的 `.status.phase in (Failed, Succeeded)` = true | +| `replicationcontrollers` | 在该命名空间中允许存在的 RC 总数上限。 | +| `resourcequotas` | 在该命名空间中允许存在的[资源配额](/docs/admin/admission-controllers/#resourcequota)总数上限。 | +| `services` | 在该命名空间中允许存在的 Service 总数上限。 | +| `services.loadbalancers` | 在该命名空间中允许存在的 LoadBalancer 类型的服务总数上限。 | +| `services.nodeports` | 在该命名空间中允许存在的 NodePort 类型的服务总数上限。 | +| `secrets` | 在该命名空间中允许存在的 Secret 总数上限。 | -例如 `pods` 配额统计并保证单个namespace下创建 `pods` 的最大数量。 - -用户可能希望在namespace中为pod设置配额,来避免有用户创建很多小的pod,从而耗尽集群提供的pod IP地址。 + +例如,`pods` 配额统计某个命名空间中所创建的、非终止状态的 `Pod` 个数并确保其不超过某上限值。用户可能希望在某命名空间中设置 `pods` 配额,以避免有用户创建很多小的 Pod,从而耗尽集群所能提供的 Pod IP 地址。 + ## 配额作用域 -每个配额都有一组相关的作用域(scope),配额只会对作用域内的资源生效。 + +每个配额都有一组相关的作用域(scope),配额只会对作用域内的资源生效。配额机制仅统计所列举的作用域的交集中的资源用量。 + 当一个作用域被添加到配额中后,它会对作用域相关的资源数量作限制。 如配额中指定了允许(作用域)集合之外的资源,会导致验证错误。 -| 范围 | 描述 | + +| 作用域 | 描述 | +| ----- | ----------- | +| `Terminating` | 匹配所有 `spec.activeDeadlineSeconds` 不小于 0 的 Pod。 | +| `NotTerminating` | 匹配所有 `spec.activeDeadlineSeconds` 是 nil 的 Pod。 | +| `BestEffort` | 匹配所有 Qos 是 BestEffort 的 Pod。 | +| `NotBestEffort` | 匹配所有 Qos 不是 BestEffort 的 Pod。 | -`BestEffort` 作用域限制配额跟踪以下资源: `pods` + +`BestEffort` 作用域限制配额跟踪以下资源:`pods` -`Terminating`、 `NotTerminating` 和 `NotBestEffort` 限制配额跟踪以下资源: + +`Terminating`、`NotTerminating` 和 `NotBestEffort` 这三种作用域限制配额跟踪以下资源: * `cpu` * `limits.cpu` @@ -122,36 +369,285 @@ title: 资源配额 * `requests.cpu` * `requests.memory` -## 请求/约束 + +### 基于优先级类(PriorityClass)来设置资源配额 -分配计算资源时,每个容器可以为CPU或内存指定请求和约束。 -也可以设置两者中的任何一个。 +{{< feature-state for_k8s_version="1.12" state="beta" >}} -如果配额中指定了 `requests.cpu` 或 `requests.memory` 的值,那么它要求每个进来的容器针对这些资源有明确的请求。 如果配额中指定了 `limits.cpu` 或 `limits.memory`的值,那么它要求每个进来的容器针对这些资源指定明确的约束。 + +Pod 可以创建为特定的[优先级](/docs/concepts/configuration/pod-priority-preemption/#pod-priority)。 +通过使用配额规约中的 `scopeSelector` 字段,用户可以根据 Pod 的优先级控制其系统资源消耗。 -## 查看和设置配额 + +仅当配额规范中的 `scopeSelector` 字段选择到某 Pod 时,配额机制才会匹配和计量 Pod 的资源消耗。 + +本示例创建一个配额对象,并将其与具有特定优先级的 Pod 进行匹配。 +该示例的工作方式如下: + + +- 集群中的 Pod 可取三个优先级类之一,即 "low"、"medium"、"high"。 +- 为每个优先级创建一个配额对象。 + + +将以下 YAML 保存到文件 `quota.yml` 中。 + +```yaml +apiVersion: v1 +kind: List +items: +- apiVersion: v1 + kind: ResourceQuota + metadata: + name: pods-high + spec: + hard: + cpu: "1000" + memory: 200Gi + pods: "10" + scopeSelector: + matchExpressions: + - operator : In + scopeName: PriorityClass + values: ["high"] +- apiVersion: v1 + kind: ResourceQuota + metadata: + name: pods-medium + spec: + hard: + cpu: "10" + memory: 20Gi + pods: "10" + scopeSelector: + matchExpressions: + - operator : In + scopeName: PriorityClass + values: ["medium"] +- apiVersion: v1 + kind: ResourceQuota + metadata: + name: pods-low + spec: + hard: + cpu: "5" + memory: 10Gi + pods: "10" + scopeSelector: + matchExpressions: + - operator : In + scopeName: PriorityClass + values: ["low"] +``` + + +使用 `kubectl create` 命令运行以下操作。 + +```shell +kubectl create -f ./quota.yml +``` + +```shell +resourcequota/pods-high created +resourcequota/pods-medium created +resourcequota/pods-low created +``` + + +使用 `kubectl describe quota` 操作验证配额的 `Used` 值为 `0`。 + +```shell +kubectl describe quota +``` + +```shell +Name: pods-high +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 1k +memory 0 200Gi +pods 0 10 + + +Name: pods-low +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 5 +memory 0 10Gi +pods 0 10 + + +Name: pods-medium +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 10 +memory 0 20Gi +pods 0 10 +``` + + +创建优先级为 "high" 的 Pod。 +将以下 YAML 保存到文件 `high-priority-pod.yml` 中。 + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: high-priority +spec: + containers: + - name: high-priority + image: ubuntu + command: ["/bin/sh"] + args: ["-c", "while true; do echo hello; sleep 10;done"] + resources: + requests: + memory: "10Gi" + cpu: "500m" + limits: + memory: "10Gi" + cpu: "500m" + priorityClassName: high +``` + + +使用 `kubectl create` 运行以下操作。 + +```shell +kubectl create -f ./high-priority-pod.yml +``` + + +确认 "high" 优先级配额 `pods-high` 的 "Used" 统计信息已更改,并且其他两个配额未更改。 + +```shell +kubectl describe quota +``` + +```shell +Name: pods-high +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 500m 1k +memory 10Gi 200Gi +pods 1 10 + + +Name: pods-low +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 5 +memory 0 10Gi +pods 0 10 + + +Name: pods-medium +Namespace: default +Resource Used Hard +-------- ---- ---- +cpu 0 10 +memory 0 20Gi +pods 0 10 +``` + + +`scopeSelector` 在 `operator` 字段中支持以下值: + +* `In` +* `NotIn` +* `Exist` +* `DoesNotExist` + + +## 请求与限制 + + +分配计算资源时,每个容器可以为 CPU 或内存指定请求和约束。 +配额可以针对二者之一进行设置。 + + +如果配额中指定了 `requests.cpu` 或 `requests.memory` 的值,则它要求每个容器都显式给出对这些资源的请求。同理,如果配额中指定了 `limits.cpu` 或 `limits.memory` 的值,那么它要求每个容器都显式设定对应资源的限制。 + + +## 查看和设置配额 {#viewing-and-setting-quotas} + + Kubectl 支持创建、更新和查看配额: ```shell -$ kubectl create namespace myspace +kubectl create namespace myspace +``` -$ cat < compute-resources.yaml +```shell +cat < compute-resources.yaml apiVersion: v1 kind: ResourceQuota metadata: name: compute-resources spec: hard: - pods: "4" requests.cpu: "1" requests.memory: 1Gi limits.cpu: "2" limits.memory: 2Gi + requests.nvidia.com/gpu: 4 EOF -$ kubectl create -f ./compute-resources.yaml --namespace=myspace +``` -$ cat < object-counts.yaml +```shell +kubectl create -f ./compute-resources.yaml --namespace=myspace +``` + +```shell +cat < object-counts.yaml apiVersion: v1 kind: ResourceQuota metadata: @@ -160,61 +656,234 @@ spec: hard: configmaps: "10" persistentvolumeclaims: "4" + pods: "4" replicationcontrollers: "20" secrets: "10" services: "10" services.loadbalancers: "2" EOF -$ kubectl create -f ./object-counts.yaml --namespace=myspace +``` -$ kubectl get quota --namespace=myspace +```shell +kubectl create -f ./object-counts.yaml --namespace=myspace +``` + +```shell +kubectl get quota --namespace=myspace +``` + +```shell NAME AGE compute-resources 30s object-counts 32s +``` -$ kubectl describe quota compute-resources --namespace=myspace -Name: compute-resources -Namespace: myspace -Resource Used Hard --------- ---- ---- -limits.cpu 0 2 -limits.memory 0 2Gi -pods 0 4 -requests.cpu 0 1 -requests.memory 0 1Gi +```shell +kubectl describe quota compute-resources --namespace=myspace +``` -$ kubectl describe quota object-counts --namespace=myspace +```shell +Name: compute-resources +Namespace: myspace +Resource Used Hard +-------- ---- ---- +limits.cpu 0 2 +limits.memory 0 2Gi +requests.cpu 0 1 +requests.memory 0 1Gi +requests.nvidia.com/gpu 0 4 +``` + +```shell +kubectl describe quota object-counts --namespace=myspace +``` + +```shell Name: object-counts Namespace: myspace Resource Used Hard -------- ---- ---- configmaps 0 10 persistentvolumeclaims 0 4 +pods 0 4 replicationcontrollers 0 20 secrets 1 10 services 0 10 services.loadbalancers 0 2 ``` + +kubectl 还使用语法 `count/.` 支持所有标准的、命名空间域的资源的对象计数配额: + +```shell +kubectl create namespace myspace +``` + +```shell +kubectl create quota test --hard=count/deployments.extensions=2,count/replicasets.extensions=4,count/pods=3,count/secrets=4 --namespace=myspace +``` + +```shell +kubectl run nginx --image=nginx --replicas=2 --namespace=myspace +``` + +```shell +kubectl describe quota --namespace=myspace +``` + +```shell +Name: test +Namespace: myspace +Resource Used Hard +-------- ---- ---- +count/deployments.extensions 1 2 +count/pods 2 3 +count/replicasets.extensions 1 4 +count/secrets 1 4 +``` + + ## 配额和集群容量 -配额对象是独立于集群容量的。它们通过绝对的单位来表示。 所以,为集群添加节点, *不会* -自动赋予每个namespace消耗更多资源的能力。 + +资源配额与集群资源总量是完全独立的。它们通过绝对的单位来配置。所以,为集群添加节点时,资源配额*不会*自动赋予每个命名空间消耗更多资源的能力。 -有时可能需要更复杂的策略,比如: + +有时可能需要资源配额支持更复杂的策略,比如: + - 在几个团队中按比例划分总的集群资源。 - - 允许每个租户根据需要增加资源使用量,但要有足够的限制以防止意外资源耗尽。 - - 在namespace中添加节点、提高配额的额外需求。 + - 允许每个租户根据需要增加资源使用量,但要有足够的限制以防止资源意外耗尽。 + - 探测某个命名空间的需求,添加物理节点并扩大资源配额值。 -这些策略可以基于 ResourceQuota,通过编写一个检测配额使用,并根据其他信号调整各namespace下的配额硬性限制的 "控制器" 来实现。 + +这些策略可以通过将资源配额作为一个组成模块、手动编写一个控制器来监控资源使用情况,并结合其他信号调整命名空间上的硬性资源配额来实现。 -注意:资源配额对集群资源总体进行划分,但它对节点没有限制:来自多个namespace的Pod可能在同一节点上运行。 + +注意:资源配额对集群资源总体进行划分,但它对节点没有限制:来自不同命名空间的 Pod 可能在同一节点上运行。 + +## 默认情况下限制特定优先级的资源消耗 + + +有时候可能希望当且仅当某名字空间中存在匹配的配额对象时,才可以创建特定优先级(例如 "cluster-services")的 Pod。 + + +通过这种机制,操作人员能够将限制某些高优先级类仅出现在有限数量的命名空间中,而并非每个命名空间默认情况下都能够使用这些优先级类。 + + +要实现此目的,应使用 kube-apiserver 标志 `--admission-control-config-file` 传递如下配置文件的路径: + +{{< tabs name="example1" >}} +{{% tab name="apiserver.config.k8s.io/v1" %}} +```yaml +apiVersion: apiserver.config.k8s.io/v1 +kind: AdmissionConfiguration +plugins: +- name: "ResourceQuota" + configuration: + apiVersion: apiserver.config.k8s.io/v1 + kind: ResourceQuotaConfiguration + limitedResources: + - resource: pods + matchScopes: + - scopeName: PriorityClass + operator: In + values: ["cluster-services"] +``` +{{% /tab %}} +{{% tab name="apiserver.k8s.io/v1alpha1" %}} +```yaml +# 在 Kubernetes 1.17 中已不被推荐使用,请使用 apiserver.config.k8s.io/v1 +apiVersion: apiserver.k8s.io/v1alpha1 +kind: AdmissionConfiguration +plugins: +- name: "ResourceQuota" + configuration: + # 在 Kubernetes 1.17 中已不被推荐使用,请使用 apiserver.config.k8s.io/v1, ResourceQuotaConfiguration + apiVersion: resourcequota.admission.k8s.io/v1beta1 + kind: Configuration + limitedResources: + - resource: pods + matchScopes: + - scopeName: PriorityClass + operator: In + values: ["cluster-services"] +``` +{{% /tab %}} +{{< /tabs >}} + + +现在,仅当命名空间中存在匹配的 `scopeSelector` 的配额对象时,才允许使用 "cluster-services" Pod。 + + +示例: + +```yaml + scopeSelector: + matchExpressions: + - scopeName: PriorityClass + operator: In + values: ["cluster-services"] +``` + + +有关更多信息,请参见 [LimitedResources](https://github.com/kubernetes/kubernetes/pull/36765) 和[优先级类配额支持的设计文档](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/scheduling/pod-priority-resourcequota.md)。 + + ## 示例 -查看 [如何使用资源配额的详细示例](/docs/tasks/administer-cluster/quota-api-object/)。 + +查看[如何使用资源配额的详细示例](/docs/tasks/administer-cluster/quota-api-object/)。 -## 更多信息 +{{% /capture %}} -查看 [资源配额设计文档](https://git.k8s.io/community/contributors/design-proposals/resource-management/admission_control_resource_quota.md) 了解更多信息。 +{{% capture whatsnext %}} + + +查看[资源配额设计文档](https://git.k8s.io/community/contributors/design-proposals/resource-management/admission_control_resource_quota.md)了解更多信息。 + +{{% /capture %}} From 751cabbb73d11f9ecd84977274068cdaba7482d1 Mon Sep 17 00:00:00 2001 From: Kirk Larkin <6025110+serpent5@users.noreply.github.com> Date: Mon, 17 Feb 2020 10:05:28 +0000 Subject: [PATCH 15/38] A few tweaks to wording (#19136) Just a few tweaks where words were missing, etc. --- content/en/docs/concepts/architecture/nodes.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/en/docs/concepts/architecture/nodes.md b/content/en/docs/concepts/architecture/nodes.md index cb5b78d55e..0b740ad46c 100644 --- a/content/en/docs/concepts/architecture/nodes.md +++ b/content/en/docs/concepts/architecture/nodes.md @@ -30,7 +30,7 @@ A node's status contains the following information: * [Capacity and Allocatable](#capacity) * [Info](#info) -Node status and other details about a node can be displayed using below command: +Node status and other details about a node can be displayed using the following command: ```shell kubectl describe node ``` @@ -188,7 +188,7 @@ a Lease object. In Kubernetes 1.4, we updated the logic of the node controller to better handle cases when a large number of nodes have problems with reaching the master -(e.g. because the master has networking problem). Starting with 1.4, the node +(e.g. because the master has networking problems). Starting with 1.4, the node controller looks at the state of all nodes in the cluster when making a decision about pod eviction. @@ -212,9 +212,9 @@ there is only one availability zone (the whole cluster). A key reason for spreading your nodes across availability zones is so that the workload can be shifted to healthy zones when one entire zone goes down. -Therefore, if all nodes in a zone are unhealthy then node controller evicts at -the normal rate `--node-eviction-rate`. The corner case is when all zones are -completely unhealthy (i.e. there are no healthy nodes in the cluster). In such +Therefore, if all nodes in a zone are unhealthy then the node controller evicts at +the normal rate of `--node-eviction-rate`. The corner case is when all zones are +completely unhealthy (i.e. there are no healthy nodes in the cluster). In such a case, the node controller assumes that there's some problem with master connectivity and stops all evictions until some connectivity is restored. From f7c02fd4c953bc830a6d03c4da80bc1a4b4acba7 Mon Sep 17 00:00:00 2001 From: Zach Corleissen Date: Mon, 17 Feb 2020 02:19:28 -0800 Subject: [PATCH 16/38] Prune Bradamant3 from permissions (#19084) --- OWNERS_ALIASES | 3 --- 1 file changed, 3 deletions(-) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 9a44dddfb3..bf898fed46 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -40,7 +40,6 @@ aliases: - mkorbi - rlenferink sig-docs-en-owners: # Admins for English content - - bradamant3 - bradtopol - daminisatya - gochist @@ -57,7 +56,6 @@ aliases: - zacharysarah - zparnold sig-docs-en-reviews: # PR reviews for English content - - bradamant3 - bradtopol - daminisatya - gochist @@ -159,7 +157,6 @@ aliases: - seokho-son - ysyukr sig-docs-maintainers: # Website maintainers - - bradamant3 - jimangel - kbarnard10 - pwittrock From bc6cb17bb739b6203217f96103afc331e695fd73 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Mon, 17 Feb 2020 18:47:29 +0300 Subject: [PATCH 17/38] Translate Start contributing page into Russian (#19124) --- content/ru/docs/contribute/start.md | 233 ++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 content/ru/docs/contribute/start.md diff --git a/content/ru/docs/contribute/start.md b/content/ru/docs/contribute/start.md new file mode 100644 index 0000000000..c6149d60a2 --- /dev/null +++ b/content/ru/docs/contribute/start.md @@ -0,0 +1,233 @@ +--- +title: Start contributing +slug: start +content_template: templates/concept +weight: 10 +card: + name: contribute + weight: 10 +--- + +{{% capture overview %}} + +Если вы хотите поучаствовать в работе над документацией Kubernetes, эта страница и связанные с ней темы могут помочь вам начать работу. Вам не нужно быть разработчиком или техническим писателем, чтобы внести вклад в документацию или улучшить сайт Kubernetes! Все, что вам нужно для тем на этой странице, это учетная запись на GitHub и браузер. + +Если вы ищете информацию про участие в репозиториях, связанным с кодом Kubernetes, обратитесь к [руководству сообщества Kubernetes](https://github.com/kubernetes/community/blob/master/governance.md). + +{{% /capture %}} + + +{{% capture body %}} + +## Основные сведения про документацию + +Документация Kubernetes написана на Markdown, обработана и развернута при помощи Hugo. Исходные файлы находятся на GitHub по адресу https://github.com/kubernetes/website. Основная часть документации хранится в директории `/content/en/docs/`. Часть справочной документации автоматически генерируется из скриптов в директории `update-imported-docs/`. + +Вы можете создавать новые задачи, редактировать содержимое и проверять изменения от других участников, — всё это доступно с сайта GitHub. Вы также можете использовать встроенный в GitHub поиск и историю коммитов. + +Не все задачи могут быть выполнены на GitHub, поэтому они обсуждаются в [intermediate](/docs/contribute/intermediate/) and +[advanced](/docs/contribute/advanced/) docs contribution guides. + +### Участие в документации SIG + +Документация Kubernetes поддерживается {{< glossary_tooltip text="специальной группой" term_id="sig" >}} (Special Interest Group, SIG) под названием SIG Docs. Мы [общаемся](#participate-in-sig-docs-discussions) с помощью канала Slack, списка рассылки и еженедельных видеозвонков. Будем рады новым участникам. Для получения дополнительной информации обратитесь к странице [Participating in SIG Docs](/docs/contribute/participating/). + +### Руководящие принципы по содержанию + +Сообщество SIG Docs разработало правила, которые касаются разрешенных видов контента в документации Kubernetes. Посмотрите [руководство по содержанию документации](/docs/contribute/style/content-guide/) для определения того, допустим ли контент, который вы хотите добавить. Задать вопросы про допустимый контент можно в Slack-канале [#sig-docs](#participate-in-sig-docs-discussions). + +### Правила оформления + +Мы поддерживаем [руководство по оформлению](/docs/contribute/style/style-guide/) с информацией о выборе, сделанном сообществом SIG Docs в отношении грамматики, синтаксиса, исходного форматирования и типографских соглашений. Прежде чем сделать свой первый вклад, просмотрите руководство по стилю и используйте его, когда у вас есть вопросы. + +SIG Docs совместными усилиями вносит изменения в руководство по оформлению. Чтобы предложить изменение или дополнение, добавьте его в повестку дня предстоящей встречи SIG Docs и посетите её, чтобы принять участие в обсуждении. Смотрите страницу с [продвинутым руководством](/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 standard](https://www.loc.gov/standards/iso639-2/php/code_list.php). Например, исходники документации для английского языка хранится в директории `/content/en/docs/`. + +Более подробную информацию про участие в работе над документацией на нескольких языках ["Localize content"](/docs/contribute/intermediate#localize-content) в промежуточном руководстве по добавлению. + +Если вы заинтересованы в переводе документации на новый язык, посмотрите раздел ["Локализация"](/docs/contribute/localization/). + +## Создание хороших заявок + +Любой, у кого есть аккаунт на GitHub, может создать заявку (issue, или отчет об ошибке) в документации Kubernetes. Если вы заметили какую-либо какую-либо ошибку, даже если вы не знаете, как её исправить, [откройте ишью](#how-to-file-an-issue). Но не делайте этого, если нашли небольшую ошибку, например, опечатку, которую вы при желании можете исправить самостоятельно. В этом случае можете [исправить ее](#improve-existing-content) вместо того, чтобы писать об этом. + +### Как создать заявку + +- **Для существующей страницы** + + Если заметили проблему на существующей странице в [документации Kubernetes](/docs/), перейдите в конец страницы и нажмите кнопку **Create an Issue**. Если вы ещё не авторизованы в GitHub, сделайте это. После этого откроется страница с форма для создания нового запроса в GitHub с уже предварительно заполненным полями. + + При помощи разметки Markdown опишите как можно подробнее, что хотите. Там, где вы видите пустые квадратные скобки (`[ ]`), проставьте `x` между скобками. Если у вас есть предлагаемое решение проблемы, напишите его. + +- **Запросить новую страницу** + + Если вы хотите добавить что-то новое, но вы не уверены, на какую страницу документации это сделать или считаете, что новая информация не вписывается в существующие страницы, всё равно создайте ишью. Вы можете либо перейти на страницу документации, куда, по вашему мнению, нужно добавить новую информацию и создать заявку прямо с этой страницы, либо перейти по адресу [https://github.com/kubernetes/website/issues/new/](https://github.com/kubernetes/website/issues/new/) и написать что вы хотите там. + +### Как заполнить хорошую заявку + +Чтобы нам самим убедиться, что понимаем вас правильно, помните следующее: + +- Используйте шаблон ишью и заполните его как можно подробнее. +- Четко изложите суть вашего проблемы, как она сказывается на пользователях. +- Как можно меньше ограничьте охват изменений в вашей заявке. Задачи с большим объемом работы разбейте на более мелкие. + Например, "Fix the security docs" не является проблемой, требующей немедленного решения, зато заявка с заголовком "Add details to the 'Restricting network access' topic", вероятно, такой является. +- Если проблема связана с другой заявкой или пулреквестом, вы можете указать сослаться на них, либо по его полному URL-адресу, либо по их номеру с `#`. Например, `Introduced by #987654`. +- Будьте уважительны и избегайте жалоб. Например, заголовок ишью "The docs about X suck" явно не несёт ничего полезного или чтобы на него реагировали. + [Нормы поведения](/community/code-of-conduct/) также применяется к общению в GitHub-репозиториях Kubernetes. + +## Участие в дискуссиях SIG Docs + +Команда SIG Docs общается следующими способами: + +- [Зарегистрируйтесь в Slack-канале Kubernetes](http://slack.k8s.io/), а затем присоединитесь к каналу `#sig-docs`, где мы в режиме реального времени обсуждаем всё, что связано с документацией. И не забудьте представиться! +- [Подпишитесь на список рассылки `kubernetes-sig-docs`](https://groups.google.com/forum/#!forum/kubernetes-sig-docs), где проходят более общие дискуссии и принимаются официальные решения. +- Участвуйте в [еженедельной видеовстрече IG Docs](https://github.com/kubernetes/community/tree/master/sig-docs), которая анонсируется в Slack-канале и списке рассылки. В данный момент эти встречи проводятся в Zoom, поэтому вам необходимо загрузить клиент Zoom или позвонить по телефону. + +{{< note >}} +Вы всегда можете узнать когда будет очередное еженедельное собрание SIG Docs в [календаре собраний сообщества Kubernetes](https://calendar.google.com/calendar/embed?src=cgnt364vd8s86hr2phapfjc6uk%40group.calendar.google.com&ctz=America/Los_Angeles). +{{< /note >}} + +## Улучшение существующего текста + +Чтобы улучшить текущее содержимое документации, вам нужно открыть _пулреквест (pull request, PR)_ после того, как вы сделаете _копию (fork)_ оригинального репозитория. Эти два термина [относятся к GitHub](https://help.github.com/categories/collaborating-with-issues-and-pull-requests/). +Для начала работы, которая показана в этом разделе, вам не нужно знать всё про эти понятия, так как вы всё можете делать в своём браузере. Когда вы перейдете к продвинутому руководству участника документации, тогда вам понадобиться пополнить свои знания Git. + +Примечание. Разработчики кода Kubernetes. Если вы документируете новую функцию для предстоящего выпуска Kubernetes, ваш процесс будет немного другим. См. Документирование функции для руководства по процессу и информации о сроках. + +{{< note >}} +**Для разработчиков кода Kubernetes**: если вы документируете новую функциональность для новой версии Kubernetes, то процесс рассмотрения будет немного другим. Посетите страницу [Документирование функциональности](/docs/contribute/intermediate/#sig-members-documenting-new-features), чтобы узнать про процесс и информацию о крайних сроках. +{{< /note >}} + +### Подписание CLA-соглашения CNCF {#sign-the-cla} + +Прежде чем внести вклад в код или документацию Kubernetes, вам **обязательно** следует прочитать [руководство для участников](https://github.com/kubernetes/community/blob/master/contributors/guide/README.md) и [подписать лицензионное соглашение участника (Contributor License Agreement, CLA)](https://github.com/kubernetes/community/blob/master/CLA.md). +Не переживайте — подписание не займет много времени! + +### Поиск задач для работы + +Если вы уже нашли что исправить, просто следуйте инструкциям ниже. Для этого вам не обязательно [создавать ишью](#file-actionable-issues) (хотя вы, безусловно, пойти этим путём). + +Если вы хотите ещё не определились с тем, над чем хотите поработать, перейдите по адресу [https://github.com/kubernetes/website/issues](https://github.com/kubernetes/website/issues) и найдите ишью с меткой `good first issue` (вы можете использовать [эту](https://github.com/kubernetes/website/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) ссылку для быстрого поиска). Прочитайте комментарии, чтобы убедиться что нет открытого пулреквеста для решения текущей ишью, а также, что никто другой не оставил комментарий, что он работает над этой задачей в последнее время (как правило, 3 дня). Добавьте комментарий, что вы хотели бы заняться решением этой задачи. + +### Выбор правильной ветки в Git + +Самым важный момент в создании пулреквестов — это выбор нужной ветки для вашей работы. Используйте эти рекомендации, чтобы принять верное решение: + +- Используйте ветку `master` для исправления ошибок в текущей документации, либо чтобы улучшить существующий текст. +- Используйте ветку `master` для документирования функциональности в текущей версии Kubernetes, для которой отсутствовала документация. Прежде всего вам нужно написать документацию на английском языке, а затем команды по переводам подхватят это изменение, чтобы актуализировать перевод. +- Если вы работаете над переводом, вам нужно следовать соглашению в этой конкретной локализации. Чтобы понять это, вы можете другие пулреквесты (подсказка: `is:pr is:merged label:language/xx`) + {{< comment >}}Localization note: when localizing that tip, replace `xx` + with the actual ISO3166 two-letter code for your target locale.{{< /comment >}} + - Некоторые команды локализации работают с пулреквестами, которые ориентированы на ветку `master` + - Другие команды локализации работают с рядом долговечных веток, периодически сливая их в ветку `master`. Такая ветка именуется как dev-\-\.\, например, `dev-{{< release-branch >}}-ja.1`. +- Если вы пишете или обновляете документацию к выпуску грядущего изменения, то вам необходимо знать мажорную и минорную версию Kubernetes, в которой это изменение впервые появится. + - Например, если переключатель возможностей (feature gates) JustAnExample должен измениться с альфа-версии на бета-версию в следующей минорной версии, вам необходимо знать номер этой версии. + - Найдите ветку выпуска, названную для этой версии. Например, функциональность, которая изменились в выпуске v{{< release-branch >}}, будет документирована в ветке `dev-{{< release-branch >}}`. + +Если вы все еще не уверены, какую ветку выбрать, спросите в Slack-канале `#sig-docs` или посетите еженедельную встречу SIG Docs, чтобы внести ясность. + +### Отправка пулреквеста + +Следуйте описанным ниже шагам, чтобы создать пулреквест для улучшения документации Kubernetes. + +1. На странице, которую вы хотите отредактировать, щелкните на иконку карандаша в правом верхнем углу. Откроется новая страница на GitHub с небольшой подсказкой. +2. Если вы ранее не делали копию репозитория документации Kubernetes, вам будет предложено это сделать. Создайте копию репозитория под своим логином GitHub, а не в организации, в которой вы состоите. URL-адрес копии репозитория будет выглядит как `https://github.com//website`, в случае у вас нет репозитория с таким же названием. + + Поскольку у вас нет доступа к оригинальному репозиторию и соответственно вы не можете отправлять напрямую изменения в основную ветку, вам нужно сделать копию репозитория Kubernetes. + +3. Откроется редактор GitHub для редактирования исходного файла в формате Markdown. Внесите свои изменения. Под редактором заполните форму **Propose file change**. Первое поле — краткое содержание вашего сообщения коммита, оно должно содержать не более 50 символов. Второе поле является необязательным, в нём вы можете подробно расписать суть ваших изменений. + + {{< note >}} + Не ссылайте на другие ишью или пулреквесты на GitHub в сообщении коммита. Вы можете сослаться на них в тексте пулреквеста. +{{< /note >}} + + Нажмите на кнопку **Propose file change**. Изменения в файле записываются в виде коммита в новой ветке вашей копии репозитория, которая автоматически будет иметь имя что-то вроде `patch-1`. + +4. На следующей странице вам будут показаны различия в вашей ветке (поля выбора **head fork** и **compare**) с текущим состоянием **оригинального репозитория (base fork)** в **основной ветке (base)** (по умолчанию ветка `master` в репозитории `kubernetes/website`). Вы можете выбрать другое значение в полях выбора, но не делайте этого сейчас. Сравните различия и если всё верно, нажмите кнопку **Create pull request**. + + {{< note >}} + Если вы не хотите создавать пулреквест в данный момент, это можно сделать позже, если перейти на страницу репозитория сайта Kubernetes или вашей копии репозитория. На сайте GitHub вам предложит открыть пулреквест, если он обнаружит новую ветку в вашей копии репозитория. +{{< /note >}} + +5. Отобразится форма с заголовком **Open a pull request**. Название пулреквеста будет содержать краткое описание из сообщения коммита, хотя вы можете изменить его при необходимости. В описании пулреквеста будет остальная информация из сообщения коммита (если оно есть) и небольшой шаблон с текстом. Прочитайте текст шаблона и сделайте то, что там описано, а затем удалите этот шаблонный текст. Если вы добавите в описание пулреквест `fixes #<000000>` или `closes #<000000>`, где `#<000000>` - номер связанной заявки, то GitHub автоматически закроет указанную заявку при слиянии пулреквеста. Оставьте флажок **Allow edits from maintainers** отмеченным. Нажмите на кнопку **Create pull request**. + + Поздравляем! Ваш пулреквест добавлен в список [пулреквестов](https://github.com/kubernetes/website/pulls). + + Через несколько минут вы сможете просмотреть версию сайта с изменениями в вашем пулреквесте. Перейдите в низ страницы пулреквеста на вкладке **Conversation** и там нажмите на ссылку **Details** рядом с проверкой `deploy/netlify`. По умолчанию она откроется в текущей вкладке. + + {{< note >}} + Пожалуйста, открывайте пулреквест, изменения которого затрагивают только один язык. Например, если вам нужно одинаково изменить один и тот же пример кода в нескольких языках, откройте по отдельному пулреквесту для каждого языка. + {{< /note >}} + +6. Ожидайте, когда проверят ваш пулреквест. Как правило, рецензенты выбираются авматоматически ботом `k8s-ci-robot`. Если рецензент попросил изменить пулреквест, вы можете сделать это, если перейдёте на вкладку **Files changed** и щёлкните на иконку с карандашом на любом изменённом файле в вашем пулреквесте. Сохранение измененного файла оформляется в виде нового коммита в ветке, указанной в пулреквесте. Если вы ожидаете новую проверку изменений от рецензента, заранее попросите его об этом не более одного раза в 7 дней. Вы также можете зайти в Slack-канал #sig-docs — это хорошее место, где можно попросить проверку пулреквеста. + +7. Если ваши изменения одобрены, то рецензент объединяет соответствующий пулреквест. Через несколько минут вы сможете сможете увидеть его в действии на сайте Kubernetes. + +Это только один из способов отправить пулреквест. Если вы уже опытный пользователь Git и GitHub, вы можете вносить изменения, используя локальный GUI-клиент или Git из терминала вместо того, чтобы использовать интерфейс GitHub для этого. Некоторые основы использования Git-клиента из командной строки обсуждаются в [продвинутом](/docs/contribute/intermediate/) руководстве участника. + +## Просмотр пулреквестов в документацию + +Новички документации могут обозревать пулреквесты. Вы можете изучить кодовую базу и завоевать доверие к себе со стороны коллег-участников. Документация на английском — это первоисточник содержимого. Мы общаемся на английском языке во время еженедельных встреч и в объявлениях сообщества. Владение английским языком может быть разным, поэтому используйте простой и прямой язык в своих обзорах пулреквестов. Полезные обзоры фокусируются как на мелких деталях, так и на потенциальном влиянии изменений. + +Обзоры не носят «обязательный характер», это означает, что только ваша проверка не приведет к слиянию пулреквеста. Тем не менее, это не делает ваши обзоры бесполезными. Даже только просмотр изменений в пулреквеста поможет вам понять как происходит рабочий процесс, какие могут быть трудности и проблемы. Перед проверкой пулреквестов ознакомьтесь с [руководством по содержанию](/docs/contribute/style/content-guide/) и [руководством по оформлению](/docs/contribute/style/style-guide/), чтобы узнать, каким должен быть содержимое и как оно должно быть оформлено.. + +### Рекомендации + +- Будьте вежливы, внимательны и помогайте другим +- Не забывайте отмечать также положительные стороны пулреквеста +- Будьте чутким и думайте, как ваши комментарии могут быть восприняты +- Проявите добрые намерения и задавайте уточняющие вопросы +- Опытным участникам: помогайте новым участникам, их работа требует глаз да глаз + +### Поиск и проверка пулреквеста + +1. Перейдите по URL-адресу [https://github.com/kubernetes/website/pulls](https://github.com/kubernetes/website/pulls). Вы увидите список всех пулреквестов в репозиторий сайта Kubernetes и его документации. + +2. По умолчанию открываются открытые пулреквесты (статус `open`), поэтому вы не увидите закрытых или принятых пулреквестов. Рекомендуется добавить дополнительный фильтр `cncf-cla: yes`, а также для вашей первой проверки пулреквеста неплохо применить ещё и `size/S` и `size/XS`. Метка с размером назначается автоматически в зависимости от количества изменённых строк кода в пулреквесте. Вы можете применить фильтры, используя поля выбора в верхней части страницы, либо воспользоваться [этой ссылкой](https://github.com/kubernetes/website/pulls?q=is%3Aopen+is%3Apr+label%3A%22cncf-cla%3A+yes%22+label%3Asize%2FS) для просмотра небольших пулреквестов. Все фильтры объединены в логическое `AND`, поэтому у вас не получиться искать по меткам `size/XS` и `size/S` одновременно. + +3. Перейдите на вкладку **Files changed**. Посмотрите изменения, внесенные в PR, а также изучите любые связанные задачи (если есть). Если вы видите ошибку, неточность или хотите внести улучшение, то наведите курсор на строку и щелкните на появившийся символ `+`. + + Вы можете написать комментарий, после чего нажать на кнопку **Add single comment** или **Start a review**. Как правило, лучше начать проверку (review), поскольку тогда вы сможете оставить несколько комментариев и уведомить автора PR только после завершения рецензирования, вместо того, чтобы упоминать его в каждом комментарии. + +4. После окончания разбора пулреквеста, нажмите на кнопку **Review changes** вверху страницы. Вы можете подвести краткий итог своей проверки и выполнить одно из действий: просто прокомментировать, одобрить или запросить изменения. Новым участникам нужно всегда только комментировать (кнопка **Comment**) пулреквесты. + + +Спасибо за обзор пулреквеста! Если вы новенький в проекте, рекомендуется попросить кого-нибудь оценить ваш обзор пулреквеста. Slack-канал `#sig-docs` — отличное место для этого. + +## Написание постов в блоге + +Любой может написать пост в блоге и отправить его на рассмотрение. Посты блога не должны носит коммерческий характер и должны отражать опыт, который может широко применён в сообществе Kubernetes. + +Чтобы заявить о посте вы можете отправить его, используя [форму блога Kubernetes](https://docs.google.com/forms/d/e/1FAIpQLSdMpMoSIrhte5omZbTE7nB84qcGBy8XnnXhDFoW0h7p2zwXrw/viewform), либо же выполнить следующие действия. + +1. [Подпишите CLA](#sign-the-cla), если вы еще этого не сделали. +2. Изучите разметку Markdown у текущих постов блога в репозитории сайта. +3. Напишите свою статью в вашем любимом текстовом редакторе. +4. По ссылке из второго шага нажмите на кнопку **Create new file**. Скопируйте из своего редактора текст и вставьте в многострочное поле. Назовите файл так, чтобы он соответствовал предлагаемому заголовку статьи в блоге, но не указывайте дату в имени файла. Рецензенты блога будут работать с вами над окончательным именем файла и датой публикации записи. +5. Когда вы сохраните файл, начнётся описанный выше процесс принятия пулреквеста в GitHub. +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 %}} From b47c665674860a26b37b3f406b1a707477556c85 Mon Sep 17 00:00:00 2001 From: Jie Shen Date: Tue, 18 Feb 2020 00:13:30 +0800 Subject: [PATCH 18/38] Upgrade command of homebrew installs minikube (#18281) --- content/de/docs/tasks/tools/install-minikube.md | 2 +- content/es/docs/tasks/tools/install-minikube.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content/de/docs/tasks/tools/install-minikube.md b/content/de/docs/tasks/tools/install-minikube.md index e305b2ec05..c3d08bac30 100644 --- a/content/de/docs/tasks/tools/install-minikube.md +++ b/content/de/docs/tasks/tools/install-minikube.md @@ -49,7 +49,7 @@ Minikube unterstützt auch die Option `--vm-driver=none`, mit der die Kubernetes Die einfachste Möglichkeit, Minikube unter macOS zu installieren, ist die Verwendung von [Homebrew](https://brew.sh): ```shell -brew cask install minikube +brew install minikube ``` Sie können es auch auf macOS installieren, indem Sie eine statische Binärdatei herunterladen: diff --git a/content/es/docs/tasks/tools/install-minikube.md b/content/es/docs/tasks/tools/install-minikube.md index de99085d50..7538afa704 100644 --- a/content/es/docs/tasks/tools/install-minikube.md +++ b/content/es/docs/tasks/tools/install-minikube.md @@ -49,7 +49,7 @@ Minikube también soporta una opción `--vm-driver=none` que ejecuta los compone La forma más fácil de instalar Minikube en macOS es usar [Homebrew](https://brew.sh): ```shell -brew cask install minikube +brew install minikube ``` También puedes instalarlo en macOS descargando un ejecutable autocontenido: From 403c6d059d02d74c75f625226b5c37307bb68a8e Mon Sep 17 00:00:00 2001 From: Felix Geelhaar Date: Mon, 17 Feb 2020 17:15:29 +0100 Subject: [PATCH 19/38] Update installation of minikube on macOS (#19143) Installation through brew cask install minikube is no longer supported, as there is not such a binary. Corrected to brew install minikube works. From e836c83b4a8876305d4064b70a277deb9d19904c Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Mon, 17 Feb 2020 18:21:29 +0000 Subject: [PATCH 20/38] =?UTF-8?q?Tidy=20=E2=80=9CParticipating=20in=20SIG?= =?UTF-8?q?=20Docs=E2=80=9D=20(#19151)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix broken link - Move localization work from Reviewers group to Anyone - Minor other tidying --- content/en/docs/contribute/participating.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/content/en/docs/contribute/participating.md b/content/en/docs/contribute/participating.md index b63c33e915..dbc44b5867 100644 --- a/content/en/docs/contribute/participating.md +++ b/content/en/docs/contribute/participating.md @@ -24,6 +24,7 @@ You can also become a [member](#members), access and entail certain responsibilities for approving and committing changes. See [community-membership](https://github.com/kubernetes/community/blob/master/community-membership.md) for more information on how membership works within the Kubernetes community. + The rest of this document outlines some unique ways these roles function within SIG Docs, which is responsible for maintaining one of the most public-facing aspects of Kubernetes -- the Kubernetes website and documentation. @@ -52,7 +53,8 @@ aspects of Kubernetes -- the Kubernetes website and documentation. Anyone can do the following: - Open a GitHub issue against any part of Kubernetes, including documentation. -- Provide non-binding feedback on a pull request/ +- Provide non-binding feedback on a pull request. +- Help to localize existing content - Bring up ideas for improvement on [Slack](http://slack.k8s.io/) or the [SIG docs mailing list](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). - Use the `/lgtm` Prow command (short for "looks good to me") to recommend the changes in a pull request for merging. {{< note >}} @@ -120,7 +122,6 @@ changes. Reviewers can: - Triage and categorize issues - Review pull requests and provide binding feedback - Create diagrams, graphics assets, and embeddable screencasts and videos -- Localization - Edit user-facing strings in code - Improve code comments @@ -166,7 +167,7 @@ add new members to a GitHub group. Approvers are members of the [@kubernetes/sig-docs-maintainers](https://github.com/orgs/kubernetes/teams/sig-docs-maintainers) -GitHub group. See [Teams and groups within SIG Docs](#teams-and-groups-within-sig-docs). +GitHub group. See [SIG Docs teams and automation](#sig-docs-teams-and-automation) for details. Approvers can do the following: From c2cc1a1c87dae46411b827da8a22ee687efb05b0 Mon Sep 17 00:00:00 2001 From: Eko Simanjuntak Date: Tue, 18 Feb 2020 09:19:28 +0700 Subject: [PATCH 21/38] Change Kontainer to Node (#19105) --- content/id/docs/concepts/configuration/assign-pod-node.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/id/docs/concepts/configuration/assign-pod-node.md b/content/id/docs/concepts/configuration/assign-pod-node.md index f78bc54b48..12cf9433d6 100644 --- a/content/id/docs/concepts/configuration/assign-pod-node.md +++ b/content/id/docs/concepts/configuration/assign-pod-node.md @@ -1,5 +1,5 @@ --- -title: Menetapkan Pod ke Kontainer +title: Menetapkan Pod ke Node content_template: templates/concept weight: 30 --- From 6b4712e47d81a53caddf8428c9e0c781f0fc0e02 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Tue, 18 Feb 2020 09:07:28 +0300 Subject: [PATCH 22/38] Translate Participating in SIG Docs page into Russian (#19150) * Translate Participating in SIG Docs page into Russian * Fixes --- content/ru/docs/contribute/participating.md | 208 ++++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 content/ru/docs/contribute/participating.md diff --git a/content/ru/docs/contribute/participating.md b/content/ru/docs/contribute/participating.md new file mode 100644 index 0000000000..2460e19d6d --- /dev/null +++ b/content/ru/docs/contribute/participating.md @@ -0,0 +1,208 @@ +--- +title: Участие в SIG Docs +content_template: templates/concept +card: + name: contribute + weight: 40 +--- + +{{% capture overview %}} + +SIG Docs — это одна из [специальных групп](https://github.com/kubernetes/community/blob/master/sig-list.md) в проекте Kubernetes, которая занимается написанием, обновлением и поддержкой документации Kubernetes в целом. Перейдите на страницу про [SIG Docs в GitHub-репозитории](https://github.com/kubernetes/community/tree/master/sig-docs), чтобы узнать подробную информацию об этой группе. + +SIG Docs активно принимает правки и дополнения в документацию, так и отзывы от всех участников. Любой может открыть пулреквест (PR), либо сообщить про ошибки в тексте или просто прокомментировать выполняемые пулреквесты. + +Вы также можете стать [членом](#члены), [рецензентом](#рецензенты) или [утверждающим](#утверждающие). Эти роли расширяют ваши возможности, но и предлагают выполнение определенных обязанностей по рассмотрению и принятию изменений. Изучите содержимого файла [community-membership](https://github.com/kubernetes/community/blob/master/community-membership.md) в директории сообщества репозитория, чтобы узнать про членство в сообществе Kubernetes. В остальной части этой страницы кратко рассматривается функционирование ролей в группе SIG Docs, которая в совокупности отвечает за поддержание одного из самой публичной части Kubernetes — сайта и документации Kubernetes. + +{{% /capture %}} + +{{% capture body %}} + +## Роли и обязанности + +- **Любой** может поучаствовать в документацию Kubernetes. Для этого вам нужно только [подписать CLA](/docs/contribute/start#sign-the-cla) и иметь аккаунт на GitHub. +- **Члены** организации Kubernetes — участники, которые активно занимаются пректом Kubernetes, как правило, открывая пулреквесты с принятыми изменениями. Посмотрите файл [Членство в сообществе](https://github.com/kubernetes/community/blob/master/community-membership.md), чтобы узнать про необходимые условия для членства. +- **Рецензент** SIG Docs — член организации Kubernetes, который занимается проверкой пулреквестов и поэтому был добавлен в соответствующую группу на GitHub и в файлы `OWNERS` в GitHub-репозитории. +- **Утверждающий** SIG Docs — член организации с хорошей репутацией, который подтвердил неизменную приверженность проекту. Утверждающий может принимать пулреквесты и публиковаться от имени организации Kubernetes. Утверждающие также могут представлять группу SIG Docs в более крупном сообществе Kubernetes. Некоторые из задач утверждающего SIG Docs, например, координация новой версии, требуют значительных затрат по времени. + +## Любой + +Кто угодно может сделать следующее: + +- Открыть ишью на GitHub в любую часть Kubernetes, включая документацию. +- Дать рекомендацию или предложить улучшение в пулреквесте. +- Предложить идею по улучшению в Slack](http://slack.k8s.io/) или в [список рассылки SIG Docs](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). +- Использовать команду `/lgtm` (сокращение от "looks good to me") бота Prow, чтобы одобрить изменения в пулреквесте. + {{< note >}} + Если вы не входите в организацию Kubernetes, то команда `/lgtm` не проставил автоматически соответствующую метку. + {{< /note >}} + +После [подписания CLA](/docs/contribute/start#sign-the-cla) каждый также может: +- Открыть пулреквест, чтобы улучшить существующий текст, либо что-то новое, или написать запись в блоге или описать пример использования. + +## Члены + +Члены — это участники проекта Kubernetes, которые удовлетворяют [критериям членства](https://github.com/kubernetes/community/blob/master/community-membership.md#member). SIG Docs ценит участие всех членов сообщества Kubernetes и часто просит дать обратную связь от членов других SIG-групп для соблюдения технической точности. + +Любой член [организации Kubernetes](https://github.com/kubernetes) может сделать следующее: + +- Всё то же самое, что и [любой другой участник](#любой) +- Использовать команду `/lgtm` в комментарии для автоматического добавления метки LGTM (looks good to me) для пулреквеста. +- Использовать команду `/hold` в комментарии для блокировки слияния пулреквеста, если он имеет метку LGTM и другие утверждающие метки. +- Использовать команду `/assign` в комментарии, чтобы назначить рецензента, который будет проверят пулреквест. + +### Членство + +После того, как вы успешно отправили не менее 5 содержательных пулреквестов, вы можете стать [членом](https://github.com/kubernetes/community/blob/master/community-membership.md#member) организации Kubernetes. Следуйте нижеперечисленным шагам: + +1. Найдите двух рецензентов или утверждающих, которые [поддержат](/docs/contribute/advanced#sponsor-a-new-contributor) ваше членство. + + Запросите спонсорство в канале [#sig-docs Kubernetes Slack](https://kubernetes.slack.com) или в [списке рассылки SIG Docs](https://groups.google.com/forum/#!forum/kubernetes-sig-docs). + + {{< note >}} + Не отправляйте электронное письмо и не пишите личное сообщение в Slack кому-либо из участников SIG Docs. + {{< /note >}} + +2. Создайте ишью в репозитории `kubernetes/org`, чтобы запросить членство. + Заполните шаблон, предварительно изучив правила [членства в сообществе](https://github.com/kubernetes/community/blob/master/community-membership.md). + +3. Сообщите вашим спонсорам про вашу заявку на GitHub, упомянув их в ней на GitHub (добавив комментарий в форме `@`), либо отправив им ссылку напрямую, чтобы они могли добавить проголосовать ( `+1`). + +4. Когда ваше членство будет одобрено, член административной команды на GitHub, назначенный для обработки вашего пулреквеста, обновит ишью на GitHub, чтобы показать одобрение, а затем закроет проблему GitHub. + Поздравляем, теперь вы член организации! + +Если ваша заявка на членство не была одобрена, членский комитет даст уточнения или перечислит шаги, которые необходимо выполнить, прежде чем снова подать заявку. + +## Рецензенты + +Рецензенты — это члены GitHub-группы [@kubernetes/sig-docs-pr-reviews](https://github.com/orgs/kubernetes/teams/sig-docs-pr-reviews). Рецензенты проверяют пулреквесты документации и оставлять обратную связь по предлагаемым изменениях. Рецензенты могут: + +- Делать всё то, что и [любой участник](#любой) и [члены](#члены) +- Писать документацию для новой функциональности +- Назначать метки и классифицировать ишью +- Проверять пулреквесты и оставлять обязательные для выполнения рекомендации +- Создавайте диаграммы, графику и встраиваемые скринкасты и видеоролики +- Заниматься локализацией +- Редактировать строки в коде, относящиеся к интерфейсу пользователя +- Улучшать комментарии к коду + +### Выбор рецензентов для проверки пулреквестов + +Процесс выбора рецензентов для проверки пулреквестов автоматизирован. Вы можете попросить проверку у определенного рецензента, написав комментарий в пулреквесте: `/assign [@_github_handle]`. Чтобы показать, что пулреквест является правильным с технической точки зрения и не требует дополнительных изменений, рецензент добавляет комментарий с командой `/lgtm`. + +Если назначенный рецензент еще не просмотрел содержимое пулреквеста, может присоединиться другой проверяющий. Кроме того, вы можете назначить технических рецензентов и подождать их одобрение через комментарий с `/lgtm`. + +Также для совсем небольшого изменения, или такого, которое не требует технического рассмотрения, [утверждающие](#утверждающие) SIG Docs одобрить его через комментарий с `/lgtm`. + +Комментарий с `/approve` от рецензента игнорируется ботом и поэтому соответствующая метка не добавится к пулреквесту. + +### Как стать рецензентом + +Если вы соответствуете [требованием](https://github.com/kubernetes/community/blob/master/community-membership.md#reviewer), то можете стать рецензентом SIG Docs. Рецензенты в других SIG-группах должны подать новую заявку для получения статуса рецензента в SIG Docs. + +Для отправки заявки откройте пулреквест с добавлением самого себя в секцию `reviewers` [корневого файла OWNERS](https://github.com/kubernetes/website/blob/master/OWNERS) в репозитории `kubernetes/website`. Запросите проверку вашего пулреквеста одному или нескольким текущим утверждающим в группе SIG Docs. + +Если ваш пулреквест одобрен, вы становитесь рецензентом SIG Docs. Теперь бот [K8s-ci-robot](https://github.com/kubernetes/test-infra/tree/master/prow#bots-home) будет назначать и предлагать вас в качестве рецензента для проверки новых пулреквестов. + +После того, как ваша кандидатура будет одобрена, попросите текущего утверждающего SIG Docs добавить вас в GitHub-группу [@kubernetes/sig-docs-pr-reviews](https://github.com/orgs/kubernetes/teams/sig-docs-pr-reviews). Только члены GitHub-группы `kubernetes-website-admins` могут добавлять новых членов в какую-либо другую группу. + +## Утверждающие + +Утверждающие — члены GitHub-группы [@kubernetes/sig-docs-maintainers](https://github.com/orgs/kubernetes/teams/sig-docs-maintainers). Перейдите в раздел [Команды и группы в SIG Docs](#teams-and-groups-within-sig-docs) для получения дополнительной информации. + +Утверждающие могут делать следующее: + +- Все то же, что и [обычные участники](#любой), [члены](#члены) и [рецензенты](#рецензенты) +- Публиковать изменения от других участников путём одобрения и слияния пулреквестов с помощью комментария с командой `/approve`. + Если кто-то оставляет комментарий, не являясь при этом официальным рецензентом, бот проигнорирует такой одобряющий комментарий. +- Примите участие в работе команды выпуска новых версий Kubernetes как представитель документации +- Предлагать улучшения в руководстве по оформлению +- Предлагать улучшения для тестов документации +- Предлагать улучшения для сайта Kubernetes или других инструментов + +Если у PR есть метка `/lgtm`, или если утверждающий оставляет комментарий с командной с `/lgtm`, PR автоматически сливается. Утверждающий SIG Docs должен оставлять комментарий с `/lgtm` только для тех изменений, которые не нуждаются в дополнительном техническом обзоре. + +### Как стать утверждающим + +Если вы соответствуете [требованием](https://github.com/kubernetes/community/blob/master/community-membership.md#approver), вы можете стать утверждающим SIG Docs. Утверждающие в других SIG-группах должны подать новую заявку для получения статуса утверждающего в SIG Docs. + +Для отправки заявки откройте пулреквест с добавлением самого себя в секцию `approvers` [корневого файла OWNERS](https://github.com/kubernetes/website/blob/master/OWNERS) в репозитории `kubernetes/website`. Запросите проверку вашего пулреквеста одному или нескольким текущим утверждающим в группе SIG Docs. + +Если ваш пулреквест одобрен, вы становитесь утверждающим SIG Docs. Теперь бот [K8s-ci-robot](https://github.com/kubernetes/test-infra/tree/master/prow#bots-home) будет назначать и предлагать вас в качестве рецензента для проверки новых пулреквестов. + +После того, как ваша кандидатура будет одобрена, попросите текущего утверждающего SIG Docs добавить вас в GitHub-группу[@kubernetes/sig-docs-maintainers](https://github.com/orgs/kubernetes/teams/sig-docs-maintainers). Только члены GitHub-группы `kubernetes-website-admins` могут добавлять новых членов в какую-либо другую группу. + +### Обязанности утверждающего + +Утверждающие улучшают документацию, проверяя и сливая пулреквесты в репозитории сайта. Из-за того, эта роль предусматривает дополнительные привилегии, на утверждающих возлагаются дополнительные обязанности: + +- Утверждающие могут использовать команду `/approve`, которая сливает PR в репозиторий. + + Невнимательное слияние может нарушить работу сайта, поэтому имейте это в виду, когда объединяете какой-либо пулреквест. + +- Убедитесь, что предлагаемые изменения соответствуют [правилам по содержанию](/docs/contribute/style/content-guide/#contributing-content). + + Если вы сомневаетесь или вы не уверены в чем-либо, не стесняйтесь обращаться для дополнительной проверки. + +- Проверьте, что тесты на Netlify пройдены успешно, перед тем как написать комментарий с `/approve` в PR. + + Netlify tests must pass before approving + +- Перед одобрением пулреквеста перейдите на предварительный просмотр сайта на Netlify для сделанных изменений в PR, и убедитесь, что всё содержимое выглядит хорошо. + +- Участвуйте в [графике дежурства смотрителя PR](https://github.com/kubernetes/website/wiki/PR-Wranglers), чтобы вас назначили дежурным проверяющим на неделю. SIG Docs ожидает, что все утверждающие примут участие в этом графике. За подробностям обратитесь к странице [Be the PR Wrangler for a week](/docs/contribute/advanced#be-the-pr-wrangler-for-a-week). + +## Председатель SIG Docs + +Каждая SIG-группа, включая SIG Docs, выбирает одного или нескольких членов из своей SIG-группы в качестве председателей. Это координаторы между SIG Docs и другими подразделениями в организации Kubernetes. От таких людей требуются обширные знания о структуре проекта Kubernetes в целом и как функционирует группа SIG Docs внутри неё. Смотрите раздел [Руководство](https://github.com/kubernetes/community/tree/master/sig-docs#leadership), чтобы узнать текущий список председателей. + +## Команды SIG Docs и автоматизация + +Автоматизация в SIG Docs основывается на двух разных механизмах: +группы GitHub и файлы OWNERS. + +### GitHub-группы + +Группа 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) + +На каждую из них можно сослаться по имени (`@name`) в комментариях на GitHub, чтобы общаться со всеми участниками в этой группе. + +Эти команды пересекаются, но назначение у них разное. Для назначения людей на ишью, пулреквестов и поддержки одобрений в PR бот использует информацию из файлов OWNERS. + +### Файлы OWNERS и вступительная часть + +Проект Kubernetes использует инструмент автоматизации под названием prow, чтобы автоматизировать процесс, связанный с ишью и пулреквестами на GitHub. [Репозиторий сайта Kubernetes](https://github.com/kubernetes/website) использует два [плагина prow](https://github.com/kubernetes/test-infra/tree/master/prow/plugins): + +- blunderbuss +- approve + +Все эти плагины используют файлы [OWNERS](https://github.com/kubernetes/website/blob/master/OWNERS) и [OWNERS_ALIASES](https://github.com/kubernetes/website/blob/master/OWNERS_ALIASES) в корневой директории GitHub-репозитория `kubernetes/website`, чтобы контролировать работу prow по всему репозиторию. + +Файл OWNERS содержит список людей, которые являются рецензентами и утверждающими в SIG Docs. Файлы OWNERS также может быть в поддиректориях и могут переопределять тех, кто может выступать в качестве рецензента или утверждающего в изменениях файлов этой директории и её поддиректорий. Для получения дополнительной информации о файлах OWNERS в целом, перейдите в [OWNERS](https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md). + +Кроме того, в каждом Markdown-файле могут быть указаны рецензенты и утверждающие в так называемой вступительной части (front-matter) в виде логинов участников или имён групп на GitHub. + +Таким образом файлы OWNERS и вступительная часть в Markdown-файлах определяет своего рода рекомендацию для бота, чтобы он знал, к кому обращаться за технической и редакционной проверкой каждого PR. + +## Как происходит слияние + +Когда пулреквест сливается в действующую ветку сайта (в данный момент это `master`), содержимое публикуется и становится общедоступным. Для обеспечения высокого качества публикуемого нами контента, мы доверяем слияние пулреквестов утверждающим SIG Docs. Ниже описан этот процесс. + +- Когда пулреквест имеет метки `lgtm` и `approve`, при этом у него нет метки `hold`, и то же время все тесты успешно проходят, то пулреквест автоматически сливается. +- Члены организации Kubernetes и утверждающие SIG Docs могут оставлять комментарии со специальными командами, которые блокирует автоматическое объединение пулреквеста (добавление комментарий с текстом `/hold` или удаление ранее установленной метки `/lgtm`). +- Любой участник Kubernetes может добавить метку `lgtm`, добавив комментарий, включающий в себя `/lgtm`. +- Только утверждающие SIG Docs могут слить пулреквест путём добавления комментария с `/approve`. Некоторые утверждающие также играют дополнительные роли, например, [смотрителя PR](#pr-wrangler) или [председателя SIG Docs](#председатель-sig-docs). + +{{% /capture %}} + +{{% capture whatsnext %}} + +Для получения дополнительной информации про участие в документации Kubernetes, посмотрите следующие страницы: + +- [Начало участия](/ru/docs/contribute/start/) +- [Правила оформления документации](/ru/docs/contribute/style/) + +{{% /capture %}} From 004bcd1ff8f6d14033651e58b3a98f587e4cf60c Mon Sep 17 00:00:00 2001 From: inductor Date: Tue, 18 Feb 2020 16:41:28 +0900 Subject: [PATCH 23/38] Second Japanese l10n work for release-1.16 (#19157) * update install kubeadm related doc (#18826) * modify terminology mechanism (#19148) --- .../concepts/architecture/cloud-controller.md | 4 +- .../api-extension/custom-resources.md | 2 +- .../extend-kubernetes/extend-cluster.md | 2 +- .../scheduling/scheduler-perf-tuning.md | 2 +- .../concepts/services-networking/service.md | 4 +- .../workloads/controllers/ttlafterfinished.md | 2 +- .../tools/kubeadm/control-plane-flags.md | 15 +- .../tools/kubeadm/create-cluster-kubeadm.md | 213 +++++++----------- .../tools/kubeadm/install-kubeadm.md | 7 +- 9 files changed, 110 insertions(+), 141 deletions(-) diff --git a/content/ja/docs/concepts/architecture/cloud-controller.md b/content/ja/docs/concepts/architecture/cloud-controller.md index 1e3e607d8b..9d76076fc7 100644 --- a/content/ja/docs/concepts/architecture/cloud-controller.md +++ b/content/ja/docs/concepts/architecture/cloud-controller.md @@ -8,7 +8,7 @@ weight: 30 クラウドコントローラマネージャー(CCM)のコンセプト(バイナリと混同しないでください)は、もともとクラウドベンダー固有のソースコードと、Kubernetesのコアソースコードを独立して進化させることが出来るように作られました。クラウドコントローラーマネージャーは、Kubernetesコントローラーマネージャー、APIサーバー、そしてスケジューラーのような他のマスターコンポーネントと並行して動きます。またKubernetesのアドオンとしても動かすことができ、その場合はKubernetes上で動きます。 -クラウドコントローラーマネージャーの設計は「プラグイン機構」をベースにしています。そうすることで、新しいクラウドプロバイダーがプラグインを使ってKubernetesと簡単に統合出来るようになります。新しいクラウドプロバイダーに向けてKubernetesのオンボーディングを行ったり、古いモデルを利用しているクラウドプロバイダーに、新しいCCMモデルに移行させるような計画があります。 +クラウドコントローラーマネージャーの設計は「プラグインメカニズム」をベースにしています。そうすることで、新しいクラウドプロバイダーがプラグインを使ってKubernetesと簡単に統合出来るようになります。新しいクラウドプロバイダーに向けてKubernetesのオンボーディングを行ったり、古いモデルを利用しているクラウドプロバイダーに、新しいCCMモデルに移行させるような計画があります。 このドキュメントでは、クラウドコントローラーマネージャーの背景にあるコンセプトと、それに関連する機能の詳細について話します。 @@ -91,7 +91,7 @@ CCMの大半の機能は、KCMから派生しています。前セクション この新しいモデルでは、kubeletはクラウド特有の情報無しでノードを初期化します。しかし、新しく作成されたノードにtaintを付けて、CCMがクラウド特有の情報でノードを初期化するまで、コンテナがスケジュールされないようにします。その後、taintを削除します。 -## プラグイン機構 +## プラグインメカニズム クラウドコントローラーマネージャーは、Goのインターフェースを利用してクラウドの実装をプラグイン化出来るようにしています。具体的には、[こちら](https://github.com/kubernetes/cloud-provider/blob/9b77dc1c384685cb732b3025ed5689dd597a5971/cloud.go#L42-L62)で定義されているクラウドプロバイダーインターフェースを利用しています。 diff --git a/content/ja/docs/concepts/extend-kubernetes/api-extension/custom-resources.md b/content/ja/docs/concepts/extend-kubernetes/api-extension/custom-resources.md index f83bc9ebc5..6d8fbc1e2e 100644 --- a/content/ja/docs/concepts/extend-kubernetes/api-extension/custom-resources.md +++ b/content/ja/docs/concepts/extend-kubernetes/api-extension/custom-resources.md @@ -170,7 +170,7 @@ CRD、またはアグリゲートAPI、どちらを使ってカスタムリソ | merge-patch | 新しいエンドポイントが`Content-Type: application/merge-patch+json`を用いたPATCHをサポート | | HTTPS | 新しいエンドポイントがHTTPSを利用 | | ビルトイン認証 | 拡張機能へのアクセスに認証のため、コアAPIサーバー(アグリゲーションレイヤー)を利用 | -| ビルトイン認可 | 拡張機能へのアクセスにコアAPIサーバーで使われている認可機構を再利用(例、RBAC) | +| ビルトイン認可 | 拡張機能へのアクセスにコアAPIサーバーで使われている認可メカニズムを再利用(例、RBAC) | | ファイナライザー | 外部リソースの削除が終わるまで、拡張リソースの削除をブロック | | Admission Webhooks | 拡張リソースの作成/更新/削除処理時に、デフォルト値の設定、バリデーションを実施 | | UI/CLI 表示 | kubectl、ダッシュボードで拡張リソースを表示 | diff --git a/content/ja/docs/concepts/extend-kubernetes/extend-cluster.md b/content/ja/docs/concepts/extend-kubernetes/extend-cluster.md index 6e6cacb3f3..b554f01819 100644 --- a/content/ja/docs/concepts/extend-kubernetes/extend-cluster.md +++ b/content/ja/docs/concepts/extend-kubernetes/extend-cluster.md @@ -121,7 +121,7 @@ Kubernetesはいくつかのビルトイン認証方式と、それらが要件 ### 認可 -[認可](/docs/reference/access-authn-authz/webhook/)は特定のユーザーがAPIリソースに対して、読み込み、書き込み、そしてその他の操作が可能かどうかを決定します。それはオブジェクト全体のレベルで機能し、任意のオブジェクトフィールドに基づいての区別は行いません。もしビルトインの認可機構が要件に合わない場合、[認可Webhook](/docs/reference/access-authn-authz/webhook/)が、ユーザー提供のコードを呼び出し認可の決定を行うことを可能にします。 +[認可](/docs/reference/access-authn-authz/webhook/)は特定のユーザーがAPIリソースに対して、読み込み、書き込み、そしてその他の操作が可能かどうかを決定します。それはオブジェクト全体のレベルで機能し、任意のオブジェクトフィールドに基づいての区別は行いません。もしビルトインの認可メカニズムが要件に合わない場合、[認可Webhook](/docs/reference/access-authn-authz/webhook/)が、ユーザー提供のコードを呼び出し認可の決定を行うことを可能にします。 ### 動的Admission Control diff --git a/content/ja/docs/concepts/scheduling/scheduler-perf-tuning.md b/content/ja/docs/concepts/scheduling/scheduler-perf-tuning.md index 8843138e73..ccc04a54f3 100644 --- a/content/ja/docs/concepts/scheduling/scheduler-perf-tuning.md +++ b/content/ja/docs/concepts/scheduling/scheduler-perf-tuning.md @@ -20,7 +20,7 @@ weight: 70 ## スコア付けするノードの割合 -Kubernetes 1.12以前では、Kube-schedulerがクラスター内の全てのノードに対して割り当て可能かをチェックし、実際に割り当て可能なノードのスコア付けをしていました。Kubernetes 1.12では新機能を追加し、ある数の割り当て可能なノードが見つかった時点で、割り当て可能なノードの探索を止めれるようになりました。これにより大規模なクラスターにおけるスケジューラーのパフォーマンスが向上しました。その数はクラスターのサイズの割合(%)として指定されます。この割合は`percentageOfNodesToScore`というオプションの設定項目によって指定可能です。この値の範囲は1から100までです。100より大きい値は100%として扱われます。0を指定したときは、この設定オプションを指定しないものとして扱われます。Kubernetes 1.14では、この値が指定されていないときは、スコア付けするノードの割合をクラスターのサイズに基づいて決定するための機構があります。この機構では100ノードのクラスターに対しては50%の割合とするような線形な式を使用します。5000ノードのクラスターに対しては10%となります。自動で算出される割合の最低値は5%となります。言い換えると、クラスターの規模がどれだけ大きくても、ユーザーがこの値を5未満に設定しない限りスケジューラーは少なくても5%のクラスター内のノードをスコア付けすることになります。 +Kubernetes 1.12以前では、Kube-schedulerがクラスター内の全てのノードに対して割り当て可能かをチェックし、実際に割り当て可能なノードのスコア付けをしていました。Kubernetes 1.12では新機能を追加し、ある数の割り当て可能なノードが見つかった時点で、割り当て可能なノードの探索を止めれるようになりました。これにより大規模なクラスターにおけるスケジューラーのパフォーマンスが向上しました。その数はクラスターのサイズの割合(%)として指定されます。この割合は`percentageOfNodesToScore`というオプションの設定項目によって指定可能です。この値の範囲は1から100までです。100より大きい値は100%として扱われます。0を指定したときは、この設定オプションを指定しないものとして扱われます。Kubernetes 1.14では、この値が指定されていないときは、スコア付けするノードの割合をクラスターのサイズに基づいて決定するためのメカニズムがあります。このメカニズムでは100ノードのクラスターに対しては50%の割合とするような線形な式を使用します。5000ノードのクラスターに対しては10%となります。自動で算出される割合の最低値は5%となります。言い換えると、クラスターの規模がどれだけ大きくても、ユーザーがこの値を5未満に設定しない限りスケジューラーは少なくても5%のクラスター内のノードをスコア付けすることになります。 `percentageOfNodesToScore`の値を50%に設定する例は下記のとおりです。 diff --git a/content/ja/docs/concepts/services-networking/service.md b/content/ja/docs/concepts/services-networking/service.md index 71c8795733..4c49ebd2a2 100644 --- a/content/ja/docs/concepts/services-networking/service.md +++ b/content/ja/docs/concepts/services-networking/service.md @@ -3,7 +3,7 @@ title: Service feature: title: サービスディスカバリーと負荷分散 description: > - Kubernetesでは、なじみのないサービスディスカバリーの機構を使用するためにユーザーがアプリケーションの修正をする必要はありません。KubernetesはPodにそれぞれのIPアドレス割り振りや、Podのセットに対する単一のDNS名を提供したり、それらのPodのセットに対する負荷分散が可能です。 + Kubernetesでは、なじみのないサービスディスカバリーのメカニズムを使用するためにユーザーがアプリケーションの修正をする必要はありません。KubernetesはPodにそれぞれのIPアドレス割り振りや、Podのセットに対する単一のDNS名を提供したり、それらのPodのセットに対する負荷分散が可能です。 content_template: templates/concept weight: 10 @@ -14,7 +14,7 @@ weight: 10 {{< glossary_definition term_id="service" length="short" >}} -Kubernetesでは、なじみのないサービスディスカバリーの機構を使用するためにユーザーがアプリケーションの修正をする必要はありません。 +Kubernetesでは、なじみのないサービスディスカバリーのメカニズムを使用するためにユーザーがアプリケーションの修正をする必要はありません。 KubernetesはPodにそれぞれのIPアドレス割り振りや、Podのセットに対する単一のDNS名を提供したり、それらのPodのセットに対する負荷分散が可能です。 {{% /capture %}} diff --git a/content/ja/docs/concepts/workloads/controllers/ttlafterfinished.md b/content/ja/docs/concepts/workloads/controllers/ttlafterfinished.md index aed6b33169..ee1dea77eb 100644 --- a/content/ja/docs/concepts/workloads/controllers/ttlafterfinished.md +++ b/content/ja/docs/concepts/workloads/controllers/ttlafterfinished.md @@ -9,7 +9,7 @@ weight: 65 {{< feature-state for_k8s_version="v1.12" state="alpha" >}} -TTLコントローラーは実行を終えたリソースオブジェクトのライフタイムを制御するためのTTL機構を提供します。 +TTLコントローラーは実行を終えたリソースオブジェクトのライフタイムを制御するためのTTLメカニズムを提供します。 TTLコントローラーは現在[Job](/docs/concepts/workloads/controllers/jobs-run-to-completion/)のみ扱っていて、将来的にPodやカスタムリソースなど、他のリソースの実行終了を扱えるように拡張される予定です。 α版の免責事項: この機能は現在α版の機能で、[Feature Gate](/docs/reference/command-line-tools-reference/feature-gates/)の`TTLAfterFinished`を有効にすることで使用可能です。 diff --git a/content/ja/docs/setup/production-environment/tools/kubeadm/control-plane-flags.md b/content/ja/docs/setup/production-environment/tools/kubeadm/control-plane-flags.md index 89ea61eb3e..5393e15b91 100644 --- a/content/ja/docs/setup/production-environment/tools/kubeadm/control-plane-flags.md +++ b/content/ja/docs/setup/production-environment/tools/kubeadm/control-plane-flags.md @@ -17,11 +17,16 @@ kubeadmの`ClusterConfiguration`オブジェクトはAPIServer、ControllerManag `extraArgs` の項目は `キー: 値` のペアです。コントロールプレーンの構成要素のフラグを上書きするには: -1. 設定内容に適切な項目を追加 -2. フラグを追加して項目を上書き +1. 設定内容に適切な項目を追加 +2. フラグを追加して項目を上書き +3. `--config <任意の設定YAMLファイル>`で`kubeadm init`を実行 各設定項目のより詳細な情報は[APIリファレンスのページ](https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm#ClusterConfiguration)を参照してください。 +{{< note >}} +`kubeadm config print init-defaults`を実行し、選択したファイルに出力を保存することで、デフォルト値で`ClusterConfiguration`オブジェクトを生成できます。 +{{< /note >}} + {{% /capture %}} {{% capture body %}} @@ -34,7 +39,7 @@ Example usage: ```yaml apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration -kubernetesVersion: v1.13.0 +kubernetesVersion: v1.16.0 apiServer: extraArgs: advertise-address: 192.168.0.103 @@ -51,7 +56,7 @@ Example usage: ```yaml apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration -kubernetesVersion: v1.13.0 +kubernetesVersion: v1.16.0 controllerManager: extraArgs: cluster-signing-key-file: /home/johndoe/keys/ca.key @@ -67,7 +72,7 @@ Example usage: ```yaml apiVersion: kubeadm.k8s.io/v1beta2 kind: ClusterConfiguration -kubernetesVersion: v1.13.0 +kubernetesVersion: v1.16.0 scheduler: extraArgs: address: 0.0.0.0 diff --git a/content/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md b/content/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md index 3d8f65775b..a79e3367d1 100644 --- a/content/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md +++ b/content/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md @@ -1,5 +1,5 @@ --- -title: kubeadmを使用したシングルマスタークラスターの作成 +title: kubeadmを使用したシングルコントロールプレーンクラスターの作成 content_template: templates/task weight: 30 --- @@ -33,17 +33,6 @@ but you may also build them from source for other OSes. ### kubeadmの成熟度 -| Area | Maturity Level | -|---------------------------|--------------- | -| Command line UX | GA | -| Implementation | GA | -| Config file API | Beta | -| CoreDNS | GA | -| kubeadm alpha subcommands | Alpha | -| High availability | Beta | -| DynamicKubeletConfig | Alpha | - - kubeadm's overall feature state is **GA**. Some sub-features, like the configuration file API are still under active development. The implementation of creating the cluster may change slightly as the tool evolves, but the overall implementation should be pretty stable. @@ -59,16 +48,10 @@ timeframe; which also applies to `kubeadm`. | Kubernetes version | Release month | End-of-life-month | |--------------------|----------------|-------------------| -| v1.6.x | March 2017 | December 2017 | -| v1.7.x | June 2017 | March 2018 | -| v1.8.x | September 2017 | June 2018 | -| v1.9.x | December 2017 | September 2018   | -| v1.10.x | March 2018 | December 2018   | -| v1.11.x | June 2018 | March 2019   | -| v1.12.x | September 2018 | June 2019   | -| v1.13.x | December 2018 | September 2019   | -| v1.14.x | March 2019 | December 2019   | -| v1.15.x | June 2019 | March 2020   | +| v1.13.x | December 2018 | September 2019 | +| v1.14.x | March 2019 | December 2019 | +| v1.15.x | June 2019 | March 2020 | +| v1.16.x | September 2019 | June 2020 | {{% /capture %}} @@ -87,7 +70,7 @@ timeframe; which also applies to `kubeadm`. ## 目的 -* Install a single master Kubernetes cluster or [high availability cluster](/ja/docs/setup/production-environment/tools/kubeadm/high-availability/) +* Install a single control-plane Kubernetes cluster or [high availability cluster](/ja/docs/setup/production-environment/tools/kubeadm/high-availability/) * Install a Pod network on the cluster so that your Pods can talk to each other @@ -103,50 +86,75 @@ apt-get upgrade` or `yum update` to get the latest version of kubeadm. When you upgrade, the kubelet restarts every few seconds as it waits in a crashloop for kubeadm to tell it what to do. This crashloop is expected and normal. -After you initialize your master, the kubelet runs normally. +After you initialize your control-plane, the kubelet runs normally. {{< /note >}} -### マスターの初期化 +### コントロールプレーンノードの初期化 The control-plane node is the machine where the control plane components run, including etcd (the cluster database) and the API server (which the kubectl CLI communicates with). -1. Choose a pod network add-on, and verify whether it requires any arguments to +1. (Recommended) If you have plans to upgrade this single control-plane kubeadm cluster +to high availability you should specify the `--control-plane-endpoint` to set the shared endpoint +for all control-plane nodes. Such an endpoint can be either a DNS name or an IP address of a load-balancer. +1. Choose a Pod network add-on, and verify whether it requires any arguments to be passed to kubeadm initialization. Depending on which third-party provider you choose, you might need to set the `--pod-network-cidr` to -a provider-specific value. See [Installing a pod network add-on](#pod-network). +a provider-specific value. See [Installing a Pod network add-on](#pod-network). 1. (Optional) Since version 1.14, kubeadm will try to detect the container runtime on Linux by using a list of well known domain socket paths. To use different container runtime or if there are more than one installed on the provisioned node, specify the `--cri-socket` argument to `kubeadm init`. See [Installing runtime](/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-runtime). 1. (Optional) Unless otherwise specified, kubeadm uses the network interface associated -with the default gateway to advertise the master's IP. To use a different -network interface, specify the `--apiserver-advertise-address=` argument +with the default gateway to set the advertise address for this particular control-plane node's API server. +To use a different network interface, specify the `--apiserver-advertise-address=` argument to `kubeadm init`. To deploy an IPv6 Kubernetes cluster using IPv6 addressing, you must specify an IPv6 address, for example `--apiserver-advertise-address=fd00::101` 1. (Optional) Run `kubeadm config images pull` prior to `kubeadm init` to verify connectivity to gcr.io registries. -Now run: +To initialize the control-plane node run: ```bash kubeadm init ``` +### Considerations about apiserver-advertise-address and ControlPlaneEndpoint + +While `--apiserver-advertise-address` can be used to set the advertise address for this particular +control-plane node's API server, `--control-plane-endpoint` can be used to set the shared endpoint +for all control-plane nodes. + +`--control-plane-endpoint` allows IP addresses but also DNS names that can map to IP addresses. +Please contact your network administrator to evaluate possible solutions with respect to such mapping. + +Here is an example mapping: + +``` +192.168.0.102 cluster-endpoint +``` + +Where `192.168.0.102` is the IP address of this node and `cluster-endpoint` is a custom DNS name that maps to this IP. +This will allow you to pass `--control-plane-endpoint=cluster-endpoint` to `kubeadm init` and pass the same DNS name to +`kubeadm join`. Later you can modify `cluster-endpoint` to point to the address of your load-balancer in an +high availability scenario. + +Turning a single control plane cluster created without `--control-plane-endpoint` into a highly available cluster +is not supported by kubeadm. + ### 詳細 For more information about `kubeadm init` arguments, see the [kubeadm reference guide](/ja/docs/reference/setup-tools/kubeadm/kubeadm/). For a complete list of configuration options, see the [configuration file documentation](/ja/docs/reference/setup-tools/kubeadm/kubeadm-init/#config-file). -To customize control plane components, including optional IPv6 assignment to liveness probe for control plane components and etcd server, provide extra arguments to each component as documented in [custom arguments](/ja/docs/admin/kubeadm#custom-args). +To customize control plane components, including optional IPv6 assignment to liveness probe for control plane components and etcd server, provide extra arguments to each component as documented in [custom arguments](/ja/docs/setup/production-environment/tools/kubeadm/control-plane-flags/). To run `kubeadm init` again, you must first [tear down the cluster](#tear-down). -If you join a node with a different architecture to your cluster, create a separate -Deployment or DaemonSet for `kube-proxy` and `kube-dns` on the node. This is because the Docker images for these -components do not currently support multi-architecture. +If you join a node with a different architecture to your cluster, make sure that your deployed DaemonSets +have container image support for this architecture. `kubeadm init` first runs a series of prechecks to ensure that the machine is ready to run Kubernetes. These prechecks expose warnings and exit on errors. `kubeadm init` @@ -165,14 +173,14 @@ The output should look like: [certs] Using certificateDir folder "/etc/kubernetes/pki" [certs] Generating "etcd/ca" certificate and key [certs] Generating "etcd/server" certificate and key -[certs] etcd/server serving cert is signed for DNS names [kubeadm-master localhost] and IPs [10.138.0.4 127.0.0.1 ::1] +[certs] etcd/server serving cert is signed for DNS names [kubeadm-cp localhost] and IPs [10.138.0.4 127.0.0.1 ::1] [certs] Generating "etcd/healthcheck-client" certificate and key [certs] Generating "etcd/peer" certificate and key -[certs] etcd/peer serving cert is signed for DNS names [kubeadm-master localhost] and IPs [10.138.0.4 127.0.0.1 ::1] +[certs] etcd/peer serving cert is signed for DNS names [kubeadm-cp localhost] and IPs [10.138.0.4 127.0.0.1 ::1] [certs] Generating "apiserver-etcd-client" certificate and key [certs] Generating "ca" certificate and key [certs] Generating "apiserver" certificate and key -[certs] apiserver serving cert is signed for DNS names [kubeadm-master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.138.0.4] +[certs] apiserver serving cert is signed for DNS names [kubeadm-cp kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 10.138.0.4] [certs] Generating "apiserver-kubelet-client" certificate and key [certs] Generating "front-proxy-ca" certificate and key [certs] Generating "front-proxy-client" certificate and key @@ -191,9 +199,9 @@ The output should look like: [apiclient] All control plane components are healthy after 31.501735 seconds [uploadconfig] storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-X.Y" in namespace kube-system with the configuration for the kubelets in the cluster -[patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "kubeadm-master" as an annotation -[mark-control-plane] Marking the node kubeadm-master as control-plane by adding the label "node-role.kubernetes.io/master=''" -[mark-control-plane] Marking the node kubeadm-master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] +[patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "kubeadm-cp" as an annotation +[mark-control-plane] Marking the node kubeadm-cp as control-plane by adding the label "node-role.kubernetes.io/master=''" +[mark-control-plane] Marking the node kubeadm-cp as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] [bootstrap-token] Using token: [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles [bootstraptoken] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials @@ -203,7 +211,7 @@ The output should look like: [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy -Your Kubernetes master has initialized successfully! +Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: @@ -211,14 +219,14 @@ To start using your cluster, you need to run the following as a regular user: sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config -You should now deploy a pod network to the cluster. +You should now deploy a Pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: /docs/concepts/cluster-administration/addons/ You can now join any number of machines by running the following on each node as root: - kubeadm join : --token --discovery-token-ca-cert-hash sha256: + kubeadm join : --token --discovery-token-ca-cert-hash sha256: ``` To make kubectl work for your non-root user, run these commands, which are @@ -251,13 +259,13 @@ created, and deleted with the `kubeadm token` command. See the This section contains important information about installation and deployment order. Read it carefully before proceeding. {{< /caution >}} -You must install a pod network add-on so that your pods can communicate with +You must install a Pod network add-on so that your Pods can communicate with each other. **The network must be deployed before any applications. Also, CoreDNS will not start up before a network is installed. kubeadm only supports Container Network Interface (CNI) based networks (and does not support kubenet).** -Several projects provide Kubernetes pod networks using CNI, some of which also +Several projects provide Kubernetes Pod networks using CNI, some of which also support [Network Policy](/ja/docs/concepts/services-networking/networkpolicies/). See the [add-ons page](/ja/docs/concepts/cluster-administration/addons/) for a complete list of available network add-ons. - IPv6 support was added in [CNI v0.6.0](https://github.com/containernetworking/cni/releases/tag/v0.6.0). - [CNI bridge](https://github.com/containernetworking/plugins/blob/master/plugins/main/bridge/README.md) and [local-ipam](https://github.com/containernetworking/plugins/blob/master/plugins/ipam/host-local/README.md) are the only supported IPv6 network plugins in Kubernetes version 1.9. @@ -268,24 +276,16 @@ Make sure that your network manifest supports RBAC. Also, beware, that your Pod network must not overlap with any of the host networks as this can cause issues. If you find a collision between your network plugin’s preferred Pod network and some of your host networks, you should think of a suitable CIDR replacement and use that during `kubeadm init` with `--pod-network-cidr` and as a replacement in your network plugin’s YAML. -You can install a pod network add-on with the following command: +You can install a Pod network add-on with the following command on the control-plane node or a node that has the kubeconfig credentials: ```bash kubectl apply -f ``` -You can install only one pod network per cluster. +You can install only one Pod network per cluster. +Below you can find installation instructions for some popular Pod network plugins: {{< tabs name="tabs-pod-install" >}} -{{% tab name="Choose one..." %}} -Please select one of the tabs to see installation instructions for the respective third-party Pod Network Provider. -{{% /tab %}} - -{{% tab name="AWS VPC" %}} -AWS VPC CNI provides native AWS VPC networking to Kubernetes clusters. - -For installation, please refer to the [AWS VPC CNI setup guide](https://github.com/aws/amazon-vpc-cni-k8s#setup). -{{% /tab %}} {{% tab name="Calico" %}} For more information about using Calico, see [Quickstart for Calico on Kubernetes](https://docs.projectcalico.org/latest/getting-started/kubernetes/), [Installing Calico for policy and networking](https://docs.projectcalico.org/latest/getting-started/kubernetes/installation/calico), and other related resources. @@ -296,39 +296,18 @@ For Calico to work correctly, you need to pass `--pod-network-cidr=192.168.0.0/1 kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/calico.yaml ``` -{{% /tab %}} -{{% tab name="Canal" %}} -Canal uses Calico for policy and Flannel for networking. Refer to the Calico documentation for the [official getting started guide](https://docs.projectcalico.org/latest/getting-started/kubernetes/installation/flannel). - -For Canal to work correctly, `--pod-network-cidr=10.244.0.0/16` has to be passed to `kubeadm init`. Note that Canal works on `amd64` only. - -```shell -kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/canal.yaml -``` - {{% /tab %}} {{% tab name="Cilium" %}} -For more information about using Cilium with Kubernetes, see [Kubernetes Install guide for Cilium](https://docs.cilium.io/en/stable/kubernetes/). - For Cilium to work correctly, you must pass `--pod-network-cidr=10.217.0.0/16` to `kubeadm init`. -These commands will deploy Cilium with its own etcd managed by etcd operator. - -_Note_: If you are running kubeadm in a single node please untaint it so that -etcd-operator pods can be scheduled in the control-plane node. - -```shell -kubectl taint nodes node-role.kubernetes.io/master:NoSchedule- -``` - To deploy Cilium you just need to run: ```shell -kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.5/examples/kubernetes/1.14/cilium.yaml +kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.6/install/kubernetes/quick-install.yaml ``` -Once all Cilium pods are marked as `READY`, you start using your cluster. +Once all Cilium Pods are marked as `READY`, you start using your cluster. ```shell kubectl get pods -n kube-system --selector=k8s-app=cilium @@ -339,6 +318,10 @@ NAME READY STATUS RESTARTS AGE cilium-drxkl 1/1 Running 0 18m ``` +Cilium can be used as a replacement for kube-proxy, see [Kubernetes without kube-proxy](https://docs.cilium.io/en/stable/gettingstarted/kubeproxy-free). + +For more information about using Cilium with Kubernetes, see [Kubernetes Install guide for Cilium](https://docs.cilium.io/en/stable/kubernetes/). + {{% /tab %}} {{% tab name="Contiv-VPP" %}} @@ -366,49 +349,25 @@ Note that `flannel` works on `amd64`, `arm`, `arm64`, `ppc64le` and `s390x` unde Windows (`amd64`) is claimed as supported in v0.11.0 but the usage is undocumented. ```shell -kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/62e44c867a2846fefb68bd5f178daf4da3095ccb/Documentation/kube-flannel.yml +kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/2140ac876ef134e0ed5af15c65e414cf26827915/Documentation/kube-flannel.yml ``` For more information about `flannel`, see [the CoreOS flannel repository on GitHub ](https://github.com/coreos/flannel). {{% /tab %}} -{{% tab name="JuniperContrail/TungstenFabric" %}} -Provides overlay SDN solution, delivering multicloud networking, hybrid cloud networking, -simultaneous overlay-underlay support, network policy enforcement, network isolation, -service chaining and flexible load balancing. - -There are multiple, flexible ways to install JuniperContrail/TungstenFabric CNI. - -Kindly refer to this quickstart: [TungstenFabric](https://tungstenfabric.github.io/website/) -{{% /tab %}} - {{% tab name="Kube-router" %}} Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information please see [here](/ja/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). -Kube-router relies on kube-controller-manager to allocate pod CIDR for the nodes. Therefore, use `kubeadm init` with the `--pod-network-cidr` flag. +Kube-router relies on kube-controller-manager to allocate Pod CIDR for the nodes. Therefore, use `kubeadm init` with the `--pod-network-cidr` flag. -Kube-router provides pod networking, network policy, and high-performing IP Virtual Server(IPVS)/Linux Virtual Server(LVS) based service proxy. +Kube-router provides Pod networking, network policy, and high-performing IP Virtual Server(IPVS)/Linux Virtual Server(LVS) based service proxy. For information on setting up Kubernetes cluster with Kube-router using kubeadm, please see official [setup guide](https://github.com/cloudnativelabs/kube-router/blob/master/docs/kubeadm.md). {{% /tab %}} -{{% tab name="Romana" %}} -Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` -to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information -please see [here](/ja/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). - -The official Romana set-up guide is [here](https://github.com/romana/romana/tree/master/containerize#using-kubeadm). - -Romana works on `amd64` only. - -```shell -kubectl apply -f https://raw.githubusercontent.com/romana/romana/master/containerize/specs/romana-kubeadm.yml -``` -{{% /tab %}} - {{% tab name="Weave Net" %}} Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information @@ -428,16 +387,16 @@ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl versio {{< /tabs >}} -Once a pod network has been installed, you can confirm that it is working by -checking that the CoreDNS pod is Running in the output of `kubectl get pods --all-namespaces`. -And once the CoreDNS pod is up and running, you can continue by joining your nodes. +Once a Pod network has been installed, you can confirm that it is working by +checking that the CoreDNS Pod is Running in the output of `kubectl get pods --all-namespaces`. +And once the CoreDNS Pod is up and running, you can continue by joining your nodes. If your network is not working or CoreDNS is not in the Running state, checkout our [troubleshooting docs](/ja/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/). ### コントロールプレーンノードの隔離 -By default, your cluster will not schedule pods on the control-plane node for security -reasons. If you want to be able to schedule pods on the control-plane node, e.g. for a +By default, your cluster will not schedule Pods on the control-plane node for security +reasons. If you want to be able to schedule Pods on the control-plane node, e.g. for a single-machine Kubernetes cluster for development, run: ```bash @@ -454,21 +413,21 @@ taint "node-role.kubernetes.io/master:" not found This will remove the `node-role.kubernetes.io/master` taint from any nodes that have it, including the control-plane node, meaning that the scheduler will then be able -to schedule pods everywhere. +to schedule Pods everywhere. ### ノードの追加 {#join-nodes} -The nodes are where your workloads (containers and pods, etc) run. To add new nodes to your cluster do the following for each machine: +The nodes are where your workloads (containers and Pods, etc) run. To add new nodes to your cluster do the following for each machine: * SSH to the machine * Become root (e.g. `sudo su -`) * Run the command that was output by `kubeadm init`. For example: ``` bash -kubeadm join --token : --discovery-token-ca-cert-hash sha256: +kubeadm join --token : --discovery-token-ca-cert-hash sha256: ``` -If you do not have the token, you can get it by running the following command on the master node: +If you do not have the token, you can get it by running the following command on the control-plane node: ``` bash kubeadm token list @@ -485,7 +444,7 @@ TOKEN TTL EXPIRES USAGES DESCRIPTION ``` By default, tokens expire after 24 hours. If you are joining a node to the cluster after the current token has expired, -you can create a new token by running the following command on the master node: +you can create a new token by running the following command on the control-plane node: ``` bash kubeadm token create @@ -497,7 +456,7 @@ The output is similar to this: 5didvk.d09sbcov8ph2amjw ``` -If you don't have the value of `--discovery-token-ca-cert-hash`, you can get it by running the following command chain on the master node: +If you don't have the value of `--discovery-token-ca-cert-hash`, you can get it by running the following command chain on the control-plane node: ``` bash openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \ @@ -511,7 +470,7 @@ The output is similar to this: ``` {{< note >}} -To specify an IPv6 tuple for `:`, IPv6 address must be enclosed in square brackets, for example: `[fd00::101]:2073`. +To specify an IPv6 tuple for `:`, IPv6 address must be enclosed in square brackets, for example: `[fd00::101]:2073`. {{< /note >}} The output should look something like: @@ -522,24 +481,24 @@ The output should look something like: ... (log output of join workflow) ... Node join complete: -* Certificate signing request sent to master and response +* Certificate signing request sent to control-plane and response received. * Kubelet informed of new secure connection details. -Run 'kubectl get nodes' on the master to see this machine join. +Run 'kubectl get nodes' on control-plane to see this machine join. ``` A few seconds later, you should notice this node in the output from `kubectl get -nodes` when run on the master. +nodes` when run on the control-plane node. -### (任意) マスター以外のマシンからのクラスター操作 +### (任意)コントロールプレーンノード以外のマシンからのクラスター操作 In order to get a kubectl on some other computer (e.g. laptop) to talk to your -cluster, you need to copy the administrator kubeconfig file from your master +cluster, you need to copy the administrator kubeconfig file from your control-plane node to your workstation like this: ``` bash -scp root@:/etc/kubernetes/admin.conf . +scp root@:/etc/kubernetes/admin.conf . kubectl --kubeconfig ./admin.conf get nodes ``` @@ -563,7 +522,7 @@ If you want to connect to the API Server from outside the cluster you can use `kubectl proxy`: ```bash -scp root@:/etc/kubernetes/admin.conf . +scp root@:/etc/kubernetes/admin.conf . kubectl --kubeconfig ./admin.conf proxy ``` @@ -575,7 +534,7 @@ To undo what kubeadm did, you should first [drain the node](/ja/docs/reference/generated/kubectl/kubectl-commands#drain) and make sure that the node is empty before shutting it down. -Talking to the master with the appropriate credentials, run: +Talking to the control-plane node with the appropriate credentials, run: ```bash kubectl drain --delete-local-data --force --ignore-daemonsets @@ -622,6 +581,8 @@ control of your Kubernetes cluster. * Learn about kubeadm's advanced usage in the [kubeadm reference documentation](/ja/docs/reference/setup-tools/kubeadm/kubeadm) * Learn more about Kubernetes [concepts](/ja/docs/concepts/) and [`kubectl`](/ja/docs/user-guide/kubectl-overview/). * Configure log rotation. You can use **logrotate** for that. When using Docker, you can specify log rotation options for Docker daemon, for example `--log-driver=json-file --log-opt=max-size=10m --log-opt=max-file=5`. See [Configure and troubleshoot the Docker daemon](https://docs.docker.com/engine/admin/) for more details. +* See the [Cluster Networking](/docs/concepts/cluster-administration/networking/) page for a bigger list +of Pod network add-ons. ## フィードバック {#feedback} diff --git a/content/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md b/content/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md index 40d46f1912..9a7973469f 100644 --- a/content/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md +++ b/content/ja/docs/setup/production-environment/tools/kubeadm/install-kubeadm.md @@ -56,6 +56,9 @@ Linuxでは、カーネルのiptablesサブシステムの最新の代替品と {{< tabs name="iptables_legacy" >}} {{% tab name="Debian or Ubuntu" %}} ```bash +# レガシーバイナリがインストールされていることを確認してください +sudo apt-get install -y iptables arptables ebtables + sudo update-alternatives --set iptables /usr/sbin/iptables-legacy sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy sudo update-alternatives --set arptables /usr/sbin/arptables-legacy @@ -189,7 +192,7 @@ systemctl enable --now kubelet `net.bridge.bridge-nf-call-iptables` is set to 1 in your `sysctl` config, e.g. ```bash - cat < /etc/sysctl.d/k8s.conf + cat < /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-ip6tables = 1 net.bridge.bridge-nf-call-iptables = 1 EOF @@ -268,6 +271,6 @@ kubeadmで問題が発生した場合は、[トラブルシューティング](/ {{% capture whatsnext %}} -* [kubeadmを使用したシングルマスタークラスターの作成](/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) +* [kubeadmを使用したシングルコントロールプレーンクラスターの作成](/ja/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) {{% /capture %}} From 1513a7b29a0dc3fdb7b963cfa93caf50a1f38075 Mon Sep 17 00:00:00 2001 From: Andrew Allbright Date: Tue, 18 Feb 2020 19:42:25 -0500 Subject: [PATCH 24/38] latin phrase removed (#19180) --- .../docs/reference/access-authn-authz/service-accounts-admin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/reference/access-authn-authz/service-accounts-admin.md b/content/en/docs/reference/access-authn-authz/service-accounts-admin.md index 329b8a1b4a..5c2dd3ddc5 100644 --- a/content/en/docs/reference/access-authn-authz/service-accounts-admin.md +++ b/content/en/docs/reference/access-authn-authz/service-accounts-admin.md @@ -18,7 +18,7 @@ incomplete features are referred to in order to better describe service accounts {{% /capture %}} {{% capture body %}} -## User accounts vs service accounts +## User accounts versus service accounts Kubernetes distinguishes between the concept of a user account and a service account for a number of reasons: From 2d0bde0458d505bc6c2771544c5a5eea27dbf1c9 Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Wed, 19 Feb 2020 02:54:24 +0200 Subject: [PATCH 25/38] kubeadm: add TS guide note about CoreOS read-only /usr (#19166) * kubeadm: add TS guide note about CoreOS read-only /usr * Update content/en/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm.md Co-Authored-By: Tim Bannister Co-authored-by: Tim Bannister --- .../tools/kubeadm/troubleshooting-kubeadm.md | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/content/en/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm.md b/content/en/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm.md index 2f51d5efd7..31f94ef137 100644 --- a/content/en/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm.md +++ b/content/en/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm.md @@ -319,4 +319,46 @@ There are at least two workarounds: ```bash kubectl taint nodes NODE_NAME role.kubernetes.io/master:NoSchedule- ``` + +## `/usr` is mounted read-only on nodes {#usr-mounted-read-only} + +On Linux distributions such as Fedora CoreOS, the directory `/usr` is mounted as a read-only filesystem. +For [flex-volume support](https://github.com/kubernetes/community/blob/ab55d85/contributors/devel/sig-storage/flexvolume.md), +Kubernetes components like the kubelet and kube-controller-manager use the default path of +`/usr/libexec/kubernetes/kubelet-plugins/volume/exec/`, yet the flex-volume directory _must be writeable_ +for the feature to work. + +To workaround this issue you can configure the flex-volume directory using the kubeadm +[configuration file](https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2). + +On the primary control-plane Node (created using `kubeadm init`) pass the following +file using `--config`: + +```yaml +apiVersion: kubeadm.k8s.io/v1beta2 +kind: InitConfiguration +nodeRegistration: + kubeletExtraArgs: + volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/" +--- +apiVersion: kubeadm.k8s.io/v1beta2 +kind: ClusterConfiguration +controllerManager: + extraArgs: + flex-volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/" +``` + +On joining Nodes: + +```yaml +apiVersion: kubeadm.k8s.io/v1beta2 +kind: JoinConfiguration +nodeRegistration: + kubeletExtraArgs: + volume-plugin-dir: "/opt/libexec/kubernetes/kubelet-plugins/volume/exec/" +``` + +Alternatively, you can modify `/etc/fstab` to make the `/usr` mount writeable, but please +be advised that this is modifying a design principle of the Linux distribution. + {{% /capture %}} From 470f932dd8649592152b0388c653d114e81ee74d Mon Sep 17 00:00:00 2001 From: Andrew Allbright Date: Wed, 19 Feb 2020 03:14:25 -0500 Subject: [PATCH 26/38] Latin Abbreviations "vs" Updated to "versus" (#19181) * grep -lR ' vs ' ./content/en/docs | xargs sed -i '' -e 's/ vs / versus /g' * Update content/en/docs/concepts/configuration/overview.md Co-Authored-By: Tim Bannister * Update content/en/docs/concepts/policy/resource-quotas.md Co-Authored-By: Tim Bannister Co-authored-by: Tim Bannister --- content/en/docs/concepts/configuration/overview.md | 3 +-- .../extend-kubernetes/api-extension/custom-resources.md | 2 +- content/en/docs/concepts/policy/resource-quotas.md | 2 +- .../docs/reference/access-authn-authz/admission-controllers.md | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/content/en/docs/concepts/configuration/overview.md b/content/en/docs/concepts/configuration/overview.md index 1f67727322..ca56089b01 100644 --- a/content/en/docs/concepts/configuration/overview.md +++ b/content/en/docs/concepts/configuration/overview.md @@ -30,7 +30,7 @@ This is a living document. If you think of something that is not on this list bu - Put object descriptions in annotations, to allow better introspection. -## "Naked" Pods vs ReplicaSets, Deployments, and Jobs +## "Naked" Pods versus ReplicaSets, Deployments, and Jobs {#naked-pods-vs-replicasets-deployments-and-jobs} - Don't use naked Pods (that is, Pods not bound to a [ReplicaSet](/docs/concepts/workloads/controllers/replicaset/) or [Deployment](/docs/concepts/workloads/controllers/deployment/)) if you can avoid it. Naked Pods will not be rescheduled in the event of a node failure. @@ -108,4 +108,3 @@ The caching semantics of the underlying image provider make even `imagePullPolic {{% /capture %}} - diff --git a/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md b/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md index 660d589169..c96ae1f5c7 100644 --- a/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md +++ b/content/en/docs/concepts/extend-kubernetes/api-extension/custom-resources.md @@ -202,7 +202,7 @@ When you create a custom resource, either via a CRDs or an AA, you get many feat | Finalizers | Block deletion of extension resources until external cleanup happens. | | Admission Webhooks | Set default values and validate extension resources during any create/update/delete operation. | | UI/CLI Display | Kubectl, dashboard can display extension resources. | -| Unset vs Empty | Clients can distinguish unset fields from zero-valued fields. | +| Unset versus Empty | Clients can distinguish unset fields from zero-valued fields. | | Client Libraries Generation | Kubernetes provides generic client libraries, as well as tools to generate type-specific client libraries. | | Labels and annotations | Common metadata across objects that tools know how to edit for core and custom resources. | diff --git a/content/en/docs/concepts/policy/resource-quotas.md b/content/en/docs/concepts/policy/resource-quotas.md index 14fde56066..92f43fe3a3 100644 --- a/content/en/docs/concepts/policy/resource-quotas.md +++ b/content/en/docs/concepts/policy/resource-quotas.md @@ -376,7 +376,7 @@ pods 0 10 * `Exist` * `DoesNotExist` -## Requests vs Limits +## Requests compared to Limits {#requests-vs-limits} When allocating compute resources, each container may specify a request and a limit value for either CPU or memory. The quota can be configured to quota either value. diff --git a/content/en/docs/reference/access-authn-authz/admission-controllers.md b/content/en/docs/reference/access-authn-authz/admission-controllers.md index 2e741afd76..2ab54051a4 100644 --- a/content/en/docs/reference/access-authn-authz/admission-controllers.md +++ b/content/en/docs/reference/access-authn-authz/admission-controllers.md @@ -737,7 +737,7 @@ phase, and therefore is the last admission controller to run. `MutatingAdmissionWebhook` appears before it in this list, because it runs in the mutating phase. - For earlier versions, there was no concept of validating vs mutating and the + For earlier versions, there was no concept of validating versus mutating and the admission controllers ran in the exact order specified. {{% /capture %}} From 601f33f4fda784d277e74f350bb8d96a16a14c57 Mon Sep 17 00:00:00 2001 From: "Jorge O. Castro" Date: Wed, 19 Feb 2020 11:24:26 -0500 Subject: [PATCH 27/38] Announce the contributor summit schedule (#19174) * Announce the contributor summit schedule Signed-off-by: Jorge O. Castro * Fix minor nits found during review Signed-off-by: Jorge O. Castro * Update content/en/blog/_posts/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced.md Make the map URL easier to read. Co-Authored-By: Tim Bannister * Add contributor summit image Signed-off-by: Jorge O. Castro Co-authored-by: Tim Bannister --- ...tor-Summit-Amsterdam-Schedule-Announced.md | 45 ++++++++++++++++++ .../contribsummit.jpg | Bin 0 -> 246927 bytes 2 files changed, 45 insertions(+) create mode 100644 content/en/blog/_posts/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced.md create mode 100644 static/images/blog/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced/contribsummit.jpg diff --git a/content/en/blog/_posts/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced.md b/content/en/blog/_posts/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced.md new file mode 100644 index 0000000000..ae05bd8b9c --- /dev/null +++ b/content/en/blog/_posts/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced.md @@ -0,0 +1,45 @@ +--- +layout: blog +title: "Contributor Summit Amsterdam Schedule Announced" +date: 2020-02-18 +slug: Contributor-Summit-Amsterdam-Schedule-Announced +--- + +**Authors:** Jeffrey Sica (Red Hat), Amanda Katona (VMware) + +tl;dr [Registration is open](https://events.linuxfoundation.org/kubernetes-contributor-summit-europe/) and the [schedule is live](https://kcseu2020.sched.com/) so register now and we’ll see you in Amsterdam! + +## Kubernetes Contributor Summit + +**Sunday, March 29, 2020** + +- Evening Contributor Celebration: +[ZuidPool](https://www.zuid-pool.nl/en/) +- Address: [Europaplein 22, 1078 GZ Amsterdam, Netherlands](https://www.google.com/search?q=KubeCon+Amsterdam+2020&ie=UTF-8&ibp=htl;events&rciv=evn&sa=X&ved=2ahUKEwiZoLvQ0dvnAhVST6wKHScBBZ8Q5bwDMAB6BAgSEAE#) +- Time: 18:00 - 21:00 + +**Monday, March 30, 2020** + +- All Day Contributor Summit: +- [Amsterdam RAI](https://www.rai.nl/en/) +- Address: [Europaplein 24, 1078 GZ Amsterdam, Netherlands](https://www.google.com/search?q=kubecon+amsterdam+2020&oq=kubecon+amste&aqs=chrome.0.35i39j69i57j0l4j69i61l2.3957j1j4&sourceid=chrome&ie=UTF-8&ibp=htl;events&rciv=evn&sa=X&ved=2ahUKEwiZoLvQ0dvnAhVST6wKHScBBZ8Q5bwDMAB6BAgSEAE#) +- Time: 09:00 - 17:00 (Breakfast at 08:00) + +![Contributor Summit](/images/blog/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced/contribsummit.jpg) + +Hello everyone and Happy 2020! It’s hard to believe that KubeCon EU 2020 is less than six weeks away, and with that another contributor summit! This year we have the pleasure of being in Amsterdam in early spring, so be sure to pack some warmer clothing. This summit looks to be exciting with a lot of fantastic community-driven content. We received **26** submissions from the CFP. From that, the events team selected **12** sessions. Each of the sessions falls into one of four categories: + +* Community +* Contributor Improvement +* Sustainability +* In-depth Technical + +On top of the presentations, there will be a dedicated Docs Sprint as well as the New Contributor Workshop 101 and 201 Sessions. All told, we will have five separate rooms of content throughout the day on Monday. Please **[see the full schedule](https://kcseu2020.sched.com/)** to see what sessions you’d be interested in. We hope between the content provided and the inevitable hallway track, everyone has a fun and enriching experience. + +Speaking of fun, the social Sunday night should be a blast! We’re hosting this summit’s social close to the conference center, at [ZuidPool](https://www.zuid-pool.nl/en/). There will be games, bingo, and unconference sign-up throughout the evening. It should be a relaxed way to kick off the week. + +[Registration is open](https://events.linuxfoundation.org/kubernetes-contributor-summit-europe/)! Space is limited so it’s always a good idea to register early. + +If you have any questions, reach out to the [Amsterdam Team](https://github.com/kubernetes/community/tree/master/events/2020/03-contributor-summit#team) on Slack in the [#contributor-summit](https://kubernetes.slack.com/archives/C7J893413) channel. + +Hope to see you there! diff --git a/static/images/blog/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced/contribsummit.jpg b/static/images/blog/2020-02-18-Contributor-Summit-Amsterdam-Schedule-Announced/contribsummit.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62c83616a830f1435bce51f8025319821cd5717c GIT binary patch literal 246927 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

Yv?5ClgrF+}a&Q!LkC-~Dd>7$8u{hlh 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 z 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 M>SdHWkF9_I*->xl&j0`b literal 0 HcmV?d00001 From 560350b4de33f74e7544f718bef74ee613896ad9 Mon Sep 17 00:00:00 2001 From: Ihor Sychevskyi <26163841+Arhell@users.noreply.github.com> Date: Wed, 19 Feb 2020 19:02:26 +0200 Subject: [PATCH 28/38] Fix Invalid link in readme section (#19178) --- README-ru.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-ru.md b/README-ru.md index aab0adcbd1..5b110b903d 100644 --- a/README-ru.md +++ b/README-ru.md @@ -34,7 +34,7 @@ > Если вы используете Windows, вам необходимо установить дополнительные инструменты через [Chocolatey](https://chocolatey.org). `choco install make` -> Если вы хотите запустить сайт локально без Docker, обратитесь к разделу [Запуск сайта с помощью Hugo](#running-the-site-locally-using-hugo) ниже на этой странице. +> Если вы хотите запустить сайт локально без Docker, обратитесь к разделу [Запуск сайта с помощью Hugo](#запуск-сайта-с-помощью-hugo) ниже на этой странице. Когда Docker [установлен и запущен](https://www.docker.com/get-started), соберите локально Docker-образ `kubernetes-hugo`, выполнив команду в консоли: From f16c41b5ac1cc3424ec9347610ca8ecdf3550cf5 Mon Sep 17 00:00:00 2001 From: Fabian Ruff Date: Wed, 19 Feb 2020 21:13:33 +0100 Subject: [PATCH 29/38] Fix inital alpha version of ValidateProxyRedirects (#19192) See: https://github.com/kubernetes/kubernetes/pull/88260 --- .../reference/command-line-tools-reference/feature-gates.md | 2 +- .../reference/command-line-tools-reference/feature-gates.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content/en/docs/reference/command-line-tools-reference/feature-gates.md b/content/en/docs/reference/command-line-tools-reference/feature-gates.md index b02b3e48bd..b0b24ba517 100644 --- a/content/en/docs/reference/command-line-tools-reference/feature-gates.md +++ b/content/en/docs/reference/command-line-tools-reference/feature-gates.md @@ -146,7 +146,7 @@ different Kubernetes components. | `TokenRequestProjection` | `true` | Beta | 1.12 | | | `TTLAfterFinished` | `false` | Alpha | 1.12 | | | `TopologyManager` | `false` | Alpha | 1.16 | | -| `ValidateProxyRedirects` | `false` | Alpha | 1.10 | 1.13 | +| `ValidateProxyRedirects` | `false` | Alpha | 1.12 | 1.13 | | `ValidateProxyRedirects` | `true` | Beta | 1.14 | | | `VolumePVCDataSource` | `false` | Alpha | 1.15 | 1.15 | | `VolumePVCDataSource` | `true` | Beta | 1.16 | | diff --git a/content/ja/docs/reference/command-line-tools-reference/feature-gates.md b/content/ja/docs/reference/command-line-tools-reference/feature-gates.md index 92fb9868df..b20bbcfd23 100644 --- a/content/ja/docs/reference/command-line-tools-reference/feature-gates.md +++ b/content/ja/docs/reference/command-line-tools-reference/feature-gates.md @@ -139,7 +139,7 @@ content_template: templates/concept | `TokenRequestProjection` | `true` | Beta | 1.12 | | | `TTLAfterFinished` | `false` | Alpha | 1.12 | | | `TopologyManager` | `false` | Alpha | 1.16 | | -| `ValidateProxyRedirects` | `false` | Alpha | 1.10 | 1.13 | +| `ValidateProxyRedirects` | `false` | Alpha | 1.12 | 1.13 | | `ValidateProxyRedirects` | `true` | Beta | 1.14 | | | `VolumePVCDataSource` | `false` | Alpha | 1.15 | 1.15 | | `VolumePVCDataSource` | `true` | Beta | 1.16 | | From fefda3e4ea11ed54f0c73e9db3af6a578fe67531 Mon Sep 17 00:00:00 2001 From: Jamie Luckett Date: Wed, 19 Feb 2020 20:38:48 +0000 Subject: [PATCH 30/38] Add missing space in documentation line (#19013) --- content/en/docs/reference/kubectl/docker-cli-to-kubectl.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/reference/kubectl/docker-cli-to-kubectl.md b/content/en/docs/reference/kubectl/docker-cli-to-kubectl.md index b86ee27042..7def04e04c 100644 --- a/content/en/docs/reference/kubectl/docker-cli-to-kubectl.md +++ b/content/en/docs/reference/kubectl/docker-cli-to-kubectl.md @@ -281,7 +281,7 @@ kubectl get po -l run=nginx-app ``` {{< note >}} -When you use kubectl, you don't delete the pod directly.You have to first delete the Deployment that owns the pod. If you delete the pod directly, the Deployment recreates the pod. +When you use kubectl, you don't delete the pod directly. You have to first delete the Deployment that owns the pod. If you delete the pod directly, the Deployment recreates the pod. {{< /note >}} ## docker login From 6a3c364706c49b1603f6f1ae56d8d2dae5af5921 Mon Sep 17 00:00:00 2001 From: Tim Bannister Date: Wed, 19 Feb 2020 20:49:45 +0000 Subject: [PATCH 31/38] =?UTF-8?q?Reword=20=E2=80=9CCreating=20a=20single?= =?UTF-8?q?=20control-plane=20cluster=20with=20kubeadm=E2=80=9D=20(#18939)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Consolidate words of caution about Pod network * Tweak wording - use tooltips - fix a TODO hyperlink - adopt style guidelines * Revise prerequisites for kubeadm * Rework page structure - Replace some headings with anchor elements (preserving inbound links) - Use a "discussion" section for the discussion part of the page. - Make Feedback be a part of the What's Next section - Skip mentioning Docker in a logging context; provide generic signposting instead. - Update overview - Document limitations and fix link to HA topology - Fixes for styling * Redo network plugin info * Use glossary tooltips to introduce terms --- .../compute-storage-net/network-plugins.md | 2 +- .../tools/kubeadm/create-cluster-kubeadm.md | 290 ++++++++++-------- 2 files changed, 159 insertions(+), 133 deletions(-) diff --git a/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md b/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md index cb9b6d83a9..3cb5f3ffa8 100644 --- a/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md +++ b/content/en/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins.md @@ -12,7 +12,7 @@ weight: 10 {{% capture overview %}} {{< feature-state state="alpha" >}} -{{< warning >}}Alpha features change rapidly. {{< /warning >}} +{{< caution >}}Alpha features can change rapidly. {{< /caution >}} Network plugins in Kubernetes come in a few flavors: diff --git a/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md b/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md index bfb26fa1ca..2c978b0653 100644 --- a/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md +++ b/content/en/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm.md @@ -8,63 +8,50 @@ weight: 30 {{% capture overview %}} -**kubeadm** helps you bootstrap a minimum viable Kubernetes cluster that conforms to best practices. With kubeadm, your cluster should pass [Kubernetes Conformance tests](https://kubernetes.io/blog/2017/10/software-conformance-certification). Kubeadm also supports other cluster -lifecycle functions, such as upgrades, downgrade, and managing [bootstrap tokens](/docs/reference/access-authn-authz/bootstrap-tokens/). +The `kubeadm` tool helps you bootstrap a minimum viable Kubernetes cluster that conforms to best practices. In fact, you can use `kubeadm` to set up a cluster that will pass the [Kubernetes Conformance tests](https://kubernetes.io/blog/2017/10/software-conformance-certification). +`kubeadm` also supports other cluster +lifecycle functions, such as [bootstrap tokens](/docs/reference/access-authn-authz/bootstrap-tokens/) and cluster upgrades. -Because you can install kubeadm on various types of machine (e.g. laptop, server, -Raspberry Pi, etc.), it's well suited for integration with provisioning systems -such as Terraform or Ansible. +The `kubeadm` tool is good if you need: -kubeadm's simplicity means it can serve a wide range of use cases: +- A simple way for you to try out Kubernetes, possibly for the first time. +- A way for existing users to automate setting up a cluster and test their application. +- A building block in other ecosystem and/or installer tools with a larger + scope. -- New users can start with kubeadm to try Kubernetes out for the first time. -- Users familiar with Kubernetes can spin up clusters with kubeadm and test their applications. -- Larger projects can include kubeadm as a building block in a more complex system that can also include other installer tools. - -kubeadm is designed to be a simple way for new users to start trying -Kubernetes out, possibly for the first time, a way for existing users to -test their application on and stitch together a cluster easily, and also to be -a building block in other ecosystem and/or installer tool with a larger -scope. - -You can install _kubeadm_ very easily on operating systems that support -installing deb or rpm packages. The responsible SIG for kubeadm, -[SIG Cluster Lifecycle](https://github.com/kubernetes/community/tree/master/sig-cluster-lifecycle), provides these packages pre-built for you, -but you may also build them from source for other OSes. - - -### kubeadm maturity - -kubeadm's overall feature state is **GA**. Some sub-features, like the configuration -file API are still under active development. The implementation of creating the cluster -may change slightly as the tool evolves, but the overall implementation should be pretty stable. -Any commands under `kubeadm alpha` are by definition, supported on an alpha level. - - -### Support timeframes - -Kubernetes releases are generally supported for nine months, and during that -period a patch release may be issued from the release branch if a severe bug or -security issue is found. Here are the latest Kubernetes releases and the support -timeframe; which also applies to `kubeadm`. - -| Kubernetes version | Release month | End-of-life-month | -|--------------------|----------------|-------------------| -| v1.13.x | December 2018 | September 2019   | -| v1.14.x | March 2019 | December 2019   | -| v1.15.x | June 2019 | March 2020   | -| v1.16.x | September 2019 | June 2020   | +You can install and use `kubeadm` on various machines: your laptop, a set +of cloud servers, a Raspberry Pi, and more. Whether you're deploying into the +cloud or on-premises, you can integrate `kubeadm` into provisioning systems such +as Ansible or Terraform. {{% /capture %}} {{% capture prerequisites %}} -- One or more machines running a deb/rpm-compatible OS, for example Ubuntu or CentOS -- 2 GB or more of RAM per machine. Any less leaves little room for your +To follow this guide, you need: + +- One or more machines running a deb/rpm-compatible Linux OS; for example: Ubuntu or CentOS. +- 2 GiB or more of RAM per machine--any less leaves little room for your apps. -- 2 CPUs or more on the control-plane node -- Full network connectivity among all machines in the cluster. A public or - private network is fine. +- At least 2 CPUs on the machine that you use as a control-plane node. +- Full network connectivity among all machines in the cluster. You can use either a + public or a private network. + + +You also need to use a version of `kubeadm` that can deploy the version +of Kubernetes that you want to use in your new cluster. + +[Kubernetes' version and version skew support policy](https://kubernetes.io/docs/setup/release/version-skew-policy/#supported-versions) applies to `kubeadm` as well as to Kubernetes overall. +Check that policy to learn about what versions of Kubernetes and `kubeadm` +are supported. This page is written for Kubernetes {{< param "version" >}}. + +The `kubeadm` tool's overall feature state is General Availability (GA). Some sub-features are +still under active development. The implementation of creating the cluster may change +slightly as the tool evolves, but the overall implementation should be pretty stable. + +{{< note >}} +Any commands under `kubeadm alpha` are, by definition, supported on an alpha level. +{{< /note >}} {{% /capture %}} @@ -94,27 +81,29 @@ After you initialize your control-plane, the kubelet runs normally. ### Initializing your control-plane node The control-plane node is the machine where the control plane components run, including -etcd (the cluster database) and the API server (which the kubectl CLI +{{< glossary_tooltip term_id="etcd" >}} (the cluster database) and the +{{< glossary_tooltip text="API Server" term_id="kube-apiserver" >}} +(which the {{< glossary_tooltip text="kubectl" term_id="kubectl" >}} command line tool communicates with). -1. (Recommended) If you have plans to upgrade this single control-plane kubeadm cluster +1. (Recommended) If you have plans to upgrade this single control-plane `kubeadm` cluster to high availability you should specify the `--control-plane-endpoint` to set the shared endpoint for all control-plane nodes. Such an endpoint can be either a DNS name or an IP address of a load-balancer. 1. Choose a Pod network add-on, and verify whether it requires any arguments to -be passed to kubeadm initialization. Depending on which +be passed to `kubeadm init`. Depending on which third-party provider you choose, you might need to set the `--pod-network-cidr` to a provider-specific value. See [Installing a Pod network add-on](#pod-network). -1. (Optional) Since version 1.14, kubeadm will try to detect the container runtime on Linux +1. (Optional) Since version 1.14, `kubeadm` tries to detect the container runtime on Linux by using a list of well known domain socket paths. To use different container runtime or if there are more than one installed on the provisioned node, specify the `--cri-socket` argument to `kubeadm init`. See [Installing runtime](/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-runtime). -1. (Optional) Unless otherwise specified, kubeadm uses the network interface associated +1. (Optional) Unless otherwise specified, `kubeadm` uses the network interface associated with the default gateway to set the advertise address for this particular control-plane node's API server. To use a different network interface, specify the `--apiserver-advertise-address=` argument to `kubeadm init`. To deploy an IPv6 Kubernetes cluster using IPv6 addressing, you must specify an IPv6 address, for example `--apiserver-advertise-address=fd00::101` 1. (Optional) Run `kubeadm config images pull` prior to `kubeadm init` to verify -connectivity to gcr.io registries. +connectivity to the gcr.io container image registry. To initialize the control-plane node run: @@ -258,26 +247,43 @@ created, and deleted with the `kubeadm token` command. See the ### Installing a Pod network add-on {#pod-network} {{< caution >}} -This section contains important information about installation and deployment order. Read it carefully before proceeding. +This section contains important information about networking setup and +deployment order. +Read all of this advice carefully before proceeding. + +**You must deploy a +{{< glossary_tooltip text="Container Network Interface" term_id="cni" >}} +(CNI) based Pod network add-on so that your Pods can communicate with each other. +Cluster DNS (CoreDNS) will not start up before a network is installed.** + +- Take care that your Pod network must not overlap with any of the host + networks: you are likely to see problems if there is any overlap. + (If you find a collision between your network plugin’s preferred Pod + network and some of your host networks, you should think of a suitable + CIDR block to use instead, then use that during `kubeadm init` with + `--pod-network-cidr` and as a replacement in your network plugin’s YAML). + +- By default, `kubeadm` sets up your cluster to use and enforce use of + [RBAC](/docs/reference/access-authn-authz/rbac/) (role based access + control). + Make sure that your Pod network plugin supports RBAC, and so do any manifests + that you use to deploy it. + +- If you want to use IPv6--either dual-stack, or single-stack IPv6 only + networking--for your cluster, make sure that your Pod network plugin + supports IPv6. + IPv6 support was added to CNI in [v0.6.0](https://github.com/containernetworking/cni/releases/tag/v0.6.0). + {{< /caution >}} -You must install a Pod network add-on so that your Pods can communicate with -each other. +Several external projects provide Kubernetes Pod networks using CNI, some of which also +support [Network Policy](/docs/concepts/services-networking/networkpolicies/). -**The network must be deployed before any applications. Also, CoreDNS will not start up before a network is installed. -kubeadm only supports Container Network Interface (CNI) based networks (and does not support kubenet).** +See the list of available +[networking and network policy add-ons](https://kubernetes.io/docs/concepts/cluster-administration/addons/#networking-and-network-policy). -Several projects provide Kubernetes Pod networks using CNI, some of which also -support [Network Policy](/docs/concepts/services-networking/networkpolicies/). See the [add-ons page](/docs/concepts/cluster-administration/addons/) for a complete list of available network add-ons. -- IPv6 support was added in [CNI v0.6.0](https://github.com/containernetworking/cni/releases/tag/v0.6.0). See each plugin's documentation to see if it supports IPv6. - -Note that kubeadm sets up a more secure cluster by default and enforces use of [RBAC](/docs/reference/access-authn-authz/rbac/). -Make sure that your network manifest supports RBAC. - -Also, beware, that your Pod network must not overlap with any of the host networks as this can cause issues. -If you find a collision between your network plugin’s preferred Pod network and some of your host networks, you should think of a suitable CIDR replacement and use that during `kubeadm init` with `--pod-network-cidr` and as a replacement in your network plugin’s YAML. - -You can install a Pod network add-on with the following command on the control-plane node or a node that has the kubeconfig credentials: +You can install a Pod network add-on with the following command on the +control-plane node or a node that has the kubeconfig credentials: ```bash kubectl apply -f @@ -291,7 +297,7 @@ Below you can find installation instructions for some popular Pod network plugin {{% tab name="Calico" %}} [Calico](https://docs.projectcalico.org/latest/introduction/) is a networking and network policy provider. Calico supports a flexible set of networking options so you can choose the most efficient option for your situation, including non-overlay and overlay networks, with or without BGP. Calico uses the same engine to enforce network policy for hosts, pods, and (if using Istio & Envoy) applications at the service mesh layer. Calico works on several architectures, including `amd64`, `arm64`, and `ppc64le`. -By default, Calico uses `192.168.0.0/16` as the Pod network CIDR, though this can be configured in the calico.yaml file. For Calico to work correctly, you need to pass this same CIDR to the kubeadm init command using the `--pod-network-cidr=192.168.0.0/16` flag or via the kubeadm configuration. +By default, Calico uses `192.168.0.0/16` as the Pod network CIDR, though this can be configured in the calico.yaml file. For Calico to work correctly, you need to pass this same CIDR to the `kubeadm init` command using the `--pod-network-cidr=192.168.0.0/16` flag or via kubeadm's configuration. ```shell kubectl apply -f https://docs.projectcalico.org/v3.11/manifests/calico.yaml @@ -340,13 +346,11 @@ For `flannel` to work correctly, you must pass `--pod-network-cidr=10.244.0.0/16 Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information -please see [here](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). +please see [Network Plugin Requirements](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). -Make sure that your firewall rules allow UDP ports 8285 and 8472 traffic for all hosts participating in the overlay network. -see [here -](https://coreos.com/flannel/docs/latest/troubleshooting.html#firewalls). +Make sure that your firewall rules allow UDP ports 8285 and 8472 traffic for all hosts participating in the overlay network. The [Firewall](https://coreos.com/flannel/docs/latest/troubleshooting.html#firewalls) section of Flannel's troubleshooting guide explains about this in more detail. -Note that `flannel` works on `amd64`, `arm`, `arm64`, `ppc64le` and `s390x` under Linux. +Flannel works on `amd64`, `arm`, `arm64`, `ppc64le` and `s390x` architectures under Linux. Windows (`amd64`) is claimed as supported in v0.11.0 but the usage is undocumented. ```shell @@ -360,23 +364,23 @@ For more information about `flannel`, see [the CoreOS flannel repository on GitH {{% tab name="Kube-router" %}} Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information -please see [here](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). +please see [Network Plugin Requirements](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). Kube-router relies on kube-controller-manager to allocate Pod CIDR for the nodes. Therefore, use `kubeadm init` with the `--pod-network-cidr` flag. Kube-router provides Pod networking, network policy, and high-performing IP Virtual Server(IPVS)/Linux Virtual Server(LVS) based service proxy. -For information on setting up Kubernetes cluster with Kube-router using kubeadm, please see official [setup guide](https://github.com/cloudnativelabs/kube-router/blob/master/docs/kubeadm.md). +For information on using the `kubeadm` tool to set up a Kubernetes cluster with Kube-router, please see the official [setup guide](https://github.com/cloudnativelabs/kube-router/blob/master/docs/kubeadm.md). {{% /tab %}} {{% tab name="Weave Net" %}} Set `/proc/sys/net/bridge/bridge-nf-call-iptables` to `1` by running `sysctl net.bridge.bridge-nf-call-iptables=1` to pass bridged IPv4 traffic to iptables' chains. This is a requirement for some CNI plugins to work, for more information -please see [here](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). +please see [Network Plugin Requirements](/docs/concepts/cluster-administration/network-plugins/#network-plugin-requirements). -The official Weave Net set-up guide is [here](https://www.weave.works/docs/net/latest/kube-addon/). +For more information on setting up your Kubernetes cluster with Weave Net, please see [Integrating Kubernetes via the Addon]((https://www.weave.works/docs/net/latest/kube-addon/). -Weave Net works on `amd64`, `arm`, `arm64` and `ppc64le` without any extra action required. +Weave Net works on `amd64`, `arm`, `arm64` and `ppc64le` platforms without any extra action required. Weave Net sets hairpin mode by default. This allows Pods to access themselves via their Service IP address if they don't know their PodIP. @@ -389,10 +393,12 @@ kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl versio Once a Pod network has been installed, you can confirm that it is working by -checking that the CoreDNS Pod is Running in the output of `kubectl get pods --all-namespaces`. +checking that the CoreDNS Pod is `Running` in the output of `kubectl get pods --all-namespaces`. And once the CoreDNS Pod is up and running, you can continue by joining your nodes. -If your network is not working or CoreDNS is not in the Running state, checkout our [troubleshooting docs](/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/). +If your network is not working or CoreDNS is not in the `Running` state, check out the +[troubleshooting guide](/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/) +for `kubeadm`. ### Control plane node isolation @@ -424,19 +430,19 @@ The nodes are where your workloads (containers and Pods, etc) run. To add new no * Become root (e.g. `sudo su -`) * Run the command that was output by `kubeadm init`. For example: -``` bash +```bash kubeadm join --token : --discovery-token-ca-cert-hash sha256: ``` If you do not have the token, you can get it by running the following command on the control-plane node: -``` bash +```bash kubeadm token list ``` The output is similar to this: -``` console +```console TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS 8ewj1p.9r9hcjoqgajrj4gi 23h 2018-06-12T02:51:28Z authentication, The default bootstrap system: signing token generated by bootstrappers: @@ -447,26 +453,26 @@ TOKEN TTL EXPIRES USAGES DESCRIPTION By default, tokens expire after 24 hours. If you are joining a node to the cluster after the current token has expired, you can create a new token by running the following command on the control-plane node: -``` bash +```bash kubeadm token create ``` The output is similar to this: -``` console +```console 5didvk.d09sbcov8ph2amjw ``` If you don't have the value of `--discovery-token-ca-cert-hash`, you can get it by running the following command chain on the control-plane node: -``` bash +```bash openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | \ openssl dgst -sha256 -hex | sed 's/^.* //' ``` -The output is similar to this: +The output is similar to: -``` console +```console 8cb2de97839780a412b93877f8507ad6c94f73add17d5d7058e91741c9d5ec78 ``` @@ -498,7 +504,7 @@ In order to get a kubectl on some other computer (e.g. laptop) to talk to your cluster, you need to copy the administrator kubeconfig file from your control-plane node to your workstation like this: -``` bash +```bash scp root@:/etc/kubernetes/admin.conf . kubectl --kubeconfig ./admin.conf get nodes ``` @@ -529,11 +535,18 @@ kubectl --kubeconfig ./admin.conf proxy You can now access the API Server locally at `http://localhost:8001/api/v1` -## Tear down {#tear-down} +## Clean up {#tear-down} -To undo what kubeadm did, you should first [drain the -node](/docs/reference/generated/kubectl/kubectl-commands#drain) and make -sure that the node is empty before shutting it down. +If you used disposable servers for your cluster, for testing, you can +switch those off and do no further clean up. You can use +`kubectl config delete-cluster` to delete your local references to the +cluster. + +However, if you want to deprovision your cluster more cleanly, you should +first [drain the node](/docs/reference/generated/kubectl/kubectl-commands#drain) +and make sure that the node is empty, then deconfigure the node. + +### Remove the node Talking to the control-plane node with the appropriate credentials, run: @@ -542,7 +555,7 @@ kubectl drain --delete-local-data --force --ignore-daemonsets kubectl delete node ``` -Then, on the node being removed, reset all kubeadm installed state: +Then, on the node being removed, reset all `kubeadm` installed state: ```bash kubeadm reset @@ -563,47 +576,55 @@ ipvsadm -C If you wish to start over simply run `kubeadm init` or `kubeadm join` with the appropriate arguments. -More options and information about the -[`kubeadm reset command`](/docs/reference/setup-tools/kubeadm/kubeadm-reset/). +### Clean up the control plane -## Maintaining a cluster {#lifecycle} +You can use `kubeadm reset` on the control plane host to trigger a best-effort +clean up. -Instructions for maintaining kubeadm clusters (e.g. upgrades,downgrades, etc.) can be found [here.](/docs/tasks/administer-cluster/kubeadm) +See the [`kubeadm reset`](/docs/reference/setup-tools/kubeadm/kubeadm-reset/) +reference documentation for more information about this subcommand and its +options. -## Explore other add-ons {#other-addons} +{{% /capture %}} -See the [list of add-ons](/docs/concepts/cluster-administration/addons/) to explore other add-ons, -including tools for logging, monitoring, network policy, visualization & -control of your Kubernetes cluster. +{{% capture discussion %}} ## What's next {#whats-next} * Verify that your cluster is running properly with [Sonobuoy](https://github.com/heptio/sonobuoy) -* Learn about kubeadm's advanced usage in the [kubeadm reference documentation](/docs/reference/setup-tools/kubeadm/kubeadm) +* See [Upgrading kubeadm clusters](/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/) + for details about upgrading your cluster using `kubeadm`. +* Learn about advanced `kubeadm` usage in the [kubeadm reference documentation](/docs/reference/setup-tools/kubeadm/kubeadm) * Learn more about Kubernetes [concepts](/docs/concepts/) and [`kubectl`](/docs/user-guide/kubectl-overview/). -* Configure log rotation. You can use **logrotate** for that. When using Docker, you can specify log rotation options for Docker daemon, for example `--log-driver=json-file --log-opt=max-size=10m --log-opt=max-file=5`. See [Configure and troubleshoot the Docker daemon](https://docs.docker.com/engine/admin/) for more details. * See the [Cluster Networking](/docs/concepts/cluster-administration/networking/) page for a bigger list of Pod network add-ons. +* See the [list of add-ons](/docs/concepts/cluster-administration/addons/) to + explore other add-ons, including tools for logging, monitoring, network policy, visualization & + control of your Kubernetes cluster. +* Configure how your cluster handles logs for cluster events and from + applications running in Pods. + See [Logging Architecture](/docs/concepts/cluster-administration/logging/) for + an overview of what is involved. -## Feedback {#feedback} +### Feedback {#feedback} -* For bugs, visit [kubeadm GitHub issue tracker](https://github.com/kubernetes/kubeadm/issues) -* For support, visit kubeadm Slack Channel: - [#kubeadm](https://kubernetes.slack.com/messages/kubeadm/) -* General SIG Cluster Lifecycle Development Slack Channel: +* For bugs, visit the [kubeadm GitHub issue tracker](https://github.com/kubernetes/kubeadm/issues) +* For support, visit the + [#kubeadm](https://kubernetes.slack.com/messages/kubeadm/) Slack channel +* General SIG Cluster Lifecycle development Slack channel: [#sig-cluster-lifecycle](https://kubernetes.slack.com/messages/sig-cluster-lifecycle/) -* SIG Cluster Lifecycle [SIG information](#TODO) -* SIG Cluster Lifecycle Mailing List: +* SIG Cluster Lifecycle [SIG information](https://github.com/kubernetes/community/tree/master/sig-cluster-lifecycle#readme) +* SIG Cluster Lifecycle mailing list: [kubernetes-sig-cluster-lifecycle](https://groups.google.com/forum/#!forum/kubernetes-sig-cluster-lifecycle) ## Version skew policy {#version-skew-policy} -The kubeadm CLI tool of version vX.Y may deploy clusters with a control plane of version vX.Y or vX.(Y-1). -kubeadm CLI vX.Y can also upgrade an existing kubeadm-created cluster of version vX.(Y-1). +The `kubeadm` tool of version vX.Y may deploy clusters with a control plane of version vX.Y or vX.(Y-1). +`kubeadm` vX.Y can also upgrade an existing kubeadm-created cluster of version vX.(Y-1). Due to that we can't see into the future, kubeadm CLI vX.Y may or may not be able to deploy vX.(Y+1) clusters. -Example: kubeadm v1.8 can deploy both v1.7 and v1.8 clusters and upgrade v1.7 kubeadm-created clusters to +Example: `kubeadm` v1.8 can deploy both v1.7 and v1.8 clusters and upgrade v1.7 kubeadm-created clusters to v1.8. These resources provide more information on supported version skew between kubelets and the control plane, and other Kubernetes components: @@ -611,7 +632,24 @@ These resources provide more information on supported version skew between kubel * Kubernetes [version and version-skew policy](/docs/setup/release/version-skew-policy/) * Kubeadm-specific [installation guide](/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-kubeadm-kubelet-and-kubectl) -## kubeadm works on multiple platforms {#multi-platform} +## Limitations {#limitations} + +### Cluster resilience {#resilience} + +The cluster created here has a single control-plane node, with a single etcd database +running on it. This means that if the control-plane node fails, your cluster may lose +data and may need to be recreated from scratch. + +Workarounds: + +* Regularly [back up etcd](https://coreos.com/etcd/docs/latest/admin_guide.html). The + etcd data directory configured by kubeadm is at `/var/lib/etcd` on the control-plane node. + +* Use multiple control-plane nodes. You can read + [Options for Highly Available topology](/docs/setup/production-environment/tools/kubeadm/ha-topology/) to pick a cluster + topology that provides higher availabilty. + +### Platform compatibility {#multi-platform} kubeadm deb/rpm packages and binaries are built for amd64, arm (32-bit), arm64, ppc64le, and s390x following the [multi-platform @@ -623,20 +661,8 @@ Only some of the network providers offer solutions for all platforms. Please con network providers above or the documentation from each provider to figure out whether the provider supports your chosen platform. -## Limitations {#limitations} - -The cluster created here has a single control-plane node, with a single etcd database -running on it. This means that if the control-plane node fails, your cluster may lose -data and may need to be recreated from scratch. - -Workarounds: - -* Regularly [back up etcd](https://coreos.com/etcd/docs/latest/admin_guide.html). The - etcd data directory configured by kubeadm is at `/var/lib/etcd` on the control-plane node. - -* Use multiple control-plane nodes by completing the - [HA setup](/docs/setup/independent/ha-topology) instead. - ## Troubleshooting {#troubleshooting} If you are running into difficulties with kubeadm, please consult our [troubleshooting docs](/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/). + +{{% /capture %}} From e433c954d05082188d84149ff92cadcda097c01a Mon Sep 17 00:00:00 2001 From: Jacky Wu Date: Thu, 20 Feb 2020 05:03:46 +0800 Subject: [PATCH 32/38] Kill all federation v1 related tasks pages. (#17949) --- content/en/docs/tasks/federation/_index.md | 5 - .../administer-federation/_index.md | 5 - .../administer-federation/cluster.md | 119 ---- .../administer-federation/configmap.md | 89 --- .../administer-federation/daemonset.md | 83 --- .../administer-federation/deployment.md | 111 ---- .../administer-federation/events.md | 50 -- .../federation/administer-federation/hpa.md | 184 ------ .../administer-federation/ingress.md | 311 ---------- .../federation/administer-federation/job.md | 109 ---- .../administer-federation/namespaces.md | 92 --- .../administer-federation/replicaset.md | 132 ---- .../administer-federation/secret.md | 93 --- .../federation-service-discovery.md | 416 ------------- .../set-up-cluster-federation-kubefed.md | 564 ------------------ .../set-up-coredns-provider-federation.md | 152 ----- .../set-up-placement-policies-federation.md | 221 ------- 17 files changed, 2736 deletions(-) delete mode 100755 content/en/docs/tasks/federation/_index.md delete mode 100755 content/en/docs/tasks/federation/administer-federation/_index.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/cluster.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/configmap.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/daemonset.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/deployment.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/events.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/hpa.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/ingress.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/job.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/namespaces.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/replicaset.md delete mode 100644 content/en/docs/tasks/federation/administer-federation/secret.md delete mode 100644 content/en/docs/tasks/federation/federation-service-discovery.md delete mode 100644 content/en/docs/tasks/federation/set-up-cluster-federation-kubefed.md delete mode 100644 content/en/docs/tasks/federation/set-up-coredns-provider-federation.md delete mode 100644 content/en/docs/tasks/federation/set-up-placement-policies-federation.md diff --git a/content/en/docs/tasks/federation/_index.md b/content/en/docs/tasks/federation/_index.md deleted file mode 100755 index 869c63fc6a..0000000000 --- a/content/en/docs/tasks/federation/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Federation" -weight: 120 ---- - diff --git a/content/en/docs/tasks/federation/administer-federation/_index.md b/content/en/docs/tasks/federation/administer-federation/_index.md deleted file mode 100755 index 555416fb9b..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Administer Federation Control Plane" -weight: 160 ---- - diff --git a/content/en/docs/tasks/federation/administer-federation/cluster.md b/content/en/docs/tasks/federation/administer-federation/cluster.md deleted file mode 100644 index 92c1ec5993..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/cluster.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: Federated Cluster -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use Clusters API resource in a Federation control plane. - -Different than other Kubernetes resources, such as Deployments, Services and ConfigMaps, -clusters only exist in the federation context, i.e. those requests must be submitted to the -federation api-server. - -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic [working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general. - -{{% /capture %}} - -{{% capture steps %}} - -## Listing Clusters - -To list the clusters available in your federation, you can use [kubectl](/docs/user-guide/kubectl/) by -running: - -``` shell -kubectl --context=federation get clusters -``` - -The `--context=federation` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. If you submit it to a k8s cluster, you will receive an error saying - -```the server doesn't have a resource type "clusters"``` - -If you passed the correct Federation context but received a message error saying - -```No resources found.``` - -it means that you haven't -added any cluster to the Federation yet. - -## Creating a Federated Cluster - -Creating a `cluster` resource in federation means joining it to the federation. To do so, you can use -`kubefed join`. Basically, you need to give the new cluster a name and say what is the name of the -context that corresponds to a cluster that hosts the federation. The following example command adds -the cluster `gondor` to the federation running on host cluster `rivendell`: - -``` shell -kubefed join gondor --host-cluster-context=rivendell -``` - -You can find more details on how to do that in the respective section in the -[kubefed guide](/docs/tutorials/federation/set-up-cluster-federation-kubefed/#adding-a-cluster-to-a-federation). - -## Deleting a Federated Cluster - -Converse to creating a cluster, deleting a cluster means unjoining this cluster from the -federation. This can be done with `kubefed unjoin` command. To remove the `gondor` cluster, just do: - -``` shell -kubefed unjoin gondor --host-cluster-context=rivendell -``` - -You can find more details on unjoin in the -[kubefed guide](/docs/tutorials/federation/set-up-cluster-federation-kubefed/#removing-a-cluster-from-a-federation). - -## Labeling Clusters - -You can label clusters the same way as any other Kubernetes object, which can help with grouping clusters and can also be leveraged by the ClusterSelector. - -``` shell -kubectl --context=rivendell label cluster gondor key1=value1 key2=value2 -``` - -## ClusterSelector Annotation - -You can use a (deprecated) annotation for directing objects across the federated clusters: `federation.alpha.kubernetes.io/cluster-selector`. The *ClusterSelector* is conceptually similar to `nodeSelector`, but instead of selecting against labels on nodes, it selects against labels on federated clusters. - -The annotation value must be JSON formatted and must be parsable into the [ClusterSelector API type](/docs/reference/federation/v1beta1/definitions/#_v1beta1_clusterselector). For example: `[{"key": "load", "operator": "Lt", "values": ["10"]}]`. Content that doesn't parse correctly will throw an error and prevent distribution of the object to any federated clusters. Objects of type ConfigMap, Secret, Daemonset, Service and Ingress are included in the alpha implementation. - -Here is an example ClusterSelector annotation, which will only select clusters WITH the label `pci=true` and WITHOUT the label `environment=test`: - -``` yaml - metadata: - annotations: - federation.alpha.kubernetes.io/cluster-selector: '[{"key": "pci", "operator": - "In", "values": ["true"]}, {"key": "environment", "operator": "NotIn", "values": - ["test"]}]' -``` - -The *key* is matched against label names on the federated clusters. - -The *values* are matched against the label values on the federated clusters. - -The possible *operators* are: `In`, `NotIn`, `Exists`, `DoesNotExist`, `Gt`, `Lt`. - -The *values* field is expected to be empty when `Exists` or `DoesNotExist` is specified and may include more than one string when `In` or `NotIn` are used. - -Currently, only integers are supported with `Gt` or `Lt`. - -## Clusters API reference - -The full clusters API reference is currently in `federation/v1beta1` and more details can be found in the -[Federation API reference page](/docs/reference/federation/). - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/configmap.md b/content/en/docs/tasks/federation/administer-federation/configmap.md deleted file mode 100644 index b3d0030928..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/configmap.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: Federated ConfigMap -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use ConfigMaps in a Federation control plane. - -Federated ConfigMaps are very similar to the traditional [Kubernetes -ConfigMaps](/docs/tasks/configure-pod-container/configure-pod-configmap/) and provide the same functionality. -Creating them in the federation control plane ensures that they are synchronized -across all the clusters in federation. - -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [ConfigMaps](/docs/tasks/configure-pod-container/configure-pod-configmap/) in particular. - -{{% /capture %}} - -{{% capture steps %}} - -## Creating a Federated ConfigMap - -The API for Federated ConfigMap is 100% compatible with the -API for traditional Kubernetes ConfigMap. You can create a ConfigMap by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f myconfigmap.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a Federated ConfigMap is created, the federation control plane will create -a matching ConfigMap in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get configmap myconfigmap -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. - -These ConfigMaps in underlying clusters will match the Federated ConfigMap. - - -## Updating a Federated ConfigMap - -You can update a Federated ConfigMap as you would update a Kubernetes -ConfigMap; however, for a Federated ConfigMap, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. -The federation control plane ensures that whenever the Federated ConfigMap is -updated, it updates the corresponding ConfigMaps in all underlying clusters to -match it. - -## Deleting a Federated ConfigMap - -You can delete a Federated ConfigMap as you would delete a Kubernetes -ConfigMap; however, for a Federated ConfigMap, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete configmap -``` - -{{< note >}} -Deleting a Federated ConfigMap does not delete the corresponding ConfigMaps from underlying clusters. You must delete the underlying ConfigMaps manually. -{{< /note >}} - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/daemonset.md b/content/en/docs/tasks/federation/administer-federation/daemonset.md deleted file mode 100644 index eb93818779..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/daemonset.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: Federated DaemonSet -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use DaemonSets in a federation control plane. - -DaemonSets in the federation control plane ("Federated Daemonsets" in -this guide) are very similar to the traditional Kubernetes -[DaemonSets](/docs/concepts/workloads/controllers/daemonset/) and provide the same functionality. -Creating them in the federation control plane ensures that they are synchronized -across all the clusters in federation. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [DaemonSets](/docs/concepts/workloads/controllers/daemonset/) in particular. - -{{% /capture %}} - -{{% capture steps %}} - -## Creating a Federated Daemonset - -The API for Federated Daemonset is 100% compatible with the -API for traditional Kubernetes DaemonSet. You can create a DaemonSet by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f mydaemonset.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a Federated Daemonset is created, the federation control plane will create -a matching DaemonSet in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get daemonset mydaemonset -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. - - -## Updating a Federated Daemonset - -You can update a Federated Daemonset as you would update a Kubernetes -DaemonSet; however, for a Federated Daemonset, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. -The federation control plane ensures that whenever the Federated Daemonset is -updated, it updates the corresponding DaemonSets in all underlying clusters to -match it. - -## Deleting a Federated Daemonset - -You can delete a Federated Daemonset as you would delete a Kubernetes -DaemonSet; however, for a Federated Daemonset, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete daemonset mydaemonset -``` - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/deployment.md b/content/en/docs/tasks/federation/administer-federation/deployment.md deleted file mode 100644 index 5fd3feb688..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/deployment.md +++ /dev/null @@ -1,111 +0,0 @@ ---- -title: Federated Deployment -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use Deployments in the Federation control plane. - -Deployments in the federation control plane (referred to as "Federated Deployments" in -this guide) are very similar to the traditional [Kubernetes -Deployment](/docs/concepts/workloads/controllers/deployment/) and provide the same functionality. -Creating them in the federation control plane ensures that the desired number of -replicas exist across the registered clusters. - -{{< feature-state for_k8s_version="1.5" state="alpha" >}} - -Some features -(such as full rollout compatibility) are still in development. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [Deployments](/docs/concepts/workloads/controllers/deployment/) in particular. - -{{% /capture %}} - -{{% capture steps %}} -## Creating a Federated Deployment - -The API for Federated Deployment is compatible with the -API for traditional Kubernetes Deployment. You can create a Deployment by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f mydeployment.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a Federated Deployment is created, the federation control plane will create -a Deployment in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get deployment mydep -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. - -These Deployments in underlying clusters will match the federation Deployment -_except_ in the number of replicas and revision-related annotations. -Federation control plane ensures that the -sum of replicas in each cluster combined matches the desired number of replicas in the -Federated Deployment. - -### Spreading Replicas in Underlying Clusters - -By default, replicas are spread equally in all the underlying clusters. For example: -if you have 3 registered clusters and you create a Federated Deployment with -`spec.replicas = 9`, then each Deployment in the 3 clusters will have -`spec.replicas=3`. -To modify the number of replicas in each cluster, you can specify -[FederatedReplicaSetPreference](https://github.com/kubernetes/federation/blob/{{< param "githubbranch" >}}/apis/federation/types.go) -as an annotation with key `federation.kubernetes.io/deployment-preferences` -on Federated Deployment. - - -## Updating a Federated Deployment - -You can update a Federated Deployment as you would update a Kubernetes -Deployment; however, for a Federated Deployment, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. -The federation control plane ensures that whenever the Federated Deployment is -updated, it updates the corresponding Deployments in all underlying clusters to -match it. So if the rolling update strategy was chosen then the underlying -cluster will do the rolling update independently and `maxSurge` and `maxUnavailable` -will apply only to individual clusters. This behavior may change in the future. - -If your update includes a change in number of replicas, the federation -control plane will change the number of replicas in underlying clusters to -ensure that their sum remains equal to the number of desired replicas in -Federated Deployment. - -## Deleting a Federated Deployment - -You can delete a Federated Deployment as you would delete a Kubernetes -Deployment; however, for a Federated Deployment, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete deployment mydep -``` - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/events.md b/content/en/docs/tasks/federation/administer-federation/events.md deleted file mode 100644 index a7358de478..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/events.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -title: Federated Events -content_template: templates/concept ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use events in federation control plane to help in debugging. - -{{% /capture %}} - - -{{% capture body %}} - -## Prerequisites - -This guide assumes that you have a running Kubernetes Cluster -Federation installation. If not, then head over to the -[federation admin guide](/docs/concepts/cluster-administration/federation/) to learn how to -bring up a cluster federation (or have your cluster administrator do -this for you). Other tutorials, for example -[this one](https://github.com/kelseyhightower/kubernetes-cluster-federation) -by Kelsey Hightower, are also available to help you. - -You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general. - -## View federation events - -Events in federation control plane (referred to as "federation events" in -this guide) are very similar to the traditional Kubernetes -Events providing the same functionality. -Federation Events are stored only in federation control plane and are not passed on to the underlying Kubernetes clusters. - -Federation controllers create events as they process API resources to surface to the -user, the state that they are in. -You can get all events from federation apiserver by running: - -```shell -kubectl --context=federation-cluster get events -``` - -The standard kubectl get, update, delete commands will all work. - -{{% /capture %}} diff --git a/content/en/docs/tasks/federation/administer-federation/hpa.md b/content/en/docs/tasks/federation/administer-federation/hpa.md deleted file mode 100644 index 45ed7a3723..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/hpa.md +++ /dev/null @@ -1,184 +0,0 @@ ---- -title: Federated Horizontal Pod Autoscalers (HPA) -content_template: templates/task ---- - -{{% capture overview %}} - -{{< feature-state state="alpha" >}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use federated horizontal pod autoscalers (HPAs) in the federation control plane. - -HPAs in the federation control plane are similar to the traditional [Kubernetes -HPAs](/docs/tasks/run-application/horizontal-pod-autoscale/), and provide the same functionality. -Creating an HPA targeting a federated object in the federation control plane ensures that the -desired number of replicas of the target object are scaled across the registered clusters, -instead of a single cluster. Also, the control plane keeps monitoring the status of each -individual HPA in the federated clusters and ensures the workload replicas move where they are -needed most by manipulating the min and max limits of the HPA objects in the federated clusters. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [HPAs](/docs/tasks/run-application/horizontal-pod-autoscale/) in particular. - -The federated HPA is an alpha feature. The API is not enabled by default on the -federated API server. To use this feature, the user or the admin deploying the federation control -plane needs to run the federated API server with option `--runtime-config=api/all=true` to -enable all APIs, including alpha APIs. Additionally, the federated HPA only works -when used with CPU utilization metrics. -{{% /capture %}} - -{{% capture steps %}} - -## Creating a federated HPA - -The API for federated HPAs is 100% compatible with the -API for traditional Kubernetes HPA. You can create an HPA by sending -a request to the federation API server. - -You can do that with [kubectl](/docs/user-guide/kubectl/) by running: - -```shell -cat <}} -A particular cluster cannot have a minimum replica sum of 0. -{{< /note >}} - -### Spreading HPA min and max replicas in underlying clusters - -By default, first max replicas are spread equally in all the underlying clusters, then min replicas are distributed to those clusters that received their maximum value. This means -that each cluster will get an HPA if the specified max replicas are greater than -the total clusters participating in this federation, and some clusters will be -skipped if specified max replicas are less than the total clusters participating -in the federation. - -For example: if you have 3 registered clusters and you create a federated HPA with -`spec.maxReplicas = 9`, and `spec.minReplicas = 2`, then each HPA in the 3 clusters -will get `spec.maxReplicas=3` and `spec.minReplicas = 1`. - -Currently the default distribution is only available on the federated HPA, but in the -future, users preferences could also be specified to control and/or restrict this -distribution. - -## Updating a federated HPA - -You can update a federated HPA as you would update a Kubernetes -HPA; however, for a federated HPA, you must send the request to -the federation API server instead of sending it to a specific Kubernetes cluster. -The Federation control plane ensures that whenever the federated HPA is -updated, it updates the corresponding HPA in all underlying clusters to -match it. - -If your update includes a change in the number of replicas, the federation -control plane will change the number of replicas in underlying clusters to -ensure that the sum of the max and min replicas remains matched as specified -in the previous section. - -## Deleting a federated HPA - -You can delete a federated HPA as you would delete a Kubernetes -HPA; however, for a federated HPA, you must send the request to -the federation API server instead of to a specific Kubernetes cluster. - -{{< note >}} -For the federated resource to be deleted from all underlying clusters, [cascading deletion](/docs/concepts/cluster-administration/federation/#cascading-deletion) should be used. -{{< /note >}} - -For example, you can do that using `kubectl` by running: - -```shell -kubectl --context=federation-cluster delete HPA php-apache -``` - -## Alternative ways to use federated HPA - -To a federation user interacting with federated control plane (or simply federation), -the interaction is almost identical to interacting with a normal Kubernetes cluster (but -with a limited set of APIs that are federated). As both Deployments and -HorizontalPodAutoscalers are now federated, `kubectl` commands like `kubectl run` -and `kubectl autoscale` work on federation. Given this fact, the mechanism specified in -[horizontal pod autoscaler walkthrough](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/) -will also work when used with federation. -Care however will need to be taken that when -[generating load on a target deployment](/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/#step-three-increase-load), -it should be done against a specific federated cluster (or multiple clusters) not the federation. - -## Conclusion - -The use of federated HPA is to ensure workload replicas move to the cluster(s) where -they are needed most, or in other words where the load is beyond expected threshold. -The federated HPA feature achieves this by manipulating the min and max replicas on the -HPAs it creates in the federated clusters. It does not directly monitor the target -object metrics from the federated clusters. It actually relies on the in-cluster HPA -controllers to monitor the metrics and update relevant fields. The in-cluster HPA -controller monitors the target pod metrics and updates the fields like desired -replicas (after metrics based calculations) and current replicas (observing the -current status of in cluster pods). The federated HPA controller, on the other hand, -monitors only the cluster-specific HPA object fields and updates the min replica and -max replica fields of those in cluster HPA objects, which have replicas matching thresholds. - -For example, if a cluster has both desired replicas and current replicas the same as the max replicas, -and averaged current CPU utilization still higher than the target CPU utilization (all of which -are fields on local HPA object), then the target app in this cluster -needs more replicas, and the scaling is currently restricted by max replicas set on this local -HPA object. In such a scenario, the federated HPA controller scans all clusters and tries to -find clusters which do not have such a condition (meaning the desired replicas are less -than the max, and current averaged CPU utilization is lower then the threshold). If it finds such -a cluster, it reduces the max replica on the HPA in this cluster and increases the max replicas -on the HPA in the cluster which needed the replicas. - -There are many other similar conditions which the federated HPA controller checks and moves the max -replicas and min replicas around the local HPAs in federated clusters to eventually ensure that -the replicas move (or remain) in the cluster(s) which need them. - -For more information, see ["federated HPA design proposal"](https://github.com/kubernetes/community/pull/593). - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/ingress.md b/content/en/docs/tasks/federation/administer-federation/ingress.md deleted file mode 100644 index 9d48987d5b..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/ingress.md +++ /dev/null @@ -1,311 +0,0 @@ ---- -title: Federated Ingress -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This page explains how to use Kubernetes Federated Ingress to deploy -a common HTTP(S) virtual IP load balancer across a federated service running in -multiple Kubernetes clusters. As of v1.4, clusters hosted in Google -Cloud (both Google Kubernetes Engine and GCE, or both) are supported. This makes it -easy to deploy a service that reliably serves HTTP(S) traffic -originating from web clients around the globe on a single, static IP -address. Low network latency, high fault tolerance and easy administration are -ensured through intelligent request routing and automatic replica -relocation (using [Federated ReplicaSets](/docs/tasks/administer-federation/replicaset/). -Clients are automatically routed, via the shortest network path, to -the cluster closest to them with available capacity (despite the fact -that all clients use exactly the same static IP address). The load balancer -automatically checks the health of the pods comprising the service, -and avoids sending requests to unresponsive or slow pods (or entire -unresponsive clusters). - -Federated Ingress is released as an alpha feature, and supports Google Cloud Platform (Google Kubernetes Engine, -GCE and hybrid scenarios involving both) in Kubernetes v1.4. Work is under way to support other cloud -providers such as AWS, and other hybrid cloud scenarios (e.g. services -spanning private on-premises as well as public cloud Kubernetes -clusters). - -You create Federated Ingresses in much that same way as traditional -[Kubernetes Ingresses](/docs/concepts/services-networking/ingress/): by making an API -call which specifies the desired properties of your logical ingress point. In the -case of Federated Ingress, this API call is directed to the -Federation API endpoint, rather than a Kubernetes cluster API -endpoint. The API for Federated Ingress is 100% compatible with the -API for traditional Kubernetes Services. - -Once created, the Federated Ingress automatically: - -* Creates matching Kubernetes Ingress objects in every cluster underlying your Cluster Federation -* Ensures that all of these in-cluster ingress objects share the same - logical global L7 (that is, HTTP(S)) load balancer and IP address -* Monitors the health and capacity of the service shards (that is, your pods) behind this ingress in each cluster -* Ensures that all client connections are routed to an appropriate healthy backend service endpoint at all times, even in the event of pod, cluster, availability zone or regional outages - -Note that in the case of Google Cloud, the logical L7 load balancer is -not a single physical device (which would present both a single point -of failure, and a single global network routing choke point), but -rather a -[truly global, highly available load balancing managed service](https://cloud.google.com/load-balancing/), -globally reachable via a single, static IP address. - -Clients inside your federated Kubernetes clusters (Pods) will be -automatically routed to the cluster-local shard of the Federated Service -backing the Ingress in their cluster if it exists and is healthy, or the closest healthy shard in a -different cluster if it does not. Note that this involves a network -trip to the HTTP(s) load balancer, which resides outside your local -Kubernetes cluster but inside the same GCP region. -{{% /capture %}} - -{{% capture prerequisites %}} -This document assumes that you have a running Kubernetes Cluster -Federation installation. If not, then see the -[federation admin guide](/docs/tasks/federation/set-up-cluster-federation-kubefed/) to learn how to -bring up a cluster federation (or have your cluster administrator do -this for you). Other tutorials, for example -[this one](https://github.com/kelseyhightower/kubernetes-cluster-federation) -by Kelsey Hightower, are also available to help you. - -You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general, and [Ingress](/docs/concepts/services-networking/ingress/) in particular. -{{% /capture %}} - -{{% capture steps %}} -## Creating a federated ingress - -You can create a federated ingress in any of the usual ways, for example, using kubectl: - -``` shell -kubectl --context=federation-cluster create -f myingress.yaml -``` -For example ingress YAML configurations, see the [Ingress User Guide](/docs/concepts/services-networking/ingress/). -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation API endpoint, with the appropriate -credentials. If you have not yet configured such a context, see the -[federation admin guide](/docs/admin/federation/) or one of the -[administration tutorials](https://github.com/kelseyhightower/kubernetes-cluster-federation) -to find out how to do so. - -The Federated Ingress automatically creates -and maintains matching Kubernetes ingresses in all of the clusters -underlying your federation. These cluster-specific ingresses (and -their associated ingress controllers) configure and manage the load -balancing and health checking infrastructure that ensures that traffic -is load balanced to each cluster appropriately. - -You can verify this by checking in each of the underlying clusters. For example: - -``` shell -kubectl --context=gce-asia-east1a get ingress myingress -NAME HOSTS ADDRESS PORTS AGE -myingress * 130.211.5.194 80, 443 1m -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. The name and -namespace of the underlying ingress automatically matches those of -the Federated Ingress that you created above (and if you happen to -have had ingresses of the same name and namespace already existing in -any of those clusters, they will be automatically adopted by the -Federation and updated to conform with the specification of your -Federated Ingress. Either way, the end result will be the same). - -The status of your Federated Ingress automatically reflects the -real-time status of the underlying Kubernetes ingresses. For example: - -``` shell -kubectl --context=federation-cluster describe ingress myingress - -Name: myingress -Namespace: default -Address: 130.211.5.194 -TLS: - tls-secret terminates -Rules: - Host Path Backends - ---- ---- -------- - * * echoheaders-https:80 (10.152.1.3:8080,10.152.2.4:8080) -Annotations: - https-target-proxy: k8s-tps-default-myingress--ff1107f83ed600c0 - target-proxy: k8s-tp-default-myingress--ff1107f83ed600c0 - url-map: k8s-um-default-myingress--ff1107f83ed600c0 - backends: {"k8s-be-30301--ff1107f83ed600c0":"Unknown"} - forwarding-rule: k8s-fw-default-myingress--ff1107f83ed600c0 - https-forwarding-rule: k8s-fws-default-myingress--ff1107f83ed600c0 -Events: - FirstSeen LastSeen Count From SubobjectPath Type Reason Message - --------- -------- ----- ---- ------------- -------- ------ ------- - 3m 3m 1 {loadbalancer-controller } Normal ADD default/myingress - 2m 2m 1 {loadbalancer-controller } Normal CREATE ip: 130.211.5.194 -``` - -Note that: - -* The address of your Federated Ingress -corresponds with the address of all of the -underlying Kubernetes ingresses (once these have been allocated - this -may take up to a few minutes). -* You have not yet provisioned any backend Pods to receive -the network traffic directed to this ingress (that is, 'Service -Endpoints' behind the service backing the Ingress), so the Federated Ingress does not yet consider these to -be healthy shards and will not direct traffic to any of these clusters. -* The federation control system -automatically reconfigures the load balancer controllers in all of the -clusters in your federation to make them consistent, and allows -them to share global load balancers. But this reconfiguration can -only complete successfully if there are no pre-existing Ingresses in -those clusters (this is a safety feature to prevent accidental -breakage of existing ingresses). So, to ensure that your federated -ingresses function correctly, either start with new, empty clusters, or make -sure that you delete (and recreate if necessary) all pre-existing -Ingresses in the clusters comprising your federation. - -## Adding backend services and pods - -To render the underlying ingress shards healthy, you need to add -backend Pods behind the service upon which the Ingress is based. There are several ways to achieve this, but -the easiest is to create a Federated Service and -Federated ReplicaSet. To -create appropriately labelled pods and services in the 13 underlying clusters of -your federation: - -``` shell -kubectl --context=federation-cluster create -f services/nginx.yaml -``` - -``` shell -kubectl --context=federation-cluster create -f myreplicaset.yaml -``` - -Note that in order for your federated ingress to work correctly on -Google Cloud, the node ports of all of the underlying cluster-local -services need to be identical. If you're using a federated service -this is easy to do. Simply pick a node port that is not already -being used in any of your clusters, and add that to the spec of your -federated service. If you do not specify a node port for your -federated service, each cluster will choose its own node port for -its cluster-local shard of the service, and these will probably end -up being different, which is not what you want. - -You can verify this by checking in each of the underlying clusters. For example: - -``` shell -kubectl --context=gce-asia-east1a get services nginx -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -nginx ClusterIP 10.63.250.98 104.199.136.89 80/TCP 9m -``` - -## Hybrid cloud capabilities - -Federations of Kubernetes Clusters can include clusters running in -different cloud providers (for example, Google Cloud, AWS), and on-premises -(for example, on OpenStack). However, in Kubernetes v1.4, Federated Ingress is only -supported across Google Cloud clusters. - -## Discovering a federated ingress - -Ingress objects (in both plain Kubernetes clusters, and in federations -of clusters) expose one or more IP addresses (via -the Status.Loadbalancer.Ingress field) that remains static for the lifetime -of the Ingress object (in future, automatically managed DNS names -might also be added). All clients (whether internal to your cluster, -or on the external network or internet) should connect to one of these IP -or DNS addresses. All client requests are automatically -routed, via the shortest network path, to a healthy pod in the -closest cluster to the origin of the request. So for example, HTTP(S) -requests from internet -users in Europe will be routed directly to the closest cluster in -Europe that has available capacity. If there are no such clusters in -Europe, the request will be routed to the next closest cluster -(typically in the U.S.). - -## Handling failures of backend pods and whole clusters - -Ingresses are backed by Services, which are typically (but not always) -backed by one or more ReplicaSets. For Federated Ingresses, it is -common practise to use the federated variants of Services and -ReplicaSets for this purpose. - -In particular, Federated ReplicaSets ensure that the desired number of -pods are kept running in each cluster, even in the event of node -failures. In the event of entire cluster or availability zone -failures, Federated ReplicaSets automatically place additional -replicas in the other available clusters in the federation to accommodate the -traffic which was previously being served by the now unavailable -cluster. While the Federated ReplicaSet ensures that sufficient replicas are -kept running, the Federated Ingress ensures that user traffic is -automatically redirected away from the failed cluster to other -available clusters. - -## Troubleshooting - -#### I cannot connect to my cluster federation API. - -Check that your: - -1. Client (typically `kubectl`) is correctly configured (including API endpoints and login credentials). -2. Cluster Federation API server is running and network-reachable. - -See the [federation admin guide](/docs/admin/federation/) to learn -how to bring up a cluster federation correctly (or have your cluster administrator do this for you), and how to correctly configure your client. - -#### I can create a Federated Ingress/service/replicaset successfully against the cluster federation API, but no matching ingresses/services/replicasets are created in my underlying clusters. - -Check that: - -1. Your clusters are correctly registered in the Cluster Federation API. (`kubectl describe clusters`) -2. Your clusters are all 'Active'. This means that the cluster - Federation system was able to connect and authenticate against the - clusters' endpoints. If not, consult the event logs of the federation-controller-manager pod to ascertain what the failure might be. (`kubectl --namespace=federation logs $(kubectl get pods --namespace=federation -l module=federation-controller-manager -o name`) -3. That the login credentials provided to the Cluster Federation API - for the clusters have the correct authorization and quota to create - ingresses/services/replicasets in the relevant namespace in the - clusters. Again you should see associated error messages providing - more detail in the above event log file if this is not the case. -4. Whether any other error is preventing the service creation - operation from succeeding (look for `ingress-controller`, - `service-controller` or `replicaset-controller`, - errors in the output of `kubectl logs federation-controller-manager --namespace federation`). - -#### I can create a federated ingress successfully, but request load is not correctly distributed across the underlying clusters. - -Check that: - -1. The services underlying your federated ingress in each cluster have - identical node ports. See [above](#creating_a_federated_ingress) for further explanation. -2. The load balancer controllers in each of your clusters are of the - correct type ("GLBC") and have been correctly reconfigured by the - federation control plane to share a global GCE load balancer (this - should happen automatically). If they are of the correct type, and - have been correctly reconfigured, the UID data item in the GLBC - configmap in each cluster will be identical across all clusters. - See - [the GLBC docs](https://github.com/kubernetes/ingress/blob/7dcb4ae17d5def23d3e9c878f3146ac6df61b09d/controllers/gce/README.md) - for further details. - If this is not the case, check the logs of your federation - controller manager to determine why this automated reconfiguration - might be failing. -3. No ingresses have been manually created in any of your clusters before the above - reconfiguration of the load balancer controller completed - successfully. Ingresses created before the reconfiguration of - your GLBC will interfere with the behavior of your federated - ingresses created after the reconfiguration (see - [the GLBC docs](https://github.com/kubernetes/ingress/blob/7dcb4ae17d5def23d3e9c878f3146ac6df61b09d/controllers/gce/README.md) - for further information). To remedy this, - delete any ingresses created before the cluster joined the - federation (and had its GLBC reconfigured), and recreate them if - necessary. -{{% /capture %}} - -{{% capture whatsnext %}} -* If you need assistance, use one of the [support channels](/docs/tasks/debug-application-cluster/troubleshooting/) to seek assistance. - * For details about use cases that motivated this work, see - [Federation proposal](https://git.k8s.io/community/contributors/design-proposals/multicluster/federation.md). -{{% /capture %}} - diff --git a/content/en/docs/tasks/federation/administer-federation/job.md b/content/en/docs/tasks/federation/administer-federation/job.md deleted file mode 100644 index 5b921fe3f6..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/job.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: Federated Jobs -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use jobs in the federation control plane. - -Jobs in the federation control plane (referred to as "federated jobs" in -this guide) are similar to the traditional [Kubernetes -jobs](/docs/concepts/workloads/controllers/job/), and provide the same functionality. -Creating jobs in the federation control plane ensures that the desired number of -parallelism and completions exist across the registered clusters. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [jobs](/docs/concepts/workloads/controllers/jobs-run-to-completion/) in particular. -{{% /capture %}} - -{{% capture steps %}} - -## Creating a federated job - -The API for federated jobs is fully compatible with the -API for traditional Kubernetes jobs. You can create a job by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f myjob.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the federation API server instead of sending it to a Kubernetes -cluster. - -Once a federated job is created, the federation control plane creates -a job in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get job myjob -``` - -The previous example assumes that you have a context named `gce-asia-east1a` -configured in your client for your cluster in that zone. - -The jobs in the underlying clusters match the federated job -except in the number of parallelism and completions. The federation control plane ensures that the -sum of the parallelism and completions in each cluster matches the desired number of parallelism and completions in the -federated job. - -### Spreading job tasks in underlying clusters - -By default, parallelism and completions are spread equally in all underlying clusters. For example: -if you have 3 registered clusters and you create a federated job with -`spec.parallelism = 9` and `spec.completions = 18`, then each job in the 3 clusters has -`spec.parallelism = 3` and `spec.completions = 6`. -To modify the number of parallelism and completions in each cluster, you can specify -[ReplicaAllocationPreferences](https://github.com/kubernetes/federation/blob/{{< param "githubbranch" >}}/apis/federation/types.go) -as an annotation with key `federation.kubernetes.io/job-preferences` -on the federated job. - - -## Updating a federated job - -You can update a federated job as you would update a Kubernetes -job; however, for a federated job, you must send the request to -the federation API server instead of sending it to a specific Kubernetes cluster. -The federation control plane ensures that whenever the federated job is -updated, it updates the corresponding job in all underlying clusters to -match it. - -If your update includes a change in number of parallelism and completions, the federation -control plane changes the number of parallelism and completions in underlying clusters to -ensure that their sum remains equal to the number of desired parallelism and completions in -federated job. - -## Deleting a federated job - -You can delete a federated job as you would delete a Kubernetes -job; however, for a federated job, you must send the request to -the federation API server instead of sending it to a specific Kubernetes cluster. - -For example, with kubectl: - -```shell -kubectl --context=federation-cluster delete job myjob -``` - -{{< note >}} -Deleting a federated job will not delete the -corresponding jobs from underlying clusters. -You must delete the underlying jobs manually. -{{< /note >}} - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/namespaces.md b/content/en/docs/tasks/federation/administer-federation/namespaces.md deleted file mode 100644 index 13c9c5dcaa..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/namespaces.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: Federated Namespaces -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use Namespaces in Federation control plane. - -Namespaces in federation control plane (referred to as "federated Namespaces" in -this guide) are very similar to the traditional [Kubernetes -Namespaces](/docs/concepts/overview/working-with-objects/namespaces/) providing the same functionality. -Creating them in the federation control plane ensures that they are synchronized -across all the clusters in federation. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You are also expected to have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [Namespaces](/docs/concepts/overview/working-with-objects/namespaces/) in particular. - -{{% /capture %}} - -{{% capture steps %}} - -## Creating a Federated Namespace - -The API for Federated Namespaces is 100% compatible with the -API for traditional Kubernetes Namespaces. You can create a Namespace by sending -a request to the federation apiserver. - -You can do that using kubectl by running: - -``` shell -kubectl --context=federation-cluster create -f myns.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a federated Namespace is created, the federation control plane will create -a matching Namespace in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get namespaces myns -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. The name and -spec of the underlying Namespace will match those of -the Federated Namespace that you created above. - - -## Updating a Federated Namespace - -You can update a federated Namespace as you would update a Kubernetes -Namespace, just send the request to federation apiserver instead of sending it -to a specific Kubernetes cluster. -Federation control plane will ensure that whenever the federated Namespace is -updated, it updates the corresponding Namespaces in all underlying clusters to -match it. - -## Deleting a Federated Namespace - -You can delete a federated Namespace as you would delete a Kubernetes -Namespace, just send the request to federation apiserver instead of sending it -to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete ns myns -``` - -As in Kubernetes, deleting a federated Namespace will delete all resources in that -Namespace from the federation control plane. - -{{< note >}} -At this point, deleting a federated Namespace will not delete the corresponding Namespace, or resources in those Namespaces, from underlying clusters. Users must delete them manually. We intend to fix this in the future. -{{< /note >}} - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/replicaset.md b/content/en/docs/tasks/federation/administer-federation/replicaset.md deleted file mode 100644 index 1fa5d856a8..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/replicaset.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Federated ReplicaSets -content_template: templates/task ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use ReplicaSets in the Federation control plane. - -ReplicaSets in the federation control plane (referred to as "federated ReplicaSets" in -this guide) are very similar to the traditional [Kubernetes -ReplicaSets](/docs/concepts/workloads/controllers/replicaset/), and provide the same functionality. -Creating them in the federation control plane ensures that the desired number of -replicas exist across the registered clusters. -{{% /capture %}} - -{{% capture prerequisites %}} - -* {{< include "federated-task-tutorial-prereqs.md" >}} -* You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [ReplicaSets](/docs/concepts/workloads/controllers/replicaset/) in particular. -{{% /capture %}} - -{{% capture steps %}} - -## Creating a Federated ReplicaSet - -The API for Federated ReplicaSet is 100% compatible with the -API for traditional Kubernetes ReplicaSet. You can create a ReplicaSet by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f myrs.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a federated ReplicaSet is created, the federation control plane will create -a ReplicaSet in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get rs myrs -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. - -The ReplicaSets in the underlying clusters will match the federation ReplicaSet -except in the number of replicas. The federation control plane will ensure that the -sum of the replicas in each cluster match the desired number of replicas in the -federation ReplicaSet. - -### Spreading Replicas in Underlying Clusters - -By default, replicas are spread equally in all the underlying clusters. For example: -if you have 3 registered clusters and you create a federated ReplicaSet with -`spec.replicas = 9`, then each ReplicaSet in the 3 clusters will have -`spec.replicas=3`. -To modify the number of replicas in each cluster, you can add an annotation with -key `federation.kubernetes.io/replica-set-preferences` to the federated ReplicaSet. -The value of the annoation is a serialized JSON that contains fields shown in -the following example: - -``` -{ - "rebalance": true, - "clusters": { - "foo": { - "minReplicas": 10, - "maxReplicas": 50, - "weight": 100 - }, - "bar": { - "minReplicas": 10, - "maxReplicas": 100, - "weight": 200 - } - } -} -``` - -The `rebalance` boolean field specifies whether replicas already scheduled and running -may be moved in order to match current state to the specified preferences. -The `clusters` object field contains a map where users can specify the constraints -for replica placement across the clusters (`foo` and `bar` in the example). -For each cluster, you can specify the minimum number of replicas that should be -assigned to it (default is zero), the maximum number of replicas the cluster can -accept (default is unbounded) and a number expressing the relative weight of -preferences to place additional replicas to that cluster. - -## Updating a Federated ReplicaSet - -You can update a federated ReplicaSet as you would update a Kubernetes -ReplicaSet; however, for a federated ReplicaSet, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. -The Federation control plane ensures that whenever the federated ReplicaSet is -updated, it updates the corresponding ReplicaSet in all underlying clusters to -match it. -If your update includes a change in number of replicas, the federation -control plane will change the number of replicas in underlying clusters to -ensure that their sum remains equal to the number of desired replicas in -federated ReplicaSet. - -## Deleting a Federated ReplicaSet - -You can delete a federated ReplicaSet as you would delete a Kubernetes -ReplicaSet; however, for a federated ReplicaSet, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete rs myrs -``` - -{{< note >}} -At this point, deleting a federated ReplicaSet will not delete the corresponding ReplicaSets from underlying clusters. You must delete the underlying ReplicaSets manually. We intend to fix this in the future. -{{< /note >}} - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/administer-federation/secret.md b/content/en/docs/tasks/federation/administer-federation/secret.md deleted file mode 100644 index d69f48de40..0000000000 --- a/content/en/docs/tasks/federation/administer-federation/secret.md +++ /dev/null @@ -1,93 +0,0 @@ ---- -title: Federated Secrets -content_template: templates/concept ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use secrets in Federation control plane. - -Secrets in federation control plane (referred to as "federated secrets" in -this guide) are very similar to the traditional [Kubernetes -Secrets](/docs/concepts/configuration/secret/) providing the same functionality. -Creating them in the federation control plane ensures that they are synchronized -across all the clusters in federation. -{{% /capture %}} - - -{{% capture body %}} - -## Prerequisites - -This guide assumes that you have a running Kubernetes Cluster -Federation installation. If not, then head over to the -[federation admin guide](/docs/admin/federation/) to learn how to -bring up a cluster federation (or have your cluster administrator do -this for you). Other tutorials, for example -[this one](https://github.com/kelseyhightower/kubernetes-cluster-federation) -by Kelsey Hightower, are also available to help you. - -You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general and [Secrets](/docs/concepts/configuration/secret/) in particular. - -## Creating a Federated Secret - -The API for Federated Secret is 100% compatible with the -API for traditional Kubernetes Secret. You can create a secret by sending -a request to the federation apiserver. - -You can do that using [kubectl](/docs/user-guide/kubectl/) by running: - -``` shell -kubectl --context=federation-cluster create -f mysecret.yaml -``` - -The `--context=federation-cluster` flag tells kubectl to submit the -request to the Federation apiserver instead of sending it to a Kubernetes -cluster. - -Once a federated secret is created, the federation control plane will create -a matching secret in all underlying Kubernetes clusters. -You can verify this by checking each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get secret mysecret -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. - -These secrets in underlying clusters will match the federated secret. - - -## Updating a Federated Secret - -You can update a federated secret as you would update a Kubernetes -secret; however, for a federated secret, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. -The Federation control plane ensures that whenever the federated secret is -updated, it updates the corresponding secrets in all underlying clusters to -match it. - -## Deleting a Federated Secret - -You can delete a federated secret as you would delete a Kubernetes -secret; however, for a federated secret, you must send the request to -the federation apiserver instead of sending it to a specific Kubernetes cluster. - -For example, you can do that using kubectl by running: - -```shell -kubectl --context=federation-cluster delete secret mysecret -``` - -{{< note >}} -At this point, deleting a federated secret will not delete the corresponding secrets from underlying clusters. You must delete the underlying secrets manually. We intend to fix this in the future. -{{< /note >}} - -{{% /capture %}} diff --git a/content/en/docs/tasks/federation/federation-service-discovery.md b/content/en/docs/tasks/federation/federation-service-discovery.md deleted file mode 100644 index 0d6d89e078..0000000000 --- a/content/en/docs/tasks/federation/federation-service-discovery.md +++ /dev/null @@ -1,416 +0,0 @@ ---- -title: Cross-cluster Service Discovery using Federated Services -reviewers: -- bprashanth -- quinton-hoole -content_template: templates/task -weight: 140 ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This guide explains how to use Kubernetes Federated Services to deploy -a common Service across multiple Kubernetes clusters. This makes it -easy to achieve cross-cluster service discovery and availability zone -fault tolerance for your Kubernetes applications. - - -Federated Services are created in much that same way as traditional -[Kubernetes Services](/docs/concepts/services-networking/service/) by making an API -call which specifies the desired properties of your service. In the -case of Federated Services, this API call is directed to the -Federation API endpoint, rather than a Kubernetes cluster API -endpoint. The API for Federated Services is 100% compatible with the -API for traditional Kubernetes Services. - -Once created, the Federated Service automatically: - -1. Creates matching Kubernetes Services in every cluster underlying your Cluster Federation, -2. Monitors the health of those service "shards" (and the clusters in which they reside), and -3. Manages a set of DNS records in a public DNS provider (like Google Cloud DNS, or AWS Route 53), thus ensuring that clients -of your federated service can seamlessly locate an appropriate healthy service endpoint at all times, even in the event of cluster, -availability zone or regional outages. - -Clients inside your federated Kubernetes clusters (that is Pods) will -automatically find the local shard of the Federated Service in their -cluster if it exists and is healthy, or the closest healthy shard in a -different cluster if it does not. - -{{% /capture %}} - -{{< toc >}} - -{{% capture prerequisites %}} - -{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} - -{{% /capture %}} - -{{% capture steps %}} - -## Prerequisites - -This guide assumes that you have a running Kubernetes Cluster -Federation installation. If not, then head over to the -[federation admin guide](/docs/admin/federation/) to learn how to -bring up a cluster federation (or have your cluster administrator do -this for you). Other tutorials, for example -[this one](https://github.com/kelseyhightower/kubernetes-cluster-federation) -by Kelsey Hightower, are also available to help you. - -You should also have a basic -[working knowledge of Kubernetes](/docs/tutorials/kubernetes-basics/) in -general, and [Services](/docs/concepts/services-networking/service/) in particular. - -## Hybrid cloud capabilities - -Federations of Kubernetes Clusters can include clusters running in -different cloud providers (such as Google Cloud or AWS), and on-premises -(such as on OpenStack). Simply create all of the clusters that you -require, in the appropriate cloud providers and/or locations, and -register each cluster's API endpoint and credentials with your -Federation API Server (See the -[federation admin guide](/docs/admin/federation/) for details). - -Thereafter, your applications and services can span different clusters -and cloud providers as described in more detail below. - -## Creating a federated service - -This is done in the usual way, for example: - -``` shell -kubectl --context=federation-cluster create -f services/nginx.yaml -``` - -The '--context=federation-cluster' flag tells kubectl to submit the -request to the Federation API endpoint, with the appropriate -credentials. If you have not yet configured such a context, visit the -[federation admin guide](/docs/admin/federation/) or one of the -[administration tutorials](https://github.com/kelseyhightower/kubernetes-cluster-federation) -to find out how to do so. - -As described above, the Federated Service will automatically create -and maintain matching Kubernetes services in all of the clusters -underlying your federation. - -You can verify this by checking in each of the underlying clusters, for example: - -``` shell -kubectl --context=gce-asia-east1a get services nginx -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -nginx ClusterIP 10.63.250.98 104.199.136.89 80/TCP 9m -``` - -The above assumes that you have a context named 'gce-asia-east1a' -configured in your client for your cluster in that zone. The name and -namespace of the underlying services will automatically match those of -the Federated Service that you created above (and if you happen to -have had services of the same name and namespace already existing in -any of those clusters, they will be automatically adopted by the -Federation and updated to conform with the specification of your -Federated Service - either way, the end result will be the same). - -The status of your Federated Service will automatically reflect the -real-time status of the underlying Kubernetes services, for example: - -``` shell -kubectl --context=federation-cluster describe services nginx -``` -``` -Name: nginx -Namespace: default -Labels: run=nginx -Annotations: -Selector: run=nginx -Type: LoadBalancer -IP: 10.63.250.98 -LoadBalancer Ingress: 104.197.246.190, 130.211.57.243, 104.196.14.231, 104.199.136.89, ... -Port: http 80/TCP -Endpoints: -Session Affinity: None -Events: -``` - -{{< note >}} -The 'LoadBalancer Ingress' addresses of your Federated Service -correspond with the 'LoadBalancer Ingress' addresses of all of the -underlying Kubernetes services (once these have been allocated - this -may take a few seconds). For inter-cluster and inter-cloud-provider -networking between service shards to work correctly, your services -need to have an externally visible IP address. [Service Type: -Loadbalancer](/docs/concepts/services-networking/service/#loadbalancer) -is typically used for this, although other options -(for example [External IPs](/docs/concepts/services-networking/service/#external-ips)) exist. -{{< /note >}} - -Note also that we have not yet provisioned any backend Pods to receive -the network traffic directed to these addresses (that is 'Service -Endpoints'), so the Federated Service does not yet consider these to -be healthy service shards, and has accordingly not yet added their -addresses to the DNS records for this Federated Service (more on this -aspect later). - -## Adding backend pods - -To render the underlying service shards healthy, we need to add -backend Pods behind them. This is currently done directly against the -API endpoints of the underlying clusters (although in future the -Federation server will be able to do all this for you with a single -command, to save you the trouble). For example, to create backend Pods -in 13 underlying clusters: - -``` shell -for CLUSTER in asia-east1-c asia-east1-a asia-east1-b \ - europe-west1-d europe-west1-c europe-west1-b \ - us-central1-f us-central1-a us-central1-b us-central1-c \ - us-east1-d us-east1-c us-east1-b -do - kubectl --context=$CLUSTER run nginx --image=nginx:1.11.1-alpine --port=80 -done -``` - -Note that `kubectl run` automatically adds the `run=nginx` labels required to associate the backend pods with their services. - -## Verifying public DNS records - -Once the above Pods have successfully started and have begun listening -for connections, Kubernetes will report them as healthy endpoints of -the service in that cluster (through automatic health checks). The Cluster -Federation will in turn consider each of these -service 'shards' to be healthy, and place them in serving by -automatically configuring corresponding public DNS records. You can -use your preferred interface to your configured DNS provider to verify -this. For example, if your Federation is configured to use Google -Cloud DNS, and a managed DNS domain 'example.com': - -``` shell -gcloud dns managed-zones describe example-dot-com -``` -``` -creationTime: '2016-06-26T18:18:39.229Z' -description: Example domain for Kubernetes Cluster Federation -dnsName: example.com. -id: '3229332181334243121' -kind: dns#managedZone -name: example-dot-com -nameServers: -- ns-cloud-a1.googledomains.com. -- ns-cloud-a2.googledomains.com. -- ns-cloud-a3.googledomains.com. -- ns-cloud-a4.googledomains.com. -``` - -```shell -gcloud dns record-sets list --zone example-dot-com -``` -``` -NAME TYPE TTL DATA -example.com. NS 21600 ns-cloud-e1.googledomains.com., ns-cloud-e2.googledomains.com. -example.com. OA 21600 ns-cloud-e1.googledomains.com. cloud-dns-hostmaster.google.com. 1 21600 3600 1209600 300 -nginx.mynamespace.myfederation.svc.example.com. A 180 104.197.246.190, 130.211.57.243, 104.196.14.231, 104.199.136.89,... -nginx.mynamespace.myfederation.svc.us-central1-a.example.com. A 180 104.197.247.191 -nginx.mynamespace.myfederation.svc.us-central1-b.example.com. A 180 104.197.244.180 -nginx.mynamespace.myfederation.svc.us-central1-c.example.com. A 180 104.197.245.170 -nginx.mynamespace.myfederation.svc.us-central1-f.example.com. CNAME 180 nginx.mynamespace.myfederation.svc.us-central1.example.com. -nginx.mynamespace.myfederation.svc.us-central1.example.com. A 180 104.197.247.191, 104.197.244.180, 104.197.245.170 -nginx.mynamespace.myfederation.svc.asia-east1-a.example.com. A 180 130.211.57.243 -nginx.mynamespace.myfederation.svc.asia-east1-b.example.com. CNAME 180 nginx.mynamespace.myfederation.svc.asia-east1.example.com. -nginx.mynamespace.myfederation.svc.asia-east1-c.example.com. A 180 130.211.56.221 -nginx.mynamespace.myfederation.svc.asia-east1.example.com. A 180 130.211.57.243, 130.211.56.221 -nginx.mynamespace.myfederation.svc.europe-west1.example.com. CNAME 180 nginx.mynamespace.myfederation.svc.example.com. -nginx.mynamespace.myfederation.svc.europe-west1-d.example.com. CNAME 180 nginx.mynamespace.myfederation.svc.europe-west1.example.com. -... etc. -``` - -{{< note >}} -If your Federation is configured to use AWS Route53, you can use one of the equivalent AWS tools, for example: - -``` shell -aws route53 list-hosted-zones -``` -and - -``` shell -aws route53 list-resource-record-sets --hosted-zone-id Z3ECL0L9QLOVBX -``` -{{< /note >}} - -Whatever DNS provider you use, any DNS query tool (for example 'dig' -or 'nslookup') will of course also allow you to see the records -created by the Federation for you. Note that you should either point -these tools directly at your DNS provider (such as `dig -@ns-cloud-e1.googledomains.com...`) or expect delays in the order of -your configured TTL (180 seconds, by default) before seeing updates, -due to caching by intermediate DNS servers. - -### Some notes about the above example - -1. Notice that there is a normal ('A') record for each service shard that has at least one healthy backend endpoint. For example, in us-central1-a, 104.197.247.191 is the external IP address of the service shard in that zone, and in asia-east1-a the address is 130.211.56.221. -2. Similarly, there are regional 'A' records which include all healthy shards in that region. For example, 'us-central1'. These regional records are useful for clients which do not have a particular zone preference, and as a building block for the automated locality and failover mechanism described below. -3. For zones where there are currently no healthy backend endpoints, a CNAME ('Canonical Name') record is used to alias (automatically redirect) those queries to the next closest healthy zone. In the example, the service shard in us-central1-f currently has no healthy backend endpoints (that is Pods), so a CNAME record has been created to automatically redirect queries to other shards in that region (us-central1 in this case). -4. Similarly, if no healthy shards exist in the enclosing region, the search progresses further afield. In the europe-west1-d availability zone, there are no healthy backends, so queries are redirected to the broader europe-west1 region (which also has no healthy backends), and onward to the global set of healthy addresses (' nginx.mynamespace.myfederation.svc.example.com.'). - -The above set of DNS records is automatically kept in sync with the -current state of health of all service shards globally by the -Federated Service system. DNS resolver libraries (which are invoked by -all clients) automatically traverse the hierarchy of 'CNAME' and 'A' -records to return the correct set of healthy IP addresses. Clients can -then select any one of the returned addresses to initiate a network -connection (and fail over automatically to one of the other equivalent -addresses if required). - -## Discovering a federated service - -### From pods inside your federated clusters - -By default, Kubernetes clusters come pre-configured with a -cluster-local DNS server ('KubeDNS'), as well as an intelligently -constructed DNS search path which together ensure that DNS queries -like "myservice", "myservice.mynamespace", -"bobsservice.othernamespace" etc issued by your software running -inside Pods are automatically expanded and resolved correctly to the -appropriate service IP of services running in the local cluster. - -With the introduction of Federated Services and Cross-Cluster Service -Discovery, this concept is extended to cover Kubernetes services -running in any other cluster across your Cluster Federation, globally. -To take advantage of this extended range, you use a slightly different -DNS name of the form ```".."``` -to resolve Federated Services. For example, you might use -`myservice.mynamespace.myfederation`. Using a different DNS name also -avoids having your existing applications accidentally traversing -cross-zone or cross-region networks and you incurring perhaps unwanted -network charges or latency, without you explicitly opting in to this -behavior. - -So, using our NGINX example service above, and the Federated Service -DNS name form just described, let's consider an example: A Pod in a -cluster in the `us-central1-f` availability zone needs to contact our -NGINX service. Rather than use the service's traditional cluster-local -DNS name (`"nginx.mynamespace"`, which is automatically expanded -to `"nginx.mynamespace.svc.cluster.local"`) it can now use the -service's Federated DNS name, which is -`"nginx.mynamespace.myfederation"`. This will be automatically -expanded and resolved to the closest healthy shard of my NGINX -service, wherever in the world that may be. If a healthy shard exists -in the local cluster, that service's cluster-local (typically -10.x.y.z) IP address will be returned (by the cluster-local KubeDNS). -This is almost exactly equivalent to non-federated service resolution -(almost because KubeDNS actually returns both a CNAME and an A record -for local federated services, but applications will be oblivious -to this minor technical difference). - -But if the service does not exist in the local cluster (or it exists -but has no healthy backend pods), the DNS query is automatically -expanded to ```"nginx.mynamespace.myfederation.svc.us-central1-f.example.com"``` -(that is, logically "find the external IP of one of the shards closest to -my availability zone"). This expansion is performed automatically by -KubeDNS, which returns the associated CNAME record. This results in -automatic traversal of the hierarchy of DNS records in the above -example, and ends up at one of the external IPs of the Federated -Service in the local us-central1 region (that is 104.197.247.191, -104.197.244.180 or 104.197.245.170). - -It is of course possible to explicitly target service shards in -availability zones and regions other than the ones local to a Pod by -specifying the appropriate DNS names explicitly, and not relying on -automatic DNS expansion. For example, -"nginx.mynamespace.myfederation.svc.europe-west1.example.com" will -resolve to all of the currently healthy service shards in Europe, even -if the Pod issuing the lookup is located in the U.S., and irrespective -of whether or not there are healthy shards of the service in the U.S. -This is useful for remote monitoring and other similar applications. - -### From other clients outside your federated clusters - -Much of the above discussion applies equally to external clients, -except that the automatic DNS expansion described is no longer -possible. So external clients need to specify one of the fully -qualified DNS names of the Federated Service, be that a zonal, -regional or global name. For convenience reasons, it is often a good -idea to manually configure additional static CNAME records in your -service, for example: - -``` shell -eu.nginx.acme.com CNAME nginx.mynamespace.myfederation.svc.europe-west1.example.com. -us.nginx.acme.com CNAME nginx.mynamespace.myfederation.svc.us-central1.example.com. -nginx.acme.com CNAME nginx.mynamespace.myfederation.svc.example.com. -``` -That way your clients can always use the short form on the left, and -always be automatically routed to the closest healthy shard on their -home continent. All of the required failover is handled for you -automatically by Kubernetes Cluster Federation. Future releases will -improve upon this even further. - -## Handling failures of backend pods and whole clusters - -Standard Kubernetes service cluster-IP's already ensure that -non-responsive individual Pod endpoints are automatically taken out of -service with low latency (a few seconds). In addition, as alluded -above, the Kubernetes Cluster Federation system automatically monitors -the health of clusters and the endpoints behind all of the shards of -your Federated Service, taking shards in and out of service as -required (for example, when all of the endpoints behind a service, or perhaps -the entire cluster or availability zone go down, or conversely recover -from an outage). Due to the latency inherent in DNS caching (the cache -timeout, or TTL for Federated Service DNS records is configured to 3 -minutes, by default, but can be adjusted), it may take up to that long -for all clients to completely fail over to an alternative cluster in -the case of catastrophic failure. However, given the number of -discrete IP addresses which can be returned for each regional service -endpoint (such as us-central1 above, which has three alternatives) -many clients will fail over automatically to one of the alternative -IP's in less time than that given appropriate configuration. - -{{% /capture %}} - -{{% capture discussion %}} - -## Troubleshooting - -### I cannot connect to my cluster federation API -Check that your - -1. Client (typically kubectl) is correctly configured (including API endpoints and login credentials). -2. Cluster Federation API server is running and network-reachable. - -See the [federation admin guide](/docs/admin/federation/) to learn -how to bring up a cluster federation correctly (or have your cluster administrator do this for you), and how to correctly configure your client. - -### I can create a federated service successfully against the cluster federation API, but no matching services are created in my underlying clusters -Check that: - -1. Your clusters are correctly registered in the Cluster Federation API (`kubectl describe clusters`). -2. Your clusters are all 'Active'. This means that the cluster Federation system was able to connect and authenticate against the clusters' endpoints. If not, consult the logs of the federation-controller-manager pod to ascertain what the failure might be. - ``` - kubectl --namespace=federation logs $(kubectl get pods --namespace=federation -l module=federation-controller-manager -o name) - ``` -3. That the login credentials provided to the Cluster Federation API for the clusters have the correct authorization and quota to create services in the relevant namespace in the clusters. Again you should see associated error messages providing more detail in the above log file if this is not the case. -4. Whether any other error is preventing the service creation operation from succeeding (look for `service-controller` errors in the output of `kubectl logs federation-controller-manager --namespace federation`). - -### I can create a federated service successfully, but no matching DNS records are created in my DNS provider. -Check that: - -1. Your federation name, DNS provider, DNS domain name are configured correctly. Consult the [federation admin guide](/docs/admin/federation/) or [tutorial](https://github.com/kelseyhightower/kubernetes-cluster-federation) to learn -how to configure your Cluster Federation system's DNS provider (or have your cluster administrator do this for you). -2. Confirm that the Cluster Federation's service-controller is successfully connecting to and authenticating against your selected DNS provider (look for `service-controller` errors or successes in the output of `kubectl logs federation-controller-manager --namespace federation`). -3. Confirm that the Cluster Federation's service-controller is successfully creating DNS records in your DNS provider (or outputting errors in its logs explaining in more detail what's failing). - -### Matching DNS records are created in my DNS provider, but clients are unable to resolve against those names -Check that: - -1. The DNS registrar that manages your federation DNS domain has been correctly configured to point to your configured DNS provider's nameservers. See for example [Google Domains Documentation](https://support.google.com/domains/answer/3290309?hl=en&ref_topic=3251230) and [Google Cloud DNS Documentation](https://cloud.google.com/dns/update-name-servers), or equivalent guidance from your domain registrar and DNS provider. - -### This troubleshooting guide did not help me solve my problem - -1. Please use one of our [support channels](/docs/tasks/debug-application-cluster/troubleshooting/) to seek assistance. - -## For more information - - * [Federation proposal](https://git.k8s.io/community/contributors/design-proposals/multicluster/federation.md) details use cases that motivated this work. -{{% /capture %}} diff --git a/content/en/docs/tasks/federation/set-up-cluster-federation-kubefed.md b/content/en/docs/tasks/federation/set-up-cluster-federation-kubefed.md deleted file mode 100644 index 4cf0fd49d1..0000000000 --- a/content/en/docs/tasks/federation/set-up-cluster-federation-kubefed.md +++ /dev/null @@ -1,564 +0,0 @@ ---- -title: Set up Cluster Federation with Kubefed -reviewers: -- madhusudancs -content_template: templates/task -weight: 125 ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -Kubernetes version 1.5 and above includes a new command line tool called -[`kubefed`](/docs/admin/kubefed/) to help you administrate your federated -clusters. `kubefed` helps you to deploy a new Kubernetes cluster federation -control plane, and to add clusters to or remove clusters from an existing -federation control plane. - -This guide explains how to administer a Kubernetes Cluster Federation -using `kubefed`. - -> Note: `kubefed` is a beta feature in Kubernetes 1.6. - -{{% /capture %}} - - -{{% capture prerequisites %}} - -{{< include "task-tutorial-prereqs.md" >}} {{< version-check >}} - -{{% /capture %}} - -{{% capture steps %}} - -## Prerequisites - -This guide assumes that you have a running Kubernetes cluster. Please -see one of the [getting started](/docs/setup/) guides -for installation instructions for your platform. - -## Getting `kubefed` - -Download the client tarball corresponding to the particular release and -extract the binaries in the tarball: - -{{< note >}} -Until Kubernetes version `1.8.x` the federation project was -maintained as part of the [core kubernetes repo](https://github.com/kubernetes/kubernetes). -Between Kubernetes releases `1.8` and `1.9`, the federation project moved into -a separate [federation repo](https://github.com/kubernetes/federation), where it is -now maintained. Consequently, the federation release information is available on the -[release page](https://github.com/kubernetes/federation/releases). -{{< /note >}} - -### For Kubernetes versions 1.8.x and earlier: - -```shell -curl -LO https://storage.googleapis.com/kubernetes-release/release/${RELEASE-VERSION}/kubernetes-client-linux-amd64.tar.gz -tar -xzvf kubernetes-client-linux-amd64.tar.gz -``` -{{< note >}} -The `RELEASE-VERSION` variable should either be set to or replaced with the actual version needed. -{{< /note >}} - -Copy the extracted binary to one of the directories in your `$PATH` -and set the executable permission on the binary. - -```shell -sudo cp kubernetes/client/bin/kubefed /usr/local/bin -sudo chmod +x /usr/local/bin/kubefed -``` - -### For Kubernetes versions 1.9.x and above: - -```shell -curl -LO https://storage.cloud.google.com/kubernetes-federation-release/release/${RELEASE-VERSION}/federation-client-linux-amd64.tar.gz -tar -xzvf federation-client-linux-amd64.tar.gz -``` - -{{< note >}} -The `RELEASE-VERSION` variable should be replaced with one of the release versions available at [federation release page](https://github.com/kubernetes/federation/releases). -{{< /note >}} - -Copy the extracted binary to one of the directories in your `$PATH` -and set the executable permission on the binary. - -```shell -sudo cp federation/client/bin/kubefed /usr/local/bin -sudo chmod +x /usr/local/bin/kubefed -``` - -### Install kubectl - -You can install a matching version of kubectl using the instructions on -the [kubectl install page](/docs/tasks/tools/install-kubectl/). - -## Choosing a host cluster. - -You'll need to choose one of your Kubernetes clusters to be the -*host cluster*. The host cluster hosts the components that make up -your federation control plane. Ensure that you have a `kubeconfig` -entry in your local `kubeconfig` that corresponds to the host cluster. -You can verify that you have the required `kubeconfig` entry by -running: - -```shell -kubectl config get-contexts -``` - -The output should contain an entry corresponding to your host cluster, -similar to the following: - -``` -CURRENT NAME CLUSTER AUTHINFO NAMESPACE -* gke_myproject_asia-east1-b_gce-asia-east1 gke_myproject_asia-east1-b_gce-asia-east1 gke_myproject_asia-east1-b_gce-asia-east1 -``` - - -You'll need to provide the `kubeconfig` context (called name in the -entry above) for your host cluster when you deploy your federation -control plane. - - -## Deploying a federation control plane - -To deploy a federation control plane on your host cluster, run -[`kubefed init`](/docs/admin/kubefed_init/) command. When you use -`kubefed init`, you must provide the following: - -* Federation name -* `--host-cluster-context`, the `kubeconfig` context for the host cluster -* `--dns-provider`, one of `'google-clouddns'`, `aws-route53` or `coredns` -* `--dns-zone-name`, a domain name suffix for your federated services - -If your host cluster is running in a non-cloud environment or an -environment that doesn't support common cloud primitives such as -load balancers, you might need additional flags. Please see the -[on-premises host clusters](#on-premises-host-clusters) section below. - -The following example command deploys a federation control plane with -the name `fellowship`, a host cluster context `rivendell`, and the -domain suffix `example.com.`: - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="google-clouddns" \ - --dns-zone-name="example.com." -``` - -The domain suffix specified in `--dns-zone-name` must be an existing -domain that you control, and that is programmable by your DNS provider. -It must also end with a trailing dot. - -Once the federation control plane is initialized, query the namespaces: - -```shell -kubectl get namespace --context=fellowship -``` - -If you do not see the `default` namespace listed (this is due to a -[bug](https://github.com/kubernetes/kubernetes/issues/33292)). Create it -yourself with the following command: - -```shell -kubectl create namespace default --context=fellowship -``` - -The machines in your host cluster must have the appropriate permissions -to program the DNS service that you are using. For example, if your -cluster is running on Google Compute Engine, you must enable the -Google Cloud DNS API for your project. - -The machines in Google Kubernetes Engine clusters are created -without the Google Cloud DNS API scope by default. If you want to use a -Google Kubernetes Engine cluster as a Federation host, you must create it using the `gcloud` -command with the appropriate value in the `--scopes` field. You cannot -modify a Google Kubernetes Engine cluster directly to add this scope, but you can create a -new node pool for your cluster and delete the old one. - -{{< note >}} -This will cause pods in the cluster to be rescheduled. -{{< /note >}} - -To add the new node pool, run: - -```shell -scopes="$(gcloud container node-pools describe --cluster=gke-cluster default-pool --format='value[delimiter=","](config.oauthScopes)')" -gcloud container node-pools create new-np \ - --cluster=gke-cluster \ - --scopes="${scopes},https://www.googleapis.com/auth/ndev.clouddns.readwrite" -``` - -To delete the old node pool, run: - -```shell -gcloud container node-pools delete default-pool --cluster gke-cluster -``` - -`kubefed init` sets up the federation control plane in the host -cluster and also adds an entry for the federation API server in your -local kubeconfig. - -{{< note >}} -In the beta release of Kubernetes 1.6, `kubefed init` does not automatically set the current context to the -newly deployed federation. You can set the current context manually by running: - -```shell -kubectl config use-context fellowship -``` - -where `fellowship` is the name of your federation. -{{< /note >}} - -### Basic and token authentication support - -`kubefed init` by default only generates TLS certificates and keys -to authenticate with the federation API server and writes them to -your local kubeconfig file. If you wish to enable basic authentication -or token authentication for debugging purposes, you can enable them by -passing the `--apiserver-enable-basic-auth` flag or the -`--apiserver-enable-token-auth` flag. - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="google-clouddns" \ - --dns-zone-name="example.com." \ - --apiserver-enable-basic-auth=true \ - --apiserver-enable-token-auth=true -``` - -### Passing command line arguments to federation components - -`kubefed init` bootstraps a federation control plane with default -arguments to federation API server and federation controller manager. -Some of these arguments are derived from `kubefed init`'s flags. -However, you can override these command line arguments by passing -them via the appropriate override flags. - -You can override the federation API server arguments by passing them -to `--apiserver-arg-overrides` and override the federation controller -manager arguments by passing them to -`--controllermanager-arg-overrides`. - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="google-clouddns" \ - --dns-zone-name="example.com." \ - --apiserver-arg-overrides="--anonymous-auth=false,--v=4" \ - --controllermanager-arg-overrides="--controllers=services=false" -``` - -### Configuring a DNS provider - -The Federated service controller programs a DNS provider to expose -federated services via DNS names. Certain cloud providers -automatically provide the configuration required to program the -DNS provider if the host cluster's cloud provider is same as the DNS -provider. In all other cases, you have to provide the DNS provider -configuration to your federation controller manager which will in-turn -be passed to the federated service controller. You can provide this -configuration to federation controller manager by storing it in a file -and passing the file's local filesystem path to `kubefed init`'s -`--dns-provider-config` flag. For example, save the config below in -`$HOME/coredns-provider.conf`. - -```ini -[Global] -etcd-endpoints = http://etcd-cluster.ns:2379 -zones = example.com. -``` - -And then pass this file to `kubefed init`: - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="coredns" \ - --dns-zone-name="example.com." \ - --dns-provider-config="$HOME/coredns-provider.conf" -``` - -### On-premises host clusters - -#### API server service type - -`kubefed init` exposes the federation API server as a Kubernetes -[service](/docs/concepts/services-networking/service/) on the host cluster. By default, -this service is exposed as a -[load balanced service](/docs/concepts/services-networking/service/#loadbalancer). -Most on-premises and bare-metal environments, and some cloud -environments lack support for load balanced services. `kubefed init` -allows exposing the federation API server as a -[`NodePort` service](/docs/concepts/services-networking/service/#nodeport) on -such environments. This can be accomplished by passing -the `--api-server-service-type=NodePort` flag. You can also specify -the preferred address to advertise the federation API server by -passing the `--api-server-advertise-address=` -flag. Otherwise, one of the host cluster's node address is chosen as -the default. - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="google-clouddns" \ - --dns-zone-name="example.com." \ - --api-server-service-type="NodePort" \ - --api-server-advertise-address="10.0.10.20" -``` - -#### Provisioning storage for etcd - -Federation control plane stores its state in -[`etcd`](https://coreos.com/etcd/docs/latest/). -[`etcd`](https://coreos.com/etcd/docs/latest/) data must be stored in -a persistent storage volume to ensure correct operation across -federation control plane restarts. On host clusters that support -[dynamic provisioning of storage volumes](/docs/concepts/storage/persistent-volumes/#dynamic), -`kubefed init` dynamically provisions a -[`PersistentVolume`](/docs/concepts/storage/persistent-volumes/#persistent-volumes) -and binds it to a -[`PersistentVolumeClaim`](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) -to store [`etcd`](https://coreos.com/etcd/docs/latest/) data. If your -host cluster doesn't support dynamic provisioning, you can also -statically provision a -[`PersistentVolume`](/docs/concepts/storage/persistent-volumes/#persistent-volumes). -`kubefed init` creates a -[`PersistentVolumeClaim`](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) -that has the following configuration: - -```yaml -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - annotations: - volume.alpha.kubernetes.io/storage-class: "yes" - labels: - app: federated-cluster - name: fellowship-federation-apiserver-etcd-claim - namespace: federation-system -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi -``` - -To statically provision a -[`PersistentVolume`](/docs/concepts/storage/persistent-volumes/#persistent-volumes), -you must ensure that the -[`PersistentVolume`](/docs/concepts/storage/persistent-volumes/#persistent-volumes) -that you create has the matching storage class, access mode and -at least as much capacity as the requested -[`PersistentVolumeClaim`](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims). - -Alternatively, you can disable persistent storage completely -by passing `--etcd-persistent-storage=false` to `kubefed init`. -However, we do not recommended this because your federation control -plane cannot survive restarts in this mode. - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="google-clouddns" \ - --dns-zone-name="example.com." \ - --etcd-persistent-storage=false -``` - -`kubefed init` still doesn't support attaching an existing -[`PersistentVolumeClaim`](/docs/concepts/storage/persistent-volumes/#persistentvolumeclaims) -to the federation control plane that it bootstraps. We are planning to -support this in a future version of `kubefed`. - -#### CoreDNS support - -Federated services now support [CoreDNS](https://coredns.io/) as one -of the DNS providers. If you are running your clusters and federation -in an environment that does not have access to cloud-based DNS -providers, then you can run your own [CoreDNS](https://coredns.io/) -instance and publish the federated service DNS names to that server. - -You can configure your federation to use -[CoreDNS](https://coredns.io/), by passing appropriate values to -`kubefed init`'s `--dns-provider` and `--dns-provider-config` flags. - -```shell -kubefed init fellowship \ - --host-cluster-context=rivendell \ - --dns-provider="coredns" \ - --dns-zone-name="example.com." \ - --dns-provider-config="$HOME/coredns-provider.conf" -``` - -For more information see -[Setting up CoreDNS as DNS provider for Cluster Federation](/docs/tasks/federation/set-up-coredns-provider-federation/). - -#### AWS Route53 support - -It is possible to utilize AWS Route53 as a cloud DNS provider when the -federation controller-manager is run on-premise. The controller-manager -Deployment must be configured with AWS credentials since it cannot implicitly -gather them from a VM running on AWS. - -Currently, `kubefed init` does not read AWS Route53 credentials from the -`--dns-provider-config` flag, so a patch must be applied. - -Specify AWS Route53 as your DNS provider when initializing your on-premise -federation controller-manager by passing the flag `--dns-provider="aws-route53"` -to `kubefed init`. - -Create a patch file with your AWS credentials: - -```yaml -spec: - template: - spec: - containers: - - name: controller-manager - env: - - name: AWS_ACCESS_KEY_ID - value: "ABCDEFG1234567890" - - name: AWS_SECRET_ACCESS_KEY - value: "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" -``` - -Patch the Deployment: - -```shell -kubectl -n federation-system patch deployment controller-manager --patch "$(cat .yml)" -``` - -Where `` is the name of the file you created above. - -## Adding a cluster to a federation - -After you've deployed a federation control plane, you'll need to make that control plane aware of the clusters it should manage. - -To join clusters into the federation: - -1. Change the context: - - ```shell - kubectl config use-context fellowship - ``` - -1. If you are using a managed cluster service, allow the service to access the cluster. To do this, create a `clusterrolebinding` for the account associated with your cluster service: - - ```shell - kubectl create clusterrolebinding -cluster-admin-binding --clusterrole=cluster-admin --user=@example.org --context= - ``` - -1. Join the cluster to the federation, using `kubefed join`, and make sure you provide the following: - - * The name of the cluster that you are joining to the federation - * `--host-cluster-context`, the kubeconfig context for the host cluster - - For example, this command adds the cluster `gondor` to the federation running on host cluster `rivendell`: - - ```shell - kubefed join gondor --host-cluster-context=rivendell - ``` - -A new context has now been added to your kubeconfig named `fellowship` (after the name of your federation). - - -{{< note >}} -The name that you provide to the `join` command is used as the joining cluster's identity in federation. This name should adhere to the rules described in the [identifiers doc](/docs/concepts/overview/working-with-objects/names/). If the context -corresponding to your joining cluster conforms to these rules, you can use the same name in the join command. Otherwise, you must choose a different name for your cluster's identity. -{{< /note >}} - -### Naming rules and customization - -The cluster name you supply to `kubefed join` must be a valid -[RFC 1035](https://www.ietf.org/rfc/rfc1035.txt) label and are -enumerated in the [Identifiers doc](/docs/concepts/overview/working-with-objects/names/). - -Furthermore, federation control plane requires credentials of the -joined clusters to operate on them. These credentials are obtained -from the local kubeconfig. `kubefed join` uses the cluster name -specified as the argument to look for the cluster's context in the -local kubeconfig. If it fails to find a matching context, it exits -with an error. - -This might cause issues in cases where context names for each cluster -in the federation don't follow -[RFC 1035](https://www.ietf.org/rfc/rfc1035.txt) label naming rules. -In such cases, you can specify a cluster name that conforms to the -[RFC 1035](https://www.ietf.org/rfc/rfc1035.txt) label naming rules -and specify the cluster context using the `--cluster-context` flag. -For example, if context of the cluster you are joining is -`gondor_needs-no_king`, then you can join the cluster by running: - -```shell -kubefed join gondor --host-cluster-context=rivendell --cluster-context=gondor_needs-no_king -``` - -#### Secret name - -Cluster credentials required by the federation control plane as -described above are stored as a secret in the host cluster. The name -of the secret is also derived from the cluster name. - -However, the name of a secret object in Kubernetes should conform -to the DNS subdomain name specification described in -[RFC 1123](https://tools.ietf.org/html/rfc1123). If this isn't the -case, you can pass the secret name to `kubefed join` using the -`--secret-name` flag. For example, if the cluster name is `noldor` and -the secret name is `11kingdom`, you can join the cluster by -running: - -```shell -kubefed join noldor --host-cluster-context=rivendell --secret-name=11kingdom -``` - -{{< note >}} -If your cluster name does not conform to the DNS subdomain name specification, all you need to do is supply the secret name using the `--secret-name` flag. `kubefed join` automatically creates the secret for you. -{{< /note >}} - -### `kube-dns` configuration - -`kube-dns` configuration must be updated in each joining cluster to -enable federated service discovery. If the joining Kubernetes cluster -is version 1.5 or newer and your `kubefed` is version 1.6 or newer, -then this configuration is automatically managed for you when the -clusters are joined or unjoined using `kubefed join` or `unjoin` -commands. - -In all other cases, you must update `kube-dns` configuration manually -as described in the -[Updating KubeDNS section of the admin guide](/docs/admin/federation/). - -## Removing a cluster from a federation - -To remove a cluster from a federation, run the [`kubefed unjoin`](/docs/reference/setup-tools/kubefed/kubefed_unjoin/) -command with the cluster name and the federation's -`--host-cluster-context`: - -```shell -kubefed unjoin gondor --host-cluster-context=rivendell -``` - -## Turning down the federation control plane - -Proper cleanup of federation control plane is not fully implemented in -this beta release of `kubefed`. However, for the time being, deleting -the federation system namespace should remove all the resources except -the persistent storage volume dynamically provisioned for the -federation control plane's etcd. You can delete the federation -namespace by running the following command: - -```shell -kubectl delete ns federation-system --context=rivendell -``` - -{{< note >}} -`rivendell` is the host cluster name. Replace that name with the appropriate name in your configuration. -{{< /note >}} - -{{% /capture %}} diff --git a/content/en/docs/tasks/federation/set-up-coredns-provider-federation.md b/content/en/docs/tasks/federation/set-up-coredns-provider-federation.md deleted file mode 100644 index 572a348a82..0000000000 --- a/content/en/docs/tasks/federation/set-up-coredns-provider-federation.md +++ /dev/null @@ -1,152 +0,0 @@ ---- -title: Set up CoreDNS as DNS provider for Cluster Federation -content_template: templates/tutorial -weight: 130 ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This page shows how to configure and deploy CoreDNS to be used as the -DNS provider for Cluster Federation. - -{{% /capture %}} - - -{{% capture objectives %}} - -* Configure and deploy CoreDNS server -* Bring up federation with CoreDNS as dns provider -* Setup CoreDNS server in nameserver lookup chain - -{{% /capture %}} - - -{{% capture prerequisites %}} - -* You need to have a running Kubernetes cluster (which is -referenced as host cluster). Please see one of the -[getting started](/docs/setup/) guides for -installation instructions for your platform. -* Support for `LoadBalancer` services in member clusters of federation is -mandatory to enable `CoreDNS` for service discovery across federated clusters. - -{{% /capture %}} - - -{{% capture lessoncontent %}} - -## Deploying CoreDNS and etcd charts - -CoreDNS can be deployed in various configurations. Explained below is a -reference and can be tweaked to suit the needs of the platform and the -cluster federation. - -To deploy CoreDNS, we shall make use of helm charts. CoreDNS will be -deployed with [etcd](https://coreos.com/etcd) as the backend and should -be pre-installed. etcd can also be deployed using helm charts. Shown -below are the instructions to deploy etcd. - - helm install --namespace my-namespace --name etcd-operator stable/etcd-operator - helm upgrade --namespace my-namespace --set cluster.enabled=true etcd-operator stable/etcd-operator - -*Note: etcd default deployment configurations can be overridden, suiting the -host cluster.* - -After deployment succeeds, etcd can be accessed with the -[http://etcd-cluster.my-namespace:2379](http://etcd-cluster.my-namespace:2379) endpoint within the host cluster. - -The CoreDNS default configuration should be customized to suit the federation. -Shown below is the Values.yaml, which overrides the default -configuration parameters on the CoreDNS chart. - -```yaml -isClusterService: false -serviceType: "LoadBalancer" -plugins: - kubernetes: - enabled: false - etcd: - enabled: true - zones: - - "example.com." - endpoint: "http://etcd-cluster.my-namespace:2379" -``` - -The above configuration file needs some explanation: - - - `isClusterService` specifies whether CoreDNS should be deployed as a -cluster-service, which is the default. You need to set it to false, so -that CoreDNS is deployed as a Kubernetes application service. - - `serviceType` specifies the type of Kubernetes service to be created -for CoreDNS. You need to choose either "LoadBalancer" or "NodePort" to -make the CoreDNS service accessible outside the Kubernetes cluster. - - Disable `plugins.kubernetes`, which is enabled by default by -setting `plugins.kubernetes.enabled` to false. - - Enable `plugins.etcd` by setting `plugins.etcd.enabled` to -true. - - Configure the DNS zone (federation domain) for which CoreDNS is -authoritative by setting `plugins.etcd.zones` as shown above. - - Configure the etcd endpoint which was deployed earlier by setting -`plugins.etcd.endpoint` - -Now deploy CoreDNS by running - - helm install --namespace my-namespace --name coredns -f Values.yaml stable/coredns - -Verify that both etcd and CoreDNS pods are running as expected. - - -## Deploying Federation with CoreDNS as DNS provider - -The Federation control plane can be deployed using `kubefed init`. CoreDNS -can be chosen as the DNS provider by specifying two additional parameters. - - --dns-provider=coredns - --dns-provider-config=coredns-provider.conf - -coredns-provider.conf has below format: - - [Global] - etcd-endpoints = http://etcd-cluster.my-namespace:2379 - zones = example.com. - coredns-endpoints = : - - - `etcd-endpoints` is the endpoint to access etcd. - - `zones` is the federation domain for which CoreDNS is authoritative and is same as --dns-zone-name flag of `kubefed init`. - - `coredns-endpoints` is the endpoint to access CoreDNS server. This is an optional parameter introduced from v1.7 onwards. - -{{< note >}} -`plugins.etcd.zones` in the CoreDNS configuration and the `--dns-zone-name` flag to `kubefed init` should match. -{{< /note >}} - - -## Setup CoreDNS server in nameserver resolv.conf chain - -{{< note >}} -The following section applies only to versions prior to v1.7 -and will be automatically taken care of if the `coredns-endpoints` -parameter is configured in `coredns-provider.conf` as described in -section above. -{{< /note >}} - -Once the federation control plane is deployed and federated clusters -are joined to the federation, you need to add the CoreDNS server to the -pod's nameserver resolv.conf chain in all the federated clusters as this -self hosted CoreDNS server is not discoverable publicly. This can be -achieved by adding the below line to `dnsmasq` container's arg in -`kube-dns` deployment. - - --server=/example.com./ - -Replace `example.com` above with federation domain. - - -Now the federated cluster is ready for cross-cluster service discovery! - -{{% /capture %}} - - diff --git a/content/en/docs/tasks/federation/set-up-placement-policies-federation.md b/content/en/docs/tasks/federation/set-up-placement-policies-federation.md deleted file mode 100644 index d7ac469ea9..0000000000 --- a/content/en/docs/tasks/federation/set-up-placement-policies-federation.md +++ /dev/null @@ -1,221 +0,0 @@ ---- -title: Set up placement policies in Federation -content_template: templates/task -weight: 135 ---- - -{{% capture overview %}} - -{{< deprecationfilewarning >}} -{{< include "federation-deprecation-warning-note.md" >}} -{{< /deprecationfilewarning >}} - -This page shows how to enforce policy-based placement decisions over Federated -resources using an external policy engine. - -{{% /capture %}} - -{{% capture prerequisites %}} - -You need to have a running Kubernetes cluster (which is referenced as host -cluster). Please see one of the [getting started](/docs/setup/) -guides for installation instructions for your platform. - -{{% /capture %}} - -{{% capture steps %}} - -## Deploying Federation and configuring an external policy engine - -The Federation control plane can be deployed using `kubefed init`. - -After deploying the Federation control plane, you must configure an Admission -Controller in the Federation API server that enforces placement decisions -received from the external policy engine. - - kubectl apply -f scheduling-policy-admission.yaml - -Shown below is an example ConfigMap for the Admission Controller: - -{{< codenew file="federation/scheduling-policy-admission.yaml" >}} - -The ConfigMap contains three files: - -* `config.yml` specifies the location of the `SchedulingPolicy` Admission - Controller config file. -* `scheduling-policy-config.yml` specifies the location of the kubeconfig file - required to contact the external policy engine. This file can also include a - `retryBackoff` value that controls the initial retry backoff delay in - milliseconds. -* `opa-kubeconfig` is a standard kubeconfig containing the URL and credentials - needed to contact the external policy engine. - -Edit the Federation API server deployment to enable the `SchedulingPolicy` -Admission Controller. - - kubectl -n federation-system edit deployment federation-apiserver - -Update the Federation API server command line arguments to enable the Admission -Controller and mount the ConfigMap into the container. If there's an existing -`--enable-admission-plugins` flag, append `,SchedulingPolicy` instead of adding -another line. - - --enable-admission-plugins=SchedulingPolicy - --admission-control-config-file=/etc/kubernetes/admission/config.yml - -Add the following volume to the Federation API server pod: - - - name: admission-config - configMap: - name: admission - -Add the following volume mount the Federation API server `apiserver` container: - - volumeMounts: - - name: admission-config - mountPath: /etc/kubernetes/admission - -## Deploying an external policy engine - -The [Open Policy Agent (OPA)](http://openpolicyagent.org) is an open source, -general-purpose policy engine that you can use to enforce policy-based placement -decisions in the Federation control plane. - -Create a Service in the host cluster to contact the external policy engine: - - kubectl apply -f policy-engine-service.yaml - -Shown below is an example Service for OPA. - -{{< codenew file="federation/policy-engine-service.yaml" >}} - -Create a Deployment in the host cluster with the Federation control plane: - - kubectl apply -f policy-engine-deployment.yaml - -Shown below is an example Deployment for OPA. - -{{< codenew file="federation/policy-engine-deployment.yaml" >}} - -## Configuring placement policies via ConfigMaps - -The external policy engine will discover placement policies created in the -`kube-federation-scheduling-policy` namespace in the Federation API server. - -Create the namespace if it does not already exist: - - kubectl --context=federation create namespace kube-federation-scheduling-policy - -Configure a sample policy to test the external policy engine: - -``` -# OPA supports a high-level declarative language named Rego for authoring and -# enforcing policies. For more information on Rego, visit -# http://openpolicyagent.org. - -# Rego policies are namespaced by the "package" directive. -package kubernetes.placement - -# Imports provide aliases for data inside the policy engine. In this case, the -# policy simply refers to "clusters" below. -import data.kubernetes.clusters - -# The "annotations" rule generates a JSON object containing the key -# "federation.kubernetes.io/replica-set-preferences" mapped to . -# The preferences values is generated dynamically by OPA when it evaluates the -# rule. -# -# The SchedulingPolicy Admission Controller running inside the Federation API -# server will merge these annotations into incoming Federated resources. By -# setting replica-set-preferences, we can control the placement of Federated -# ReplicaSets. -# -# Rules are defined to generate JSON values (booleans, strings, objects, etc.) -# When OPA evaluates a rule, it generates a value IF all of the expressions in -# the body evaluate successfully. All rules can be understood intuitively as -# if where is true if AND AND ... -# is true (for some set of data.) -annotations["federation.kubernetes.io/replica-set-preferences"] = preferences { - input.kind = "ReplicaSet" - value = {"clusters": cluster_map, "rebalance": true} - json.marshal(value, preferences) -} - -# This "annotations" rule generates a value for the "federation.alpha.kubernetes.io/cluster-selector" -# annotation. -# -# In English, the policy asserts that resources in the "production" namespace -# that are not annotated with "criticality=low" MUST be placed on clusters -# labelled with "on-premises=true". -annotations["federation.alpha.kubernetes.io/cluster-selector"] = selector { - input.metadata.namespace = "production" - not input.metadata.annotations.criticality = "low" - json.marshal([{ - "operator": "=", - "key": "on-premises", - "values": "[true]", - }], selector) -} - -# Generates a set of cluster names that satisfy the incoming Federated -# ReplicaSet's requirements. In this case, just PCI compliance. -replica_set_clusters[cluster_name] { - clusters[cluster_name] - not insufficient_pci[cluster_name] -} - -# Generates a set of clusters that must not be used for Federated ReplicaSets -# that request PCI compliance. -insufficient_pci[cluster_name] { - clusters[cluster_name] - input.metadata.annotations["requires-pci"] = "true" - not pci_clusters[cluster_name] -} - -# Generates a set of clusters that are PCI certified. In this case, we assume -# clusters are annotated to indicate if they have passed PCI compliance audits. -pci_clusters[cluster_name] { - clusters[cluster_name].metadata.annotations["pci-certified"] = "true" -} - -# Helper rule to generate a mapping of desired clusters to weights. In this -# case, weights are static. -cluster_map[cluster_name] = {"weight": 1} { - replica_set_clusters[cluster_name] -} -``` - -Shown below is the command to create the sample policy: - - kubectl --context=federation -n kube-federation-scheduling-policy create configmap scheduling-policy --from-file=policy.rego - -This sample policy illustrates a few key ideas: - -* Placement policies can refer to any field in Federated resources. -* Placement policies can leverage external context (for example, Cluster - metadata) to make decisions. -* Administrative policy can be managed centrally. -* Policies can define simple interfaces (such as the `requires-pci` annotation) to - avoid duplicating logic in manifests. - -## Testing placement policies - -Annotate one of the clusters to indicate that it is PCI certified. - - kubectl --context=federation annotate clusters cluster-name-1 pci-certified=true - -Deploy a Federated ReplicaSet to test the placement policy. - -{{< codenew file="federation/replicaset-example-policy.yaml" >}} - -Shown below is the command to deploy a ReplicaSet that *does* match the policy. - - kubectl --context=federation create -f replicaset-example-policy.yaml - -Inspect the ReplicaSet to confirm the appropriate annotations have been applied: - - kubectl --context=federation get rs nginx-pci -o jsonpath='{.metadata.annotations}' - -{{% /capture %}} - - From ceccbc049c6dbbc82df3e16e648c617727407a9b Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Thu, 20 Feb 2020 07:44:30 +0800 Subject: [PATCH 33/38] Resource name constraints (1) (#19106) xref: #17969, #19099, #18746 --- .../overview/working-with-objects/names.md | 34 +++++++++++++++++-- .../extensible-admission-controllers.md | 2 ++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/content/en/docs/concepts/overview/working-with-objects/names.md b/content/en/docs/concepts/overview/working-with-objects/names.md index af24d5f184..60c07391a5 100644 --- a/content/en/docs/concepts/overview/working-with-objects/names.md +++ b/content/en/docs/concepts/overview/working-with-objects/names.md @@ -2,7 +2,7 @@ reviewers: - mikedanese - thockin -title: Names +title: Object Names and IDs content_template: templates/concept weight: 20 --- @@ -18,14 +18,41 @@ For non-unique user-provided attributes, Kubernetes provides [labels](/docs/conc {{% /capture %}} - {{% capture body %}} ## Names {{< glossary_definition term_id="name" length="all" >}} -Kubernetes resources can have names up to 253 characters long. The characters allowed in names are: digits (0-9), lower case letters (a-z), `-`, and `.`. +Below are three types of commonly used name constraints for resources. + +### DNS Subdomain Names + +Most resource types require a name that can be used as a DNS subdomain name +as defined in [RFC 1123](https://tools.ietf.org/html/rfc1123). +This means the name must: + +- contain no more than 253 characters +- contain only lowercase alphanumeric characters, '-' or '.' +- start with an alphanumeric character +- end with an alphanumeric character + +### DNS Label Names + +Some resource types require their names to follow the DNS +label standard as defined in [RFC 1123](https://tools.ietf.org/html/rfc1123). +This means the name must: + +- contain at most 63 characters +- contain only lowercase alphanumeric characters or '-' +- start with an alphanumeric character +- end with an alphanumeric character + +### Path Segment Names + +Some resource types require their names to be able to be safely encoded as a +path segment. In other words, the name may not be "." or ".." and the name may +not contain "/" or "%". Here’s an example manifest for a Pod named `nginx-demo`. @@ -42,6 +69,7 @@ spec: - containerPort: 80 ``` + {{< note >}} Some resource types have additional restrictions on their names. {{< /note >}} diff --git a/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md b/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md index 3500ed0c53..4131a79df8 100644 --- a/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md +++ b/content/en/docs/reference/access-authn-authz/extensible-admission-controllers.md @@ -631,6 +631,8 @@ So a webhook response to add that label would be: ## Webhook configuration To register admission webhooks, create `MutatingWebhookConfiguration` or `ValidatingWebhookConfiguration` API objects. +The name of a `MutatingWebhookConfiguration` or a `ValidatingWebhookConfiguration` object must be a valid +[DNS subdomain name](/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). Each configuration can contain one or more webhooks. If multiple webhooks are specified in a single configuration, each should be given a unique name. From f24680eab59cefe12da7aacd640692ae47def5a5 Mon Sep 17 00:00:00 2001 From: Jacky Wu Date: Thu, 20 Feb 2020 09:15:03 +0800 Subject: [PATCH 34/38] doc: remove tasks federation index from tasks main page. (#19205) --- content/en/docs/tasks/_index.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/content/en/docs/tasks/_index.md b/content/en/docs/tasks/_index.md index a9298a3329..1dee1f38f1 100644 --- a/content/en/docs/tasks/_index.md +++ b/content/en/docs/tasks/_index.md @@ -57,10 +57,6 @@ Configure your application to trust and use the cluster root Certificate Authori Learn common tasks for administering a cluster. -## Administering Federation - -Configure components in a cluster federation. - ## Managing Stateful Applications Perform common tasks for managing Stateful applications, including scaling, deleting, and debugging StatefulSets. From 21cbf8ea91a1c2c869e41785662e81a2bf9848df Mon Sep 17 00:00:00 2001 From: Kohei Toyoda Date: Thu, 20 Feb 2020 21:37:04 +0900 Subject: [PATCH 35/38] Update output of creating replicaset in controllers/replicaset (#19088) --- .../workloads/controllers/replicaset.md | 82 +++++++++---------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/content/en/docs/concepts/workloads/controllers/replicaset.md b/content/en/docs/concepts/workloads/controllers/replicaset.md index 7077bd5ad3..42451f0089 100644 --- a/content/en/docs/concepts/workloads/controllers/replicaset.md +++ b/content/en/docs/concepts/workloads/controllers/replicaset.md @@ -75,53 +75,50 @@ kubectl describe rs/frontend And you will see output similar to: ```shell -Name: frontend -Namespace: default -Selector: tier=frontend -Labels: app=guestbook - tier=frontend -Annotations: -Replicas: 3 current / 3 desired -Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed +Name: frontend +Namespace: default +Selector: tier=frontend +Labels: app=guestbook + tier=frontend +Annotations: kubectl.kubernetes.io/last-applied-configuration: + {"apiVersion":"apps/v1","kind":"ReplicaSet","metadata":{"annotations":{},"labels":{"app":"guestbook","tier":"frontend"},"name":"frontend",... +Replicas: 3 current / 3 desired +Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed Pod Template: - Labels: app=guestbook - tier=frontend + Labels: 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: + Image: gcr.io/google_samples/gb-frontend:v3 + Port: + Host Port: + Environment: + 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 + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal SuccessfulCreate 117s replicaset-controller Created pod: frontend-wtsmm + Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-b2zdv + Normal SuccessfulCreate 116s replicaset-controller Created pod: frontend-vcmts ``` And lastly you can check for the Pods brought up: ```shell -kubectl get Pods +kubectl get pods ``` You should see Pod information similar to: ```shell -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 +NAME READY STATUS RESTARTS AGE +frontend-b2zdv 1/1 Running 0 6m36s +frontend-vcmts 1/1 Running 0 6m36s +frontend-wtsmm 1/1 Running 0 6m36s ``` You can also verify that the owner reference of these pods is set to the frontend ReplicaSet. To do this, get the yaml of one of the Pods running: ```shell -kubectl get pods frontend-9si5l -o yaml +kubectl get pods frontend-b2zdv -o yaml ``` The output will look similar to this, with the frontend ReplicaSet's info set in the metadata's ownerReferences field: @@ -129,11 +126,11 @@ The output will look similar to this, with the frontend ReplicaSet's info set in apiVersion: v1 kind: Pod metadata: - creationTimestamp: 2019-01-31T17:20:41Z + creationTimestamp: "2020-02-12T07:06:16Z" generateName: frontend- labels: tier: frontend - name: frontend-9si5l + name: frontend-b2zdv namespace: default ownerReferences: - apiVersion: apps/v1 @@ -141,7 +138,7 @@ metadata: controller: true kind: ReplicaSet name: frontend - uid: 892a2330-257c-11e9-aecd-025000000001 + uid: f391f6db-bb9b-4c09-ae74-6a1f77f3d5cf ... ``` @@ -170,16 +167,17 @@ its desired count. Fetching the Pods: ```shell -kubectl get Pods +kubectl get pods ``` The output shows that the new Pods are either already terminated, or in the process of being terminated: ```shell 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 -pod2 0/1 Terminating 0 4s +frontend-b2zdv 1/1 Running 0 10m +frontend-vcmts 1/1 Running 0 10m +frontend-wtsmm 1/1 Running 0 10m +pod1 0/1 Terminating 0 1s +pod2 0/1 Terminating 0 1s ``` If you create the Pods first: @@ -195,15 +193,15 @@ kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml You shall see that the ReplicaSet has acquired the Pods and has only created new ones according to its spec until the number of its new Pods and the original matches its desired count. As fetching the Pods: ```shell -kubectl get Pods +kubectl get pods ``` Will reveal in its output: ```shell NAME READY STATUS RESTARTS AGE -frontend-pxj4r 1/1 Running 0 5s -pod1 1/1 Running 0 13s -pod2 1/1 Running 0 13s +frontend-hmmj2 1/1 Running 0 9s +pod1 1/1 Running 0 36s +pod2 1/1 Running 0 36s ``` In this manner, a ReplicaSet can own a non-homogenous set of Pods From ec7a6de75231bb29abb799a49249cb7308947db2 Mon Sep 17 00:00:00 2001 From: Ihor Sychevskyi <26163841+Arhell@users.noreply.github.com> Date: Thu, 20 Feb 2020 17:45:07 +0200 Subject: [PATCH 36/38] Fix Invalid link in readme (en) (#19204) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fc0bccb0b9..8be2ae4249 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ The recommended way to run the Kubernetes website locally is to run a specialize > If you are running on Windows, you'll need a few more tools which you can install with [Chocolatey](https://chocolatey.org). `choco install make` -> If you'd prefer to run the website locally without Docker, see [Running the website locally using Hugo](#running-the-site-locally-using-hugo) below. +> If you'd prefer to run the website locally without Docker, see [Running the website locally using Hugo](#running-the-website-locally-using-hugo) below. If you have Docker [up and running](https://www.docker.com/get-started), build the `kubernetes-hugo` Docker image locally: From fef685e16199566b4b75863db2ce6752ba980cdb Mon Sep 17 00:00:00 2001 From: Dan POP Date: Thu, 20 Feb 2020 11:45:57 -0800 Subject: [PATCH 37/38] Added 'ClaimRef' to make documentation clearer (#17914) * added final period (.) * removed backticks Co-authored-by: Leonardo Di Donato Signed-off-by: Dan POP Co-authored-by: Leo Di Donato --- content/en/docs/concepts/storage/persistent-volumes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/storage/persistent-volumes.md b/content/en/docs/concepts/storage/persistent-volumes.md index 8346fc562c..c59cb2ee3c 100644 --- a/content/en/docs/concepts/storage/persistent-volumes.md +++ b/content/en/docs/concepts/storage/persistent-volumes.md @@ -71,7 +71,7 @@ check [kube-apiserver](/docs/admin/kube-apiserver/) documentation. ### Binding -A user creates, or in the case of dynamic provisioning, has already created, a `PersistentVolumeClaim` with a specific amount of storage requested and with certain access modes. A control loop in the master watches for new PVCs, finds a matching PV (if possible), and binds them together. If a PV was dynamically provisioned for a new PVC, the loop will always bind that PV to the PVC. Otherwise, the user will always get at least what they asked for, but the volume may be in excess of what was requested. Once bound, `PersistentVolumeClaim` binds are exclusive, regardless of how they were bound. A PVC to PV binding is a one-to-one mapping. +A user creates, or in the case of dynamic provisioning, has already created, a PersistentVolumeClaim with a specific amount of storage requested and with certain access modes. A control loop in the master watches for new PVCs, finds a matching PV (if possible), and binds them together. If a PV was dynamically provisioned for a new PVC, the loop will always bind that PV to the PVC. Otherwise, the user will always get at least what they asked for, but the volume may be in excess of what was requested. Once bound, PersistentVolumeClaim binds are exclusive, regardless of how they were bound. A PVC to PV binding is a one-to-one mapping, using a ClaimRef which is a bi-directional binding between the PersistentVolume and the PersistentVolumeClaim. Claims will remain unbound indefinitely if a matching volume does not exist. Claims will be bound as matching volumes become available. For example, a cluster provisioned with many 50Gi PVs would not match a PVC requesting 100Gi. The PVC can be bound when a 100Gi PV is added to the cluster. From bad124b857a2927b75be739646244aacc5190580 Mon Sep 17 00:00:00 2001 From: Fabian Baumanis Date: Thu, 20 Feb 2020 21:41:58 +0100 Subject: [PATCH 38/38] Change back cronjob timezone note to UTC (#18715) --- content/en/docs/concepts/workloads/controllers/cron-jobs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/concepts/workloads/controllers/cron-jobs.md b/content/en/docs/concepts/workloads/controllers/cron-jobs.md index 13b304b120..24492cd18c 100644 --- a/content/en/docs/concepts/workloads/controllers/cron-jobs.md +++ b/content/en/docs/concepts/workloads/controllers/cron-jobs.md @@ -18,7 +18,7 @@ One CronJob object is like one line of a _crontab_ (cron table) file. It runs a on a given schedule, written in [Cron](https://en.wikipedia.org/wiki/Cron) format. {{< note >}} -All **CronJob** `schedule:` times are based on the timezone of the master where the job is initiated. +All **CronJob** `schedule:` times are denoted in UTC. {{< /note >}} When creating the manifest for a CronJob resource, make sure the name you provide