Spring into
Kubernetes
Paul Czarkowski
[email protected]
Twitter: @pczarkowski
© Copyright 2018 Pivotal Software, Inc. All rights Reserved.
Spring into
Kubernetes
Paul Czarkowski
[email protected]
Twitter: @pczarkowski
© Copyright 2018 Pivotal Software, Inc. All rights Reserved.
"Kubernetes is named after the
greek god of spending money on
cloud services" - @QuinnyPig
More Control Less Control
Less Efficiency More Efficiency
Build App Build App App → to the
?????
Artifact Container(s) Platform
Traditional Config Deployment CF API ??? API
Ticket Management Manifest
Based Application
PaaS Function
PaaS
Human Application Platform
Platform Application Platform
Platform
Infrastructure K8s API
Toil As
Code CaaS
Container
Container
Platform
Orchestrator
IaaS API
Infrastructure
Container Runtime
PXE boot ? Container Hosts
Platform
Hardware
IaaS
Platform
6
Containers
Saurabh Gupta. "Containers and Pivotal Cloud Foundry" 2016.
FROM maven:3.6-jdk-11-slim as BUILD
COPY . /src
WORKDIR /src
RUN mvn install -DskipTests
FROM openjdk:11.0.1-jre-slim-stretch
EXPOSE 8080
WORKDIR /app
ARG JAR=hello-0.0.1-SNAPSHOT.jar
COPY --from=BUILD /src/target/$JAR /app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
$ docker build -t paulczar/hello .
$ docker push paulczar/hello
$ docker pull paulczar/hello
$ docker run -d -p 8080:8080 paulczar/hello
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>1.6.1</version>
<configuration>
<to>
<image>myimage</image>
</to>
</configuration>
</plugin>
Kubernetes
Users
Control Plane
API Controller
Server Manager
etcd
Cloud Ctrl
Scheduler
Manager
Master
Master
Master
Data Plane
Kubelet docker Kubelet docker Kubelet docker
kube-proxy Flannel kube-proxy Flannel kube-proxy Flannel
Worker Worker Worker
Controllers
Desired State
Actual State
Unix Philosophy:
Do one thing. Do it well.
$ kubectl
Imperative
$ kubectl run hello \
--image=paulczar/go-hello-world
$ kubectl scale hello \
--replicas=3
$ kubectl create service clusterip \
hello --tcp=80:80
Declarative
$ kubectl apply -f hello-world.yaml
Declarative
Vs
Imperative
manifests
apiVersion: v1
kind: Pod
metadata:
name: hello
spec:
containers:
- image: paulczar/go-hello-world
imagePullPolicy: Always
name: hello
Resources
● Pods
● Services
● Volumes
POD
one or more containers that share
a network and storage
the minimum scalable unit
of your application
$ kubectl
$ kubectl create deployment hello \
--image=paulczar/hello
● kubectl run created a deployment “deployments.apps/hello”
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/hello 1 1 1 1 1m
● The deployment created a replicaset “replicaset.apps/hello-64f6bf9dd4”
NAME DESIRED CURRENT READY AGE
replicaset.apps/hello-64f6bf9dd4 1 1 1 1m
● Which created a pod “pod/hello-64f6bf9dd4-tq5dq”
NAME READY STATUS RESTARTS AGE
pod/hello-64f6bf9dd4-tq5dq 1/1 Running 0 2s
$ kubectl scale --replicas=3 \
deployment/hello
$ kubectl scale --replicas=3 deployment/hello
deployment.extensions/hello scaled
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/hello-64f6bf9dd4-2bndq 1/1 Running 0 15m
pod/hello-64f6bf9dd4-4kq9l 0/1 ContainerCreating 0 2s
pod/hello-64f6bf9dd4-8lkcs 1/1 Running 0 5s
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/hello 3 3 2 3 16m
NAME DESIRED CURRENT READY AGE
replicaset.apps/hello-64f6bf9dd4 3 3 2 16m
$ kubectl set env deployment/hello \
--env “MESSAGE=Hello Krakow”
$ kubectl get all
NAME READY STATUS RESTARTS AGE
pod/hello-5c75b546c7-4lwnn 1/1 Running 0 1m
pod/hello-5c75b546c7-bwxxq 1/1 Running 0 1m
pod/hello-5c75b546c7-sl2pg 1/1 Running 0 1m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deployment.apps/hello 3 3 3 3 23m
NAME DESIRED CURRENT READY AGE
replicaset.apps/hello-5c75b546c7 3 3 3 1m
replicaset.apps/hello-64f6bf9dd4 0 0 0 23m
$ kubectl get deployment hello \
-o yaml
$ kubectl port-forward deployment/hello 8080
Forwarding from 127.0.0.1:8080 -> 8080
$ curl localhost:8080
<html><head><title>HELLO I LOVE YOU!!!!</title></head><body>HELLO I LOVE
YOU!!!!!</body></html>
Service
$ kubectl expose deployment \
hello --type=LoadBalancer \
--port 80 --target-port 8080
kubectl expose deployment hello
● creates a service with a ClusterIP that acts as an internal loadbalancer to all
pods in the “hello” deployment
--type=LoadBalancer
● Creates a NodePort
● Configures a LoadBalancer to access the pods via the NodePort
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello LoadBalancer 10.39.248.123 35.184.17.129 80:30468/TCP 5m
$ curl 35.184.17.129
<html><head><title>HELLO I LOVE YOU!!!!</title></head><body>HELLO I LOVE
YOU!!!!!</body></html>
Service
app=bacon 10.3.55.7 Service
track Pods based on metadata and provides
connectivity and service discovery (DNS, Env
app=bacon app=bacon variables) for them.
Container Container Type
ClusterIP (default) exposes service on a
cluster-internal IP.
Container Container
Pod Pod
192.168.0.5:4530 192.168.0.6:4530
K8s Worker K8s Worker
Service
Service track Pods based on metadata and provides
connectivity and service discovery (DNS, Env
app=bacon 10.3.55.7 variables) for them.
Type
app=bacon app=bacon
NodePort extends ClusterIP to expose services on
Container Container
each node’s IP via a static port.
Container Container
Pod Pod
33.6.5.22:80
Load Balancer
192.168.0.5:4530 192.168.0.6:4530
K8s Worker K8s Worker Service
track Pods based on metadata and provides
Service connectivity and service discovery (DNS, Env
variables) for them.
app=bacon 10.3.55.7
Type
app=bacon app=bacon LoadBalancer extends NodePort to configure a cloud
provider’s load balancer using the
Container Container
cloud-controller-manager.
Container Container
Pod Pod
https://example.com
Ingress Ingress
a controller that manages an external entity to provide
/bacon /eggs load balancing, SSL termination and name-based
virtual hosting to services based on a set of rules.
Service Service
app=bacon app=eggs
Volume
Volume
Is [effectively] a Directory, possibly with data in it,
available to all containers in a Pod.
Usually Shares lifecycle of a Pod (Created when Pod
Container is created, destroyed when Pod is destroyed).
Persistent Volumes outlive Pods.
Container Can be mounted from local disk, or from a network
storage device such as a EBS volume, iscsi, NFS, etc.
Pod
Config Map / Secret
$ kubectl create configmap hello \
--from-literal=’message=Hello S1T’
kubectl create configmap hello --from-file=index.html
● creates a configmap called “hello” containing the contents index.html
$ kubectl get configmap hello -o yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: hello
data:
index.html: "<html>\n<head>\n\t<title>Hello to my
friends</title>\n</head>\n<body>\n\tHello
to my friends\n</body>\n</html>\n\n"
kubectl create secret generic hello --from-file=index.html
● creates a secret called “hello” containing a base64 hash of contents index.html
$ kubectl get secret hello -o yaml
apiVersion: v1
kind: Secret
metadata:
name: hello
data:
index.html:
PGh0bWw+CjxoZWFkPgoJPHRpdGxlPkhlbGxvIHRvIG15IGZyaWVuZHM8L3RpdGxlPgo8L2hlYWQ+Cjxib2R5
PgoJSGVsbG8gdG8gbXkgZnJpZW5kcwo8L2JvZHk+CjwvaHRtbD4KCg==
ConfigMaps/Secrets (user-data)
Provides key-value pairs to be injected into a pod much like user-data is injected into a Virtual
Machine in the cloud.
Allows you to do last minute configuration of applications running on Kubernetes such as
setting a database host, or a admin password.
ConfigMaps store values as strings, Secrets store them as byte arrays (serialized as base64
encoded strings).
Secrets are [currently] not encrypted by default. This is likely to change.
Can be injected as files in a Volume, or as Environment Variables.
Spring
Cloud
Kubernetes
● Discovery
● Ribbon Discovery
● Dynamic Config
● Profile Autoconfiguration
● Istio Awareness
● Pod Health Indicators
Service Discovery
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes</artifactId>
</dependency>
---
@SpringBootApplication
@EnableDiscoveryClient
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
---
@Autowired
private DiscoveryClient discoveryClient;
spring-cloud-kubernetes-ribbon
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
</dependency>
spring-cloud-kubernetes-ribbon
@SpringBootApplication
@EnableDiscoveryClient
@EnableWebFlux
public class EdgeServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EdgeServiceApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Native Service Discovery
spring-cloud-kubernetes-config
<dependencies>
<!-- needed for spring kubernetes config reloads -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- spring cloud kubernetes config server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-config</artifactId>
</dependency>
</dependencies>
spring-cloud-kubernetes-config
spring:
application:
name: cloud-k8s-app
cloud:
kubernetes:
config:
name: default-name
namespace: default-namespace
sources:
- name: c1
- namespace: n2
- namespace: n3
name: c3
oh and automatic prometheus
metrics
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
Transforming How The World Builds Software
@pczarkowski
© Copyright 2019 Pivotal Software, Inc. All rights Reserved.