Merge pull request #48592 from mrgiles/41625_html_tutorials_html_to_md
Rewrite tutorials in Markdownpull/50406/head
commit
8cd43fb092
|
@ -1,117 +0,0 @@
|
|||
---
|
||||
title: Learn Kubernetes Basics
|
||||
linkTitle: Learn Kubernetes Basics
|
||||
no_list: true
|
||||
weight: 10
|
||||
card:
|
||||
name: tutorials
|
||||
weight: 20
|
||||
title: Walkthrough the basics
|
||||
---
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<div class="layout" id="top">
|
||||
|
||||
<main class="content">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<h2>Kubernetes Basics</h2>
|
||||
<p>This tutorial provides a walkthrough of the basics of the Kubernetes cluster orchestration system. Each module contains some background information on major Kubernetes features and concepts, and a tutorial for you to follow along.</p>
|
||||
<p>Using the tutorials, you can learn to:</p>
|
||||
<ul>
|
||||
<li>Deploy a containerized application on a cluster.</li>
|
||||
<li>Scale the deployment.</li>
|
||||
<li>Update the containerized application with a new software version.</li>
|
||||
<li>Debug the containerized application.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-9">
|
||||
<h2>What can Kubernetes do for you?</h2>
|
||||
<p>With modern web services, users expect applications to be available 24/7, and developers expect to deploy new versions of those applications several times a day. Containerization helps package software to serve these goals, enabling applications to be released and updated without downtime. Kubernetes helps you make sure those containerized applications run where and when you want, and helps them find the resources and tools they need to work. Kubernetes is a production-ready, open source platform designed with Google's accumulated experience in container orchestration, combined with best-of-breed ideas from the community.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div id="basics-modules" class="content__modules">
|
||||
<h2>Kubernetes Basics Modules</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_01.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/"><h5>1. Create a Kubernetes cluster</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_02.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/"><h5>2. Deploy an app</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/explore/explore-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_03.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="/docs/tutorials/kubernetes-basics/explore/explore-intro/"><h5>3. Explore your app</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/expose/expose-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_04.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="/docs/tutorials/kubernetes-basics/expose/expose-intro/"><h5>4. Expose your app publicly</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/scale/scale-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_05.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="/docs/tutorials/kubernetes-basics/scale/scale-intro/"><h5>5. Scale up your app</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="thumbnail">
|
||||
<a href="/docs/tutorials/kubernetes-basics/update/update-intro/"><img src="/docs/tutorials/kubernetes-basics/public/images/module_06.svg?v=1469803628347" alt=""></a>
|
||||
<div class="caption">
|
||||
<a href="/docs/tutorials/kubernetes-basics/update/update-intro/"><h5>6. Update your app</h5></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,83 @@
|
|||
---
|
||||
title: Learn Kubernetes Basics
|
||||
main_menu: true
|
||||
no_list: true
|
||||
weight: 20
|
||||
content_type: concept
|
||||
card:
|
||||
name: tutorials
|
||||
weight: 20
|
||||
title: Walkthrough the basics
|
||||
---
|
||||
|
||||
## {{% heading "objectives" %}}
|
||||
|
||||
This tutorial provides a walkthrough of the basics of the Kubernetes cluster orchestration
|
||||
system. Each module contains some background information on major Kubernetes features
|
||||
and concepts, and a tutorial for you to follow along.
|
||||
|
||||
Using the tutorials, you can learn to:
|
||||
|
||||
* Deploy a containerized application on a cluster.
|
||||
* Scale the deployment.
|
||||
* Update the containerized application with a new software version.
|
||||
* Debug the containerized application.
|
||||
|
||||
## What can Kubernetes do for you?
|
||||
|
||||
With modern web services, users expect applications to be available 24/7, and developers
|
||||
expect to deploy new versions of those applications several times a day. Containerization
|
||||
helps package software to serve these goals, enabling applications to be released and updated
|
||||
without downtime. Kubernetes helps you make sure those containerized applications run where
|
||||
and when you want, and helps them find the resources and tools they need to work. Kubernetes
|
||||
is a production-ready, open source platform designed with Google's accumulated experience in
|
||||
container orchestration, combined with best-of-breed ideas from the community.
|
||||
|
||||
## Kubernetes Basics Modules
|
||||
|
||||
<!-- css code to preserve original format -->
|
||||
<link rel="stylesheet" href="/css/style_tutorials.css">
|
||||
|
||||
<div class="tutorials-modules">
|
||||
<div class="module">
|
||||
<a href="/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_01.svg?v=1469803628347" alt="Module 1">
|
||||
<h5>1. Create a Kubernetes cluster</h5>
|
||||
</a>
|
||||
</div>
|
||||
<div class="module">
|
||||
<a href="/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_02.svg?v=1469803628347" alt="Module 2">
|
||||
<h5>2. Deploy an app</h5>
|
||||
</a>
|
||||
</div>
|
||||
<div class="module">
|
||||
<a href="/docs/tutorials/kubernetes-basics/explore/explore-intro/">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_03.svg?v=1469803628347" alt="Module 3">
|
||||
<h5>3. Explore your app</h5>
|
||||
</a>
|
||||
</div>
|
||||
<div class="module">
|
||||
<a href="/docs/tutorials/kubernetes-basics/expose/expose-intro/">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_04.svg?v=1469803628347" alt="Module 4">
|
||||
<h5>4. Expose your app publicly</h5>
|
||||
</a>
|
||||
</div>
|
||||
<div class="module">
|
||||
<a href="/docs/tutorials/kubernetes-basics/scale/scale-intro/">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_05.svg?v=1469803628347" alt="Module 5">
|
||||
<h5>5. Scale up your app</h5>
|
||||
</a>
|
||||
</div>
|
||||
<div class="module">
|
||||
<a href="/docs/tutorials/kubernetes-basics/update/update-intro/">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06.svg?v=1469803628347" alt="Module 6">
|
||||
<h5>6. Update your app</h5>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
* Tutorial [Using Minikube to Create a
|
||||
Cluster](/docs/tutorials/kubernetes-basics/create-cluster/)
|
|
@ -1,105 +0,0 @@
|
|||
---
|
||||
title: Using Minikube to Create a Cluster
|
||||
weight: 10
|
||||
description: |-
|
||||
Learn what a Kubernetes cluster is.
|
||||
Learn what Minikube is.
|
||||
Start a Kubernetes cluster.
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<div class="layout" id="top">
|
||||
|
||||
<main class="content">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-8">
|
||||
<h3>Objectives</h3>
|
||||
<ul>
|
||||
<li>Learn what a Kubernetes cluster is.</li>
|
||||
<li>Learn what Minikube is.</li>
|
||||
<li>Start a Kubernetes cluster on your computer.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<h3>Kubernetes Clusters</h3>
|
||||
<p>
|
||||
<b>Kubernetes coordinates a highly available cluster of computers that are connected to work as a single unit.</b> The abstractions in Kubernetes allow you to deploy containerized applications to a cluster without tying them specifically to individual machines. To make use of this new model of deployment, applications need to be packaged in a way that decouples them from individual hosts: they need to be containerized. Containerized applications are more flexible and available than in past deployment models, where applications were installed directly onto specific machines as packages deeply integrated into the host. <b>Kubernetes automates the distribution and scheduling of application containers across a cluster in a more efficient way.</b> Kubernetes is an open-source platform and is production-ready.
|
||||
</p>
|
||||
<p>A Kubernetes cluster consists of two types of resources:
|
||||
<ul>
|
||||
<li>The <b>Control Plane</b> coordinates the cluster</li>
|
||||
<li><b>Nodes</b> are the workers that run applications</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_lined">
|
||||
<h3>Summary:</h3>
|
||||
<ul>
|
||||
<li>Kubernetes cluster</li>
|
||||
<li>Minikube</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>
|
||||
Kubernetes is a production-grade, open-source platform that orchestrates the placement (scheduling) and execution of application containers within and across computer clusters.
|
||||
</i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2 style="color: #3771e3;">Cluster Diagram</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_01_cluster.svg"></p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p><b>The Control Plane is responsible for managing the cluster.</b> The Control Plane coordinates all activities in your cluster, such as scheduling applications, maintaining applications' desired state, scaling applications, and rolling out new updates.</p>
|
||||
<p><b>A node is a VM or a physical computer that serves as a worker machine in a Kubernetes cluster.</b> Each node has a Kubelet, which is an agent for managing the node and communicating with the Kubernetes control plane. The node should also have tools for handling container operations, such as {{< glossary_tooltip text="containerd" term_id="containerd" >}} or {{< glossary_tooltip term_id="cri-o" >}}. A Kubernetes cluster that handles production traffic should have a minimum of three nodes because if one node goes down, both an <a href="/docs/concepts/architecture/#etcd">etcd</a> member and a control plane instance are lost, and redundancy is compromised. You can mitigate this risk by adding more control plane nodes.</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>Control Planes manage the cluster and the nodes that are used to host the running applications.</i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p>When you deploy applications on Kubernetes, you tell the control plane to start the application containers. The control plane schedules the containers to run on the cluster's nodes. <b>Node-level components, such as the kubelet, communicate with the control plane using the <a href="/docs/concepts/overview/kubernetes-api/">Kubernetes API</a></b>, which the control plane exposes. End users can also use the Kubernetes API directly to interact with the cluster.</p>
|
||||
|
||||
<p>A Kubernetes cluster can be deployed on either physical or virtual machines. To get started with Kubernetes development, you can use Minikube. Minikube is a lightweight Kubernetes implementation that creates a VM on your local machine and deploys a simple cluster containing only one node. Minikube is available for Linux, macOS, and Windows systems. The Minikube CLI provides basic bootstrapping operations for working with your cluster, including start, stop, status, and delete.</p>
|
||||
|
||||
<p>Now that you know more about what Kubernetes is, visit <a href="/docs/tutorials/hello-minikube/">Hello Minikube</a>
|
||||
to try this out on your computer.</p>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,75 @@
|
|||
---
|
||||
title: Using Minikube to Create a Cluster
|
||||
weight: 10
|
||||
---
|
||||
|
||||
## {{% heading "objectives" %}}
|
||||
|
||||
* Learn what a Kubernetes cluster is.
|
||||
* Learn what Minikube is.
|
||||
* Start a Kubernetes cluster on your computer.
|
||||
|
||||
## Kubernetes Clusters
|
||||
|
||||
{{% alert %}}
|
||||
_Kubernetes is a production-grade, open-source platform that orchestrates
|
||||
the placement (scheduling) and execution of application containers
|
||||
within and across computer clusters._
|
||||
{{% /alert %}}
|
||||
|
||||
**Kubernetes coordinates a highly available cluster of computers that are connected
|
||||
to work as a single unit.** The abstractions in Kubernetes allow you to deploy
|
||||
containerized applications to a cluster without tying them specifically to individual
|
||||
machines. To make use of this new model of deployment, applications need to be packaged
|
||||
in a way that decouples them from individual hosts: they need to be containerized.
|
||||
Containerized applications are more flexible and available than in past deployment models,
|
||||
where applications were installed directly onto specific machines as packages deeply
|
||||
integrated into the host. **Kubernetes automates the distribution and scheduling of
|
||||
application containers across a cluster in a more efficient way.** Kubernetes is an
|
||||
open-source platform and is production-ready.
|
||||
|
||||
A Kubernetes cluster consists of two types of resources:
|
||||
|
||||
* The **Control Plane** coordinates the cluster
|
||||
* **Nodes** are the workers that run applications
|
||||
|
||||
### Cluster Diagram
|
||||
|
||||
{{< figure src="/docs/tutorials/kubernetes-basics/public/images/module_01_cluster.svg" style="width: 100%;" >}}
|
||||
|
||||
**The Control Plane is responsible for managing the cluster.** The Control Plane
|
||||
coordinates all activities in your cluster, such as scheduling applications, maintaining
|
||||
applications' desired state, scaling applications, and rolling out new updates.
|
||||
|
||||
{{% alert %}}
|
||||
_Control Planes manage the cluster and the nodes that are used to host the running
|
||||
applications._
|
||||
{{% /alert %}}
|
||||
|
||||
**A node is a VM or a physical computer that serves as a worker machine in a Kubernetes
|
||||
cluster.** Each node has a Kubelet, which is an agent for managing the node and
|
||||
communicating with the Kubernetes control plane. The node should also have tools for
|
||||
handling container operations, such as {{< glossary_tooltip text="containerd" term_id="containerd" >}}
|
||||
or {{< glossary_tooltip term_id="cri-o" >}}. A Kubernetes cluster that handles production
|
||||
traffic should have a minimum of three nodes because if one node goes down, both an
|
||||
[etcd](/docs/concepts/architecture/#etcd) member and a control plane instance are lost,
|
||||
and redundancy is compromised. You can mitigate this risk by adding more control plane nodes.
|
||||
|
||||
When you deploy applications on Kubernetes, you tell the control plane to start
|
||||
the application containers. The control plane schedules the containers to run on
|
||||
the cluster's nodes. **Node-level components, such as the kubelet, communicate
|
||||
with the control plane using the [Kubernetes API](/docs/concepts/overview/kubernetes-api/)**,
|
||||
which the control plane exposes. End users can also use the Kubernetes API directly
|
||||
to interact with the cluster.
|
||||
|
||||
A Kubernetes cluster can be deployed on either physical or virtual machines. To
|
||||
get started with Kubernetes development, you can use Minikube. Minikube is a lightweight
|
||||
Kubernetes implementation that creates a VM on your local machine and deploys a
|
||||
simple cluster containing only one node. Minikube is available for Linux, macOS,
|
||||
and Windows systems. The Minikube CLI provides basic bootstrapping operations for
|
||||
working with your cluster, including start, stop, status, and delete.
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
* Tutorial [Hello Minikube](/docs/tutorials/hello-minikube/).
|
||||
* Learn more about [Cluster Architecture](/docs/concepts/architecture/).
|
|
@ -1,173 +0,0 @@
|
|||
---
|
||||
title: Using kubectl to Create a Deployment
|
||||
weight: 10
|
||||
description: |-
|
||||
Learn about application Deployments.
|
||||
Deploy your first app on Kubernetes with kubectl.
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<div class="layout" id="top">
|
||||
|
||||
<main class="content">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h3>Objectives</h3>
|
||||
<ul>
|
||||
<li>Learn about application Deployments.</li>
|
||||
<li>Deploy your first app on Kubernetes with kubectl.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<h3>Kubernetes Deployments</h3>
|
||||
|
||||
{{< note >}}
|
||||
<p>This tutorial uses a container that requires the AMD64 architecture. If you are using
|
||||
minikube on a computer with a different CPU architecture, you could try using minikube with
|
||||
a driver that can emulate AMD64. For example, the Docker Desktop driver can do this.</p>
|
||||
{{< /note >}}
|
||||
|
||||
<p>
|
||||
Once you have a <a href="/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/">running Kubernetes cluster</a>, you can deploy your containerized applications on top of it.
|
||||
To do so, you create a Kubernetes <b>Deployment</b>. The Deployment instructs Kubernetes
|
||||
how to create and update instances of your application. Once you've created a Deployment, the Kubernetes
|
||||
control plane schedules the application instances included in that Deployment to run on individual Nodes in the
|
||||
cluster.
|
||||
</p>
|
||||
|
||||
<p>Once the application instances are created, a Kubernetes Deployment controller continuously monitors those instances. If the Node hosting an instance goes down or is deleted, the Deployment controller replaces the instance with an instance on another Node in the cluster. <b>This provides a self-healing mechanism to address machine failure or maintenance.</b></p>
|
||||
|
||||
<p>In a pre-orchestration world, installation scripts would often be used to start applications, but they did not allow recovery from machine failure. By both creating your application instances and keeping them running across Nodes, Kubernetes Deployments provide a fundamentally different approach to application management.</p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_lined">
|
||||
<h3>Summary:</h3>
|
||||
<ul>
|
||||
<li>Deployments</li>
|
||||
<li>Kubectl</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>
|
||||
A Deployment is responsible for creating and updating instances of your application
|
||||
</i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2 style="color: #3771e3;">Deploying your first app on Kubernetes</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_02_first_app.svg"></p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
|
||||
<p>You can create and manage a Deployment by using the Kubernetes command line interface, <b>kubectl</b>. Kubectl uses the Kubernetes API to interact with the cluster. In this module, you'll learn the most common kubectl commands needed to create Deployments that run your applications on a Kubernetes cluster.</p>
|
||||
|
||||
<p>When you create a Deployment, you'll need to specify the container image for your application and the number of replicas that you want to run. You can change that information later by updating your Deployment; Modules <a href="/docs/tutorials/kubernetes-basics/scale/scale-intro/">5</a> and <a href="/docs/tutorials/kubernetes-basics/update/update-intro/">6</a> of the bootcamp discuss how you can scale and update your Deployments.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i> Applications need to be packaged into one of the supported container formats in order to be deployed on Kubernetes </i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p>
|
||||
For your first Deployment, you'll use a hello-node application packaged in a Docker container that uses NGINX to echo back all the requests. (If you didn't already try creating a hello-node application and deploying it using a container, you can do that first by following the instructions from the <a href="/docs/tutorials/hello-minikube/">Hello Minikube tutorial</a>).
|
||||
<p>You will need to have installed kubectl as well. If you need to install it, visit <a href="/docs/tasks/tools/#kubectl">install tools</a>.</p>
|
||||
<p>Now that you know what Deployments are, let's deploy our first app!</p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h3>kubectl basics</h3>
|
||||
<p>The common format of a kubectl command is: <code>kubectl <i>action resource</i></code></p>
|
||||
<p>This performs the specified <em>action</em> (like <tt>create</tt>, <tt>describe</tt> or <tt>delete</tt>) on the specified <em>resource</em> (like <tt>node</tt> or <tt>deployment</tt>). You can use <code>-<span />-help</code> after the subcommand to get additional info about possible parameters (for example: <code>kubectl get nodes --help</code>).</p>
|
||||
<p>Check that kubectl is configured to talk to your cluster, by running the <b><code>kubectl version</code></b> command.</p>
|
||||
<p>Check that kubectl is installed and you can see both the client and the server versions.</p>
|
||||
<p>To view the nodes in the cluster, run the <b><code>kubectl get nodes</code></b> command.</p>
|
||||
<p>You see the available nodes. Later, Kubernetes will choose where to deploy our application based on Node available resources.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<a id="deploy-an-app"></a>
|
||||
<h3>Deploy an app</h3>
|
||||
<p>Let’s deploy our first app on Kubernetes with the <code>kubectl create deployment</code> command. We need to provide the deployment name and app image location (include the full repository url for images hosted outside Docker Hub).</p>
|
||||
<p><b><code>kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1</code></b></p>
|
||||
<p>Great! You just deployed your first application by creating a deployment. This performed a few things for you:</p>
|
||||
<ul>
|
||||
<li>searched for a suitable node where an instance of the application could be run (we have only 1 available node)</li>
|
||||
<li>scheduled the application to run on that Node</li>
|
||||
<li>configured the cluster to reschedule the instance on a new Node when needed</li>
|
||||
</ul>
|
||||
<p>To list your deployments use the <code>kubectl get deployments</code> command:</p>
|
||||
<p><b><code>kubectl get deployments</code></b></p>
|
||||
<p>We see that there is 1 deployment running a single instance of your app. The instance is running inside a container on your node.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>View the app</h3>
|
||||
<p><a href="/docs/concepts/workloads/pods/">Pods</a> that are running inside Kubernetes are running on a private, isolated network.
|
||||
By default they are visible from other pods and services within the same Kubernetes cluster, but not outside that network.
|
||||
When we use <code>kubectl</code>, we're interacting through an API endpoint to communicate with our application.</p>
|
||||
<p>We will cover other options on how to expose your application outside the Kubernetes cluster later, in <a href="/docs/tutorials/kubernetes-basics/expose/">Module 4</a>.
|
||||
Also as a basic tutorial, we're not explaining what <code>Pods</code> are in any detail here, it will be covered in later topics.</p>
|
||||
<p>The <code>kubectl proxy</code> command can create a proxy that will forward communications into the cluster-wide, private network. The proxy can be terminated by pressing control-C and won't show any output while it's running.</p>
|
||||
<p><strong>You need to open a second terminal window to run the proxy.</strong></p>
|
||||
<p><b><code>kubectl proxy</b></code>
|
||||
<p>We now have a connection between our host (the terminal) and the Kubernetes cluster. The proxy enables direct access to the API from these terminals.</p>
|
||||
<p>You can see all those APIs hosted through the proxy endpoint. For example, we can query the version directly through the API using the <code>curl</code> command:</p>
|
||||
<p><b><code>curl http://localhost:8001/version</code></b></p>
|
||||
<div class="alert alert-info note callout" role="alert"><strong>Note:</strong> If port 8001 is not accessible, ensure that the <code>kubectl proxy</code> that you started above is running in the second terminal.</div>
|
||||
<p>The API server will automatically create an endpoint for each pod, based on the pod name, that is also accessible through the proxy.</p>
|
||||
<p>First we need to get the Pod name, and we'll store it in the environment variable <tt>POD_NAME</tt>:</p>
|
||||
<p><b><code>export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')</code></b><br />
|
||||
<b><code>echo Name of the Pod: $POD_NAME</code></b></p>
|
||||
<p>You can access the Pod through the proxied API, by running:</p>
|
||||
<p><b><code>curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME:8080/proxy/</code></b></p>
|
||||
<p>In order for the new Deployment to be accessible without using the proxy, a Service is required which will be explained in <a href="/docs/tutorials/kubernetes-basics/expose/">Module 4</a>.</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<p>
|
||||
Once you're ready, move on to <a href="/docs/tutorials/kubernetes-basics/explore/explore-intro/" title="Viewing Pods and Nodes">Viewing Pods and Nodes</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,171 @@
|
|||
---
|
||||
title: Using kubectl to Create a Deployment
|
||||
weight: 10
|
||||
---
|
||||
|
||||
## {{% heading "objectives" %}}
|
||||
|
||||
* Learn about application Deployments.
|
||||
* Deploy your first app on Kubernetes with kubectl.
|
||||
|
||||
## Kubernetes Deployments
|
||||
|
||||
{{% alert %}}
|
||||
_A Deployment is responsible for creating and updating instances of your application._
|
||||
{{% /alert %}}
|
||||
|
||||
{{< note >}}
|
||||
This tutorial uses a container that requires the AMD64 architecture. If you are using
|
||||
minikube on a computer with a different CPU architecture, you could try using minikube with
|
||||
a driver that can emulate AMD64. For example, the Docker Desktop driver can do this.
|
||||
{{< /note >}}
|
||||
|
||||
Once you have a [running Kubernetes cluster](/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/),
|
||||
you can deploy your containerized applications on top of it. To do so, you create a
|
||||
Kubernetes **Deployment**. The Deployment instructs Kubernetes how to create and
|
||||
update instances of your application. Once you've created a Deployment, the Kubernetes
|
||||
control plane schedules the application instances included in that Deployment to run
|
||||
on individual Nodes in the cluster.
|
||||
|
||||
Once the application instances are created, a Kubernetes Deployment controller continuously
|
||||
monitors those instances. If the Node hosting an instance goes down or is deleted,
|
||||
the Deployment controller replaces the instance with an instance on another Node
|
||||
in the cluster. **This provides a self-healing mechanism to address machine failure
|
||||
or maintenance.**
|
||||
|
||||
In a pre-orchestration world, installation scripts would often be used to start
|
||||
applications, but they did not allow recovery from machine failure. By both creating
|
||||
your application instances and keeping them running across Nodes, Kubernetes Deployments
|
||||
provide a fundamentally different approach to application management.
|
||||
|
||||
## Deploying your first app on Kubernetes
|
||||
|
||||
{{% alert %}}
|
||||
_Applications need to be packaged into one of the supported container formats in
|
||||
order to be deployed on Kubernetes._
|
||||
{{% /alert %}}
|
||||
|
||||
{{< figure src="/docs/tutorials/kubernetes-basics/public/images/module_02_first_app.svg" class="diagram-medium" >}}
|
||||
|
||||
You can create and manage a Deployment by using the Kubernetes command line interface,
|
||||
[kubectl](/docs/reference/kubectl/). `kubectl` uses the Kubernetes API to interact
|
||||
with the cluster. In this module, you'll learn the most common `kubectl` commands
|
||||
needed to create Deployments that run your applications on a Kubernetes cluster.
|
||||
|
||||
When you create a Deployment, you'll need to specify the container image for your
|
||||
application and the number of replicas that you want to run. You can change that
|
||||
information later by updating your Deployment; [Module 5](/docs/tutorials/kubernetes-basics/scale/scale-intro/)
|
||||
and [Module 6](/docs/tutorials/kubernetes-basics/update/update-intro/) of the bootcamp
|
||||
discuss how you can scale and update your Deployments.
|
||||
|
||||
For your first Deployment, you'll use a hello-node application packaged in a Docker
|
||||
container that uses NGINX to echo back all the requests. (If you didn't already try
|
||||
creating a hello-node application and deploying it using a container, you can do
|
||||
that first by following the instructions from the [Hello Minikube tutorial](/docs/tutorials/hello-minikube/).
|
||||
|
||||
You will need to have installed kubectl as well. If you need to install it, visit
|
||||
[install tools](/docs/tasks/tools/#kubectl) install tools.
|
||||
|
||||
Now that you know what Deployments are, let's deploy our first app!
|
||||
|
||||
### kubectl basics
|
||||
|
||||
The common format of a kubectl command is: `kubectl action resource`.
|
||||
|
||||
This performs the specified _action_ (like `create`, `describe` or `delete`) on the
|
||||
specified _resource_ (like `node` or `deployment`. You can use `--help` after the
|
||||
subcommand to get additional info about possible parameters (for example: `kubectl get nodes --help`).
|
||||
|
||||
Check that kubectl is configured to talk to your cluster, by running the `kubectl version` command.
|
||||
|
||||
Check that kubectl is installed and that you can see both the client and the server versions.
|
||||
|
||||
To view the nodes in the cluster, run the `kubectl get nodes` command.
|
||||
|
||||
You see the available nodes. Later, Kubernetes will choose where to deploy our
|
||||
application based on Node available resources.
|
||||
|
||||
### Deploy an app
|
||||
|
||||
Let’s deploy our first app on Kubernetes with the `kubectl create deployment` command.
|
||||
We need to provide the deployment name and app image location (include the full
|
||||
repository url for images hosted outside Docker Hub).
|
||||
|
||||
```shell
|
||||
kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1
|
||||
```
|
||||
|
||||
Great! You just deployed your first application by creating a deployment. This performed a few things for you:
|
||||
|
||||
* searched for a suitable node where an instance of the application could be run (we have only 1 available node)
|
||||
* scheduled the application to run on that Node
|
||||
* configured the cluster to reschedule the instance on a new Node when needed
|
||||
|
||||
To list your deployments use the `kubectl get deployments` command:
|
||||
|
||||
```shell
|
||||
kubectl get deployments
|
||||
```
|
||||
|
||||
We see that there is 1 deployment running a single instance of your app. The instance
|
||||
is running inside a container on your node.
|
||||
|
||||
### View the app
|
||||
|
||||
[Pods](/docs/concepts/workloads/pods/) that are running inside Kubernetes are running
|
||||
on a private, isolated network. By default they are visible from other pods and services
|
||||
within the same Kubernetes cluster, but not outside that network. When we use `kubectl`,
|
||||
we're interacting through an API endpoint to communicate with our application.
|
||||
|
||||
We will cover other options on how to expose your application outside the Kubernetes
|
||||
cluster later, in [Module 4](/docs/tutorials/kubernetes-basics/expose/).
|
||||
Also as a basic tutorial, we're not explaining what `Pods` are in any
|
||||
detail here, it will be covered in later topics.
|
||||
|
||||
The `kubectl proxy` command can create a proxy that will forward communications
|
||||
into the cluster-wide, private network. The proxy can be terminated by pressing
|
||||
control-C and won't show any output while it's running.
|
||||
|
||||
**You need to open a second terminal window to run the proxy.**
|
||||
|
||||
```shell
|
||||
kubectl proxy
|
||||
```
|
||||
We now have a connection between our host (the terminal) and the Kubernetes cluster.
|
||||
The proxy enables direct access to the API from these terminals.
|
||||
|
||||
You can see all those APIs hosted through the proxy endpoint. For example, we can
|
||||
query the version directly through the API using the `curl` command:
|
||||
|
||||
```shell
|
||||
curl http://localhost:8001/version
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
If port 8001 is not accessible, ensure that the `kubectl proxy` that you started
|
||||
above is running in the second terminal.
|
||||
{{< /note >}}
|
||||
|
||||
The API server will automatically create an endpoint for each pod, based on the
|
||||
pod name, that is also accessible through the proxy.
|
||||
|
||||
First we need to get the Pod name, and we'll store it in the environment variable `POD_NAME`.
|
||||
|
||||
```shell
|
||||
export POD_NAME=$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')
|
||||
echo Name of the Pod: $POD_NAME
|
||||
```
|
||||
|
||||
You can access the Pod through the proxied API, by running:
|
||||
|
||||
```shell
|
||||
curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME:8080/proxy/
|
||||
```
|
||||
|
||||
In order for the new Deployment to be accessible without using the proxy, a Service
|
||||
is required which will be explained in [Module 4](/docs/tutorials/kubernetes-basics/expose/).
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
* Tutorial [Viewing Pods and Nodes](/docs/tutorials/kubernetes-basics/explore/explore-intro/).
|
||||
* Learn more about [Deployments](/docs/concepts/workloads/controllers/deployment/).
|
|
@ -1,202 +0,0 @@
|
|||
---
|
||||
title: Viewing Pods and Nodes
|
||||
weight: 10
|
||||
description: |-
|
||||
Learn how to troubleshoot Kubernetes applications using
|
||||
kubectl get, kubectl describe, kubectl logs and
|
||||
kubectl exec.
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<div class="layout" id="top">
|
||||
|
||||
<main class="content">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-8">
|
||||
<h3>Objectives</h3>
|
||||
<ul>
|
||||
<li>Learn about Kubernetes Pods.</li>
|
||||
<li>Learn about Kubernetes Nodes.</li>
|
||||
<li>Troubleshoot deployed applications.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<h2>Kubernetes Pods</h2>
|
||||
<p>When you created a Deployment in Module <a href="/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/">2</a>, Kubernetes created a <b>Pod</b> to host your application instance. A Pod is a Kubernetes abstraction that represents a group of one or more application containers (such as Docker), and some shared resources for those containers. Those resources include:</p>
|
||||
<ul>
|
||||
<li>Shared storage, as Volumes</li>
|
||||
<li>Networking, as a unique cluster IP address</li>
|
||||
<li>Information about how to run each container, such as the container image version or specific ports to use</li>
|
||||
</ul>
|
||||
<p>A Pod models an application-specific "logical host" and can contain different application containers which are relatively tightly coupled. For example, a Pod might include both the container with your Node.js app as well as a different container that feeds the data to be published by the Node.js webserver. The containers in a Pod share an IP Address and port space, are always co-located and co-scheduled, and run in a shared context on the same Node.</p>
|
||||
|
||||
<p>Pods are the atomic unit on the Kubernetes platform. When we create a Deployment on Kubernetes, that Deployment creates Pods with containers inside them (as opposed to creating containers directly). Each Pod is tied to the Node where it is scheduled, and remains there until termination (according to restart policy) or deletion. In case of a Node failure, identical Pods are scheduled on other available Nodes in the cluster.</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_lined">
|
||||
<h3>Summary:</h3>
|
||||
<ul>
|
||||
<li>Pods</li>
|
||||
<li>Nodes</li>
|
||||
<li>Kubectl main commands</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>
|
||||
A Pod is a group of one or more application containers (such as Docker) and includes shared storage (volumes), IP address and information about how to run them.
|
||||
</i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2 style="color: #3771e3;">Pods overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_03_pods.svg"></p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2>Nodes</h2>
|
||||
<p>A Pod always runs on a <b>Node</b>. A Node is a worker machine in Kubernetes and may be either a virtual or a physical machine, depending on the cluster. Each Node is managed by the control plane. A Node can have multiple pods, and the Kubernetes control plane automatically handles scheduling the pods across the Nodes in the cluster. The control plane's automatic scheduling takes into account the available resources on each Node.</p>
|
||||
|
||||
<p>Every Kubernetes Node runs at least:</p>
|
||||
<ul>
|
||||
<li>Kubelet, a process responsible for communication between the Kubernetes control plane and the Node; it manages the Pods and the containers running on a machine.</li>
|
||||
<li>A container runtime (like Docker) responsible for pulling the container image from a registry, unpacking the container, and running the application.</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i> Containers should only be scheduled together in a single Pod if they are tightly coupled and need to share resources such as disk. </i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2 style="color: #3771e3;">Node overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_03_nodes.svg"></p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2>Troubleshooting with kubectl</h2>
|
||||
<p>In Module <a href="/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/">2</a>, you used the kubectl command-line interface. You'll continue to use it in Module 3 to get information about deployed applications and their environments. The most common operations can be done with the following kubectl subcommands:</p>
|
||||
<ul>
|
||||
<li><tt><b>kubectl get</b></tt> - list resources</li>
|
||||
<li><tt><b>kubectl describe</b></tt> - show detailed information about a resource</li>
|
||||
<li><tt><b>kubectl logs</b></tt> - print the logs from a container in a pod</li>
|
||||
<li><tt><b>kubectl exec</b></tt> - execute a command on a container in a pod</li>
|
||||
</ul>
|
||||
|
||||
<p>You can use these commands to see when applications were deployed, what their current statuses are, where they are running and what their configurations are.</p>
|
||||
|
||||
<p>Now that we know more about our cluster components and the command line, let's explore our application.</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i> A node is a worker machine in Kubernetes and may be a VM or physical machine, depending on the cluster. Multiple Pods can run on one Node. </i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Check application configuration</h3>
|
||||
<p>Let's verify that the application we deployed in the previous scenario is running. We'll use the <code>kubectl get</code> command and look for existing Pods:</p>
|
||||
<p><b><code>kubectl get pods</code></b></p>
|
||||
<p>If no pods are running, please wait a couple of seconds and list the Pods again. You can continue once you see one Pod running.</p>
|
||||
<p>Next, to view what containers are inside that Pod and what images are used to build those containers we run the <code>kubectl describe pods</code> command:</p>
|
||||
<p><b><code>kubectl describe pods</code></b></p>
|
||||
<p>We see here details about the Pod’s container: IP address, the ports used and a list of events related to the lifecycle of the Pod.</p>
|
||||
<p>The output of the <tt>describe</tt> subcommand is extensive and covers some concepts that we didn’t explain yet, but don’t worry, they will become familiar by the end of this bootcamp.</p>
|
||||
<p><em><strong>Note:</strong> the <tt>describe</tt> subcommand can be used to get detailed information about most of the Kubernetes primitives, including Nodes, Pods, and Deployments. The describe output is designed to be human readable, not to be scripted against.</em></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Show the app in the terminal</h3>
|
||||
<p>Recall that Pods are running in an isolated, private network - so we need to proxy access
|
||||
to them so we can debug and interact with them. To do this, we'll use the <code>kubectl proxy</code> command to run a proxy in a <strong>second terminal</strong>. Open a new terminal window, and in that new terminal, run:</p>
|
||||
<p><code><b>kubectl proxy</b></code></p>
|
||||
<p>Now again, we'll get the Pod name and query that pod directly through the proxy.
|
||||
To get the Pod name and store it in the <tt>POD_NAME</tt> environment variable:</p>
|
||||
<p><code><b>export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"</b></code><br />
|
||||
<code><b>echo Name of the Pod: $POD_NAME</b></code></p>
|
||||
<p>To see the output of our application, run a <code>curl</code> request:</p>
|
||||
<p><code><b>curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME:8080/proxy/</b></code></p>
|
||||
<p>The URL is the route to the API of the Pod.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>View the container logs</h3>
|
||||
<p>Anything that the application would normally send to standard output becomes logs for the container within the Pod. We can retrieve these logs using the <code>kubectl logs</code> command:</p>
|
||||
<p><code><b>kubectl logs "$POD_NAME"</b></code></p>
|
||||
<p><em><strong>Note:</strong> We don't need to specify the container name, because we only have one container inside the pod.</em></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Executing command on the container</h3>
|
||||
<p>We can execute commands directly on the container once the Pod is up and running.
|
||||
For this, we use the <code>exec</code> subcommand and use the name of the Pod as a parameter. Let’s list the environment variables:</p>
|
||||
<p><code><b>kubectl exec "$POD_NAME" -- env</b></code></p>
|
||||
<p>Again, it's worth mentioning that the name of the container itself can be omitted since we only have a single container in the Pod.</p>
|
||||
<p>Next let’s start a bash session in the Pod’s container:</p>
|
||||
<p><code><b>kubectl exec -ti $POD_NAME -- bash</b></code></p>
|
||||
<p>We have now an open console on the container where we run our NodeJS application. The source code of the app is in the <tt>server.js</tt> file:</p>
|
||||
<p><code><b>cat server.js</b></code></p>
|
||||
<p>You can check that the application is up by running a <tt>curl</tt> command:</p>
|
||||
<p><code><b>curl http://localhost:8080</b></code></p>
|
||||
<p><em><strong>Note:</strong> here we used <tt>localhost</tt> because we executed the command inside the NodeJS Pod. If you cannot connect to localhost:8080, check to make sure you have run the <code>kubectl exec</code> command and are launching the command from within the Pod</em></p>
|
||||
<p>To close your container connection, type <code><b>exit</b></code>.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
<p>
|
||||
Once you're ready, move on to <a href="/docs/tutorials/kubernetes-basics/expose/expose-intro/" title="Using A Service To Expose Your App">Using A Service To Expose Your App</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,198 @@
|
|||
---
|
||||
title: Viewing Pods and Nodes
|
||||
weight: 10
|
||||
---
|
||||
|
||||
## {{% heading "objectives" %}}
|
||||
|
||||
* Learn about Kubernetes Pods.
|
||||
* Learn about Kubernetes Nodes.
|
||||
* Troubleshoot deployed applications.
|
||||
|
||||
## Kubernetes Pods
|
||||
|
||||
{{% alert %}}
|
||||
_A Pod is a group of one or more application containers (such as Docker) and includes
|
||||
shared storage (volumes), IP address and information about how to run them._
|
||||
{{% /alert %}}
|
||||
|
||||
When you created a Deployment in [Module 2](/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/),
|
||||
Kubernetes created a **Pod** to host your application instance. A Pod is a Kubernetes
|
||||
abstraction that represents a group of one or more application containers (such as Docker),
|
||||
and some shared resources for those containers. Those resources include:
|
||||
|
||||
* Shared storage, as Volumes
|
||||
* Networking, as a unique cluster IP address
|
||||
* Information about how to run each container, such as the container image version
|
||||
or specific ports to use
|
||||
|
||||
A Pod models an application-specific "logical host" and can contain different application
|
||||
containers which are relatively tightly coupled. For example, a Pod might include
|
||||
both the container with your Node.js app as well as a different container that feeds
|
||||
the data to be published by the Node.js webserver. The containers in a Pod share an
|
||||
IP Address and port space, are always co-located and co-scheduled, and run in a shared
|
||||
context on the same Node.
|
||||
|
||||
Pods are the atomic unit on the Kubernetes platform. When we create a Deployment
|
||||
on Kubernetes, that Deployment creates Pods with containers inside them (as opposed
|
||||
to creating containers directly). Each Pod is tied to the Node where it is scheduled,
|
||||
and remains there until termination (according to restart policy) or deletion. In
|
||||
case of a Node failure, identical Pods are scheduled on other available Nodes in
|
||||
the cluster.
|
||||
|
||||
### Pods overview
|
||||
|
||||
{{< figure src="/docs/tutorials/kubernetes-basics/public/images/module_03_pods.svg" class="diagram-medium" >}}
|
||||
|
||||
{{% alert %}}
|
||||
_Containers should only be scheduled together in a single Pod if they are tightly
|
||||
coupled and need to share resources such as disk._
|
||||
{{% /alert %}}
|
||||
|
||||
## Nodes
|
||||
|
||||
A Pod always runs on a **Node**. A Node is a worker machine in Kubernetes and may
|
||||
be either a virtual or a physical machine, depending on the cluster. Each Node is
|
||||
managed by the control plane. A Node can have multiple pods, and the Kubernetes
|
||||
control plane automatically handles scheduling the pods across the Nodes in the
|
||||
cluster. The control plane's automatic scheduling takes into account the available
|
||||
resources on each Node.
|
||||
|
||||
Every Kubernetes Node runs at least:
|
||||
|
||||
* Kubelet, a process responsible for communication between the Kubernetes control
|
||||
plane and the Node; it manages the Pods and the containers running on a machine.
|
||||
|
||||
* A container runtime (like Docker) responsible for pulling the container image
|
||||
from a registry, unpacking the container, and running the application.
|
||||
|
||||
### Nodes overview
|
||||
|
||||
{{< figure src="/docs/tutorials/kubernetes-basics/public/images/module_03_nodes.svg" class="diagram-medium" >}}
|
||||
|
||||
## Troubleshooting with kubectl
|
||||
|
||||
In [Module 2](/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro/), you used
|
||||
the kubectl command-line interface. You'll continue to use it in Module 3 to get
|
||||
information about deployed applications and their environments. The most common
|
||||
operations can be done with the following kubectl subcommands:
|
||||
|
||||
* `kubectl get` - list resources
|
||||
* `kubectl describe` - show detailed information about a resource
|
||||
* `kubectl logs` - print the logs from a container in a pod
|
||||
* `kubectl exec` - execute a command on a container in a pod
|
||||
|
||||
You can use these commands to see when applications were deployed, what their current
|
||||
statuses are, where they are running and what their configurations are.
|
||||
|
||||
Now that we know more about our cluster components and the command line, let's
|
||||
explore our application.
|
||||
|
||||
### Check application configuration
|
||||
|
||||
Let's verify that the application we deployed in the previous scenario is running.
|
||||
We'll use the `kubectl get` command and look for existing Pods:
|
||||
|
||||
```shell
|
||||
kubectl get pods
|
||||
```
|
||||
|
||||
If no pods are running, please wait a couple of seconds and list the Pods again.
|
||||
You can continue once you see one Pod running.
|
||||
|
||||
Next, to view what containers are inside that Pod and what images are used to build
|
||||
those containers we run the `kubectl describe pods` command:
|
||||
|
||||
```shell
|
||||
kubectl describe pods
|
||||
```
|
||||
|
||||
We see here details about the Pod’s container: IP address, the ports used and a
|
||||
list of events related to the lifecycle of the Pod.
|
||||
|
||||
The output of the `describe` subcommand is extensive and covers some concepts that
|
||||
we didn’t explain yet, but don’t worry, they will become familiar by the end of this tutorial.
|
||||
|
||||
{{< note >}}
|
||||
The `describe` subcommand can be used to get detailed information about most of the
|
||||
Kubernetes primitives, including Nodes, Pods, and Deployments. The describe output is
|
||||
designed to be human readable, not to be scripted against.
|
||||
{{< /note >}}
|
||||
|
||||
### Show the app in the terminal
|
||||
|
||||
Recall that Pods are running in an isolated, private network - so we need to proxy access
|
||||
to them so we can debug and interact with them. To do this, we'll use the `kubectl proxy`
|
||||
command to run a proxy in a **second terminal**. Open a new terminal window, and
|
||||
in that new terminal, run:
|
||||
|
||||
```shell
|
||||
kubectl proxy
|
||||
```
|
||||
|
||||
Now again, we'll get the Pod name and query that pod directly through the proxy.
|
||||
To get the Pod name and store it in the `POD_NAME` environment variable:
|
||||
|
||||
```shell
|
||||
export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"
|
||||
echo Name of the Pod: $POD_NAME
|
||||
```
|
||||
|
||||
To see the output of our application, run a `curl` request:
|
||||
|
||||
```shell
|
||||
curl http://localhost:8001/api/v1/namespaces/default/pods/$POD_NAME:8080/proxy/
|
||||
```
|
||||
|
||||
The URL is the route to the API of the Pod.
|
||||
|
||||
{{< note >}}
|
||||
We don't need to specify the container name, because we only have one container inside the pod.
|
||||
{{< /note >}}
|
||||
|
||||
### Executing commands on the container
|
||||
|
||||
We can execute commands directly on the container once the Pod is up and running.
|
||||
For this, we use the `exec` subcommand and use the name of the Pod as a parameter.
|
||||
Let’s list the environment variables:
|
||||
|
||||
```shell
|
||||
kubectl exec "$POD_NAME" -- env
|
||||
```
|
||||
|
||||
Again, it's worth mentioning that the name of the container itself can be omitted
|
||||
since we only have a single container in the Pod.
|
||||
|
||||
Next let’s start a bash session in the Pod’s container:
|
||||
|
||||
```shell
|
||||
kubectl exec -ti $POD_NAME -- bash
|
||||
```
|
||||
|
||||
We have now an open console on the container where we run our NodeJS application.
|
||||
The source code of the app is in the `server.js` file:
|
||||
|
||||
```shell
|
||||
cat server.js
|
||||
```
|
||||
|
||||
You can check that the application is up by running a curl command:
|
||||
|
||||
```shell
|
||||
curl http://localhost:8080
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
Here we used `localhost` because we executed the command inside the NodeJS Pod.
|
||||
If you cannot connect to `localhost:8080`, check to make sure you have run the
|
||||
`kubectl exec` command and are launching the command from within the Pod.
|
||||
{{< /note >}}
|
||||
|
||||
To close your container connection, type `exit`.
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
* Tutorial
|
||||
[Using A Service To Expose Your App](/docs/tutorials/kubernetes-basics/expose/expose-intro/).
|
||||
* Learn more about [Pods](/docs/concepts/workloads/pods/).
|
||||
* Learn more about [Nodes](/docs/concepts/architecture/nodes/).
|
|
@ -1,178 +0,0 @@
|
|||
---
|
||||
title: Using a Service to Expose Your App
|
||||
weight: 10
|
||||
description: |-
|
||||
Learn about a Service in Kubernetes.
|
||||
Understand how labels and selectors relate to a Service.
|
||||
Expose an application outside a Kubernetes cluster.
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<div class="layout" id="top">
|
||||
|
||||
<main class="content">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h3>Objectives</h3>
|
||||
<ul>
|
||||
<li>Learn about a Service in Kubernetes</li>
|
||||
<li>Understand how labels and selectors relate to a Service</li>
|
||||
<li>Expose an application outside a Kubernetes cluster using a Service</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<h3>Overview of Kubernetes Services</h3>
|
||||
|
||||
<p>Kubernetes <a href="/docs/concepts/workloads/pods/">Pods</a> are mortal. Pods have a <a href="/docs/concepts/workloads/pods/pod-lifecycle/">lifecycle</a>. When a worker node dies, the Pods running on the Node are also lost. A <a href="/docs/concepts/workloads/controllers/replicaset/">ReplicaSet</a> might then dynamically drive the cluster back to the desired state via the creation of new Pods to keep your application running. As another example, consider an image-processing backend with 3 replicas. Those replicas are exchangeable; the front-end system should not care about backend replicas or even if a Pod is lost and recreated. That said, each Pod in a Kubernetes cluster has a unique IP address, even Pods on the same Node, so there needs to be a way of automatically reconciling changes among Pods so that your applications continue to function.</p>
|
||||
|
||||
<p>A Service in Kubernetes is an abstraction which defines a logical set of Pods and a policy by which to access them. Services enable a loose coupling between dependent Pods. A Service is defined using YAML or JSON, like all Kubernetes object manifests. The set of Pods targeted by a Service is usually determined by a <i>label selector</i> (see below for why you might want a Service without including a <code>selector</code> in the spec).</p>
|
||||
|
||||
<p>Although each Pod has a unique IP address, those IPs are not exposed outside the cluster without a Service. Services allow your applications to receive traffic. Services can be exposed in different ways by specifying a <code>type</code> in the <tt>spec</tt> of the Service:</p>
|
||||
<ul>
|
||||
<li><i>ClusterIP</i> (default) - Exposes the Service on an internal IP in the cluster. This type makes the Service only reachable from within the cluster.</li>
|
||||
<li><i>NodePort</i> - Exposes the Service on the same port of each selected Node in the cluster using NAT. Makes a Service accessible from outside the cluster using <code><NodeIP>:<NodePort></code>. Superset of ClusterIP.</li>
|
||||
<li><i>LoadBalancer</i> - Creates an external load balancer in the current cloud (if supported) and assigns a fixed, external IP to the Service. Superset of NodePort.</li>
|
||||
<li><i>ExternalName</i> - Maps the Service to the contents of the <code>externalName</code> field (e.g. <code>foo.bar.example.com</code>), by returning a <code>CNAME</code> record with its value. No proxying of any kind is set up. This type requires v1.7 or higher of <code>kube-dns</code>, or CoreDNS version 0.0.8 or higher.</li>
|
||||
</ul>
|
||||
<p>More information about the different types of Services can be found in the <a href="/docs/tutorials/services/source-ip/">Using Source IP</a> tutorial. Also see <a href="/docs/tutorials/services/connect-applications-service/">Connecting Applications with Services</a>.</p>
|
||||
<p>Additionally, note that there are some use cases with Services that involve not defining a <code>selector</code> in the spec. A Service created without <code>selector</code> will also not create the corresponding Endpoints object. This allows users to manually map a Service to specific endpoints. Another possibility why there may be no selector is you are strictly using <code>type: ExternalName</code>.</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_lined">
|
||||
<h3>Summary</h3>
|
||||
<ul>
|
||||
<li>Exposing Pods to external traffic</li>
|
||||
<li>Load balancing traffic across multiple Pods</li>
|
||||
<li>Using labels</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>A Kubernetes Service is an abstraction layer which defines a logical set of Pods and enables external traffic exposure, load balancing and service discovery for those Pods.</i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h3>Services and Labels</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p>A Service routes traffic across a set of Pods. Services are the abstraction that allows pods to die and replicate in Kubernetes without impacting your application. Discovery and routing among dependent Pods (such as the frontend and backend components in an application) are handled by Kubernetes Services.</p>
|
||||
<p>Services match a set of Pods using <a href="/docs/concepts/overview/working-with-objects/labels">labels and selectors</a>, a grouping primitive that allows logical operation on objects in Kubernetes. Labels are key/value pairs attached to objects and can be used in any number of ways:</p>
|
||||
<ul>
|
||||
<li>Designate objects for development, test, and production</li>
|
||||
<li>Embed version tags</li>
|
||||
<li>Classify an object using tags</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p><img src="/docs/tutorials/kubernetes-basics/public/images/module_04_labels.svg"></p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p>Labels can be attached to objects at creation time or later on. They can be modified at any time. Let's expose our application now using a Service and apply some labels.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Step 1: Creating a new Service</h3>
|
||||
<p>Let’s verify that our application is running. We’ll use the <code>kubectl get</code> command and look for existing Pods:</p>
|
||||
<p><code><b>kubectl get pods</b></code></p>
|
||||
<p>If no Pods are running then it means the objects from the previous tutorials were cleaned up. In this case, go back and recreate the deployment from the <a href="/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro#deploy-an-app">Using kubectl to create a Deployment</a> tutorial.
|
||||
Please wait a couple of seconds and list the Pods again. You can continue once you see the one Pod running.</p>
|
||||
<p>Next, let’s list the current Services from our cluster:</p>
|
||||
<p><code><b>kubectl get services</b></code></p>
|
||||
<p>We have a Service called <tt>kubernetes</tt> that is created by default when minikube starts the cluster.
|
||||
To create a new service and expose it to external traffic we'll use the expose command with NodePort as parameter.</p>
|
||||
<p><code><b>kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080</b></code></p>
|
||||
<p>Let's run again the <code>get services</code> subcommand:</p>
|
||||
<p><code><b>kubectl get services</b></code></p>
|
||||
<p>We have now a running Service called kubernetes-bootcamp. Here we see that the Service received a unique cluster-IP, an internal port and an external-IP (the IP of the Node).</p>
|
||||
<p>To find out what port was opened externally (for the <tt>type: NodePort</tt> Service) we’ll run the <code>describe service</code> subcommand:</p>
|
||||
<p><code><b>kubectl describe services/kubernetes-bootcamp</b></code></p>
|
||||
<p>Create an environment variable called <tt>NODE_PORT</tt> that has the value of the Node port assigned:</p>
|
||||
<p><code><b>export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"</b></code><br />
|
||||
<code><b>echo "NODE_PORT=$NODE_PORT"</b></code></p>
|
||||
<p>Now we can test that the app is exposed outside of the cluster using <code>curl</code>, the IP address of the Node and the externally exposed port:</p>
|
||||
<p><code><b>curl http://"$(minikube ip):$NODE_PORT"</b></code></p>
|
||||
{{< note >}}<p>If you're running minikube with Docker Desktop as the container driver, a minikube tunnel is needed. This is because containers inside Docker Desktop are isolated from your host computer.<br>
|
||||
<p>In a separate terminal window, execute:<br>
|
||||
<code><b>minikube service kubernetes-bootcamp --url</b></code></p>
|
||||
<p>The output looks like this:
|
||||
<pre><b>http://127.0.0.1:51082<br>! Because you are using a Docker driver on darwin, the terminal needs to be open to run it.</b></pre></p>
|
||||
<p>Then use the given URL to access the app:<br>
|
||||
<code><b>curl 127.0.0.1:51082</b></code></p>
|
||||
{{< /note >}}
|
||||
<p>And we get a response from the server. The Service is exposed.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Step 2: Using labels</h3>
|
||||
<div class="content">
|
||||
<p>The Deployment created automatically a label for our Pod. With the <code>describe deployment</code> subcommand you can see the name (the <em>key</em>) of that label:</p>
|
||||
<p><code><b>kubectl describe deployment</b></code></p>
|
||||
<p>Let’s use this label to query our list of Pods. We’ll use the <code>kubectl get pods</code> command with <tt>-l</tt> as a parameter, followed by the label values:</p>
|
||||
<p><code><b>kubectl get pods -l app=kubernetes-bootcamp</b></code></p>
|
||||
<p>You can do the same to list the existing Services:</p>
|
||||
<p><code><b>kubectl get services -l app=kubernetes-bootcamp</b></code></p>
|
||||
<p>Get the name of the Pod and store it in the <tt>POD_NAME</tt> environment variable:</p>
|
||||
<p><code><b>export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"</b></code><br />
|
||||
<code><b>echo "Name of the Pod: $POD_NAME"</b></code></p>
|
||||
<p>To apply a new label we use the <code>label</code> subcommand followed by the object type, object name and the new label:</p>
|
||||
<p><code><b>kubectl label pods "$POD_NAME" version=v1</b></code></p>
|
||||
<p>This will apply a new label to our Pod (we pinned the application version to the Pod), and we can check it with the describe pod command:</p>
|
||||
<p><code><b>kubectl describe pods "$POD_NAME"</b></code></p>
|
||||
<p>We see here that the label is attached now to our Pod. And we can query now the list of pods using the new label:</p>
|
||||
<p><code><b>kubectl get pods -l version=v1</b></code></p>
|
||||
<p>And we see the Pod.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Step 3: Deleting a service</h3>
|
||||
<p>To delete Services you can use the <code>delete service</code> subcommand. Labels can be used also here:</p>
|
||||
<p><code><b>kubectl delete service -l app=kubernetes-bootcamp</b></code></p>
|
||||
<p>Confirm that the Service is gone:</p>
|
||||
<p><code><b>kubectl get services</b></code></p>
|
||||
<p>This confirms that our Service was removed. To confirm that route is not exposed anymore you can <tt>curl</tt> the previously exposed IP and port:</p>
|
||||
<p><code><b>curl http://"$(minikube ip):$NODE_PORT"</b></code></p>
|
||||
<p>This proves that the application is not reachable anymore from outside of the cluster.
|
||||
You can confirm that the app is still running with a <tt>curl</tt> from inside the pod:</p>
|
||||
<p><code><b>kubectl exec -ti $POD_NAME -- curl http://localhost:8080</b></code></p>
|
||||
<p>We see here that the application is up. This is because the Deployment is managing the application. To shut down the application, you would need to delete the Deployment as well.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p>
|
||||
Once you're ready, move on to <a href="/docs/tutorials/kubernetes-basics/scale/scale-intro/" title="Running Multiple Instances of Your App">Running Multiple Instances of Your App</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,245 @@
|
|||
---
|
||||
title: Using a Service to Expose Your App
|
||||
weight: 10
|
||||
---
|
||||
|
||||
## {{% heading "objectives" %}}
|
||||
|
||||
* Learn about a Service in Kubernetes.
|
||||
* Understand how labels and selectors relate to a Service.
|
||||
* Expose an application outside a Kubernetes cluster.
|
||||
|
||||
## Overview of Kubernetes Services
|
||||
|
||||
Kubernetes [Pods](/docs/concepts/workloads/pods/) are mortal. Pods have a
|
||||
[lifecycle](/docs/concepts/workloads/pods/pod-lifecycle/). When a worker node dies,
|
||||
the Pods running on the Node are also lost. A [Replicaset](/docs/concepts/workloads/controllers/replicaset/)
|
||||
might then dynamically drive the cluster back to the desired state via the creation
|
||||
of new Pods to keep your application running. As another example, consider an image-processing
|
||||
backend with 3 replicas. Those replicas are exchangeable; the front-end system should
|
||||
not care about backend replicas or even if a Pod is lost and recreated. That said,
|
||||
each Pod in a Kubernetes cluster has a unique IP address, even Pods on the same Node,
|
||||
so there needs to be a way of automatically reconciling changes among Pods so that your
|
||||
applications continue to function.
|
||||
|
||||
{{% alert %}}
|
||||
_A Kubernetes Service is an abstraction layer which defines a logical set of Pods and
|
||||
enables external traffic exposure, load balancing and service discovery for those Pods._
|
||||
{{% /alert %}}
|
||||
|
||||
A [Service](/docs/concepts/services-networking/service/) in Kubernetes is an abstraction
|
||||
which defines a logical set of Pods and a policy by which to access them. Services
|
||||
enable a loose coupling between dependent Pods. A Service is defined using YAML or JSON,
|
||||
like all Kubernetes object manifests. The set of Pods targeted by a Service is usually
|
||||
determined by a _label selector_ (see below for why you might want a Service without
|
||||
including a `selector` in the spec).
|
||||
|
||||
Although each Pod has a unique IP address, those IPs are not exposed outside the
|
||||
cluster without a Service. Services allow your applications to receive traffic.
|
||||
Services can be exposed in different ways by specifying a `type` in the `spec` of the Service:
|
||||
|
||||
* _ClusterIP_ (default) - Exposes the Service on an internal IP in the cluster. This
|
||||
type makes the Service only reachable from within the cluster.
|
||||
|
||||
* _NodePort_ - Exposes the Service on the same port of each selected Node in the cluster using NAT.
|
||||
Makes a Service accessible from outside the cluster using `NodeIP:NodePort`. Superset of ClusterIP.
|
||||
|
||||
* _LoadBalancer_ - Creates an external load balancer in the current cloud (if supported)
|
||||
and assigns a fixed, external IP to the Service. Superset of NodePort.
|
||||
|
||||
* _ExternalName_ - Maps the Service to the contents of the `externalName` field
|
||||
(e.g. `foo.bar.example.com`), by returning a `CNAME` record with its value.
|
||||
No proxying of any kind is set up. This type requires v1.7 or higher of `kube-dns`,
|
||||
or CoreDNS version 0.0.8 or higher.
|
||||
|
||||
More information about the different types of Services can be found in the
|
||||
[Using Source IP](/docs/tutorials/services/source-ip/) tutorial. Also see
|
||||
[Connecting Applications with Services](/docs/tutorials/services/connect-applications-service/).
|
||||
|
||||
Additionally, note that there are some use cases with Services that involve not defining
|
||||
a `selector` in the spec. A Service created without `selector` will also not create
|
||||
the corresponding Endpoints object. This allows users to manually map a Service to
|
||||
specific endpoints. Another possibility why there may be no selector is you are strictly
|
||||
using `type: ExternalName`.
|
||||
|
||||
## Services and Labels
|
||||
|
||||
A Service routes traffic across a set of Pods. Services are the abstraction that allows
|
||||
pods to die and replicate in Kubernetes without impacting your application. Discovery
|
||||
and routing among dependent Pods (such as the frontend and backend components in an application)
|
||||
are handled by Kubernetes Services.
|
||||
|
||||
Services match a set of Pods using
|
||||
[labels and selectors](/docs/concepts/overview/working-with-objects/labels), a grouping
|
||||
primitive that allows logical operation on objects in Kubernetes. Labels are key/value
|
||||
pairs attached to objects and can be used in any number of ways:
|
||||
|
||||
* Designate objects for development, test, and production
|
||||
* Embed version tags
|
||||
* Classify an object using tags
|
||||
|
||||
{{< figure src="/docs/tutorials/kubernetes-basics/public/images/module_04_labels.svg" class="diagram-medium" >}}
|
||||
|
||||
Labels can be attached to objects at creation time or later on. They can be modified
|
||||
at any time. Let's expose our application now using a Service and apply some labels.
|
||||
|
||||
### Step 1: Creating a new Service
|
||||
|
||||
Let’s verify that our application is running. We’ll use the `kubectl get` command
|
||||
and look for existing Pods:
|
||||
|
||||
```shell
|
||||
kubectl get pods
|
||||
```
|
||||
|
||||
If no Pods are running then it means the objects from the previous tutorials were
|
||||
cleaned up. In this case, go back and recreate the deployment from the
|
||||
[Using kubectl to create a Deployment](/docs/tutorials/kubernetes-basics/deploy-app/deploy-intro#deploy-an-app)
|
||||
tutorial. Please wait a couple of seconds and list the Pods again. You can continue
|
||||
once you see the one Pod running.
|
||||
|
||||
Next, let’s list the current Services from our cluster:
|
||||
|
||||
```shell
|
||||
kubectl get services
|
||||
```
|
||||
|
||||
We have now a running Service called kubernetes-bootcamp. Here we see that the Service
|
||||
received a unique cluster-IP, an internal port and an external-IP (the IP of the Node).
|
||||
|
||||
To find out what port was opened externally (for the `type: NodePort` Service) we’ll
|
||||
run the `describe service` subcommand:
|
||||
|
||||
```shell
|
||||
kubectl describe services/kubernetes-bootcamp
|
||||
```
|
||||
|
||||
Create an environment variable called `NODE_PORT` that has the value of the Node
|
||||
port assigned:
|
||||
|
||||
```shell
|
||||
export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"
|
||||
echo "NODE_PORT=$NODE_PORT"
|
||||
```
|
||||
|
||||
Now we can test that the app is exposed outside of the cluster using `curl`, the
|
||||
IP address of the Node and the externally exposed port:
|
||||
|
||||
```shell
|
||||
curl http://"$(minikube ip):$NODE_PORT"
|
||||
```
|
||||
{{< note >}}
|
||||
If you're running minikube with Docker Desktop as the container driver, a minikube
|
||||
tunnel is needed. This is because containers inside Docker Desktop are isolated
|
||||
from your host computer.
|
||||
|
||||
In a separate terminal window, execute:
|
||||
|
||||
```shell
|
||||
minikube service kubernetes-bootcamp --url
|
||||
```
|
||||
|
||||
The output looks like this:
|
||||
|
||||
```
|
||||
http://127.0.0.1:51082
|
||||
! Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
|
||||
```
|
||||
|
||||
Then use the given URL to access the app:
|
||||
|
||||
```shell
|
||||
curl 127.0.0.1:51082
|
||||
```
|
||||
{{< /note >}}
|
||||
|
||||
And we get a response from the server. The Service is exposed.
|
||||
|
||||
### Step 2: Using labels
|
||||
|
||||
The Deployment created automatically a label for our Pod. With the `describe deployment`
|
||||
subcommand you can see the name (the _key_) of that label:
|
||||
|
||||
```shell
|
||||
kubectl describe deployment
|
||||
```
|
||||
|
||||
Let’s use this label to query our list of Pods. We’ll use the `kubectl get pods`
|
||||
command with `-l` as a parameter, followed by the label values:
|
||||
|
||||
```shell
|
||||
kubectl get pods -l app=kubernetes-bootcamp
|
||||
```
|
||||
You can do the same to list the existing Services:
|
||||
|
||||
```shell
|
||||
kubectl get services -l app=kubernetes-bootcamp
|
||||
```
|
||||
|
||||
Get the name of the Pod and store it in the POD_NAME environment variable:
|
||||
|
||||
```shell
|
||||
export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"
|
||||
echo "Name of the Pod: $POD_NAME"
|
||||
```
|
||||
|
||||
To apply a new label we use the label subcommand followed by the object type,
|
||||
object name and the new label:
|
||||
|
||||
```shell
|
||||
kubectl label pods "$POD_NAME" version=v1
|
||||
```
|
||||
|
||||
This will apply a new label to our Pod (we pinned the application version to the Pod),
|
||||
and we can check it with the `describe pod` command:
|
||||
|
||||
```shell
|
||||
kubectl describe pods "$POD_NAME"
|
||||
```
|
||||
|
||||
We see here that the label is attached now to our Pod. And we can query now the
|
||||
list of pods using the new label:
|
||||
|
||||
```shell
|
||||
kubectl get pods -l version=v1
|
||||
```
|
||||
And we see the Pod.
|
||||
|
||||
### Step 3: Deleting a service
|
||||
|
||||
To delete Services you can use the `delete service` subcommand. Labels can be used
|
||||
also here:
|
||||
|
||||
```shell
|
||||
kubectl delete service -l app=kubernetes-bootcamp
|
||||
```
|
||||
|
||||
Confirm that the Service is gone:
|
||||
|
||||
```shell
|
||||
kubectl get services
|
||||
```
|
||||
|
||||
This confirms that our Service was removed. To confirm that route is not exposed
|
||||
anymore you can `curl` the previously exposed IP and port:
|
||||
|
||||
```shell
|
||||
curl http://"$(minikube ip):$NODE_PORT"
|
||||
```
|
||||
|
||||
This proves that the application is not reachable anymore from outside of the cluster.
|
||||
You can confirm that the app is still running with a `curl` from inside the pod:
|
||||
|
||||
```shell
|
||||
kubectl exec -ti $POD_NAME -- curl http://localhost:8080
|
||||
```
|
||||
|
||||
We see here that the application is up. This is because the Deployment is managing
|
||||
the application. To shut down the application, you would need to delete the Deployment
|
||||
as well.
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
* Tutorial
|
||||
[Running Multiple Instances of Your App](/docs/tutorials/kubernetes-basics/scale/scale-intro/).
|
||||
* Learn more about [Service](/docs/concepts/services-networking/service/).
|
|
@ -1,214 +0,0 @@
|
|||
---
|
||||
title: Running Multiple Instances of Your App
|
||||
weight: 10
|
||||
description: |-
|
||||
Scale an existing app manually using kubectl.
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<div class="layout" id="top">
|
||||
|
||||
<main class="content">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-8">
|
||||
|
||||
<h3>Objectives</h3>
|
||||
<ul>
|
||||
<li>Scale an app using kubectl.</li>
|
||||
</ul>
|
||||
|
||||
<h3>Scaling an application</h3>
|
||||
|
||||
<p>Previously we created a <a href="/docs/concepts/workloads/controllers/deployment/"> Deployment</a>, and then exposed it publicly via a <a href="/docs/concepts/services-networking/service/">Service</a>. The Deployment created only one Pod for running our application. When traffic increases, we will need to scale the application to keep up with user demand.</p>
|
||||
<p>If you haven't worked through the earlier sections, start from <a href="/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/">Using minikube to create a cluster</a>.</p>
|
||||
|
||||
<p><em>Scaling</em> is accomplished by changing the number of replicas in a Deployment</p>
|
||||
</br>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_lined">
|
||||
<h3>Summary:</h3>
|
||||
<ul>
|
||||
<li>Scaling a Deployment</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i> You can create from the start a Deployment with multiple instances using the --replicas parameter for the kubectl create deployment command </i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{< note >}}
|
||||
<p>If you are trying this after <a href="/docs/tutorials/kubernetes-basics/expose/expose-intro/">the previous section </a>, then you
|
||||
may have deleted the service you created, or have created a Service of <tt>type: NodePort</tt>.
|
||||
In this section, it is assumed that a service with <tt>type: LoadBalancer</tt> is created for the kubernetes-bootcamp Deployment.</p>
|
||||
<p>If you have <em>not</em> deleted the Service created in <a href="/docs/tutorials/kubernetes-basics/expose/expose-intro">the previous section</a>,
|
||||
first delete that Service and then run the following command to create a new Service with its
|
||||
<tt>type</tt> set to <tt>LoadBalancer</tt>:</p>
|
||||
<p><code><b>kubectl expose deployment/kubernetes-bootcamp --type="LoadBalancer" --port 8080</b></code></p>
|
||||
{{< /note >}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2 style="color: #3771e3;">Scaling overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-8">
|
||||
<div id="myCarousel" class="carousel" data-ride="carousel" data-interval="3000">
|
||||
<ol class="carousel-indicators">
|
||||
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="1"></li>
|
||||
</ol>
|
||||
<div class="carousel-inner" role="listbox">
|
||||
<div class="item carousel-item active">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_05_scaling1.svg">
|
||||
</div>
|
||||
|
||||
<div class="item carousel-item">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_05_scaling2.svg">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
|
||||
<span class="sr-only ">Previous</span>
|
||||
</a>
|
||||
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
|
||||
<span class="sr-only">Next</span>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
|
||||
<p>Scaling out a Deployment will ensure new Pods are created and scheduled to Nodes with available resources. Scaling will increase the number of Pods to the new desired state. Kubernetes also supports <a href="/docs/tasks/run-application/horizontal-pod-autoscale/">autoscaling</a> of Pods, but it is outside of the scope of this tutorial. Scaling to zero is also possible, and it will terminate all Pods of the specified Deployment.</p>
|
||||
|
||||
<p>Running multiple instances of an application will require a way to distribute the traffic to all of them. Services have an integrated load-balancer that will distribute network traffic to all Pods of an exposed Deployment. Services will monitor continuously the running Pods using endpoints, to ensure the traffic is sent only to available Pods.</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>Scaling is accomplished by changing the number of replicas in a Deployment.</i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p> Once you have multiple instances of an application running, you would be able to do Rolling updates without downtime. We'll cover that in the next section of the tutorial. Now, let's go to the terminal and scale our application.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Scaling a Deployment</h3>
|
||||
<p>To list your Deployments, use the <code>get deployments</code> subcommand:</p>
|
||||
<p><code><b>kubectl get deployments</b></code></p>
|
||||
<p>The output should be similar to:</p>
|
||||
<pre>
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
kubernetes-bootcamp 1/1 1 1 11m
|
||||
</pre>
|
||||
<p>We should have 1 Pod. If not, run the command again. This shows:</p>
|
||||
<ul>
|
||||
<li><em>NAME</em> lists the names of the Deployments in the cluster.</li>
|
||||
<li><em>READY</em> shows the ratio of CURRENT/DESIRED replicas</li>
|
||||
<li><em>UP-TO-DATE</em> displays the number of replicas that have been updated to achieve the desired state.</li>
|
||||
<li><em>AVAILABLE</em> displays how many replicas of the application are available to your users.</li>
|
||||
<li><em>AGE</em> displays the amount of time that the application has been running.</li>
|
||||
</ul>
|
||||
<p>To see the ReplicaSet created by the Deployment, run:</p>
|
||||
<p><code><b>kubectl get rs</b></code></p>
|
||||
<p>Notice that the name of the ReplicaSet is always formatted as <tt>[DEPLOYMENT-NAME]-[RANDOM-STRING]</tt>. The random string is randomly generated and uses the <em>pod-template-hash</em> as a seed.</p>
|
||||
<p>Two important columns of this output are:</p>
|
||||
<ul>
|
||||
<li><em>DESIRED</em> displays the desired number of replicas of the application, which you define when you create the Deployment. This is the desired state.</li>
|
||||
<li><em>CURRENT</em> displays how many replicas are currently running.</li>
|
||||
</ul>
|
||||
<p>Next, let’s scale the Deployment to 4 replicas. We’ll use the <code>kubectl scale</code> command, followed by the Deployment type, name and desired number of instances:</p>
|
||||
<p><code><b>kubectl scale deployments/kubernetes-bootcamp --replicas=4</b></code></p>
|
||||
<p>To list your Deployments once again, use <code>get deployments</code>:</p>
|
||||
<p><code><b>kubectl get deployments</b></code></p>
|
||||
<p>The change was applied, and we have 4 instances of the application available. Next, let’s check if the number of Pods changed:</p>
|
||||
<p><code><b>kubectl get pods -o wide</b></code></p>
|
||||
<p>There are 4 Pods now, with different IP addresses. The change was registered in the Deployment events log. To check that, use the describe subcommand:</p>
|
||||
<p><code><b>kubectl describe deployments/kubernetes-bootcamp</b></code></p>
|
||||
<p>You can also view in the output of this command that there are 4 replicas now.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Load Balancing</h3>
|
||||
<p>Let's check that the Service is load-balancing the traffic. To find out the exposed IP and Port we can use the describe service as we learned in the previous part of the tutorial:</p>
|
||||
<p><code><b>kubectl describe services/kubernetes-bootcamp</b></code></p>
|
||||
<p>Create an environment variable called <tt>NODE_PORT</tt> that has a value as the Node port:</p>
|
||||
<p><code><b>export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"</b></code><br />
|
||||
<p><code><b>echo NODE_PORT=$NODE_PORT</b></code></p>
|
||||
<p>Next, we’ll do a <code>curl</code> to the exposed IP address and port. Execute the command multiple times:</p>
|
||||
<p><code><b>curl http://"$(minikube ip):$NODE_PORT"</b></b></b></code></p>
|
||||
<p>We hit a different Pod with every request. This demonstrates that the load-balancing is working.</p>
|
||||
<p>The output should be similar to:</p>
|
||||
<pre>
|
||||
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-wp67j | v=1
|
||||
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-hs9dj | v=1
|
||||
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-4hjvf | v=1
|
||||
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-wp67j | v=1
|
||||
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-4hjvf | v=1
|
||||
</pre>
|
||||
{{< note >}}<p>If you're running minikube with Docker Desktop as the container driver, a minikube tunnel is needed. This is because containers inside Docker Desktop are isolated from your host computer.<br>
|
||||
<p>In a separate terminal window, execute:<br>
|
||||
<code><b>minikube service kubernetes-bootcamp --url</b></code></p>
|
||||
<p>The output looks like this:
|
||||
<pre><b>http://127.0.0.1:51082<br>! Because you are using a Docker driver on darwin, the terminal needs to be open to run it.</b></pre></p>
|
||||
<p>Then use the given URL to access the app:<br>
|
||||
<code><b>curl 127.0.0.1:51082</b></code></p>
|
||||
{{< /note >}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Scale Down</h3>
|
||||
<p>To scale down the Deployment to 2 replicas, run again the <code>scale</code> subcommand:</p>
|
||||
<p><code><b>kubectl scale deployments/kubernetes-bootcamp --replicas=2</b></code></p>
|
||||
<p>List the Deployments to check if the change was applied with the <code>get deployments</code> subcommand:</p>
|
||||
<p><code><b>kubectl get deployments</b></code></p>
|
||||
<p>The number of replicas decreased to 2. List the number of Pods, with <code>get pods</code>:</p>
|
||||
<p><code><b>kubectl get pods -o wide</b></code></p>
|
||||
<p>This confirms that 2 Pods were terminated.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<p>
|
||||
Once you're ready, move on to <a href="/docs/tutorials/kubernetes-basics/update/update-intro/" title="Performing a Rolling Update">Performing a Rolling Update</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,232 @@
|
|||
---
|
||||
title: Running Multiple Instances of Your App
|
||||
weight: 10
|
||||
---
|
||||
|
||||
## {{% heading "objectives" %}}
|
||||
|
||||
* Scale an existing app manually using kubectl.
|
||||
|
||||
## Scaling an application
|
||||
|
||||
{{% alert %}}
|
||||
_You can create from the start a Deployment with multiple instances using the --replicas
|
||||
parameter for the kubectl create deployment command._
|
||||
{{% /alert %}}
|
||||
|
||||
Previously we created a [Deployment](/docs/concepts/workloads/controllers/deployment/),
|
||||
and then exposed it publicly via a [Service](/docs/concepts/services-networking/service/).
|
||||
The Deployment created only one Pod for running our application. When traffic increases,
|
||||
we will need to scale the application to keep up with user demand.
|
||||
|
||||
If you haven't worked through the earlier sections, start from
|
||||
[Using minikube to create a cluster](/docs/tutorials/kubernetes-basics/create-cluster/cluster-intro/).
|
||||
|
||||
_Scaling_ is accomplished by changing the number of replicas in a Deployment.
|
||||
|
||||
{{< note >}}
|
||||
If you are trying this after the
|
||||
[previous section](/docs/tutorials/kubernetes-basics/expose/expose-intro/), then you
|
||||
may have deleted the service you created, or have created a Service of `type: NodePort`.
|
||||
In this section, it is assumed that a service with `type: LoadBalancer` is created
|
||||
for the kubernetes-bootcamp Deployment.
|
||||
|
||||
If you have _not_ deleted the Service created in
|
||||
[the previous section](/docs/tutorials/kubernetes-basics/expose/expose-intro),
|
||||
first delete that Service and then run the following command to create a new Service
|
||||
with its `type` set to `LoadBalancer`:
|
||||
|
||||
```shell
|
||||
kubectl expose deployment/kubernetes-bootcamp --type="LoadBalancer" --port 8080
|
||||
```
|
||||
{{< /note >}}
|
||||
|
||||
## Scaling overview
|
||||
|
||||
<!-- animation -->
|
||||
<div class="col-md-8">
|
||||
<div id="myCarousel" class="carousel" data-ride="carousel" data-interval="3000">
|
||||
<div class="carousel-inner" role="listbox">
|
||||
<div class="item carousel-item active">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_05_scaling1.svg">
|
||||
</div>
|
||||
<div class="item carousel-item">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_05_scaling2.svg">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{% alert %}}
|
||||
_Scaling is accomplished by changing the number of replicas in a Deployment._
|
||||
{{% /alert %}}
|
||||
|
||||
Scaling out a Deployment will ensure new Pods are created and scheduled to Nodes
|
||||
with available resources. Scaling will increase the number of Pods to the new desired
|
||||
state. Kubernetes also supports [autoscaling](/docs/tasks/run-application/horizontal-pod-autoscale/)
|
||||
of Pods, but it is outside of the scope of this tutorial. Scaling to zero is also
|
||||
possible, and it will terminate all Pods of the specified Deployment.
|
||||
|
||||
Running multiple instances of an application will require a way to distribute the
|
||||
traffic to all of them. Services have an integrated load-balancer that will distribute
|
||||
network traffic to all Pods of an exposed Deployment. Services will monitor continuously
|
||||
the running Pods using endpoints, to ensure the traffic is sent only to available Pods.
|
||||
|
||||
Once you have multiple instances of an application running, you would be able to
|
||||
do Rolling updates without downtime. We'll cover that in the next section of the
|
||||
tutorial. Now, let's go to the terminal and scale our application.
|
||||
|
||||
### Scaling a Deployment
|
||||
|
||||
To list your Deployments, use the `get deployments` subcommand:
|
||||
|
||||
```shell
|
||||
kubectl get deployments
|
||||
```
|
||||
|
||||
The output should be similar to:
|
||||
|
||||
```
|
||||
NAME READY UP-TO-DATE AVAILABLE AGE
|
||||
kubernetes-bootcamp 1/1 1 1 11m
|
||||
```
|
||||
|
||||
We should have 1 Pod. If not, run the command again. This shows:
|
||||
|
||||
* _NAME_ lists the names of the Deployments in the cluster.
|
||||
* _READY_ shows the ratio of CURRENT/DESIRED replicas
|
||||
* _UP-TO-DATE_ displays the number of replicas that have been updated to achieve the desired state.
|
||||
* _AVAILABLE_ displays how many replicas of the application are available to your users.
|
||||
* _AGE_ displays the amount of time that the application has been running.
|
||||
|
||||
To see the ReplicaSet created by the Deployment, run:
|
||||
|
||||
```shell
|
||||
kubectl get rs
|
||||
```
|
||||
|
||||
Notice that the name of the ReplicaSet is always formatted as
|
||||
<nobr>[DEPLOYMENT-NAME]-[RANDOM-STRING]</nobr>.
|
||||
The random string is randomly generated and uses the pod-template-hash as a seed.
|
||||
|
||||
Two important columns of this output are:
|
||||
|
||||
* _DESIRED_ displays the desired number of replicas of the application, which you
|
||||
define when you create the Deployment. This is the desired state.
|
||||
* _CURRENT_ displays how many replicas are currently running.
|
||||
Next, let’s scale the Deployment to 4 replicas. We’ll use the `kubectl scale` command,
|
||||
followed by the Deployment type, name and desired number of instances:
|
||||
|
||||
```shell
|
||||
kubectl scale deployments/kubernetes-bootcamp --replicas=4
|
||||
```
|
||||
|
||||
To list your Deployments once again, use `get deployments`:
|
||||
|
||||
```shell
|
||||
kubectl get deployments
|
||||
```
|
||||
|
||||
The change was applied, and we have 4 instances of the application available. Next,
|
||||
let’s check if the number of Pods changed:
|
||||
|
||||
```shell
|
||||
kubectl get pods -o wide
|
||||
```
|
||||
|
||||
There are 4 Pods now, with different IP addresses. The change was registered in
|
||||
the Deployment events log. To check that, use the `describe` subcommand:
|
||||
|
||||
```shell
|
||||
kubectl describe deployments/kubernetes-bootcamp
|
||||
```
|
||||
|
||||
You can also view in the output of this command that there are 4 replicas now.
|
||||
|
||||
### Load Balancing
|
||||
|
||||
Let's check that the Service is load-balancing the traffic. To find out the exposed
|
||||
IP and Port we can use `describe service` as we learned in the previous part of the tutorial:
|
||||
|
||||
```shell
|
||||
kubectl describe services/kubernetes-bootcamp
|
||||
```
|
||||
|
||||
Create an environment variable called NODE_PORT that has a value as the Node port:
|
||||
|
||||
```shell
|
||||
export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"
|
||||
echo NODE_PORT=$NODE_PORT
|
||||
```
|
||||
|
||||
Next, we’ll do a `curl` to the exposed IP address and port. Execute the command multiple times:
|
||||
|
||||
```shell
|
||||
curl http://"$(minikube ip):$NODE_PORT"
|
||||
```
|
||||
|
||||
We hit a different Pod with every request. This demonstrates that the load-balancing is working.
|
||||
|
||||
The output should be similar to:
|
||||
|
||||
```
|
||||
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-wp67j | v=1
|
||||
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-hs9dj | v=1
|
||||
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-4hjvf | v=1
|
||||
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-wp67j | v=1
|
||||
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-644c5687f4-4hjvf | v=1
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
If you're running minikube with Docker Desktop as the container driver, a minikube
|
||||
tunnel is needed. This is because containers inside Docker Desktop are isolated
|
||||
from your host computer.
|
||||
|
||||
In a separate terminal window, execute:
|
||||
|
||||
```shell
|
||||
minikube service kubernetes-bootcamp --url
|
||||
```
|
||||
|
||||
The output looks like this:
|
||||
|
||||
```
|
||||
http://127.0.0.1:51082
|
||||
! Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
|
||||
```
|
||||
|
||||
Then use the given URL to access the app:
|
||||
|
||||
```shell
|
||||
curl 127.0.0.1:51082
|
||||
```
|
||||
{{< /note >}}
|
||||
|
||||
### Scale Down
|
||||
|
||||
To scale down the Deployment to 2 replicas, run again the `scale` subcommand:
|
||||
|
||||
```shell
|
||||
kubectl scale deployments/kubernetes-bootcamp --replicas=2
|
||||
```
|
||||
|
||||
List the Deployments to check if the change was applied with the `get deployments` subcommand:
|
||||
|
||||
```shell
|
||||
kubectl get deployments
|
||||
```
|
||||
|
||||
The number of replicas decreased to 2. List the number of Pods, with `get pods`:
|
||||
|
||||
```shell
|
||||
kubectl get pods -o wide
|
||||
```
|
||||
|
||||
This confirms that 2 Pods were terminated.
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
* Tutorial
|
||||
[Performing a Rolling Update](/docs/tutorials/kubernetes-basics/update/update-intro/).
|
||||
* Learn more about [ReplicaSet](/docs/concepts/workloads/controllers/replicaset/).
|
||||
* Learn more about [Autoscaling](/docs/concepts/workloads/autoscaling/).
|
|
@ -1,196 +0,0 @@
|
|||
---
|
||||
title: Performing a Rolling Update
|
||||
weight: 10
|
||||
description: |-
|
||||
Perform a rolling update using kubectl.
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<body>
|
||||
|
||||
<div class="layout" id="top">
|
||||
|
||||
<main class="content">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-md-8">
|
||||
<h3>Objectives</h3>
|
||||
<ul>
|
||||
<li>Perform a rolling update using kubectl.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="col-md-8">
|
||||
<h3>Updating an application</h3>
|
||||
|
||||
<p>Users expect applications to be available all the time, and developers are expected to deploy new versions of them several times a day. In Kubernetes this is done with rolling updates. A <b>rolling update</b> allows a Deployment update to take place with zero downtime. It does this by incrementally replacing the current Pods with new ones. The new Pods are scheduled on Nodes with available resources, and Kubernetes waits for those new Pods to start before removing the old Pods.</p>
|
||||
|
||||
<p>In the previous module we scaled our application to run multiple instances. This is a requirement for performing updates without affecting application availability. By default, the maximum number of Pods that can be unavailable during the update and the maximum number of new Pods that can be created, is one. Both options can be configured to either numbers or percentages (of Pods).
|
||||
In Kubernetes, updates are versioned and any Deployment update can be reverted to a previous (stable) version.</p>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_lined">
|
||||
<h3>Summary:</h3>
|
||||
<ul>
|
||||
<li>Updating an app</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>Rolling updates allow Deployments' update to take place with zero downtime by incrementally updating Pods instances with new ones. </i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h2 style="color: #3771e3;">Rolling updates overview</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-1"></div>
|
||||
<div class="col-md-8">
|
||||
<div id="myCarousel" class="carousel" data-ride="carousel" data-interval="3000">
|
||||
<ol class="carousel-indicators">
|
||||
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="1"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="2"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="3"></li>
|
||||
</ol>
|
||||
<div class="carousel-inner" role="listbox">
|
||||
<div class="item carousel-item active">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates1.svg" >
|
||||
</div>
|
||||
|
||||
<div class="item carousel-item">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates2.svg">
|
||||
</div>
|
||||
|
||||
<div class="item carousel-item">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates3.svg">
|
||||
</div>
|
||||
|
||||
<div class="item carousel-item">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates4.svg">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a class="left carousel-control" href="#myCarousel" role="button" data-slide="prev">
|
||||
<span class="sr-only ">Previous</span>
|
||||
</a>
|
||||
<a class="right carousel-control" href="#myCarousel" role="button" data-slide="next">
|
||||
<span class="sr-only">Next</span>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
|
||||
<p>Similar to application Scaling, if a Deployment is exposed publicly, the Service will load-balance the traffic only to available Pods during the update. An available Pod is an instance that is available to the users of the application.</p>
|
||||
|
||||
<p>Rolling updates allow the following actions:</p>
|
||||
<ul>
|
||||
<li>Promote an application from one environment to another (via container image updates)</li>
|
||||
<li>Rollback to previous versions</li>
|
||||
<li>Continuous Integration and Continuous Delivery of applications with zero downtime</li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="content__box content__box_fill">
|
||||
<p><i>If a Deployment is exposed publicly, the Service will load-balance the traffic only to available Pods during the update. </i></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<p> In the following interactive tutorial, we'll update our application to a new version, and also perform a rollback.</p>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Update the version of the app</h3>
|
||||
<p>To list your Deployments, run the <code>get deployments</code> subcommand:
|
||||
<code><b>kubectl get deployments</b></code></p>
|
||||
<p>To list the running Pods, run the <code>get pods</code> subcommand:</p>
|
||||
<p><code><b>kubectl get pods</b></code></p>
|
||||
<p>To view the current image version of the app, run the <code>describe pods</code> subcommand
|
||||
and look for the <code>Image</code> field:</p>
|
||||
<p><code><b>kubectl describe pods</b></code></p>
|
||||
<p>To update the image of the application to version 2, use the <code>set image</code> subcommand, followed by the deployment name and the new image version:</p>
|
||||
<p><code><b>kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2</b></code></p>
|
||||
<p>The command notified the Deployment to use a different image for your app and initiated a rolling update. Check the status of the new Pods, and view the old one terminating with the <code>get pods</code> subcommand:</p>
|
||||
<p><code><b>kubectl get pods</b></code></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Verify an update</h3>
|
||||
<p>First, check that the service is running, as you might have deleted it in previous tutorial step, run <code>describe services/kubernetes-bootcamp</code>. If it's missing, you can create it again with:
|
||||
<p><code><b>kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080</b></code></p>
|
||||
<p>Create an environment variable called <tt>NODE_PORT</tt> that has the value of the Node port assigned:</p>
|
||||
<p><code><b>export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"</b></code><br />
|
||||
<code><b>echo "NODE_PORT=$NODE_PORT"</b></code></p>
|
||||
<p>Next, do a <code>curl</code> to the exposed IP and port:</p>
|
||||
<p><code><b>curl http://"$(minikube ip):$NODE_PORT"</b></code></p>
|
||||
<p>Every time you run the <code>curl</code> command, you will hit a different Pod. Notice that all Pods are now running the latest version (v2).</p>
|
||||
<p>You can also confirm the update by running the <code>rollout status</code> subcommand:</p>
|
||||
<p><code><b>kubectl rollout status deployments/kubernetes-bootcamp</b></code></p>
|
||||
<p>To view the current image version of the app, run the <code>describe pods</code> subcommand:</p>
|
||||
<p><code><b>kubectl describe pods</b></code></p>
|
||||
<p>In the <code>Image</code> field of the output, verify that you are running the latest image version (v2).</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h3>Roll back an update</h3>
|
||||
<p>Let’s perform another update, and try to deploy an image tagged with <code>v10</code>:</p>
|
||||
<p><code><b>kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/google-samples/kubernetes-bootcamp:v10</b></code></p>
|
||||
<p>Use <code>get deployments</code> to see the status of the deployment:</p>
|
||||
<p><code><b>kubectl get deployments</b></code></p>
|
||||
<p>Notice that the output doesn't list the desired number of available Pods. Run the <code>get pods</code> subcommand to list all Pods:</p>
|
||||
<p><code><b>kubectl get pods</b></code></p>
|
||||
<p>Notice that some of the Pods have a status of <tt>ImagePullBackOff</tt>.</p>
|
||||
<p>To get more insight into the problem, run the <code>describe pods</code> subcommand:</p>
|
||||
<p><code><b>kubectl describe pods</b></code></p>
|
||||
<p>In the <code>Events</code> section of the output for the affected Pods, notice that the <code>v10</code> image version did not exist in the repository.</p>
|
||||
<p>To roll back the deployment to your last working version, use the <code>rollout undo</code> subcommand:</p>
|
||||
<p><code><b>kubectl rollout undo deployments/kubernetes-bootcamp</b></code></p>
|
||||
<p>The <code>rollout undo</code> command reverts the deployment to the previous known state (v2 of the image). Updates are versioned and you can revert to any previously known state of a Deployment.</p>
|
||||
<p>Use the <code>get pods</code> subcommand to list the Pods again:</p>
|
||||
<p><code><b>kubectl get pods</b></code></p>
|
||||
<p>To check the image deployed on the running Pods, use the <code>describe pods</code> subcommand:</p>
|
||||
<p><code><b>kubectl describe pods</b></code></p>
|
||||
<p>The Deployment is once again using a stable version of the app (v2). The rollback was successful.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p>Remember to clean up your local cluster</p>
|
||||
<p><code><b>kubectl delete deployments/kubernetes-bootcamp services/kubernetes-bootcamp</b></code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</main>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,215 @@
|
|||
---
|
||||
title: Performing a Rolling Update
|
||||
weight: 10
|
||||
---
|
||||
|
||||
## {{% heading "objectives" %}}
|
||||
|
||||
Perform a rolling update using kubectl.
|
||||
|
||||
## Updating an application
|
||||
|
||||
{{% alert %}}
|
||||
_Rolling updates allow Deployments' update to take place with zero downtime by
|
||||
incrementally updating Pods instances with new ones._
|
||||
{{% /alert %}}
|
||||
|
||||
Users expect applications to be available all the time, and developers are expected
|
||||
to deploy new versions of them several times a day. In Kubernetes this is done with
|
||||
rolling updates. A **rolling update** allows a Deployment update to take place with
|
||||
zero downtime. It does this by incrementally replacing the current Pods with new ones.
|
||||
The new Pods are scheduled on Nodes with available resources, and Kubernetes waits
|
||||
for those new Pods to start before removing the old Pods.
|
||||
|
||||
In the previous module we scaled our application to run multiple instances. This
|
||||
is a requirement for performing updates without affecting application availability.
|
||||
By default, the maximum number of Pods that can be unavailable during the update
|
||||
and the maximum number of new Pods that can be created, is one. Both options can
|
||||
be configured to either numbers or percentages (of Pods). In Kubernetes, updates are
|
||||
versioned and any Deployment update can be reverted to a previous (stable) version.
|
||||
|
||||
## Rolling updates overview
|
||||
|
||||
<!-- animation -->
|
||||
<div class="col-md-8">
|
||||
<div id="myCarousel" class="carousel" data-ride="carousel" data-interval="3000">
|
||||
<div class="carousel-inner" role="listbox">
|
||||
<div class="item carousel-item active">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates1.svg">
|
||||
</div>
|
||||
<div class="item carousel-item">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates2.svg">
|
||||
</div>
|
||||
<div class="item carousel-item">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates3.svg">
|
||||
</div>
|
||||
<div class="item carousel-item">
|
||||
<img src="/docs/tutorials/kubernetes-basics/public/images/module_06_rollingupdates4.svg">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{% alert %}}
|
||||
_If a Deployment is exposed publicly, the Service will load-balance the traffic
|
||||
only to available Pods during the update._
|
||||
{{% /alert %}}
|
||||
|
||||
Similar to application Scaling, if a Deployment is exposed publicly, the Service
|
||||
will load-balance the traffic only to available Pods during the update. An available
|
||||
Pod is an instance that is available to the users of the application.
|
||||
|
||||
Rolling updates allow the following actions:
|
||||
|
||||
* Promote an application from one environment to another (via container image updates)
|
||||
* Rollback to previous versions
|
||||
* Continuous Integration and Continuous Delivery of applications with zero downtime
|
||||
|
||||
In the following interactive tutorial, we'll update our application to a new version,
|
||||
and also perform a rollback.
|
||||
|
||||
### Update the version of the app
|
||||
|
||||
To list your Deployments, run the `get deployments` subcommand:
|
||||
|
||||
```shell
|
||||
kubectl get deployments
|
||||
```
|
||||
|
||||
To list the running Pods, run the `get pods` subcommand:
|
||||
|
||||
```shell
|
||||
kubectl get pods
|
||||
```
|
||||
|
||||
To view the current image version of the app, run the `describe pods` subcommand
|
||||
and look for the `Image` field:
|
||||
|
||||
```shell
|
||||
kubectl describe pods
|
||||
```
|
||||
|
||||
To update the image of the application to version 2, use the `set image` subcommand,
|
||||
followed by the deployment name and the new image version:
|
||||
|
||||
```shell
|
||||
kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2
|
||||
```
|
||||
|
||||
The command notified the Deployment to use a different image for your app and initiated
|
||||
a rolling update. Check the status of the new Pods, and view the old one terminating
|
||||
with the `get pods` subcommand:
|
||||
|
||||
```shell
|
||||
kubectl get pods
|
||||
```
|
||||
|
||||
### Verify an update
|
||||
|
||||
First, check that the service is running, as you might have deleted it in previous
|
||||
tutorial step, run `describe services/kubernetes-bootcamp`. If it's missing,
|
||||
you can create it again with:
|
||||
|
||||
```shell
|
||||
kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
|
||||
```
|
||||
|
||||
Create an environment variable called `NODE_PORT` that has the value of the Node
|
||||
port assigned:
|
||||
|
||||
```shell
|
||||
export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"
|
||||
echo "NODE_PORT=$NODE_PORT"
|
||||
```
|
||||
|
||||
Next, do a `curl` to the exposed IP and port:
|
||||
|
||||
```shell
|
||||
curl http://"$(minikube ip):$NODE_PORT"
|
||||
```
|
||||
|
||||
Every time you run the `curl` command, you will hit a different Pod. Notice that
|
||||
all Pods are now running the latest version (`v2`).
|
||||
|
||||
You can also confirm the update by running the `rollout status` subcommand:
|
||||
|
||||
```shell
|
||||
kubectl rollout status deployments/kubernetes-bootcamp
|
||||
```
|
||||
|
||||
To view the current image version of the app, run the describe pods subcommand:
|
||||
|
||||
```shell
|
||||
kubectl describe pods
|
||||
```
|
||||
|
||||
In the `Image` field of the output, verify that you are running the latest image
|
||||
version (`v2`).
|
||||
|
||||
### Roll back an update
|
||||
|
||||
Let’s perform another update, and try to deploy an image tagged with `v10`:
|
||||
|
||||
```shell
|
||||
kubectl set image deployments/kubernetes-bootcamp kubernetes-bootcamp=gcr.io/google-samples/kubernetes-bootcamp:v10
|
||||
```
|
||||
|
||||
Use `get deployments` to see the status of the deployment:
|
||||
|
||||
```shell
|
||||
kubectl get deployments
|
||||
```
|
||||
|
||||
Notice that the output doesn't list the desired number of available Pods. Run the
|
||||
`get pods` subcommand to list all Pods:
|
||||
|
||||
```shell
|
||||
kubectl get pods
|
||||
```
|
||||
|
||||
Notice that some of the Pods have a status of `ImagePullBackOff`.
|
||||
|
||||
To get more insight into the problem, run the `describe pods` subcommand:
|
||||
|
||||
```shell
|
||||
kubectl describe pods
|
||||
```
|
||||
|
||||
In the `Events` section of the output for the affected Pods, notice that the `v10`
|
||||
image version did not exist in the repository.
|
||||
|
||||
To roll back the deployment to your last working version, use the `rollout undo`
|
||||
subcommand:
|
||||
|
||||
```shell
|
||||
kubectl rollout undo deployments/kubernetes-bootcamp
|
||||
```
|
||||
|
||||
The `rollout undo` command reverts the deployment to the previous known state
|
||||
(`v2` of the image). Updates are versioned and you can revert to any previously
|
||||
known state of a Deployment.
|
||||
|
||||
Use the `get pods` subcommand to list the Pods again:
|
||||
|
||||
```shell
|
||||
kubectl get pods
|
||||
```
|
||||
|
||||
To check the image deployed on the running Pods, use the `describe pods` subcommand:
|
||||
|
||||
```shell
|
||||
kubectl describe pods
|
||||
```
|
||||
|
||||
The Deployment is once again using a stable version of the app (`v2`). The rollback
|
||||
was successful.
|
||||
|
||||
Remember to clean up your local cluster.
|
||||
|
||||
```shell
|
||||
kubectl delete deployments/kubernetes-bootcamp services/kubernetes-bootcamp
|
||||
```
|
||||
|
||||
## {{% heading "whatsnext" %}}
|
||||
|
||||
* Learn more about [Deployments](/docs/concepts/workloads/controllers/deployment/).
|
|
@ -0,0 +1,20 @@
|
|||
/* kubernetes-basics tutorials */
|
||||
.tutorials-modules {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.module {
|
||||
width: 30%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.module img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.module h5 {
|
||||
margin: 10px 0 0;
|
||||
}
|
Loading…
Reference in New Issue