Skip to main contentIBM Garage for Cloud

Inventory Micro App - Part 2

Extending Part 1 of your 3 tier app to include Continuous Delivery to Test, Securing the User Interface and integrating the service to a cloud database

Guide

This Micro App guidance continues to build upon the microserivces that were built in the Inventory Micro App Part 1 guide. Make sure you have complete Part 1 or deployed the working Inventory Solution.

In part 1, we implemented the three tiers in the Inventory Mico App and deployed the app to the dev namespace/project. In Part 2, we will take that app and make these additions:

  • Deploy the app to the test namespace/project using CD techniques and ArgoCD
  • Add application security using IBM Cloud App ID
  • Add database persistence using IBM Cloudant

Using CD to deploy to Test

ArgoCD is a tool that provides continuous delivery for projects and applications. If you haven’t already, be sure to read through the Continuous Delivery with ArgoCD guide.

For this exercise, we are going to use ArgoCD to push the Inventory app from dev to test (and possibly staging as well). If you have already completed the Inventory Micro App (see Part 1), then it can be used for the ArgoCD process (although perhaps with some minor pipeline updates). If you haven’t completed the exercise, you can start from the solution repositories to perform the ArgoCD steps.

Set up the GitOps repo

Let’s get started with using Argo CD.

  • Create a new repo from the ArgoCD Code Pattern

  • Clone the project to your machine

  • Create a branch named test

    git checkout -b test
  • Push the branch to the remote

    git push -u origin test
  • Create the test namespace with the CLI by running igc namespace test-{initials}

Register the GitOps repo in ArgoCD

Now that the repository has been created, we need to tell ArgoCD where it is.

  • Get the ArgoCD login information from the igc credentials cli command

  • Log into ArgoCD (use igc credentials to obtain your credentials and login to argo)

  • Click on the gear icon on the left menu to access the Settings options

    ArgoCD config

  • Select the Repositories option

  • Click either the Connect Repo using HTTPS or Connect Repo using SSH button at the top and provide the information for the GitOps repo you just created.

Create a project in ArgoCD (Optional)

In ArgoCD terms, each deployable component is an Application and applications are grouped into Projects. Projects are not required for ArgoCD to be able to deploy applications but it helps to organize applications and provide some restrictions on what can be done for applications that make up a project.

