IBM Z Day on Nov. 21: Discover the ideal environment for modern, mission-critical workloads. Learn more

Develop a custom Appsody template

Appsody is an open source project that simplifies your cloud-native application development. Appsody stacks build a pre-configured Docker image that is ready for you to deploy in a cloud environment. These Docker images can include any amount of customized content and allow stack builders to decide which parts are fixed (stack image) and which parts application developers can modify or extend (templates).

This article gives you a quick introduction to the process of creating a new Appsody template. A stack architect generally creates a template in an existing stack, so that the application developers working on that stack can use the template to quickly develop their application.

Repositories, stacks, and templates

Before we show you how to create a new template, let’s review the different parts of Appsody, including the stacks, repositories, and templates.

An Appsody application contains a Docker image created from a stack and injects the template and the application developer’s files into it. Because Dockerfiles are part of the stack, they can’t be modified by an application developer accessing a stack. However, templates are copied into your working directory during the appsody init process. So application developers are free to make changes to anything that’s part of the template, which is combined with the stack image during the appsody build phase. Repositories are collections of stacks and their corresponding templates. Repositories can be referenced from remote sources (e.g., GitHub) or can be stored locally on a filesystem.

See the Create an Appsody stack tutorial to learn how to create an entirely new stack.

Appsody roles

  • A stack architect creates stacks and templates that define the set of technologies (and their versions), as well as chosen solutions for monitoring, logging, and health for given classes of applications.

  • An application developer uses Appsody stacks and templates to write applications without having to know how to install or configure the technologies involved, or to know about any particular deployment requirements for those technologies.

Step 1: Clone an Appsody repository

Clone an existing appsody repository:

 git clone https://github.com/appsody/stacks.git

This downloads a collection of stacks and templates you can work with locally. If you look at the contents of the Java MicroProfile stack at incubator/java-microprofile/templates, you’ll notice there is one template included, default. (This is the template that appsody init uses to create an application instance.)

$ [master] [k|] #  tree incubator/java-microprofile/templates
incubator/java-microprofile/templates                                                                                                                                                               
└── default                                                                                                                                                                                         
    ├── pom.xml                                                                                                                                                                                     
    └── src                                                                                                                                                                                         
        ├── main                                                                                                                                                                                    
        │   ├── java                                                                                                                                                                                
        │   │   └── dev                                                                                                                                                                             
        │   │       └── appsody
        │   │           └── starter
        │   │               ├── health
        │   │               │   ├── StarterLivenessCheck.java
        │   │               │   └── StarterReadinessCheck.java
        │   │               └── StarterApplication.java
        │   ├── liberty
        │   │   └── config
        │   │       └── server.xml
        │   └── webapp
        │       ├── index.html
        │       └── WEB-INF
        │           └── beans.xml
        └── test
            └── java
                └── it
                    └── dev
                        └── appsody
                            └── starter
                                └── HealthEndpointTest.java

18 directories, 8 files

Step 2: Add your template code

The following code shows you how to add a new template called rest that contains minimal REST endpoints for creating, deleting, and managing resources. In Appsody, application developers fill in the sections in the template with business logic for their specific use cases. You can also include much more sophisticated embedded logic in the templates.

The source code for this template is here: https://github.com/ykoyfman/appsody-repo/tree/master/template. Note that I did not include the HealthEndpoint from the new template to keep it as small as possible for this example.

    @GET
    @Path("/v1/StarterGet")
    @Produces(MediaType.APPLICATION_JSON)
    public Response StarterGet() {

        return Response.ok("{\"status:\":\"ok\"}").build();
    }

    @POST
    @Path("/v1/StarterPost")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response StarterPost(String body) {

        return Response.ok("{\"status:\":\"ok\"}").build();         
    }

This example creates a minimal JAX-RS based REST API project, so we only need to add a couple of files into the src tree. After creating the new template, this is the new structure under the “stacks” directory.

I include the server.xml from the default template, as this adds the MicroProfile 3.0 feature that pulls in many features required for web development (JAX-RS, OpenAPI, JSON libraries, etc.)

