Author: Faheem Javed
This tutorial is adapted from the Web Age course Kubernetes for Developers on AKS Training.
By default, AKS can only connect to the public Docker Hub registry. To allow AKS to connect to your private ACR, you are required to configure the AKS cluster.
The following command ensures the AKS cluster can access images in the custom ACR registry.
az aks update -n $AKS_NAME -g $RESOURCE_GROUP --attach-acr $ACR_NAME
To refer to ACR images, use the following convention:
{acr_login_server}/{image}:{tag}
There are various methods that can be used to deploy a workload to Kubernetes.
Method 1: Using Generators (kubectl run, kubectl create (without .yaml), kubectl expose)
If you want to check quickly whether the container is working then you might use Generators.
# creates simple pods that you cannot scale after deployment.
kubectl run nginx-deployment --image=nginx
# creates a deployment that can be scaled after the deployment has been performed
kubectl create deployment nginx-deployment --image=nginx
Method 2: Using Imperative way (kubectl create with .yaml)
It can work with one object configuration file at a time that can be checked into a source control repository, such as Git.
It’s a one-time operation, i.e. you cannot run the same configuration file to make changes.
kubectl create -f deployment.yaml
Method 3: Using Declarative way (kubectl apply)
It works with files, directories, and sub-directories containing object configuration YAML files.
You can modify the configuration file(s) and rerun them to update the deployment(s).
kubectl apply -f deployment.yaml
kubectl apply -f folder_name_with_a_bunch_of_yaml_files/
Kubernetes services expose applications running on a set of Pods as network services.
Services are a solution to the following situation:
- Instances of an application run in separate Pods
- Each Pod gets its own IP address
- Pods come and go based on load
- How can we access applications when we don’t know which instances are running and what their IP addresses are?
Using the Generators method, you can use the following commands to deploy an application and expose the service.
kubectl create deployment nginx-deployment --image=nginx
kubectl expose deployment {deployment-name} --type={type} --port={port} --target-port={target-port}
In production, it’s preferred to use yaml files to define Kubernetes Service Resource Objects.
Example:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
This spec creates the ‘my-service” service which exposes “MyApp” on the internal cluster IP address at port 9376.
Services can have one of the following types:
- ClusterIP (default) – IP address internal to the cluster
- NodePort – Port on the parent node’s internal cluster IP address. Can be exposed outside the cluster.
- LoadBalancer – Provides access through a load balancer’s IP address
- ExternalName – Maps to the external DNS name in the externalName field
ClusterIP is the default service type. Services created without a type field are assigned this type.
The following command creates a ClusterIP type service:
kubectl expose deployment hello-nginx --port=8080 --targetPort=80
Details of the created service:
kubectl get services hello-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-nginx ClusterIP 10.98.16.57 <none> 8080/TCP 4m59s
Service can be accessed by shelling into the cluster.
minikube ssh
curl http://10.98.16.57:8080
With a NodePort type of service, Kubernetes exposes the service through a randomly generated port number off of the node where the application pods reside.
Node ports can also be created using the expose command:
kubectl expose deployment hello-nginx --type=NodePort --port=80
Details of the created service
kubectl get services hello-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-nginx NodePort 10.110.148.227 <none> 80:31164/TCP 36s
The service can be accessed through the node IP address and service’s port number:
minikube service hello-nginx --url=true
http://192.168.99.100:31164
curl http://192.168.99.100:31164
The “minikube service {service-name} –url=true” command combines the node ip address and the service’s port to create a URL that can be used to address the given service
NodePort services can also be created by applying Service Resource specifications like this one:
# my-service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app: MyApp
ports:
- port: 80
targetPort: 80
nodePort: 30007
Command creates/updates the service:
kubectl apply service -f my-service.yaml
This service type provisions an external LoadBalancer to direct traffic to the selected Pods. This type is often used when running Kubernetes on cloud providers that include their own load balancers. The IP address of the external load balancer populates the service’s status.loadBalancer.ip field
The following command can be used to create this type of service:
kubectl expose deployment hello-nginx --name hello-nginx-lb --type=LoadBalancer --port=80
Details of the created service:
kubectl get services hello-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-nginx LoadBalancer 10.111.8.184 192.168.122.1 80:30725/TCP 51m
The service can be accessed through the node IP address and service’s port number:
minikube service hello-nginx --url=true
http://192.168.122.1:31164
curl http://192.168.122.1:31164
LoadBalance type services can also be created from yaml file specs:
# example-service.yaml
apiVersion: v1
kind: Service
metadata:
name: example-service
spec:
selector:
app: example
ports:
- port: 8765
targetPort: 9376
type: LoadBalancer
Command to apply the spec:
kubectl apply -f example-service.yaml
Remember: the above requires an external load balancer to work
ExternalName type services map the service to a DNS name. Redirection to the service happens at the DNS level rather than by proxy or forwarding. This type maps ‘my-service’ in the ‘prod’ namespace to a server identified by a name (my.database.example.com) that can be resolved by an external network DNS.
Example spec:
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
This type might be used for example to map a service name inside the cluster to a database server outside the cluster.
More information on the external name type is available here:
https://kubernetes.io/docs/concepts/services-networking/service/#externalname
Applications can be accessed in a variety of ways:
- Shell into the app’s container and use localhost
- Shell into any container in the same pod as the app and again use localhost to access the app
- Apps on the same node can access apps in different pods using the app pod’s name or IP address
- Apps outside a cluster can access a service in a k8s cluster through a service-defined port on the cluster’s IP address.
- The ‘kubectl port-forward’ command can be used to forward a port on the local machine where the cluster is running to a pod running inside the cluster.
The selector in a service specification is used to identify Pods for a service to point to
spec:
selector:
app: MyApp
When a service is meant to point to some other type of back-end (as opposed to Pods) the selector is omitted. You might do this:
- To access an external production database cluster
- To point to a service in a different namespace or cluster
- When only some of your back-ends are hosted by Kubernetes
- When the service points to one or more Pods an Endpoint is automatically created for the service.
For non-Pod services the endpoint must be added manually:
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: 192.0.2.42
ports:
- port: 9376
This endpoint then allows the service to point to the IP address and port of any server you choose.
For more information see:
https://kubernetes.io/docs/concepts/services-networking/service/#services-without-selectors
An Ingress Resource is a Kubernetes object that acts as the entry point for your cluster. An Ingress sits between the external network and the services in the K8s Cluster and lets you expose multiple services under the same IP address.
Ingresses can be used to provide:
- Routes from network traffic outside the cluster to services within the cluster
- Load balancing
- SSL/TLS Termination
- Name-based virtual hosting
1.15 Ingress Resource Example
Example:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: example-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: hello-world.info
http:
paths:
- path: /
backend:
serviceName: web
servicePort: 8080
Documentation for Ingress’ can be found here:
https://kubernetes.io/docs/concepts/services-networking/ingress/
An ingress tutorial can be found here:
https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/
An Ingress Controller implements the features defined in the Ingress object. Ingress objects will have NO EFFECT unless an ingress controller has been deployed.
Two Ingress Controllers supported by the Kubernetes project are:
- nginx ingress controller for Kubernetes
- GCE ingress-gce
Several other ingress controllers are also available.
Setting up to use the ingress-nginx ingress controller on minikube:
minikube addons enable ingress
Setting up the ingress-nginx controller on other platforms:
Documentation on Ingress Controllers can be found here:
https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/
A service mesh can be thought of as an infrastructure layer for service-to-service communication. A service mesh can implement a variety of cross-cutting features including: Load Balancing, Circuit Breaking Retry & Timeout, Seciurity(TLS), Monitoring, Traffic Metrics. A Service Mesh is typically implemented as a proxy deployed in a sidecar container next to each instance container of an application
Examples of Service Mesh include:
- Open Service Mesh (OSM) (backed by Microsoft)
- Istio (backed by Google & IBM)
- Maesh
- Kuma
- AWS App Mesh
For more information on Service Mesh see:
https://servicemesh.es/
In this tutorial, we covered:
- Kubernetes Services
- Service Type
- ClusterIP
- NodePort
- LoadBalancer
- ExternalName
- Accessing Applications
- Services Without a Selector
- Ingresses
- Service Mesh