To create a project, do the following:

  • Log into ArgoCD

  • Click on the gear icon on the left menu to access the Settings options

    ArgoCD config

  • Select the Projects option

  • Click the New Project button at the top of the page.

  • Provide the following values then press Create:

    • name - the name for the project (provide `inventory-management)

    • description - a brief description of the project

    • sources - click add source and pick the Git repository from the list that was added previously

    • destinations - Add https://kubernetes.default.svc for the cluster url and test-{initials} for the namespace - Add https://kubernetes.default.svc for the cluster url and staging-{initials} for the namespace

      Note: Initially, the only cluster that is available is the one in which ArgoCD is - https://kubernetes.default.svc. By adding the two destinations we have allowed the project to be deployed to both the test-{initials} and staging-{initials} namespaces within the current cluster.

Configure the GitOps repo for Inventory Management service

  • Copy the app-artifactory folder and give it a name that matches the Inventory Management service component (e.g. inventory-management-svc-{initials})

  • Update inventory-management-svc-{initials}/Chart.yaml and update the name to match the directory name

  • Update inventory-management-svc-{initials}/requirements.yaml with the following values:

    • name - the name of helm chart/image. This should match the folder name
    • version - the version number of the helm chart
    • repository - the url to the helm repository including the folder where helm charts are being stored.
  • here is an example

    dependencies:
    - name: inventory-management-svc-mjp
    version: 1.0.0-1
    repository: http://artifactory.mooc-one-rhos-cluster.us-east.containers.appdomain.cloud/artifactory/generic-local/mooc-team-one/
  • Run kubectl get configmap/ibmcloud-config -n tools -o yaml to print the configuration information for the cluster

  • In inventory-management-svc-{initials}/values.yaml replace <app-chart-name> with the directory name. Replace ingressSubdomain with the value from the previous step. Update tlsSecretName with the value from the previous step. The result should look something like the following

    inventory-management-svc-{initials}/values.yaml
    global:
    ingressSubdomain: sms-test.us-south.containers.appdomain.cloud
    tlsSecretName: sms-test-cluster
    inventory-management-svc-{initials}:
    replicaCount: 1
    ingress:
    enabled: true
  • Commit and push the changes

    git add .
    git commit -m "Adds inventory-management-svc config"
    git push

Add an application in ArgoCD for the Inventory Management service

The last step in the process is to define the application(s) within ArgoCD that should be managed. This consists of connecting the config within the Git repo to the cluster and namespace.

  • Log into ArgoCD

  • Click New Application and provide the following values:

    • application name - test-inventory-management-svc
    • project - inventory-management
    • sync-policy - Automatic
    • repository url - The Git url where the configuration is stored
    • revision - test
    • path - inventory-management-svc-{initials}
    • destination cluster - The cluster url for the deployment
    • destination namespace - test-{initials}
    • values file - values.yaml
  • Click Create

  • Click on the newly created application. A graph of kubernetes resources should be shown if everything is configured correctly.

Make a change in the GitOps repo

In order to trigger a (re-)deployment we can make an update to a value in the GitOps repo and watch ArgoCD apply the change.

  • Open a terminal and navigate to your GitOps repo directory

  • Be sure that you are in the test branch

    git checkout test
  • Update inventory-management-svc-{initials}/values.yaml to increase the replica count

    inventory-management-svc-{initials}/values.yaml
    global:
    ingressSubdomain: sms-test.us-south.containers.appdomain.cloud
    tlsSecretName: sms-test-cluster
    inventory-management-svc-{initials}:
    replicaCount: 3
    ingress:
    enabled: true
  • Commit and push the change

    git add .
    git commit -m "Increases replica count"
  • Log into the ArgoCD UI and look at the state of the application. It should say Synchronizing. If you don’t want to wait you can manually by pressing the Synchronize button.

Hook the CI pipeline to the CD pipeline

The last stage in the CI pipeline updates the version number in the requirements.yaml to the version of the helm chart that was just built. Through a couple naming conventions the only thing the pipeline needs in order to interact with the CD process is a kubernetes secret named gitops-cd-secret that provides the details needed to connect to the git repo to push updates.

The IGC CLI has a command that provides a helper to make the creating of a kubernetes secret with git credentials very easy.

  • Log into the cluster on the command-line.

  • Change the directory to the root of the ArgoCD Code Pattern repo that was cloned previously.

  • Run igc git-secret gitops-repo -n dev-{initials} to create the secret. This command will prompt for the username, personal access token, and the branch to put in the secret.

What just happened?

  • The git-secret command creates a secret in a kubernetes namespace containing the url, username, password, and branch information for a git repo. In the command above, we provided gitops-cd-secret for the secret name. (If that value is left off the secret name defaults to {git org}.{git repo}.) You can verify the secret was created by running:
    kubectl get secrets/gitops-cd-secret -n dev-{initials} -o yaml

Note:

  • For the secret to be available to the CI pipeline, the secret needs to be created in the same namespace where the pipeline is running (e.g. dev-{initials}).

  • The value provided for branch is the one the pipeline will use to when committing changes to trigger the CD pipeline. test is the recommended value for the branch field.

  • Trigger the pipeline for the Inventory Management service to build by making a change to the Inventory Management Service code and push the changes to Git.

Repeat for BFF and UI components

Starting from Configure the GitOps repo for Inventory Management service, the steps need to be repeated for each application within the project.

Securing the solution with App ID

To secure the application we are using the capabilities available within the IBMCloud platform that use a simple annotation on the ingress to enable integration with AppId. The Code Patterns have already been set up to use this feature and all that is required is update the configuration within the values.yaml file of the helm chart.

Inventory Management UI

  • Find the app id binding secret by running the following command from a terminal where the kubernetes context has been set up (i.e. oc login has been done)

    kubectl get -n dev secrets | grep -E "binding.*appid"
  • Update the values.yaml file in the Inventory Management UI chart to set ingress.appId.enabled=true and to set the value for the AppId binding secret from the previous step

    /chart/template-node-react/values.yaml
    ...
    ingress:
    enabled: true
    appid:
    enabled: true
    # web or app - https://cloud.ibm.com/docs/services/appid?topic=appid-kube-auth
    requestType: web
    binding:

AppId redirect url config

  • Get the ingress for the UI component by running igc ingress -n dev-{initials}.

  • Open the IBM Cloud resource list - https://cloud.ibm.com/resources

  • Open the AppId instance to the Manage Authentication -> Authentication Settings view

    AppId authentication settings

  • Add the redirect url for the application to the web redirect URLs. The redirect url will have the following form:

    `{ingress url}/appid_callback`
    e.g. `https://inventory-manangement-ui-dev.sms-test-oc-cluster.us-east.containers.appdomain.cloud/appid_callback`

Add users to AppId

  • Open the AppId instance to Cloud Directory -> Users

    AppId cloud directory users

  • Add yourself as a user with an email address, name, and password

Access the UI

  • Open a browser to the UI ingress

  • You should be met with the AppId login screen. (This screen can be customized from the AppId service console but for now we are showing the default screen.)

  • Provide the email address and password you configured in the previous steps. You should be granted access to the UI.

Add a Cloudant integration to your backend service

  • While logged into the IBM Cloud account use the resource list to find your pre installed Cloudant database instance name after your development cluster.

  • Open the database instance dashboard.

  • Click on the Service Credentials on the left-hand menu.

  • You will see the credentials for the database.

  • Open a terminal window folder/directory called data

    mkdir data
  • To help create test JSON data we are going to supply a template to the JSON Generator tool, this helps when creating dummy data for testing. Navigate to the following link https://www.json-generator.com/

  • Replace the default template with the following template (using cut and paste). This will enable a 100 records of test data to be created to represent a products database. Click on the Generate button.

    [
    '{{repeat(1, 50)}}',
    {
    id: '{{objectId()}}',
    manufacturer: '{{company().toUpperCase()}}',
    name: '{{lorem(3, "words")}}',
    price: '{{floating(10, 1000, 2, "0.00")}}',
    stock: '{{integer(1, 100)}}'
    }
  • Copy the generated contents on the right hand side into a file called inventory.json and save it into the same folder. Wrap the array with a docs statement.

    {
    "docs": <Add Generated array here>
    }
  • Save the documents that will be loaded into Cloudant

  • Add the username and apikey to CLOUDANT_USERNAME and CLOUDANT_API_KEY variables in the dataload.sh script. You can get the credentials from the Cloudant credentials view in the IBM Cloud console.

  • Add DATABASE value to be inventory-<replace with namespace> using the dev namespace/project name you have been using.

  • Save the script, make it executable, and then run it by passing in the filename

    chmod +x ./dataload.sh
    ./dataload.sh inventory.json
  • The data from the inventory.json file will then be used to populate the database, to confirm this on the Dashboard click on Manage menu on the left and then Launch button to see the Cloudant dashboard.

  • Click on the Left icon that looks like a Database and you will see the inventory-<namespace> database created.

  • Click on the inventory database, then click Table view.

  • You can see the rows of data Database

  • If you click on a row of data, you will see the raw NoSQL form of the data record.

  • This completes the setup of the database and populating it with data.

Enable database in the solution

If you are starting from the solution, use the following steps to enable the Cloudant database

Set up local development

  • Open the mappings.json file under src/main/resources and add a DATABASE_NAME value with the value inventory-{namespace} where namespace is the namespace where the pipeline is running (e.g. dev-{initials})

    src/main/resources/mappings.json
    {
    "DATABASE_NAME": "inventory-{namespace}"
    }
  • Log into cloud.ibm.com and open the Cloudant service from the resource list

  • Click on service credentials and expand the listed credentials

  • Copy the json contents from the credentials into mappings.json under the CLOUDANT_CONFIG object (note that CLOUDANT_CONFIG value must be a string type not a json type, so you must use escaping characters for this value)

    src/main/resources/mappings.json
    {
    "DATABASE_NAME": "inventory-{namespace}",
    "CLOUDANT_CONFIG": "{paste json here}"
    }

Activate the Clouant service implementation

  • Open src/main/java/com/ibm/inventory_management/services/StockItemMockService.java and remove the @Primary annotation

  • Open src/main/java/com/ibm/inventory_management/services/StockItemService.java and add the @Primary annotation. The file should look like the following

    src/main/java/com/ibm/inventory_management/services/StockItemService.java
    package com.ibm.inventory_management.services;
    import java.io.IOException;
    import java.util.List;
    import javax.annotation.PostConstruct;
    import org.springframework.context.annotation.Primary;
    import org.springframework.stereotype.Service;

Update the configuration values in the values.yaml helm chart

  • Open the values.yaml file and update the values for cloudantBinding and databaseName

    chart/template-java-spring/values.yaml
    cloudantBinding="{binding name}"
    databaseName="inventory-{namespace}"

    Note: The cloudantBinding value should match the name of the cloudant binding secret

(For manual solution) Add a Cloudant integration to your backend service

If you are following the instructions from MicroApp part 1 and want to enable the Cloudant database yourself, use the following directions.

Update the gradle config to include cloudant dependencies

  • Add build-services.gradle to the gradle folder
gradle/build-cloudant.gradle
dependencies {
compile group: 'com.cloudant', name: 'cloudant-client', version: '2.17.0'
compile group: 'com.jayway.jsonpath', name: 'json-path', version: '2.4.0'
compile group: 'javax.xml.bind', name: 'jaxb-api', version: '2.1'
compile group: 'joda-time', name: 'joda-time', version: '2.10.3'
}
  • Enable the cloudant libraries by applying the build-cloudant.gradle to the end of the build.gradle file
build.gradle
apply from: 'gradle/build-cloudant.gradle'
  • Run ./gradlew init to validate the changes and load the libraries

Add configuration values

  • Add CloudantConfig to hold the url, username, password, and databaseName values
src/main/java/com/ibm/inventory_management/config/CloudantConfig.java
package com.ibm.inventory_management.config;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@JsonIgnoreProperties(ignoreUnknown = true)
public class CloudantConfig {
private String url;
private String username;
private String password;
  • Implement logic to load the configuration from the secret binding or local file
src/main/java/com/ibm/inventory_management/config/CloudantMapping.java
package com.ibm.inventory_management.config;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonProperty;
public class CloudantMapping implements Serializable {
@JsonProperty(value = "CLOUDANT_CONFIG")
private String cloudantConfig;
src/main/java/com/ibm/inventory_management/config/CloudantConfigFactory.java
package com.ibm.inventory_management.config;
import java.io.IOException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component

Set up local development

  • Open the mappings.json file under src/main/resources and add a DATABASE_NAME value with the value inventory-{namespace} where namespace is the namespace where the pipeline is running (e.g. dev-{initials})
src/main/resources/mappings.json
{
"DATABASE_NAME": "inventory-{namespace}"
}
  • Log into cloud.ibm.com and open the Cloudant service from the resource list

  • Click on service credentials and expand the listed credentials

  • Copy the json contents from the credentials into mappings.json under the CLOUDANT_CONFIG object

src/main/resources/mappings.json
{
"DATABASE_NAME": "inventory-{namespace}",
"CLOUDANT_CONFIG": "{paste json here}"
}

Implement the service

  • Add a CloudantApi component to create the CloudantClient instance from the configuration
src/main/java/com/ibm/inventory_management/services/CloudServicesException.java
package com.ibm.inventory_management.services;
public class CloudServicesException extends Exception {
public CloudServicesException() {
}
public CloudServicesException(String message) {
super(message);
}
src/main/java/com/ibm/inventory_management/services/CloudantApi.java
package com.ibm.inventory_management.services;
import java.net.MalformedURLException;
import java.net.URL;
import com.cloudant.client.api.ClientBuilder;
import com.cloudant.client.api.CloudantClient;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
  • Add the service implementation
src/main/java/com/ibm/inventory_management/services/StockItemService.java
package com.ibm.inventory_management.services;
import java.io.IOException;
import java.util.List;
import javax.annotation.PostConstruct;
import com.cloudant.client.api.CloudantClient;
import com.cloudant.client.api.Database;
import org.springframework.context.annotation.Primary;
  1. Remove the @Primary annotation from the mock service

Add the values to the helm chart

  • Open the values.yaml file and add properties for cloudantBinding and databaseName to the top of the file
chart/template-java-spring/values.yaml
cloudantBinding="{binding name}"
databaseName="inventory-{namespace}"
**Note:** The cloudantBinding value should match the name of the cloudant binding secret
  • Open the deployment.yaml file and add environment variables that use those values to the top of the existing env block
chart/template-java-spring/templates/deployment.yaml
env:
- name: CLOUDANT_CONFIG
valueFrom:
secretKeyRef:
name: {{ .Values.cloudantBinding | quote }}
key: binding
- name: DATABASE_NAME
value: {{ .Values.databaseName | quote }}

Review Application End to End

Now that you have completed Part 1, and Part 2 you should review your application functionality end to end. This pattern for three tier applications is very common in the industry and being and hopefully you have learnt a lot of along the way of creating this Micro App.

Summary

You have now completed the Micro App Guide demonstrating the Inventory solution.