Your First Deployment & Service
Deploying an application to Kubernetes involves defining its desired state and how it should be exposed to consumers. This typically entails creating at…
Deploying an application to Kubernetes involves defining its desired state and how it should be exposed to consumers. This typically entails creating at least two core Kubernetes objects: a Deployment to manage the application's lifecycle and a Service to provide stable network access. This article details the essential components of a basic web application deployment, using Nginx as an example, and its corresponding Service definition.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
labels:
app: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web-container
image: nginx:alpine
ports:
- containerPort: 80
name: http
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "128Mi"
cpu: "200m"
---
apiVersion: v1
kind: Service
metadata:
name: web
labels:
app: web
spec:
type: LoadBalancer
selector:
app: web
ports:
- port: 80
targetPort: http # Refers to the name of the container port, 'http'
protocol: TCP
Understanding the Deployment Object
The Kubernetes Deployment object manages a replicated set of Pods. It declares the desired state for your application, and the Kubernetes controller manager works to maintain that state. If a Pod crashes or a node fails, the Deployment automatically replaces the affected Pods to ensure the desired replica count is met.
apiVersion: apps/v1
This specifies the API version for the Deployment object. apps/v1 is the stable and recommended API version for Deployments since Kubernetes 1.9.
kind: Deployment
This explicitly declares the type of Kubernetes object being defined.
metadata
The metadata section provides identifying information for the Deployment.
name: web: A unique name for this Deployment within its namespace. This name will be used to refer to the Deployment inkubectlcommands.labels: { app: web }: Key-value pairs that help organize and select Kubernetes objects. These labels are crucial for the Service to identify the Pods it should route traffic to.
spec
The spec section defines the desired state of the Deployment.
replicas: 3: Instructs the Deployment controller to maintain three identical Pods running your application. If any Pods fail, new ones will be created until this count is reached.selector: { matchLabels: { app: web } }: This field is critical. It defines how the Deployment finds the Pods it manages. It must match the labels defined in the Pod template. In this case, any Pod with the labelapp: webis considered part of this Deployment.template: This is the Pod template, which describes the Pods that the Deployment will create. Any changes here will trigger a rolling update of the Pods.metadata: { labels: { app: web } }: Labels for the Pods themselves. These labels must match the Deployment'sselector.spec:: Defines the Pod's configuration.containers:: A list of containers to run inside the Pod. A Pod can contain multiple containers that share network and storage, but typically one primary application container is used.name: web-container: A unique name for this container within the Pod.image: nginx:alpine: The Docker image to pull and run.nginx:alpineis a lightweight Nginx image based on Alpine Linux.ports: [{ containerPort: 80, name: http }]: Declares that the container listens on TCP port 80. Thename: httpis optional but highly recommended for readability and for referencing in Service definitions (as seen later withtargetPort: http).resources:: Defines resource requests and limits for the container. This is crucial for scheduling and stability.requests:: The minimum resources guaranteed to the container. The scheduler uses these values to place Pods on nodes.memory: "64Mi": Request 64 mebibytes of memory.cpu: "100m": Request 100 millicores (0.1 CPU core).
limits:: The maximum resources the container can consume. If a container exceeds its memory limit, it will be terminated. If it exceeds its CPU limit, it will be throttled.memory: "128Mi": Limit memory to 128 mebibytes.cpu: "200m": Limit CPU to 200 millicores (0.2 CPU core).
Understanding the Service Object
While a Deployment ensures your Pods are running, Pods are ephemeral and can be replaced with new IP addresses. A Kubernetes Service provides a stable network endpoint for a set of Pods. It acts as an abstraction, allowing clients to access the application without needing to know the specific IP addresses of individual Pods.
apiVersion: v1
This specifies the API version for the Service object. v1 is the stable API version for Services.
kind: Service
This explicitly declares the type of Kubernetes object being defined.
metadata
The metadata section provides identifying information for the Service.
name: web: A unique name for this Service within its namespace. This name is often used for DNS resolution within the cluster.labels: { app: web }: Similar to Deployments, labels help organize and identify the Service.
spec
The spec section defines the behavior of the Service.
type: LoadBalancer: This defines how the Service is exposed.ClusterIP(default): Exposes the Service on an internal IP address within the cluster. Only reachable from within the cluster.NodePort: Exposes the Service on each Node's IP at a static port (the NodePort). Makes the Service accessible from outside the cluster using<NodeIP>:<NodePort>.LoadBalancer: Exposes the Service externally using a cloud provider's load balancer. This type automatically provisions an external IP address and load balancer, making your application directly accessible from the internet (e.g., AWS ELB, GCP Load Balancer). This requires a cloud provider integration.ExternalName: Maps the Service to a DNS name, not to a selector.
selector: { app: web }: This is how the Service finds the Pods it should route traffic to. It uses labels to select all Pods that haveapp: web. This is the crucial link between your Deployment and your Service.ports:: Defines the ports the Service will expose.port: 80: The port on the Service itself that clients will connect to.targetPort: http: The port on the Pods (containers) that the Service will forward traffic to. It's best practice to use the named port (httpin this case) defined in the container spec for clarity and flexibility, rather than the raw number (80). This allows you to change the container's internal port without modifying the Service, as long as the port name remains consistent.protocol: TCP: The IP protocol used for the port. Can beTCPorUDP.
Applying the Configuration
Once you have your YAML manifest, you can deploy it to your Kubernetes cluster using kubectl.
kubectl apply -f web.yaml
This command creates or updates the Deployment and Service objects defined in web.yaml.
Verifying the Deployment
After applying the configuration, you can check the status of your created objects:
kubectl get pods -l app=web
This command lists Pods with the label app=web. You should see three Pods in a Running state.
NAME READY STATUS RESTARTS AGE
web-6789abcd-jklmn 1/1 Running 0 2m
web-6789abcd-opqrs 1/1 Running 0 2m
web-6789abcd-tuvwx 1/1 Running 0 2m
kubectl get svc web
This command shows the details of your web Service.
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web LoadBalancer 10.96.10.100 <pending> 80:30000/TCP 2m
Initially, EXTERNAL-IP might show <pending>. It takes a short time for the cloud provider to provision and assign an external IP address to the LoadBalancer. Keep checking with kubectl get svc web --watch until an IP address appears. Once assigned, you can access your Nginx welcome page using that external IP address in your browser.
Common Pitfalls
- Label Mismatch: The most common error. The
selector.matchLabelsin your Deployment and theselectorin your Service must exactly match themetadata.labelsin your Pod template. If they don't, the Service won't find any Pods to route traffic to, and the Deployment won't manage the correct Pods. - Port Mismatch: Ensure that
targetPortin your Service points to the correctcontainerPort(or its named equivalent) defined in your Deployment's Pod template. If the Nginx container listens on 80, but your Service'stargetPortis 8080, traffic won't reach the application. LoadBalancerExternal IP Pending: When usingtype: LoadBalanceron a cloud provider, it takes time for the external IP to be provisioned. Don't assume an error if it's<pending>immediately after deployment. If it remains pending for an unusually long time (e.g., over 5-10 minutes), check your cloud provider's network logs or Kubernetes events for provisioning failures (kubectl describe svc web).- Resource Limits and Requests: While not directly preventing deployment, inadequate resource requests can lead to Pods not being scheduled, and insufficient limits can cause Pods to be evicted (OOMKilled) or throttled, leading to application instability.
- Image Pull Errors: Verify the image name and tag (e.g.,
nginx:alpine). If the image doesn't exist or there's an issue with container registry access (e.g., private registry authentication), Pods will enter anImagePullBackOfforErrImagePullstate. Checkkubectl describe pod <pod-name>andkubectl logs <pod-name>for details.