With both templates, this is the directory structure:

$ [master|?] [k|] #  tree incubator/java-microprofile/templates    
incubator/java-microprofile/templates
├── default
│   ├── pom.xml
│   └── src
│       ├── main
│       │   ├── java
│       │   │   └── dev
│       │   │       └── appsody
│       │   │           └── starter
│       │   │               ├── health
│       │   │               │   ├── StarterLivenessCheck.java
│       │   │               │   └── StarterReadinessCheck.java
│       │   │               └── StarterApplication.java
│       │   ├── liberty
│       │   │   └── config
│       │   │       └── server.xml
│       │   └── webapp
│       │       ├── index.html
│       │       └── WEB-INF
│       │           └── beans.xml
│       └── test
│           └── java
│               └── it
│                   └── dev
│                       └── appsody
│                           └── starter
│                               └── HealthEndpointTest.java
└── rest
    ├── pom.xml
    └── src
        └── main
            ├── java
            │   └── com
            │       └── ibm
            │           └── starter
            │               ├── JAXRSConfiguration.java
            │               └── StarterResource.java
            ├── liberty
            │   └── config
            │       └── server.xml
            ├── resources
            │   └── META-INF
            │       └── persistence.xml
            └── webapp
                └── WEB-INF
                    └── beans.xml

31 directories, 14 files

However, the template is not ready for use yet. For that, you have to run a build script to recreate the stack archive and add this new stack and template to our local repository.

Step 3: Add new template to local Appsody repository

Once the directory structure and source files are created, use the following command to build the stack with the new template and add it to the local Appsody repository index. Note that this should be run from the incubator/java-microprofile path:

appsody stack package

See Appsody product documentation for further details. Once the build process completes, the new stack and template are available in a local repository.

Step 4: Verify the new template is available

Now you need to verify the new repository is present. The previous step added the new stack (and new template) to a local repository called incubator-index-local.

$  [k|] #  appsody list dev.local

REPO                    ID                      VERSION         TEMPLATES         DESCRIPTION                                              
dev.local              java-microprofile       0.2.17          *default, rest    Eclipse MicroProfile on Open Liberty & OpenJ9 using Maven

In the next steps, I show you how to create, run, and modify an application based on the template.

Step 5: Create an Appsody application based on the new template

You can use the appsody init command with the appropriate arguments (as shown below) to create an application based on this template.

$  [k|] #  appsody init dev.local/java-microprofile rest
Running appsody init...
<..Appsody messages..>
Successfully initialized Appsody project

At this point, let’s run the application to verify it’s working before we starting adding code to customize the template to our use case.

Step 6: Run your application

One the application is initialized, you can run it in a local Docker container. During this process, Appsody creates a Docker container based on the parent stack Dockerfile, and combines it with the source code in the template. In this case, the java-microprofile stack pulls in Open Liberty 19.x

$  [k|] #  appsody run
Running development environment...
Pulling docker image appsody/java-microprofile:0.2
Running command: docker pull appsody/java-microprofile:0.2
0.2: Pulling from appsody/java-microprofile
5667fdb72017: Pulling fs layer
... many layers ...
Running docker command: docker run --rm -p 7777:7777 -p 9080:9080 -p 9443:9443 --name rest-dev -v /home/yan/.m2/repository:/mvn/repository -v /home/yan/src/adv/appsody/template/rest/src:/project/user-app/src -v /home/yan/src/adv/appsody/template/rest/pom.xml:/project/user-app/pom.xml -v /home/yan/.appsody/appsody-controller:/appsody/appsody-controller -t --entrypoint /appsody/appsody-controller appsody/java-microprofile:0.2 --mode=run
[Container] Running APPSODY_PREP command: ../validate.sh && mvn -B -Dmaven.repo.local=/mvn/repository install -DskipTests
[Container] Installing parent dev.appsody:java-microprofile:0.2.17

<Maven build snipped>

