Writing our manifest files for Kubernetes / Openshift often forces us to edit xml, json and yml files by hand.
A new library, ap4k allows to specify metadata for these manifest files directly in our Java code using annotations.
In the following short example I am going to demonstrate how to generate manifest files using Maven and ap4k.
Dependencies
Using Maven we just need to add the following one dependency to our project’s pom.xml
<dependency>
<groupId>io.ap4k</groupId>
<artifactId>kubernetes-annotations</artifactId>
<version>0.2.2</version>
</dependency>
Sample Application
This is our first and simplest version as we’re just adding one annotation, @KubernetesApplication to our Java class:
package com.hascode.tutorial;
import io.ap4k.kubernetes.annotation.KubernetesApplication;
import java.time.Instant;
@KubernetesApplication
public class App {
public static void main(String[] args) {
System.out.printf("hello world, it's %s%n", Instant.now());
}
}
Adding additional Metadata
This is not much yet .. we may use additional declarations to configure ports, volumes, JVM options and much more.
For a complete list of possible configurations, please visit the project’s documentation on GitHub.
The following example adds a port and mounts/volumes:
package com.hascode.tutorial;
import io.ap4k.kubernetes.annotation.KubernetesApplication;
import io.ap4k.kubernetes.annotation.Mount;
import io.ap4k.kubernetes.annotation.Port;
import java.time.Instant;
@KubernetesApplication(ports = @Port(name = "http", containerPort = 8080),
mounts = @Mount(name = "mysql-volume", path = "/var/lib/mysql")
)
public class App {
public static void main(String[] args) {
System.out.printf("hello world, it's %s%n", Instant.now());
}
}
Generating the Manifest
We may use the following command to generate the manifest files:
mvn clean install
Our project directory might look similar to this one now:
tree target
target
├── ap4k-tutorial-1.0.0.jar
├── classes
│ ├── com
│ │ └── hascode
│ │ └── tutorial
│ │ └── App.class
│ └── META-INF
│ └── ap4k
│ ├── kubernetes.json
│ └── kubernetes.yml
├── generated-sources
│ └── annotations
├── maven-archiver
│ └── pom.properties
└── maven-status
└── maven-compiler-plugin
├── compile
│ └── default-compile
│ ├── createdFiles.lst
│ └── inputFiles.lst
└── testCompile
└── default-testCompile
└── inputFiles.lst
So let’s inspect the generated manifest files
Example 1
JSON Manifest
This is the generated kubernetes.json for our first simple example:
{
"apiVersion" : "v1",
"kind" : "List",
"items" : [ {
"apiVersion" : "apps/v1",
"kind" : "Deployment",
"metadata" : {
"labels" : {
"app" : "ap4k-tutorial",
"version" : "1.0.0",
"group" : "soma"
},
"name" : "ap4k-tutorial"
},
"spec" : {
"replicas" : 1,
"selector" : {
"matchLabels" : {
"app" : "ap4k-tutorial",
"version" : "1.0.0",
"group" : "soma"
}
},
"template" : {
"metadata" : {
"labels" : {
"app" : "ap4k-tutorial",
"version" : "1.0.0",
"group" : "soma"
}
},
"spec" : {
"containers" : [ {
"env" : [ {
"name" : "KUBERNETES_NAMESPACE",
"valueFrom" : {
"fieldRef" : {
"fieldPath" : "metadata.namespace"
}
}
} ],
"image" : "soma/ap4k-tutorial:1.0.0",
"imagePullPolicy" : "IfNotPresent",
"name" : "ap4k-tutorial"
} ]
}
}
}
} ]
}
YAML Manifest
This is our generated kubernetes.yml:
---
apiVersion: "v1"
kind: "List"
items:
- apiVersion: "apps/v1"
kind: "Deployment"
metadata:
labels:
app: "ap4k-tutorial"
version: "1.0.0"
group: "soma"
name: "ap4k-tutorial"
spec:
replicas: 1
selector:
matchLabels:
app: "ap4k-tutorial"
version: "1.0.0"
group: "soma"
template:
metadata:
labels:
app: "ap4k-tutorial"
version: "1.0.0"
group: "soma"
spec:
containers:
- env:
- name: "KUBERNETES_NAMESPACE"
valueFrom:
fieldRef:
fieldPath: "metadata.namespace"
image: "soma/ap4k-tutorial:1.0.0"
imagePullPolicy: "IfNotPresent"
name: "ap4k-tutorial"
Example 2
JSON Manifest
This is our generated kubernetes.json
{
"apiVersion" : "v1",
"kind" : "List",
"items" : [ {
"apiVersion" : "v1",
"kind" : "Service",
"metadata" : {
"labels" : {
"app" : "ap4k-tutorial",
"version" : "1.0.0",
"group" : "soma"
},
"name" : "ap4k-tutorial"
},
"spec" : {
"ports" : [ {
"name" : "http",
"port" : 8080,
"targetPort" : 8080
} ],
"selector" : {
"app" : "ap4k-tutorial",
"version" : "1.0.0",
"group" : "soma"
},
"type" : "ClusterIP"
}
}, {
"apiVersion" : "apps/v1",
"kind" : "Deployment",
"metadata" : {
"labels" : {
"app" : "ap4k-tutorial",
"version" : "1.0.0",
"group" : "soma"
},
"name" : "ap4k-tutorial"
},
"spec" : {
"replicas" : 1,
"selector" : {
"matchLabels" : {
"app" : "ap4k-tutorial",
"version" : "1.0.0",
"group" : "soma"
}
},
"template" : {
"metadata" : {
"labels" : {
"app" : "ap4k-tutorial",
"version" : "1.0.0",
"group" : "soma"
}
},
"spec" : {
"containers" : [ {
"env" : [ {
"name" : "KUBERNETES_NAMESPACE",
"valueFrom" : {
"fieldRef" : {
"fieldPath" : "metadata.namespace"
}
}
} ],
"image" : "soma/ap4k-tutorial:1.0.0",
"imagePullPolicy" : "IfNotPresent",
"name" : "ap4k-tutorial",
"ports" : [ {
"containerPort" : 8080,
"name" : "http",
"protocol" : "TCP"
} ],
"volumeMounts" : [ {
"mountPath" : "/var/lib/mysql",
"name" : "mysql-volume",
"readOnly" : false,
"subPath" : ""
} ]
} ]
}
}
}
} ]
}
YAMLManifest
This is our generated kubernetes.yml
---
apiVersion: "v1"
kind: "List"
items:
- apiVersion: "v1"
kind: "Service"
metadata:
labels:
app: "ap4k-tutorial"
version: "1.0.0"
group: "soma"
name: "ap4k-tutorial"
spec:
ports:
- name: "http"
port: 8080
targetPort: 8080
selector:
app: "ap4k-tutorial"
version: "1.0.0"
group: "soma"
type: "ClusterIP"
- apiVersion: "apps/v1"
kind: "Deployment"
metadata:
labels:
app: "ap4k-tutorial"
version: "1.0.0"
group: "soma"
name: "ap4k-tutorial"
spec:
replicas: 1
selector:
matchLabels:
app: "ap4k-tutorial"
version: "1.0.0"
group: "soma"
template:
metadata:
labels:
app: "ap4k-tutorial"
version: "1.0.0"
group: "soma"
spec:
containers:
- env:
- name: "KUBERNETES_NAMESPACE"
valueFrom:
fieldRef:
fieldPath: "metadata.namespace"
image: "soma/ap4k-tutorial:1.0.0"
imagePullPolicy: "IfNotPresent"
name: "ap4k-tutorial"
ports:
- containerPort: 8080
name: "http"
protocol: "TCP"
volumeMounts:
- mountPath: "/var/lib/mysql"
name: "mysql-volume"
readOnly: false
subPath: ""
Tutorial Sources
Please feel free to download the tutorial sources from my GitHub repository, fork it there or clone it using Git:
git clone https://github.com/hascode/ap4k-tutorial.git