Apache Karaf dynamic and static approach, docker and kubernetes
Most of the Karaf users know the Apache Karaf “standard” distribution.
Apache Karaf dynamic approach (“standard” distribution)
You can download Apache Karaf “standard” or “minimal” distributions, you download a “dynamic” distribution.
By “dynamic”, it means that you start the Karaf runtime and, later, you deploy applications in it.
The resolution is performed at runtime, at deployment time. It’s a “application container” approach (like Apache Tomcat, …).
You can create your own custom Karaf runtime (using boot features for instance), where the container starts a set of applications at bootstrap.
However, it’s not the only approach ! Apache Karaf is a complete polymorphic application runtime, meaning that it can take different form to match your expectations, use cases and devops requirements.
Apache Karaf static approach (likely immutable)
You can use a “static” approach with Apache Karaf. It’s similar to kind of spring-boot bootstrap and especially very convenient used with docker and on the cloud.
The resolution is made at build time, predictable.
This approach is super light, standalone/immutable while supporting all Karaf features !
We also have new tools coming that can directly generate dockerfile or even docker images.
In this blog, I will show how to create a application running in Karaf “static” runtime.
As I have some work in progress, this blog is based on the current pull request: https://github.com/apache/karaf/pull/789.
Your application
That’s where actually your business code will be located. It’s a regular Karaf application.
For the demo, I’m creating a very simple Servlet
.
The code is pretty simple: it uses SCR to expose the Servlet
as a service.
package org.apache.karaf.examples.docker;import org.osgi.service.component.annotations.Component;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import javax.servlet.Servlet;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;@Component( property = { "alias=/servlet-example", "servlet-name=Example"})public class ExampleServlet extends HttpServlet implements Servlet { private final static Logger LOGGER = LoggerFactory.getLogger(ExampleServlet.class); @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { LOGGER.info("Client " + request.getRemoteAddr() + " request received on " + request.getRequestURL()); try (PrintWriter writer = response.getWriter()) { writer.println("<html>"); writer.println("<head>"); writer.println("<title>Example</title>"); writer.println("</head>"); writer.println("<body align='center'>"); writer.println("<h1>Example Servlet</h1>"); writer.println("</body>"); writer.println("</html>"); } }}
This application is packaged as a bundle as defined in the pom.xml
. As we need a features XML to package in Karaf, we use the karaf-maven-plugin
features-generate-descriptor
goal to automatically create the feature.xml
:
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache.karaf.examples</groupId> <artifactId>karaf-docker-example</artifactId> <version>4.3.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <artifactId>karaf-docker-example-app</artifactId> <packaging>bundle</packaging> <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.osgi</groupId> <artifactId>osgi.cmpn</artifactId> <version>6.0.0</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.karaf.tooling</groupId> <artifactId>karaf-maven-plugin</artifactId> <executions> <execution> <goals> <goal>features-generate-descriptor</goal> </goals> <configuration> <includeProjectArtifact>true</includeProjectArtifact> </configuration> </execution> </executions> </plugin> </plugins> </build></project>
The features XML has been generated in the target
folder and attached to the Maven project.
That’s it ! We now have an application module (that could be a service/micro-service as well) that you can either deploy in the regular Karaf container (dynamic approach) or a Karaf “static” runtime.
The runtime assembly
The “static” runtime will assemble and package a set of application modules. You just pick the modules you want.
The assembly is a simple pom.xml
containing the following steps:
assembly
creates the runtime filesystemarchive
packages the runtime filesystem (generated byassembly
) as a zip and tar.gz archivedockerfile
creates a turnkeyDockerfile
with your runtimedocker
optionally directly use Docker to create a docker image using the generatedDockerfile
. We do this step only if thedocker
profile is enabled.
Here’s the complete pom.xml
:
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache.karaf.examples</groupId> <artifactId>karaf-docker-example</artifactId> <version>4.3.0-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent> <artifactId>karaf-docker-example-dist</artifactId> <packaging>pom</packaging> <dependencies> <dependency> <groupId>org.apache.karaf.features</groupId> <artifactId>static</artifactId> <type>kar</type> </dependency> <dependency> <groupId>org.apache.karaf.features</groupId> <artifactId>standard</artifactId> <classifier>features</classifier> <type>xml</type> </dependency> <dependency> <groupId>org.apache.karaf.services</groupId> <artifactId>org.apache.karaf.services.staticcm</artifactId> </dependency> <dependency> <groupId>org.apache.karaf.examples</groupId> <artifactId>karaf-docker-example-app</artifactId> <type>xml</type> <classifier>features</classifier> <version>${project.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.karaf.tooling</groupId> <artifactId>karaf-maven-plugin</artifactId> <executions> <execution> <id>process-resources</id> <phase>process-resources</phase> <goals> <goal>assembly</goal> </goals> </execution> <execution> <id>package</id> <goals> <goal>archive</goal> </goals> </execution> <execution> <id>dockerfile</id> <goals> <goal>dockerfile</goal> </goals> </execution> </executions> <configuration> <startupFeatures> <startupFeature>static-framework</startupFeature> <startupFeature>scr</startupFeature> <startupFeature>http-whiteboard</startupFeature> <startupFeature>karaf-docker-example-app</startupFeature> </startupFeatures> <framework>static</framework> <useReferenceUrls>true</useReferenceUrls> <environment>static</environment> </configuration> </plugin> </plugins> </build> <profiles> <profile> <id>docker</id> <build> <plugins> <plugin> <groupId>org.apache.karaf.tooling</groupId> <artifactId>karaf-maven-plugin</artifactId> <executions> <execution> <id>docker-image</id> <goals> <goal>docker</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </profile> </profiles></project>
We can note in this pom.xml
:
- the
startupFeatures
contains thestatic-framework
which is the core “static” runtime. Then we add the prerequisite features for our application:scr
andhttp-whiteboard
. Finally, we also add “our” generated application feature:karaf-docker-example-app
. - the
environment
isstatic
meaning that the resolution is performed at build time - the
useReferenceUrls
disable Maven support and directly use the jar/resources populated in the runtimesystem
folder.
We now build the project with a simple mvn clean install
.
In the dist/target
folder, we can find:
- the
assembly
directory containing the runtime filesystem - the zip and tar.gz archives
- the ready to use
Dockerfile
for the runtime including your application
$ ls targetassemblyDockerfilekaraf-docker-example-dist-4.3.0-SNAPSHOT.tar.gzkaraf-docker-example-dist-4.3.0-SNAPSHOT.zip
We can locally use the assembly
or archive runtime.
Let’s use the tar.gz archive.
First we extract the tar.gz:
$ tar zxvf karaf-docker-example-dist-4.3.0-SNAPSHOT.tar.gz$ cd karaf-docker-example-dist-4.3.0-SNAPSHOT/
We go into the bin
folder and we can use karaf run
to start the runtime:
$ cd bin$ ./karaf runMar 21, 2019 4:47:16 PM org.apache.karaf.main.Main launchINFO: Installing and starting initial bundlesMar 21, 2019 4:47:16 PM org.apache.karaf.main.Main launchINFO: All initial bundles installed and set to startMar 21, 2019 4:47:16 PM org.apache.karaf.main.Main$KarafLockCallback lockAcquiredINFO: Lock acquired. Setting startlevel to 10016:47:17.002 INFO [FelixStartLevel] Logging initialized @892ms to org.eclipse.jetty.util.log.Slf4jLog16:47:17.014 INFO [FelixStartLevel] EventAdmin support is not available, no servlet events will be posted!16:47:17.015 INFO [FelixStartLevel] LogService support enabled, log events will be created.16:47:17.016 INFO [FelixStartLevel] Pax Web started16:47:17.282 INFO [paxweb-config-1-thread-1] No ALPN class available16:47:17.282 INFO [paxweb-config-1-thread-1] HTTP/2 not available, creating standard ServerConnector for Http16:47:17.299 INFO [paxweb-config-1-thread-1] Pax Web available at [0.0.0.0]:[8181]16:47:17.304 INFO [paxweb-config-1-thread-1] Binding bundle: [org.ops4j.pax.web.pax-web-extender-whiteboard [48]] to http service16:47:17.316 INFO [paxweb-config-1-thread-1] Binding bundle: [org.apache.karaf.examples.karaf-docker-example-app [15]] to http service16:47:17.329 INFO [paxweb-config-1-thread-1] will add org.apache.jasper.servlet.JasperInitializer to ServletContainerInitializers16:47:17.330 INFO [paxweb-config-1-thread-1] Skipt org.apache.jasper.servlet.JasperInitializer, because specialized handler will be present16:47:17.330 INFO [paxweb-config-1-thread-1] will add org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer to ServletContainerInitializers16:47:17.383 INFO [paxweb-config-1-thread-1] added ServletContainerInitializer: org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer16:47:17.383 INFO [paxweb-config-1-thread-1] will add org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer to ServletContainerInitializers16:47:17.383 INFO [paxweb-config-1-thread-1] added ServletContainerInitializer: org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer16:47:17.422 INFO [paxweb-config-1-thread-1] registering context DefaultHttpContext [bundle=org.apache.karaf.examples.karaf-docker-example-app [15], contextID=default], with context-name: 16:47:17.436 INFO [paxweb-config-1-thread-1] registering JasperInitializer16:47:17.466 INFO [paxweb-config-1-thread-1] No DecoratedObjectFactory provided, using new org.eclipse.jetty.util.DecoratedObjectFactory[decorators=1]16:47:17.540 INFO [paxweb-config-1-thread-1] DefaultSessionIdManager workerName=node016:47:17.540 INFO [paxweb-config-1-thread-1] No SessionScavenger set, using defaults16:47:17.541 INFO [paxweb-config-1-thread-1] node0 Scavenging every 600000ms16:47:17.551 INFO [paxweb-config-1-thread-1] Started HttpServiceContext{httpContext=DefaultHttpContext [bundle=org.apache.karaf.examples.karaf-docker-example-app [15], contextID=default]}16:47:17.557 INFO [paxweb-config-1-thread-1] jetty-9.4.12.v20180830; built: 2018-08-30T13:59:14.071Z; git: 27208684755d94a92186989f695db2d7b21ebc51; jvm 1.8.0_181-b1316:47:17.602 INFO [paxweb-config-1-thread-1] Started default@26472f57{HTTP/1.1,[http/1.1]}{0.0.0.0:8181}16:47:17.602 INFO [paxweb-config-1-thread-1] Started @1500ms16:47:17.605 INFO [paxweb-config-1-thread-1] Binding bundle: [org.apache.karaf.http.core [16]] to http service
We can see the runtime starting with our application.
In a browser, you can access the example servlet on http://localhost:8181/servlet-example.
Then, we can see in the log:
16:48:19.132 INFO [qtp1285811510-36] Client 0:0:0:0:0:0:0:1 request received on http://localhost:8181/servlet-example
Our runtime is running locally, now, let’s use the docker form of our runtime.
Docker
If you have Docker installed on your machine (the machine where you build), you can use the docker
profile to directly create the Docker image:
$ mvn clean install -Pdocker
If you don’t have docker on your machine, the build at least creates a Dockerfile
. By default, the Docker image name is karaf
, but you can pass the image name using the imageName
configuration:
<configuration> <imageName>${project.artifactId}</imageName></configuration>
You can use this Dockerfile
(and the whole target
) folder to create the Docker image with:
$ cd target$ docker build -t mykaraf .Sending build context to Docker daemon 57.41MBStep 1/7 : FROM openjdk:8-jre ---> d60154a7d9b2Step 2/7 : ENV KARAF_INSTALL_PATH /opt ---> Running in 9518c5e2141eRemoving intermediate container 9518c5e2141e ---> c49033d75fefStep 3/7 : ENV KARAF_HOME $KARAF_INSTALL_PATH/apache-karaf ---> Running in 6a8f314162eaRemoving intermediate container 6a8f314162ea ---> 6bd1124f27c9Step 4/7 : ENV PATH $PATH:$KARAF_HOME/bin ---> Running in ab00f87fda1dRemoving intermediate container ab00f87fda1d ---> cfa06b1e5bceStep 5/7 : COPY assembly $KARAF_HOME ---> c74c5a3adda3Step 6/7 : EXPOSE 8101 1099 44444 8181 ---> Running in 667de77413bcRemoving intermediate container 667de77413bc ---> ee720e290d7fStep 7/7 : CMD ["karaf", "run"] ---> Running in d283a0c53d93Removing intermediate container d283a0c53d93 ---> 23eb3c781a39Successfully built 23eb3c781a39Successfully tagged mykaraf:latest
You have a Docker image ready:
$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEmykaraf latest 23eb3c781a39 26 seconds ago 463MB
If you used the docker
profile, you have a karaf
Docker image ready:
$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEkaraf latest f12b3148c33e 3 seconds ago 463MB
Now, you can run a Docker container using this image:
$ docker run --name mykaraf -p 8181:8181 karafkaraf: Ignoring predefined value for KARAF_HOMEMar 21, 2019 3:55:03 PM org.apache.karaf.main.Main launchINFO: Installing and starting initial bundlesMar 21, 2019 3:55:03 PM org.apache.karaf.main.Main launchINFO: All initial bundles installed and set to startMar 21, 2019 3:55:03 PM org.apache.karaf.main.Main$KarafLockCallback lockAcquiredINFO: Lock acquired. Setting startlevel to 10015:55:04.287 INFO [FelixStartLevel] Logging initialized @957ms to org.eclipse.jetty.util.log.Slf4jLog15:55:04.298 INFO [FelixStartLevel] EventAdmin support is not available, no servlet events will be posted!15:55:04.299 INFO [FelixStartLevel] LogService support enabled, log events will be created.15:55:04.301 INFO [FelixStartLevel] Pax Web started15:55:04.515 INFO [paxweb-config-1-thread-1] No ALPN class available15:55:04.515 INFO [paxweb-config-1-thread-1] HTTP/2 not available, creating standard ServerConnector for Http15:55:04.531 INFO [paxweb-config-1-thread-1] Pax Web available at [0.0.0.0]:[8181]15:55:04.536 INFO [paxweb-config-1-thread-1] Binding bundle: [org.apache.karaf.http.core [16]] to http service15:55:04.552 INFO [paxweb-config-1-thread-1] Binding bundle: [org.apache.karaf.examples.karaf-docker-example-app [15]] to http service15:55:04.564 INFO [paxweb-config-1-thread-1] will add org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer to ServletContainerInitializers15:55:04.564 INFO [paxweb-config-1-thread-1] added ServletContainerInitializer: org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer15:55:04.565 INFO [paxweb-config-1-thread-1] will add org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer to ServletContainerInitializers15:55:04.618 INFO [paxweb-config-1-thread-1] added ServletContainerInitializer: org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer15:55:04.619 INFO [paxweb-config-1-thread-1] will add org.apache.jasper.servlet.JasperInitializer to ServletContainerInitializers15:55:04.619 INFO [paxweb-config-1-thread-1] Skipt org.apache.jasper.servlet.JasperInitializer, because specialized handler will be present15:55:04.655 INFO [paxweb-config-1-thread-1] registering context DefaultHttpContext [bundle=org.apache.karaf.examples.karaf-docker-example-app [15], contextID=default], with context-name: 15:55:04.671 INFO [paxweb-config-1-thread-1] registering JasperInitializer15:55:04.716 INFO [paxweb-config-1-thread-1] No DecoratedObjectFactory provided, using new org.eclipse.jetty.util.DecoratedObjectFactory[decorators=1]15:55:04.801 INFO [paxweb-config-1-thread-1] DefaultSessionIdManager workerName=node015:55:04.802 INFO [paxweb-config-1-thread-1] No SessionScavenger set, using defaults15:55:04.803 INFO [paxweb-config-1-thread-1] node0 Scavenging every 600000ms15:55:04.814 INFO [paxweb-config-1-thread-1] Started HttpServiceContext{httpContext=DefaultHttpContext [bundle=org.apache.karaf.examples.karaf-docker-example-app [15], contextID=default]}15:55:04.820 INFO [paxweb-config-1-thread-1] jetty-9.4.12.v20180830; built: 2018-08-30T13:59:14.071Z; git: 27208684755d94a92186989f695db2d7b21ebc51; jvm 1.8.0_181-8u181-b13-2~deb9u1-b1315:55:04.864 INFO [paxweb-config-1-thread-1] Started default@28e475cc{HTTP/1.1,[http/1.1]}{0.0.0.0:8181}15:55:04.865 INFO [paxweb-config-1-thread-1] Started @1539ms15:55:04.867 INFO [paxweb-config-1-thread-1] Binding bundle: [org.ops4j.pax.web.pax-web-extender-whiteboard [48]] to http service
By default, the runtime executes in foreground. We can use -d
to run in daemon mode:
$ docker run --name mykaraf -p 8181:8181 -d karafc05645357cd17a0828ef7acaf619071cc3c94f316ca605217890371c0c1e4ab0
We can see our container running:
$ docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESc05645357cd1 karaf "karaf run" 27 seconds ago Up 27 seconds 1099/tcp, 8101/tcp, 44444/tcp, 0.0.0.0:8181->8181/tcp mykaraf
We can see the log of our container:
$ docker logs mykarafdocker logs mykarafkaraf: Ignoring predefined value for KARAF_HOMEMar 21, 2019 3:56:45 PM org.apache.karaf.main.Main launchINFO: Installing and starting initial bundlesMar 21, 2019 3:56:45 PM org.apache.karaf.main.Main launchINFO: All initial bundles installed and set to startMar 21, 2019 3:56:45 PM org.apache.karaf.main.Main$KarafLockCallback lockAcquiredINFO: Lock acquired. Setting startlevel to 10015:56:45.831 INFO [FelixStartLevel] Logging initialized @946ms to org.eclipse.jetty.util.log.Slf4jLog15:56:45.844 INFO [FelixStartLevel] EventAdmin support is not available, no servlet events will be posted!15:56:45.845 INFO [FelixStartLevel] LogService support enabled, log events will be created.15:56:45.847 INFO [FelixStartLevel] Pax Web started15:56:46.055 INFO [paxweb-config-1-thread-1] No ALPN class available15:56:46.055 INFO [paxweb-config-1-thread-1] HTTP/2 not available, creating standard ServerConnector for Http15:56:46.071 INFO [paxweb-config-1-thread-1] Pax Web available at [0.0.0.0]:[8181]15:56:46.075 INFO [paxweb-config-1-thread-1] Binding bundle: [org.apache.karaf.examples.karaf-docker-example-app [15]] to http service15:56:46.093 INFO [paxweb-config-1-thread-1] will add org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer to ServletContainerInitializers15:56:46.093 INFO [paxweb-config-1-thread-1] added ServletContainerInitializer: org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer15:56:46.094 INFO [paxweb-config-1-thread-1] will add org.apache.jasper.servlet.JasperInitializer to ServletContainerInitializers15:56:46.094 INFO [paxweb-config-1-thread-1] Skipt org.apache.jasper.servlet.JasperInitializer, because specialized handler will be present15:56:46.094 INFO [paxweb-config-1-thread-1] will add org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer to ServletContainerInitializers15:56:46.132 INFO [paxweb-config-1-thread-1] added ServletContainerInitializer: org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer15:56:46.163 INFO [paxweb-config-1-thread-1] registering context DefaultHttpContext [bundle=org.apache.karaf.examples.karaf-docker-example-app [15], contextID=default], with context-name: 15:56:46.174 INFO [paxweb-config-1-thread-1] registering JasperInitializer15:56:46.203 INFO [paxweb-config-1-thread-1] No DecoratedObjectFactory provided, using new org.eclipse.jetty.util.DecoratedObjectFactory[decorators=1]15:56:46.272 INFO [paxweb-config-1-thread-1] DefaultSessionIdManager workerName=node015:56:46.273 INFO [paxweb-config-1-thread-1] No SessionScavenger set, using defaults15:56:46.274 INFO [paxweb-config-1-thread-1] node0 Scavenging every 660000ms15:56:46.284 INFO [paxweb-config-1-thread-1] Started HttpServiceContext{httpContext=DefaultHttpContext [bundle=org.apache.karaf.examples.karaf-docker-example-app [15], contextID=default]}15:56:46.289 INFO [paxweb-config-1-thread-1] jetty-9.4.12.v20180830; built: 2018-08-30T13:59:14.071Z; git: 27208684755d94a92186989f695db2d7b21ebc51; jvm 1.8.0_181-8u181-b13-2~deb9u1-b1315:56:46.324 INFO [paxweb-config-1-thread-1] Started default@28e475cc{HTTP/1.1,[http/1.1]}{0.0.0.0:8181}15:56:46.324 INFO [paxweb-config-1-thread-1] Started @1444ms15:56:46.326 INFO [paxweb-config-1-thread-1] Binding bundle: [org.ops4j.pax.web.pax-web-extender-whiteboard [48]] to http service15:56:46.328 INFO [paxweb-config-1-thread-1] Binding bundle: [org.apache.karaf.http.core [16]] to http service
You can now access to http://localhost:8181/servlet-example in your browser.
Then you see the logs updated in the Docker container:
$ docker logs mykaraf...15:58:24.068 INFO [qtp117150641-37] Client 172.17.0.1 request received on http://localhost:8181/servlet-example
We can stop our Docker container:
$ docker stop mykarafmykaraf
Running on AWS with Kubernetes
Now that we have our Docker image ready, we can push to AWS ECR (Docker container Registry).
First, we create a ECR repository on AWS:
Than, we tag and push our image to AWS ECR (using IAM user):
$ docker tag karaf:latest 295331841498.dkr.ecr.eu-west-1.amazonaws.com/karaf:latest$ aws ecr get-login --no-include-email --region eu-west-1 $ docker push 295331841498.dkr.ecr.eu-west-1.amazonaws.com/karaf:latest
We can now see our Karaf image on ECR:
Now that we have our Docker image on ECR, we can create cluster using it.
Let’s start with a simple ECS cluster.
Using ECS
ECS directly run docker containers (tasks).
We create a ECS cluster:
We add a new task there (Docker container):
We can see the public IP address on the task and so we can use it directly in a browser:
We can see the logs updated:
We can update the service to have multiple containers running:
We can see the service using 5 instances now:
Instead of ECS, you can use Kubernetes on EKS cluster.
Using EKS
First, let’s create the EKS cluster on AWS:
We can now access this cluster using our local kubectl
:
$ aws eks update-kubeconfig ...$ kubectl get svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.100.0.1 <none> 443/TCP 50m
We now create some nodes in our cluster:
Once the nodes are part of our cluster, we create a POD descriptor with our Karaf image:
apiVersion: v1kind: Podmetadata: name: karaf-docker-example-distspec: containers: - name: karaf-docker-example-dist-ctr image: 295331841498.dkr.ecr.eu-west-1.amazonaws.com/karaf:latest resources: limits: memory: "500Mi" requests: memory: "250Mi" command: ["karaf", "run"] args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]
Then, we create the POD in the EKS cluster:
$ kubectl create -f karaf-docker-example-dist.yaml pod/karaf-docker-example-dist created
We can see our POD boostrapping on EKS:
$ kubectl get podNAME READY STATUS RESTARTS AGEkaraf-docker-example-dist 0/1 Pending 0 2m
Conclusion
We can see here how Apache Karaf is flexible, supporting two completely different approaches:
- The “dynamic/container” approach (aka “standard” distribution) allows you to start Karaf as a “container” and deploy dynamically at runtime new applications.
- The “static” approach allows you to package all at build time and easily bootstrap your application powered by Karaf.
Your applications are able to run in both mode, it’s just a matter of assembly/packaging/distribution.
We can see here the “polymorphic” part of Apache Karaf, where you can use it on premise, on the cloud, running as a container, running as a bootstrapper, for small to large production platform.
In the coming releases, we will work to provide even better tooling for both dev and devops.
Stay tuned !
Comments
Post a Comment