[Container] [INFO] [AUDIT   ] CWWKT0016I: Web application available (default_host): http://a28ea1bb33d3:9080/openapi/ui/
[Container] [INFO] [AUDIT   ] CWWKT0016I: Web application available (default_host): http://a28ea1bb33d3:9080/metrics/
[Container] [INFO] [AUDIT   ] CWWKT0016I: Web application available (default_host): http://a28ea1bb33d3:9080/health/
[Container] [INFO] [AUDIT   ] CWWKT0016I: Web application available (default_host): http://a28ea1bb33d3:9080/ibm/api/
[Container] [INFO] [AUDIT   ] CWWKT0016I: Web application available (default_host): http://a28ea1bb33d3:9080/jwt/
[Container] [INFO] [AUDIT   ] CWWKT0016I: Web application available (default_host): http://a28ea1bb33d3:9080/openapi/
[Container] [INFO] [AUDIT   ] CWWKT0016I: Web application available (default_host): http://a28ea1bb33d3:9080/
[Container] [INFO] [AUDIT   ] CWWKZ0001I: Application starter-app started in 2.777 seconds.
[Container] [INFO] [AUDIT   ] CWWKF0012I: The server installed the following features: [appSecurity-2.0, cdi-2.0, concurrent-1.0, distributedMap-1.0, jaxrs-2.1, jaxrsClient-2.1, jndi-1.0, json-1.0, jsonb-1.0, jsonp-1.1, jwt-1.0, microProfile-3.0, mpConfig-1.3, mpFaultTolerance-2.0, mpHealth-2.0, mpJwt-1.1, mpMetrics-2.0, mpOpenAPI-1.1, mpOpenTracing-1.3, mpRestClient-1.3, opentracing-1.3, servlet-4.0, ssl-1.0].
[Container] [INFO] [AUDIT   ] CWWKF0011I: The defaultServer server is ready to run a smarter planet. The defaultServer server started in 12.150 seconds.

Notice that the application developer’s code is made available inside the container: -v /home/yan/src/adv/appsody/template/rest/src:/project/user-app/src so it can be accessed in subsequent part of the Maven build process.

The build downloads the stack base image (Open Liberty + Open J9 JVM) and combines the base stack container with the template and custom code. Eventually, the build completes and the Open Liberty application server starts, running our REST starter app.

When the appsody run completes, check docker ps to ensure that the container was created. Because the Docker container forwarded the ports we need to connect to our application, we can start testing it right away.

$ [master|?] [k|] #  docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                                                                    NAMES
5cab68e81425        appsody/java-microprofile:0.2   "/appsody/appsody-co…"   7 minutes ago       Up 7 minutes        0.0.0.0:7777->7777/tcp, 0.0.0.0:9080->9080/tcp, 0.0.0.0:9443->9443/tcp   r2-dev

If you point your web browser at OpenAPI URL at http://localhost:9080/openapi/ui, you’ll see that the REST endpoints in the template are available for testing:

openapi

Step 7: Modify your Appsody application

The benefit of putting this kind of code into an Appsody stack template is that you get all the features of the Appsody CLI and tooling (see more articles here. One of my favorite benefits is the Appsody daemon (appsody-controller) that watches for file changes in your source code directory. So, when you make a change and save the file, Appsody rebuilds it and restarts the application inside the Docker container.

The animation below shows how a simple change to the application (when the file is saved) causes the application to rebuild and restart in a few seconds.

Initially, there are four REST endpoints in our StarterApp. In the animation, I add a fifth one called “MyNewAPI” by:

  1. Copying the information from the other endpoints and pasting it below in the CLI.
  2. Replacing “/v1/StarterUpdate” with the name of my new API: “MyNewAPI”.
  3. Save the changes.

Once the code changes are done and the file is saved, you can see that the Maven build is rerun inside the Docker container, and the Open Liberty server quickly reloads the app. When the browser is refreshed, the new (fifth) endpoint is available.

Open Liberty changes

Conclusion

Using Appsody can help you get started creating cloud-native applications through its use of pre-built stacks and templates. In this article, we showed you how to extend Appsody to provide new functions in an existing technology stack.

Yan Koyfman