<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Kok Sing Khong on Medium]]></title>
        <description><![CDATA[Stories by Kok Sing Khong on Medium]]></description>
        <link>https://medium.com/@khongks?source=rss-dbd3cf73ac04------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*-l7mc2ZjWthEea9MtLKnOQ@2x.jpeg</url>
            <title>Stories by Kok Sing Khong on Medium</title>
            <link>https://medium.com/@khongks?source=rss-dbd3cf73ac04------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 23:36:54 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@khongks/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[API Connect installation with 2nd Gateway Cluster]]></title>
            <link>https://khongks.medium.com/api-connect-installation-with-2nd-gateway-cluster-9f90790be627?source=rss-dbd3cf73ac04------2</link>
            <guid isPermaLink="false">https://medium.com/p/9f90790be627</guid>
            <dc:creator><![CDATA[Kok Sing Khong]]></dc:creator>
            <pubDate>Thu, 04 May 2023 16:38:14 GMT</pubDate>
            <atom:updated>2023-05-04T16:38:14.119Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*y81j3U_hdgrTkWDQmSZokg.png" /></figure><p>The write-up describes how to install API Connect with the secondary GatewayCluster. When you install API Connect using the top-level custom resource (CR) called APIConnectCluster, all the subsystems will be installed — Management cluster, Analytics cluster, Portal cluster and gateway cluster.</p><p>In many cases, you will need a second Gateway cluster for external APIs. You can deploy using the custom resource (CR) called GatewayCluster.</p><p>We should assume that we have these components installed</p><ol><li>Red Hat OpenShift Container Platform v4.12</li><li>Cloud Pak for Integration (common services) v2022.4.1</li><li>API Connect Operator 3.3</li></ol><p>Steps</p><ol><li>Create a project/namespace</li></ol><pre>% oc new-project apic</pre><p>2. Create an IBM entitlement key</p><pre>% oc create secret docker-registry ibm-entitlement-key \<br>    --docker-username=cp \<br>    --docker-password=[REPLACE_ME]<br>    --docker-server=cp.icr.io \<br>    --namespace=apic</pre><p>3. Create <em>APIConnectCluster</em> by applying the following YAML file.</p><pre>% oc apply -f apiconnectcluster.yaml -n apic</pre><pre>## apiconnectcluster.yaml<br>apiVersion: apiconnect.ibm.com/v1beta1<br>kind: APIConnectCluster<br>metadata:<br>  name: myapic<br>  labels:<br>    app.kubernetes.io/instance: apiconnect<br>    app.kubernetes.io/managed-by: ibm-apiconnect<br>    app.kubernetes.io/name: myapic<br>  namespace: apic<br>spec:<br>  license:<br>    accept: true<br>    license: L-VQYA-YNM22H<br>    metric: VIRTUAL_PROCESSOR_CORE<br>    use: nonproduction<br>  gateway:<br>    datapowerLogLevel: 3<br>    replicaCount: 1<br>    webGUIManagementEnabled: true<br>    webGUIManagementPort: 9090<br>  analytics:<br>    storage:<br>      enabled: true<br>      type: shared<br>    mtlsValidateClient: true<br>  portal:<br>    mtlsValidateClient: true<br>  profile: n1xc7.m48<br>  version: 10.0.5.3</pre><p>4. Create <em>Certificates</em> for external gateway.</p><pre>% oc apply -f ext-gw-certificate.yaml -n apic</pre><pre>## ext-gw-certificate.yaml<br>apiVersion: cert-manager.io/v1<br>kind: Certificate<br>metadata:<br>  name: myapic-ext-gw-svc<br>  labels: {<br>    app.kubernetes.io/instance: &quot;myapic&quot;,<br>    app.kubernetes.io/managed-by: &quot;ibm-apiconnect&quot;,<br>    app.kubernetes.io/name: &quot;myapic-ext-gw-svc&quot;<br>  }<br>spec:<br>  commonName: myapic-ext-gw-svc<br>  secretName: myapic-ext-gw-svc<br>  issuerRef:<br>    name: myapic-ingress-issuer<br>  usages:<br>  - &quot;client auth&quot;<br>  - &quot;signing&quot;<br>  - &quot;key encipherment&quot;<br>  duration: 17520h # 2 years<br>  renewBefore: 48h<br>---<br>apiVersion: cert-manager.io/v1<br>kind: Certificate<br>metadata:<br>  name: myapic-ext-gw-peer<br>  labels: {<br>    app.kubernetes.io/instance: &quot;myapic&quot;,<br>    app.kubernetes.io/managed-by: &quot;ibm-apiconnect&quot;,<br>    app.kubernetes.io/name: &quot;myapic-ext-gw-peer&quot;<br>  }<br>spec:<br>  commonName: myapic-ext-gw-peer<br>  secretName: myapic-ext-gw-peer<br>  issuerRef:<br>    name: myapic-ingress-issuer<br>  usages:<br>  - &quot;server auth&quot;<br>  - &quot;client auth&quot;<br>  - &quot;signing&quot;<br>  - &quot;key encipherment&quot;<br>  duration: 17520h # 2 years<br>  renewBefore: 48h</pre><p>5. Create admin secret for external gateway.</p><pre>% oc create secret generic myapic-ext-gw-admin --from-literal=password=[REPLACE_ME]</pre><p>6. Create <em>GatewayCluster</em> by applying the following YAML file.</p><pre>% oc apply -f ext-gatewaycluster.yaml -n apic</pre><pre>## ext-gatewaycluster.yaml<br>apiVersion: gateway.apiconnect.ibm.com/v1beta1<br>kind: GatewayCluster<br>metadata:<br>  name: myapic-ext-gw<br>  labels:<br>    app.kubernetes.io/part-of: myapic<br>spec:<br>  version: 10.0.5.3<br>  profile: n1xc4.m8<br>  apicGatewayServiceV5CompatibilityMode: false<br>  gatewayEndpoint:<br>    annotations:<br>      cert-manager.io/issuer: myapic-ingress-issuer<br>    hosts:<br>    - name: [NAME]-gateway-[NAMESPACE].[DOMAIN_NAME]<br>      secretName: myapic-ext-gw<br>  gatewayManagerEndpoint:<br>    annotations:<br>      cert-manager.io/issuer: myapic-ingress-issuer<br>    hosts:<br>    - name: [NAME]-gateway-manager-[NAMESPACE].[DOMAIN_NAME]<br>      secretName: [NAME]-gateway-manager<br>  apicGatewayServiceTLS:<br>    secretName: myapic-ext-gw-svc<br>  apicGatewayPeeringTLS:<br>    secretName: myapic-ext-gw-peer<br>  certManagerIssuer:<br>    kind: Issuer<br>    name: myapic-self-signed<br>  datapowerLogLevel: 3<br>  defaultLogFormat: text<br>  replicaCount: 1<br>  webGUIManagementEnabled: true<br>  webGUIManagementPort: 9090<br>  configSequenceInterval: 3000<br>  mtlsValidateClient: false<br>  apiDebugProbeMaxRecords: 1000<br>  apiDebugProbe: true<br>  apiDebugProbeExpirationMinutes: 60<br>  license:<br>    accept: true<br>    use: nonproduction<br>    license: L-VQYA-YNM22H<br>    metric: VIRTUAL_PROCESSOR_CORE<br>  adminUser:<br>    secretName: myapic-ext-gw-admin</pre><p>7. Check the status of the <em>APIConnectCluster</em> deployment.</p><pre>% oc get apiconnectcluster -n apic<br>NAME     READY   STATUS   VERSION    RECONCILED VERSION   MESSAGE                        AGE<br>myapic   7/7     Ready    10.0.5.3   10.0.5.3-4934        API Connect cluster is ready   2d12h</pre><p>8. Check the status of the <em>GatewayCluster</em> deployment.</p><pre>NAME            READY   STATUS    VERSION    RECONCILED VERSION   AGE<br>myapic-ext-gw   2/2     Running   10.0.5.3   10.0.5.3-4934        2d12h<br>myapic-gw       2/2     Running   10.0.5.3   10.0.5.3-4934        2d12h</pre><p>9. After installation is complete, you will need to Register the Gateway.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9f90790be627" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[App Connect Enterprise on K8S]]></title>
            <link>https://khongks.medium.com/app-connect-enterprise-on-k8s-69adbfd8cb2a?source=rss-dbd3cf73ac04------2</link>
            <guid isPermaLink="false">https://medium.com/p/69adbfd8cb2a</guid>
            <category><![CDATA[k8s]]></category>
            <category><![CDATA[azure-kubernetes-service]]></category>
            <category><![CDATA[app-connect-enterprise]]></category>
            <dc:creator><![CDATA[Kok Sing Khong]]></dc:creator>
            <pubDate>Sat, 25 Mar 2023 01:14:40 GMT</pubDate>
            <atom:updated>2023-03-25T01:14:40.584Z</atom:updated>
            <content:encoded><![CDATA[<p>The following is tested on Azure Kubernetes Server (AKS).</p><p>Tools to be installed:</p><ol><li>Kubernetes CLI (kubectl)</li><li>Helm CLI (helm)</li><li>Operator SDK (olm)</li><li>Curl</li></ol><h3><strong>Install certificate manager</strong></h3><p>(1) Run the following command to install the cert-manager resources from a YAML manifest file on GitHub:</p><pre>% kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yaml</pre><p>(2) To verify the installation</p><pre>% kubectl get pods --namespace cert-manager<br>NAME                                       READY   STATUS    RESTARTS   AGE<br>cert-manager-655bf9748f-4t5fd              1/1     Running   0          41s<br>cert-manager-cainjector-7985fb445b-7hfpb   1/1     Running   0          42s<br>cert-manager-webhook-6dc9656f89-qcf5n      1/1     Running   0          40s</pre><p>(3) Run the following command to patch your deployment. Do not replace ${POD_NAMESPACE} in this command; this value is referenced within the <strong><em>cert-manager.yaml</em></strong> file. When the command completes, it adds a flag to ensure that any auto-generated secrets that store certificates are automatically removed when necessary.</p><pre>% kubectl patch deployment \<br>  cert-manager \<br>  --namespace cert-manager  \<br>  --type=&#39;json&#39; \<br>  -p=&#39;[{&quot;op&quot;: &quot;replace&quot;, &quot;path&quot;: &quot;/spec/template/spec/containers/0/args&quot;, &quot;value&quot;: [<br>  &quot;--v=2&quot;,<br>  &quot;--cluster-resource-namespace=$(POD_NAMESPACE)&quot;,<br>  &quot;--leader-election-namespace=kube-system&quot;,<br>  &quot;--enable-certificate-owner-ref&quot;<br>]}]&#39;</pre><h3><strong>Install Operator Lifecycle Manage</strong>r</h3><p>(1) Before this, you need to install <strong><em>Operator SDK </em></strong>on MacOS.</p><pre>% brew install operator-sdk</pre><p>(2) Install <strong><em>Operator Lifecycle Manager</em></strong> in your cluster. This command creates the relevant custom resources definition.</p><pre>% operator-sdk olm install</pre><p>The output is:</p><pre>INFO[0003] Fetching CRDs for version &quot;latest&quot;           <br>INFO[0003] Fetching resources for resolved version &quot;latest&quot; <br>INFO[0018] Creating CRDs and resources                  <br>INFO[0018]   Creating CustomResourceDefinition &quot;catalogsources.operators.coreos.com&quot; <br>INFO[0019]   Creating CustomResourceDefinition &quot;clusterserviceversions.operators.coreos.com&quot; <br>INFO[0020]   Creating CustomResourceDefinition &quot;installplans.operators.coreos.com&quot; <br>INFO[0021]   Creating CustomResourceDefinition &quot;olmconfigs.operators.coreos.com&quot; <br>INFO[0021]   Creating CustomResourceDefinition &quot;operatorconditions.operators.coreos.com&quot; <br>INFO[0021]   Creating CustomResourceDefinition &quot;operatorgroups.operators.coreos.com&quot; <br>INFO[0022]   Creating CustomResourceDefinition &quot;operators.operators.coreos.com&quot; <br>INFO[0022]   Creating CustomResourceDefinition &quot;subscriptions.operators.coreos.com&quot; <br>INFO[0022]   Creating Namespace &quot;olm&quot;                   <br>INFO[0023]   Creating Namespace &quot;operators&quot;             <br>INFO[0023]   Creating ServiceAccount &quot;olm/olm-operator-serviceaccount&quot; <br>INFO[0023]   Creating ClusterRole &quot;system:controller:operator-lifecycle-manager&quot; <br>INFO[0023]   Creating ClusterRoleBinding &quot;olm-operator-binding-olm&quot; <br>INFO[0024]   Creating OLMConfig &quot;cluster&quot;               <br>INFO[0025]   Creating Deployment &quot;olm/olm-operator&quot;     <br>INFO[0025]   Creating Deployment &quot;olm/catalog-operator&quot; <br>INFO[0025]   Creating ClusterRole &quot;aggregate-olm-edit&quot;  <br>INFO[0026]   Creating ClusterRole &quot;aggregate-olm-view&quot;  <br>INFO[0026]   Creating OperatorGroup &quot;operators/global-operators&quot; <br>INFO[0026]   Creating OperatorGroup &quot;olm/olm-operators&quot; <br>INFO[0027]   Creating ClusterServiceVersion &quot;olm/packageserver&quot; <br>INFO[0027]   Creating CatalogSource &quot;olm/operatorhubio-catalog&quot; <br>INFO[0027] Waiting for deployment/olm-operator rollout to complete <br>INFO[0028]   Waiting for Deployment &quot;olm/olm-operator&quot; to rollout: 0 of 1 updated replicas are available <br>INFO[0030]   Deployment &quot;olm/olm-operator&quot; successfully rolled out <br>INFO[0030] Waiting for deployment/catalog-operator rollout to complete <br>INFO[0030]   Deployment &quot;olm/catalog-operator&quot; successfully rolled out <br>INFO[0030] Waiting for deployment/packageserver rollout to complete <br>INFO[0031]   Waiting for Deployment &quot;olm/packageserver&quot; to rollout: 0 of 2 updated replicas are available <br>INFO[0036]   Deployment &quot;olm/packageserver&quot; successfully rolled out <br>INFO[0042] Successfully installed OLM version &quot;latest&quot;                          olm          CatalogSource               Installed</pre><p>(3) Verify the CRDs installed.</p><pre>% kubectl get crds</pre><p>The output is:</p><pre>NAME                                            NAMESPACE    KIND                        STATUS<br>catalogsources.operators.coreos.com                          CustomResourceDefinition    Installed<br>clusterserviceversions.operators.coreos.com                  CustomResourceDefinition    Installed<br>installplans.operators.coreos.com                            CustomResourceDefinition    Installed<br>olmconfigs.operators.coreos.com                              CustomResourceDefinition    Installed<br>operatorconditions.operators.coreos.com                      CustomResourceDefinition    Installed<br>operatorgroups.operators.coreos.com                          CustomResourceDefinition    Installed<br>operators.operators.coreos.com                               CustomResourceDefinition    Installed<br>subscriptions.operators.coreos.com                           CustomResourceDefinition    Installed<br>olm                                                          Namespace                   Installed<br>operators                                                    Namespace                   Installed<br>olm-operator-serviceaccount                     olm          ServiceAccount              Installed<br>system:controller:operator-lifecycle-manager                 ClusterRole                 Installed<br>olm-operator-binding-olm                                     ClusterRoleBinding          Installed<br>cluster                                                      OLMConfig                   Installed<br>olm-operator                                    olm          Deployment                  Installed<br>catalog-operator                                olm          Deployment                  Installed<br>aggregate-olm-edit                                           ClusterRole                 Installed<br>aggregate-olm-view                                           ClusterRole                 Installed<br>global-operators                                operators    OperatorGroup               Installed<br>olm-operators                                   olm          OperatorGroup               Installed<br>packageserver                                   olm          ClusterServiceVersion       Installed<br>operatorhubio-catalog                           olm          CatalogSource               Installed</pre><h3>Create Operator Group for IBM App Connect Operator</h3><p>(1) Create a namespace <em>a</em>ce of App Connect Operator</p><pre>% kubectl create namespace ace</pre><p>(2) Create <strong><em>OperatorGroup</em></strong> (<em>ace </em>as the namespace) using the <em>yaml</em> file below</p><pre>## <br>## appconn-operator-group.yaml<br>## <br>apiVersion: operators.coreos.com/v1<br>kind: OperatorGroup<br>metadata:<br>  name: ace-operator-group<br>  namespace: ace<br>spec:<br>  targetNamespaces:<br>  - ace</pre><pre>% kubectl apply -f appconn-operator-group.yaml</pre><h3>Create the IBM App Connect Operator catalog</h3><p>(1) Create a <strong><em>CatalogSource</em></strong> object for the IBM App Connect Operator using the <em>yaml</em> file below.</p><pre>## <br>## appconn-catalog-source.yaml<br>## <br>apiVersion: operators.coreos.com/v1alpha1<br>kind: CatalogSource<br>metadata:<br>  name: ibm-appconnect-catalog<br>  namespace: olm<br>spec:<br>  displayName: &quot;IBM App Connect Operator Catalog k8S&quot;<br>  publisher: IBM<br>  sourceType: grpc<br>  image: icr.io/cpopen/appconnect-operator-catalog-k8s<br>  updateStrategy:<br>    registryPoll:<br>      interval: 45m<br>  grpcPodConfig:<br>    securityContextConfig: restricted</pre><pre>% kubectl apply -f appconn-catalog-source.yaml -n olm</pre><p>(2) Verify the installation.</p><pre>% kubectl get CatalogSources ibm-appconnect-catalog -n olm<br>NAME                     DISPLAY                                TYPE   PUBLISHER   AGE<br>ibm-appconnect-catalog   IBM App Connect Operator Catalog k8S   grpc   IBM         2m21s</pre><p>(3) If there is problem, check the pods and CatalogSource resources</p><pre>% kubectl get catalogsource,pods -n olm<br>NAME                                                        DISPLAY                                TYPE   PUBLISHER        AGE<br>catalogsource.operators.coreos.com/ibm-appconnect-catalog   IBM App Connect Operator Catalog k8S   grpc   IBM              4m6s<br>catalogsource.operators.coreos.com/operatorhubio-catalog    Community Operators                    grpc   OperatorHub.io   5h32m<br><br>NAME                                    READY   STATUS    RESTARTS   AGE<br>pod/catalog-operator-655fb46cd4-gzfvn   1/1     Running   0          5h32m<br>pod/ibm-appconnect-catalog-vjdsj        1/1     Running   0          4m6s<br>pod/olm-operator-67fdb4b99d-sdklb       1/1     Running   0          5h32m<br>pod/operatorhubio-catalog-jbmkg         1/1     Running   0          5h32m<br>pod/packageserver-586d76ddcf-9rhbp      1/1     Running   0          5h32m<br>pod/packageserver-586d76ddcf-cc4mx      1/1     Running   0          5h32m</pre><h3>Create the IBM App Connect Operator subscription</h3><p>(1) Create <strong><em>Subscription</em></strong> object for IBM App Connect Operator.</p><pre>##<br>## appconn-sub.yaml<br>##<br>kind: Subscription<br>metadata:<br>  name: ibm-appconnect<br>  namespace: ace<br>spec:<br>  channel: v7.2<br>  name: ibm-appconnect<br>  source: ibm-appconnect-catalog<br>  sourceNamespace: olm</pre><pre>% kubectl apply -f appconn-sub.yaml</pre><p>(2) Check progress of installation — view the logs for the Catalog Operator pod in the <strong><em>olm</em></strong> namespace.</p><pre>% kubectl logs catalog-operator-655fb46cd4-gzfvn -n olm</pre><h3>Add entitlement key to namespace</h3><p>(1) Obtain the entitlement key from this <a href="https://myibm.ibm.com/products-services/containerlibrary"><strong>IBM Container software library</strong></a>.</p><p>(2) Create a secret that holds the entitlement key.</p><pre>% oc create secret docker-registry ibm-entitlement-key \<br>    --docker-username=cp \<br>    --docker-password=myEntitlementKey \<br>    --docker-server=cp.icr.io \<br>    --namespace=ace</pre><h3>Creating ingress definitions for external access to your IBM App Connect instances</h3><p>(1) Create <strong><em>namespace</em></strong> for ingress</p><pre>% kubectl create namespace ingress</pre><p>(2) Add the <strong><em>NGINX ingress controller</em></strong> chart repository and then update all Helm repositories in your system.</p><pre>% helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx<br>% helm repo update</pre><p>(3) Install the Helm chart in the <strong><em>ingress</em></strong> namespace.</p><pre>% helm install nginx-ingress ingress-nginx/ingress-nginx \<br>     --namespace ingress \<br>     --set controller.replicaCount=2 \<br>     --set controller.nodeSelector.&quot;beta\.kubernetes\.io/os&quot;=linux \<br>     --set defaultBackend.nodeSelector.&quot;beta\.kubernetes\.io/os&quot;=linux \<br>     --set controller.admissionWebhooks.patch.nodeSelector.&quot;beta\.kubernetes\.io/os&quot;=linux</pre><p>Result output:</p><pre>NAME: nginx-ingress<br>LAST DEPLOYED: Fri Mar 24 22:31:05 2023<br>NAMESPACE: ingress<br>STATUS: deployed<br>REVISION: 1<br>TEST SUITE: None<br>NOTES:<br>The ingress-nginx controller has been installed.<br>It may take a few minutes for the LoadBalancer IP to be available.<br>You can watch the status by running &#39;kubectl --namespace ingress get services -o wide -w nginx-ingress-ingress-nginx-controller&#39;</pre><p>(4) To check the status for the Load Balancer IP.</p><pre>% kubectl --namespace ingress get services -o wide nginx-ingress-ingress-nginx-controller<br>NAME                                     TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                      AGE    SELECTOR<br>nginx-ingress-ingress-nginx-controller   LoadBalancer   10.0.169.121   xxx.xxx.xxx.xxx   80:30461/TCP,443:30688/TCP   4m6s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=nginx-ingress,app.kubernetes.io/name=ingress-nginx</pre><p>(5) Note down the external IP address. We will used this to configure our <strong><em>Ingress</em></strong> objects later.</p><h3>Deploy App Connect Dashboard</h3><p>(1) Create <strong><em>Storage Class</em></strong> for writing purpose.</p><pre>##<br>## my-azurefile-csi-premium.yaml<br>##<br>kind: StorageClass<br>apiVersion: storage.k8s.io/v1<br>metadata:<br>  name: my-azurefile-csi-premium<br>provisioner: kubernetes.io/azure-file<br>mountOptions:<br>- mfsymlinks<br>- actimeo=30<br>- dir_mode=0777<br>- file_mode=0777<br>- uid=1000<br>- cache=strict<br>parameters:<br>  skuName: Premium_LRS <br>reclaimPolicy: Delete<br>volumeBindingMode: Immediate</pre><pre>% oc apply -f my-azurefile-csi-premium.yaml</pre><p>(2) Create <strong><em>App Connect Dashboard</em></strong>. See <a href="https://ibm.biz/acelicense">https://ibm.biz/acelicense</a> for <strong><em>license</em></strong> and <strong><em>use</em></strong> fields.</p><pre>##<br>## appconn-ace-dashboard.yaml<br>## <br>apiVersion: appconnect.ibm.com/v1beta1<br>kind: Dashboard<br>metadata:<br>  name: ace-dashboard<br>  namespace: ace<br>spec:<br>  license:<br>    accept: true<br>    license: L-APEH-CJUCNR<br>    use: AppConnectEnterpriseNonProductionFREE<br>  pod:<br>    containers:<br>      content-server:<br>        resources:<br>          limits:<br>            cpu: 250m<br>            memory: 512Mi<br>          requests:<br>            cpu: 50m<br>            memory: 50Mi<br>      control-ui:<br>        resources:<br>          limits:<br>            cpu: 500m<br>            memory: 512Mi<br>          requests:<br>            cpu: 50m<br>            memory: 125Mi<br>  replicas: 1<br>  storage:<br>    size: 5Gi<br>    type: persistent-claim<br>    class: my-azurefile-csi-premium<br>  useCommonServices: false<br>  version: &#39;12.0.7-lts&#39;</pre><pre>% kubectl apply -f appconn-ace-dashboard.yaml  -n ace</pre><p>(3) Create ingress route for <strong><em>App Connect Dashboard</em></strong>. Since you do not have DNS, we will use nip.io to configure the host name. Use the External IP you have noted earlier.</p><pre>##<br>## appconn-ingress-dashboard.yaml<br>## <br>kind: Ingress<br>apiVersion: networking.k8s.io/v1<br>metadata:<br>  name: ace-dashboard-ingress<br>  namespace: ace<br>  annotations:<br>    kubernetes.io/ingress.class: &quot;nginx&quot;<br>    nginx.ingress.kubernetes.io/backend-protocol: HTTPS<br>spec:<br>  tls:<br>    - hosts:<br>      - ace-dashboard.XXX.XXX.XXX.XXX.nip.io<br>  rules:<br>    - host: ace-dashboard.XXX.XXX.XXX.XXX.nip.io<br>      http:<br>        paths:<br>        - path: /<br>          pathType: Prefix<br>          backend:<br>            service:<br>              name: ace-dashboard-dash<br>              port:<br>                number: 8300</pre><pre>% kubectl apply -f appconn-ingress-dashboard.yaml -n ace</pre><p>(4) Check the status of the <strong><em>Dashboard</em></strong>.</p><pre>% kubectl get dashboard -n ace<br>NAME            RESOLVEDVERSION   REPLICAS   CUSTOMIMAGES   STATUS    URL        AGE<br>ace-dashboard   12.0.7.0-r4       1          false          Ready     https://   11h</pre><p>(5) Finally, you can access the <strong><em>Dashboard</em></strong> using the URL</p><pre>https://ace-dashboard.XXX.XXX.XXX.XXX.nip.io</pre><h3>Deploy App Connect Integration Server</h3><p>(1) Before we start, we are going to use this sample BAR file.</p><pre>https://github.com/khongks/cp4i-ace-books/raw/main/BARfiles/Books.bar</pre><p>(2) Create a <strong><em>Configuration</em></strong> object that contains authentication information to git repository.</p><pre>##<br>## github-barauth.yaml<br>##<br>apiVersion: appconnect.ibm.com/v1beta1<br>kind: Configuration<br>metadata:<br>  name: github-barauth<br>  namespace: ace<br>spec:<br>  description: Stores bar auth<br>  data: eyJhdXRoVHlwZSI6IkJBU0lDX0FVVEgiLCJjcmVkZW50aWFscyI6eyJ1c2VybmFtZSI6IiIsInBhc3N3b3JkIjoiIn19Cg==<br>  type: baraut</pre><pre>% oc apply -f github-barauth.yaml -n ace</pre><p>Note that the <strong><em>data</em></strong> field contains a base64 encoding of the authentication information.</p><pre>{&quot;authType&quot;:&quot;BASIC_AUTH&quot;,&quot;credentials&quot;:{&quot;username&quot;:&quot;&quot;,&quot;password&quot;:&quot;&quot;}}</pre><p>(3) Create <strong><em>App Connect Integration Server</em></strong>. See <a href="https://ibm.biz/acelicense">https://ibm.biz/acelicense</a> for <strong><em>license</em></strong> and <strong><em>use</em></strong> fields.</p><pre>##<br>## appconn-ingress-intserverhttp.yaml<br>##<br>apiVersion: networking.k8s.io/v1<br>kind: Ingress<br>metadata:<br>  name: ace-books-ingress<br>  namespace: ace<br>  annotations:<br>    kubernetes.io/ingress.class: &quot;nginx&quot;<br>    nginx.ingress.kubernetes.io/backend-protocol: HTTP<br>spec:<br>  tls:<br>    - hosts:<br>      - ace-books.xxx.xxx.xxx.xxx.nip.io<br>  rules:<br>    - host: ace-books.xxx.xxx.xxx.xxx..nip.io<br>      http:<br>        paths:<br>        - path: /<br>          pathType: Prefix<br>          backend:<br>            service:<br>              name: ace-books-is<br>              port:<br>                number: 7800</pre><p>(4) Check the status of the <strong><em>Integration Server</em></strong>.</p><pre>% kubectl get integrationserver -n ace<br>NAME        RESOLVEDVERSION   REPLICAS   AVAILABLEREPLICAS   CUSTOMIMAGES   STATUS   AGE<br>ace-books   12.0.7.0-r4       1          1                   false          Ready    11h</pre><p>(5) Finally, you can test the REST API running on the <strong><em>Integration Server</em></strong>.</p><pre>curl -kv https://ace-books.xxx.xxx.xxx.xxx..nip.io/api/v1/books</pre><p>Reference Links:</p><p><a href="https://www.ibm.com/docs/en/app-connect/containers_cd?topic=operator-installing-kubernetes">Installing IBM App Connect in a Kubernetes environment</a></p><p><a href="https://community.ibm.com/community/user/integration/blogs/joel-gomez1/2022/02/15/installing-the-ibm-app-connect-operator-on-amazon">https://community.ibm.com/community/user/integration/blogs/joel-gomez1/2022/02/15/installing-the-ibm-app-connect-operator-on-amazon</a></p><p><a href="https://learn.microsoft.com/en-us/troubleshoot/azure/azure-kubernetes/connection-issues-application-hosted-aks-cluster">https://learn.microsoft.com/en-us/troubleshoot/azure/azure-kubernetes/connection-issues-application-hosted-aks-cluster</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=69adbfd8cb2a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[IBM software deployment and platform options]]></title>
            <link>https://khongks.medium.com/ibm-software-deployment-and-platform-options-1f806acbc09a?source=rss-dbd3cf73ac04------2</link>
            <guid isPermaLink="false">https://medium.com/p/1f806acbc09a</guid>
            <category><![CDATA[cloud-pak-for-integration]]></category>
            <category><![CDATA[deployment]]></category>
            <dc:creator><![CDATA[Kok Sing Khong]]></dc:creator>
            <pubDate>Tue, 28 Jun 2022 08:45:56 GMT</pubDate>
            <atom:updated>2022-06-28T08:49:53.939Z</atom:updated>
            <content:encoded><![CDATA[<p>In the last few years, IBM software has evolved extensively from traditional installation on bare metal or virtual machines to containers on OpenShift platform or Kubernetes. This article summaries, in general, what are the deployment and platform options available when you are looking to install IBM software. We will take specified examples based on IBM integration products within the Cloud Pak for Integration portfolio.</p><p>I have drawn up a simple chart the illustrate the available deployment and platform options.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/682/1*boImALX7rwueg8PnDBhtvw.png" /></figure><p>If you look at the product in Cloud Pak for Integration (v2022.1), we could map out the deployment options in the following table.</p><p><a href="https://airtable.com/embed/shr1sGjSIHtlTQysc">Grid view - Airtable</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1f806acbc09a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Deploy DataPower on CP4I using Jenkins]]></title>
            <link>https://khongks.medium.com/deploy-datapower-on-cp4i-using-jenkins-803e94359a48?source=rss-dbd3cf73ac04------2</link>
            <guid isPermaLink="false">https://medium.com/p/803e94359a48</guid>
            <category><![CDATA[openshift]]></category>
            <category><![CDATA[cicd-pipeline]]></category>
            <category><![CDATA[jenkins]]></category>
            <category><![CDATA[cloud-pak-for-integration]]></category>
            <category><![CDATA[datapower]]></category>
            <dc:creator><![CDATA[Kok Sing Khong]]></dc:creator>
            <pubDate>Mon, 30 May 2022 15:39:29 GMT</pubDate>
            <atom:updated>2022-12-06T05:54:22.201Z</atom:updated>
            <content:encoded><![CDATA[<p>This write-up is the 3rd installment of the series. The first 2 series are about <a href="https://khongks.medium.com/deploy-mq-on-cp4i-using-jenkins-82e54f0ac4fe">Deploying MQ</a> and <a href="https://khongks.medium.com/deploy-ace-on-cp4i-using-jenkins-6a1f7dae90e8">Deploying ACE</a>. Before we read about the steps to set up the Jenkins pipeline, let us review the development approach of DataPower and the relationship between DataPower Kubernetes custom resources.</p><p>In the traditional world, where DataPower runs on physical or virtual appliances, the developer will define the services and configuration within a DataPower domain using the DataPower WebUI. The changes are applied and saved; and because service becomes active immediately. In the container world, the development process will be slightly different. The following diagram illustrates this process:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/801/1*ySq54lBYgrQ5CtzCI5ekog.png" /><figcaption>DataPower development on Kubernetes/OpenShift</figcaption></figure><h3><strong>Development Process</strong></h3><ol><li>The DataPower developer could use a DataPower running on a Docker container to develop the DataPower services. There is a couple of good articles on how to do this <a href="https://github.com/fxnaranjo/datapower-operator">https://github.com/fxnaranjo/datapower-operator</a> or <a href="https://github.com/ibm-datapower/datapower-tutorials/blob/master/getting-started/start-with-docker.md">https://github.com/ibm-datapower/datapower-tutorials/blob/master/getting-started/start-with-docker.md</a>.</li><li>Once, the development work is completed and unit tested, the developer can export the configuration to an export file.</li><li>The developer can use the <a href="https://www.ibm.com/links?url=https%3A%2F%2Fgithub.com%2FIBM%2Fdatapower-operator-scripts%23migrate-backupsh">migrate-backup.sh</a> script to extract the configuration from the export file into YAML files (in a folder). These generated YAML files can be applied directly to create config maps.</li><li>The developer will then check-in the export folder into a Git repository. The check-in event can be configured to trigger a Jenkins Pipeline.</li></ol><p>The detailed steps are found in this <a href="https://www.ibm.com/docs/en/cloud-paks/cp-integration/2021.4?topic=integration-datapower-gateway-transformation-guide">IBM documentation</a>.</p><h3>Jenkins Pipeline</h3><ol><li>Pre-deploy stage: creates the <em>Namespace</em>, pull <em>Secret</em> for IBM entitlement key, admin credential, for TLS keys and certificates (not shown in the article), and <em>ConfigMaps</em> for configurations.</li><li>Deploy stage: creates <em>DataPowerService</em> (which in turn creates <em>DataPowerMonitor</em>), <em>Service</em> that sends requests to the defined DataPower service endpoint, and <em>Route</em> that sends requests to the <em>Service</em>.</li><li>Test service stage: Runs a curl command to test the endpoint (via the <em>Route</em>).</li></ol><h3>Step by Step:</h3><p>Before you begin, you must have the following setup</p><ul><li><strong>Jenkins </strong>— see my <a href="https://khongks.medium.com/deploy-mq-on-cp4i-using-jenkins-82e54f0ac4fe">previous article</a> on installing Jenkins on the same OpenShift cluster of the CP4I.</li><li><strong>Red Hat OpenShift</strong> cluster installed (my version is 4.8.36), Also tested on v4.10.17.</li><li><strong>Cloud Pak for Integration</strong> is installed on the OpenShift cluster (my version is 2021.4.1). Also tested on v2022.2.1.</li><li><strong>Github</strong> account. Updated to v2022.2.1 (using DataPower v10.5.0.0).</li><li>Clone/fork this <a href="https://github.com/khongks/dp-jenkins">repository</a>.</li></ul><p><strong>Create a credential in Jenkins to store the IBM entitlement key and DataPower admin password (from Jenkins Console)</strong></p><ol><li>Create Global credentials (<em>kind: Secret text</em>) to store the IBM entitlement key and DataPower admin password. See the detailed steps in the <a href="https://khongks.medium.com/deploy-mq-on-cp4i-using-jenkins-82e54f0ac4fe">previous article</a>.</li><li>These two credentials will be referenced in the Jenkinsfile to be used by the pipeline.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tXNIoYiRpzTqtbRcfMW8Vg.png" /><figcaption>Global credentials</figcaption></figure><p><strong>Configure a pipeline to deploy DataPower service (from Jenkins Console)</strong></p><ol><li>Click on <strong>Dashboard &gt; New Item &gt; Pipeline</strong>. Provide a name (e.g. <em>mq-pipeline</em>) and click <strong>Ok</strong>.</li><li>Go to <strong>Pipeline</strong> section, specify the following and click <strong>Save</strong>.</li></ol><ul><li>Definition: <em>Pipeline script from SCM</em></li><li>SCM: <em>Git</em></li><li>Repository URL: <a href="https://github.com/khongks/dp-jenkins.git"><em>https://github.com/khongks/dp-jenkins.git</em></a></li><li>Branch Specifier: <em>*/main</em></li><li>Script Path: <em>Jenkinsfile</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EbmbnvJPsSW00ZUdkfFKJw.png" /><figcaption>Setup Jenkins Pipeline</figcaption></figure><p><strong>Perform test build (from Jenkins Console)</strong></p><ol><li>Click <strong>Build Now.</strong></li><li>Click <strong>Build History &gt; #1 &gt; Console Output</strong></li><li>When the pipeline is completed, you should see the following output, with the test results of the curl command.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zx78PAD3KHqNVmYFIN5WKg.png" /><figcaption>Successful Pipeline Execution</figcaption></figure><p><strong>Pre Deploy Output</strong></p><pre>Pre-Deploy ~ setup configuration before deploy<br>[Pipeline] sh<br>+ ./scripts/01-pre-deploy.sh **** hello dp ****<br>----------------------------------------------------------------------<br> INFO: Pre deploy<br>----------------------------------------------------------------------</pre><pre>Namespace dp found<br>create_pull_secret ibm-entitlement-key, dp, cp.icr.io, cp, ****, khongks@gmail.com</pre><pre>Secret ibm-entitlement-key already created<br>Apply all YAMLs from the backup<br>export-output/default-cfg.yaml<br>oc apply -f export-output/default-cfg.yaml -n dp</pre><pre>configmap/default-cfg configured<br>export-output/default-local.yaml<br>oc apply -f export-output/default-local.yaml -n dp</pre><pre>configmap/default-local configured<br>export-output/hello-cfg.yaml<br>oc apply -f export-output/hello-cfg.yaml -n dp</pre><pre>configmap/hello-cfg configured</pre><pre>Delete and Create admin-credentials secret</pre><pre>secret &quot;admin-credentials&quot; deleted</pre><pre>secret/admin-credentials created</pre><p><strong>Deploy Output</strong></p><pre>Deploy ~ deploy DataPowerService<br>[Pipeline] sh<br>+ ./scripts/02-deploy.sh hello dp L-RJON-C5SF54 production 10.0.4.0<br>----------------------------------------------------------------------<br> INFO: Deploy<br>----------------------------------------------------------------------</pre><pre>datapowerservice.datapower.ibm.com/hello unchanged<br>service/hello-service unchanged<br>route.route.openshift.io/hello-route unchanged<br>Waiting for [hello] of type [DatapowerService] in namespace [dp] to be in [Running] status</pre><pre>Installation status: Failed<br>=== Installation has failed ===<br>=== Retry again ===<br>Sleeping 30 seconds...</pre><pre>Installation status: Running</pre><p><strong>Test Service Output</strong></p><pre>Test Service<br>[Pipeline] sh<br>+ ./scripts/03-test-service.sh hello</pre><pre>----------------------------------------------------------------------<br> INFO: Test endpoint <a href="https://hello.itzroks-3100015379-wxzo6e-6ccd7f378ae819553d37d5f2ee142bd6-0000.au-syd.containers.appdomain.cloud/api/v1/users">https://hello.itzroks-3100015379-wxzo6e-6ccd7f378ae819553d37d5f2ee142bd6-0000.au-syd.containers.appdomain.cloud/api/v1/users</a><br>----------------------------------------------------------------------</pre><pre>% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current<br>                                 Dload  Upload   Total   Spent    Left  Speed</pre><pre>0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0</pre><pre>...</pre><pre>{&quot;createdAt&quot;:&quot;2022-05-27T09:40:32.058Z&quot;,&quot;name&quot;:&quot;Anthony Gorczany&quot;,&quot;avatar&quot;:&quot;<a href="https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/409.jpg">https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/409.jpg</a>&quot;,&quot;id&quot;:&quot;45&quot;},{&quot;createdAt&quot;:&quot;202<br>100  8562    0  8562    0     0    325      0 --:--:--  0:00:26 --:--:--  1756<br>100  9084    0  9084    0     0    345      0 --:--:--  0:00:26 --:--:--  2346<br>[Pipeline] }<br>[Pipeline] // stage<br>[Pipeline] }</pre><pre>[Pipeline] // withEnv<br>[Pipeline] }<br>[Pipeline] // withCredentials<br>[Pipeline] }</pre><pre>[Pipeline] // withEnv<br>[Pipeline] }<br>[Pipeline] // node</pre><pre>[Pipeline] End of Pipeline<br>Finished: SUCCESS</pre><h3>References</h3><p><a href="https://github.com/fxnaranjo/datapower-operator">https://github.com/fxnaranjo/datapower-operator</a></p><p><a href="https://github.com/ibm-datapower/datapower-tutorials/blob/master/getting-started/start-with-docker.md">https://github.com/ibm-datapower/datapower-tutorials/blob/master/getting-started/start-with-docker.md</a></p><p><a href="https://www.ibm.com/docs/en/cloud-paks/cp-integration/2021.4?topic=integration-datapower-gateway-transformation-guide">https://www.ibm.com/docs/en/cloud-paks/cp-integration/2021.4?topic=integration-datapower-gateway-transformation-guide</a></p><p><a href="https://www.ibm.com/docs/en/cloud-paks/cp-integration/2022.2?topic=integration-datapower-gateway-transformation-guide">https://www.ibm.com/docs/en/cloud-paks/cp-integration/2022.2?topic=integration-datapower-gateway-transformation-guide</a></p><p><a href="https://ibm.github.io/datapower-operator-doc/">IBM DataPower Operator</a></p><p><strong>Disclaimer:</strong></p><p><em>All opinions expressed here are very much my own and not of IBM. All codes/scripts/artifacts are provided as-is with no support unless otherwise stated</em><strong><em>.</em></strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=803e94359a48" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A high-level approach to automate your API Connect (in CP4I)]]></title>
            <link>https://khongks.medium.com/a-high-level-approach-to-automate-your-api-connect-in-cp4i-998fe5de8fbf?source=rss-dbd3cf73ac04------2</link>
            <guid isPermaLink="false">https://medium.com/p/998fe5de8fbf</guid>
            <category><![CDATA[devops]]></category>
            <category><![CDATA[cicd]]></category>
            <category><![CDATA[ibm]]></category>
            <category><![CDATA[apiconnect]]></category>
            <category><![CDATA[cp4i]]></category>
            <dc:creator><![CDATA[Kok Sing Khong]]></dc:creator>
            <pubDate>Thu, 17 Mar 2022 05:36:04 GMT</pubDate>
            <atom:updated>2022-06-24T03:52:31.784Z</atom:updated>
            <content:encoded><![CDATA[<p>Recently, I was approached to share my experience in how best to automate the installation and configuration of the entire stack of API Connect environments.</p><p>The following diagram show <strong>ONE</strong> strategy on how you can do that for API Connect deployed on OpenShift (via the Cloud Pak for Integration). Note that this strategy is not the only way.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*xoZ6dLEeVA9y3GjPb3MwiA.png" /></figure><p><strong>Disclaimer:</strong></p><p><em>All opinions expressed here are very much my own and not of IBM. All codes/scripts/artifacts are provided as-is with no support unless otherwise stated</em><strong><em>.</em></strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=998fe5de8fbf" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Deploy ACE on CP4I using Jenkins]]></title>
            <link>https://khongks.medium.com/deploy-ace-on-cp4i-using-jenkins-6a1f7dae90e8?source=rss-dbd3cf73ac04------2</link>
            <guid isPermaLink="false">https://medium.com/p/6a1f7dae90e8</guid>
            <category><![CDATA[app-connect-enterprise]]></category>
            <category><![CDATA[openshift]]></category>
            <category><![CDATA[cloud-pak-for-integration]]></category>
            <category><![CDATA[jenkins]]></category>
            <category><![CDATA[ibm]]></category>
            <dc:creator><![CDATA[Kok Sing Khong]]></dc:creator>
            <pubDate>Sun, 27 Feb 2022 04:41:07 GMT</pubDate>
            <atom:updated>2022-09-08T23:45:33.162Z</atom:updated>
            <content:encoded><![CDATA[<h3><strong>Overview</strong></h3><p>This is a continuation of my previous story (<a href="https://khongks.medium.com/deploy-mq-on-cp4i-using-jenkins-82e54f0ac4fe">link</a>)on how to deploy MQ on CP4I using Jenkins. Deploying ACE is more complex than MQ because to me, ACE is really an <em>integration</em> application where you need to compile into a deployable unit called Broker Archive (BAR) file before you can deploy to an <em>integration</em> server.</p><p>Therefore, a typical CI/CD pipeline of deploying ACE applications would look very similar to any other applications pipeline. The diagram shows the System Context diagram of the pipeline for the purpose of this article.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/912/1*stXN29wzOWHTFsJgSk_AeQ.png" /><figcaption>Jenkins pipeline — ACE on Cloud Pak for Integration</figcaption></figure><p>Our pipeline above has the following stages:</p><ul><li><strong>Git Checkout </strong>— This stage check out the source code for App Connect Enterprise (ACE) from a Git repository</li><li><strong>Build Bar File</strong> — Package the ACE application artifacts into a BAR file. To do so, we need to run this using a Docker image that is installed with ACE Toolkit.</li><li><strong>Upload Bar File </strong>— Upload the BAR file into a file repository, e.g. JFrog Artifactory.</li><li><strong>Deploy Integration Server — </strong>Deploy an integration server that is configured to point to the file location of the previous BAR file.</li><li><strong>Unit Test </strong>— Use a curl command to test the API endpoint of the integration application.</li></ul><h3>Required components/systems</h3><p>The following software is needed to implement this pipeline. I will not write in detail how to install the various software; I will just provide references on how to do this.</p><ul><li><strong>Jenkins</strong> — see my previous <a href="https://khongks.medium.com/deploy-mq-on-cp4i-using-jenkins-82e54f0ac4fe">article</a> on installing Jenkins on the same OpenShift cluster of the CP4I.</li><li><strong>JFrog Artifactory</strong> — We use this for artifact management. I installed it in the OpenShift cluster using the <a href="https://cloudnativetoolkit.dev/">IBM Cloud Native Toolkit</a>.</li><li><strong>Docker Registry</strong> — I used the default OpenShift image registry.</li><li><strong>GitHub</strong> — I used the public GitHub.com. I have two repositories, one contains the <a href="https://github.com/khongks/cp4i-ace-books">source code</a> of the integration application and another contains the <a href="https://github.com/khongks/cp4i-devops-utils">utility artifacts</a> like scripts and templates.</li><li><strong>OpenShift cluster</strong> — installed with CP4I and ACE dashboard. OCP is v4.8.26. CP4I is v2021.4.1.</li></ul><h3>Create build and deploy images</h3><p>I used 3 images for the pipeline.</p><ul><li><strong>jnlp-slave image</strong> which is located <a href="http://jenkins/jnlp-slave:latest">here</a></li><li><strong>oc-deploy image</strong> that has these tools — openshift-client, kubectl, curl, jq, git, sed, wget. This image is used in the stages-Upload Bar File, Deploy Integration Server, and Unit Test. The Dockerfile is located <a href="https://github.com/khongks/cp4i-devops-utils/blob/main/docker/Dockerfile.oc-deploy">here</a>.</li><li><strong>ace-buildbar image</strong> that has the ACE toolkit and configured with libraries to run <em>mqsicreatebar </em>(e.g. libgtk2.0–0 libxtst6 xvfb libswt-gtk-4-java libswt-gtk-4-jni). The Dockerfile is located <a href="https://github.com/khongks/cp4i-devops-utils/blob/main/docker/Docker.ace-12.0.2-buildbar">here</a>.</li></ul><p>You need to build the image, tag, and push to the OpenShift image registry. The following are the instructions for building the <em>ace-buildbar</em> image. You can follow the same instructions for the <em>oc-deploy</em> image.</p><pre>// Build the image<br>docker build -t ace-buildbar:12.0.4.0-ubuntu -f Docker.ace-12.0.4-buildbar .</pre><pre>// Create an external route for the image registry<br>oc patch configs.imageregistry.operator.openshift.io/cluster --patch &#39;{&quot;spec&quot;:{&quot;defaultRoute&quot;:true}}&#39; --type=merge</pre><pre>// Get the hostname of the image registry<br>oc get route -n openshift-image-registry default-route -ojson | jq -r .spec.host</pre><pre>// Get the hostname into variable HOST<br>HOST=$(oc get route default-route -n openshift-image-registry --template=&#39;{{ .spec.host }}&#39;)</pre><pre>// Login to OpenShift image registry<br>docker login -u $(oc whoami) -p $(oc whoami -t) $HOST</pre><pre>// Tag the image<br>docker tag ace-buildbar:12.0.4.0-ubuntu $HOST/jenkins/ace-buildbar:12.0.4.0-ubuntu</pre><pre>// Push the image into the OpenShift image registry<br>docker push $HOST/jenkins/ace-buildbar:12.0.4.0-ubuntu</pre><p>The image can now be pulled by containers within the OpenShift cluster via the following tag.</p><pre>image-registry.openshift-image-registry.svc:5000/jenkins/ace-buildbar:12.0.4.0-ubuntu</pre><h3>Set up Artifactory credentials in Jenkins</h3><ol><li>Create Global credentials (<em>kind: Username with password</em>) to store the username and password for JFrog Artifactory. I used the name <em>artifactory_credentials</em> in the Jenkinsfile to reference the username/password securely.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I8HeH4miR9pv0JvmEiobkA.png" /><figcaption>List of Global credentials</figcaption></figure><h3>Set up Artifactory credentials (BarAuth) for ACE</h3><p>We use the <em>spec.barURL</em> in the integration server to retrieve the Bar file from JFrog Artifactory. To do that we need to set up the <em>BarAuth</em> configuration that contains both the credentials and CA certificate.</p><p>Here is the IBM ACE documentation on <a href="https://www.ibm.com/docs/en/app-connect/containers_cd?topic=resources-configuration-reference"><em>Configuration</em></a> and <a href="https://www.ibm.com/docs/en/app-connect/containers_cd?topic=types-barauth-type"><em>BarAuth</em></a>.</p><p><strong>Create a secret for the certificate</strong></p><ol><li>Get the certificate for the JFrog Artifactory endpoint.</li></ol><pre>openssl s_client -connect artifactory-tools.itzroks-3100015379-x94hbr-6ccd7f378ae819553d37d5f2ee142bd6-0000.au-syd.containers.appdomain.cloud:443</pre><p>2. Create a secret using the following YAML (artifactory-cacert-secret.yaml).</p><pre>kind: Secret<br>apiVersion: v1<br>metadata:<br>    name: artifactory-cacert-secret<br>    namespace: ace<br>data:<br>    ca.crt: &#39;{{ base64 encoded of the certificate }}&#39;<br>    tls.crt: &#39;&#39;<br>    tls.key: &#39;&#39;<br>type: kubernetes.io/tls</pre><p>3. Note: Use the following instruction to get the <em>ca.crt</em> value</p><pre>cat artifactory-ca.crt | base64</pre><p>4. Finally, run the following command to create the secret.</p><pre>oc apply -f artifactory-cacert-secret.yaml</pre><p><strong>Create a <em>BarAuth</em> configuration</strong></p><ol><li>Create a <em>BarAuth</em> JSON file, see <a href="https://github.com/khongks/cp4i-devops-utils/blob/main/configuration/bar-auth.json">here</a>. Populate the values as follows.</li></ol><pre>{<br>    &quot;authType&quot;:&quot;BASIC_AUTH&quot;,<br>    &quot;credentials&quot;: {<br>        &quot;username&quot;:&quot;{{username}}&quot;,<br>        &quot;password&quot;:&quot;{{password}}&quot;,<br>        &quot;caCertSecret&quot;:&quot;artifactory-cacert-secret&quot;<br>    }<br>}</pre><p>2. Create a <em>BarAuth </em>secret using the JSON file in the namespace you want to deploy the ACE integration server.</p><pre>oc create secret generic bar-auth-secret --from-file=configuration=bar-auth.json --namespace=ace</pre><p>3. Finally, create the ACE <em>Configuration</em> object referencing the secret name, the YAML file <a href="https://github.com/khongks/cp4i-devops-utils/blob/main/configuration/bar-auth-config.yaml">here</a>.</p><pre>oc create -n ace -f bar-auth-config.yaml</pre><pre>// bar-auth-config.yaml<br>apiVersion: appconnect.ibm.com/v1beta1<br>kind: Configuration<br>metadata:  <br>    name: bar-auth-config  <br>    namespace: ace<br>spec:  <br>    description: Stores bar auth<br>    secretName: bar-auth-secret<br>    type: barauth</pre><h3>Set up Jenkins pipeline</h3><ol><li>Create a pipeline that points to our source code Git repository. The Git repository contains a <a href="https://github.com/khongks/cp4i-ace-books/blob/main/Jenkinsfile"><strong>Jenkinsfile</strong></a> that defines the entire Pipeline script.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bWkhwIPaBq3CsegLTgyHzQ.png" /><figcaption>Pipeline configuration</figcaption></figure><h3>Upload and retrieve files from JFrog Artifactory</h3><ol><li>The easiest way to know how to use upload and retrieve is to go to the JFrog Artifactory UI and click on the <em>Set Me Up</em> button (top right).</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0j1x5B-a_-PGuK5TVU6RsA.png" /><figcaption>Set Me Up in JFrog Artifactory</figcaption></figure><p>2. I have written two scripts to do this — in this <a href="https://github.com/khongks/cp4i-devops-utils/tree/main/scripts">folder</a>. To upload a file, we need to calculate the checksum and include it in the HTTP header.</p><pre>CHECKSUM=`shasum -a 1 $ARTIFACTORY_BAR_FILE | awk &#39;{ print $1 }&#39;`</pre><pre>-H &#39;X-Checksum-Sha1:${CHECKSUM}&#39;</pre><h3>Anatomy of the Jenkinfiles</h3><p>The following pipeline is implemented in the <a href="https://github.com/khongks/cp4i-ace-books/blob/main/Jenkinsfile">Jenkinsfile</a> that is conveniently located together with the source code Git repository.</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*stXN29wzOWHTFsJgSk_AeQ.png" /><figcaption>Jenkins pipeline — ACE on Cloud Pak for Integration</figcaption></figure><p><strong>Git Checkout stage: </strong>This stage check out the <a href="https://github.com/khongks/cp4i-ace-books">source code</a> and <a href="https://github.com/khongks/cp4i-devops-utils">utility files</a> (scripts and templates) from their respective Git repositories. The script files and template file (integration server YAML file) are copied into the source code folder.</p><p><strong>Build Bar File stage</strong>: This stage uses the <em>ace-buildbar</em> container to create the Bar file. The runs the following commands:</p><ul><li>It runs the X virtual frame buffer to enable you to run graphical applications without a display. It is needed for the <em>mqsicreatebar</em> command because it uses some SWT libraries.</li><li>Run the <em>mqsiprofile</em> to configure the environment for ACE toolkit.</li><li>Append the build number to the Bar file name.</li><li>Run <em>mqsicreatebar</em> to generate the Bar file.</li></ul><pre>Xvfb -ac :99 &amp;<br>export DISPLAY=:99</pre><pre>export LICENSE=accept</pre><pre>pwd<br>source /opt/ibm/ace-12/server/bin/mqsiprofile<br>cd $PROJECT_DIR</pre><pre>BAR_FILE=&quot;${BAR_NAME}_${BUILD_NUMBER}.bar&quot;<br>mqsicreatebar -data . -b $BAR_FILE -a $APP_NAME -cleanBuild -trace -configuration .</pre><pre>ls -lha</pre><p><strong>Build Bar File stage</strong>: This stage uses the <em>ace-buildbar</em> container to create the Bar file. The runs the following commands:</p><ul><li>Run the script <em>upload-barfile-to-artifactory.sh</em> that does precisely that.</li></ul><pre>set -e</pre><pre>cd $PROJECT_DIR</pre><pre>ls -lha</pre><pre>echo &quot;Calling upload-barfile-to-artifactory.sh ${ARTIFACTORY_HOST} ${ARTIFACTORY_REPO} ${ARTIFACTORY_BASE_PATH} &quot;${BAR_NAME}_${BUILD_NUMBER}.bar&quot; ${ARTIFACTORY_USER} ${ARTIFACTORY_PASSWORD}&quot;</pre><pre>./upload-barfile-to-artifactory.sh ${ARTIFACTORY_HOST} ${ARTIFACTORY_REPO} ${ARTIFACTORY_BASE_PATH} &quot;${BAR_NAME}_${BUILD_NUMBER}.bar&quot; ${ARTIFACTORY_USER} ${ARTIFACTORY_PASSWORD}</pre><p><strong>Deploy Integration Server stage</strong>: This stage deploys the ACE integration server by fetching the Bar file from JFrog Artifactory. The commands are as follows:</p><ul><li>Create the <em>integration-server.yaml</em> file from the <a href="https://github.com/khongks/cp4i-devops-utils/blob/main/templates/integration-server.yaml.tmpl">template</a> file, but substitute the variables.</li><li>Run an <em>oc</em> command to deploy the integration server, using the YAML file.</li></ul><pre>set -e<br>cd $PROJECT_DIR<br>BAR_FILE=&quot;${BAR_NAME}_${BUILD_NUMBER}.bar&quot;<br>cat integration-server.yaml.tmpl<br>sed -e &quot;s/{{NAME}}/$SERVER_NAME/g&quot; \<br>    -e &quot;s/{{NAMESPACE}}/$NAMESPACE/g&quot; \<br>    -e &quot;s/{{ARTIFACTORY_HOST}}/$ARTIFACTORY_HOST/g&quot; \<br>    -e &quot;s/{{ARTIFACTORY_PORT}}/$ARTIFACTORY_PORT/g&quot; \<br>    -e &quot;s/{{ARTIFACTORY_REPO}}/$ARTIFACTORY_REPO/g&quot; \<br>    -e &quot;s/{{ARTIFACTORY_BASE_PATH}}/$ARTIFACTORY_BASE_PATH/g&quot; \<br>    -e &quot;s/{{BAR_FILE}}/$BAR_FILE/g&quot; \<br>    -e &quot;s/{{CONFIGURATION_LIST}}/$CONFIGURATION_LIST/g&quot; \<br>    -e &quot;s/{{ACE_VERSION}}/$ACE_VERSION/g&quot; \<br>    -e &quot;s/{{ACE_LICENSE}}/$ACE_LICENSE/g&quot; \<br>    -e &quot;s/{{REPLICAS}}/$REPLICAS/g&quot; \<br>    integration-server.yaml.tmpl &gt; integration-server.yaml<br>cat integration-server.yaml<br>oc apply -f integration-server.yaml</pre><p>The sample copy of the <em>integration-server.yaml</em> file is as follows. It configures the following files</p><ul><li><em>metadata.name</em> — with the integration server name.</li><li><em>spec.barURL</em> — with artifactory host, artifactory port, artifactory repository, bar file name.</li><li><em>spec.configurations</em> — with configurationList variable.</li></ul><pre>apiVersion: appconnect.ibm.com/v1beta1<br>kind: IntegrationServer<br>metadata:<br>  name: books<br>  namespace: ace<br>spec:<br>  license:<br>    accept: true<br>    license: L-APEH-C79J9U<br>    use: CloudPakForIntegrationNonProduction<br>  pod:<br>    containers:<br>      runtime:<br>        resources:<br>          limits:<br>            cpu: 300m<br>            memory: 350Mi<br>          requests:<br>            cpu: 300m<br>            memory: 300Mi<br>  adminServerSecure: true<br>  enableMetrics: true<br>  createDashboardUsers: true<br>  barURL: <a href="https://artifactory-tools.itzroks-3100015379-x94hbr-6ccd7f378ae819553d37d5f2ee142bd6-0000.au-syd.containers.appdomain.cloud/artifactory/generic-local/cp4i/Books_14.bar">https://artifactory-tools.itzroks-3100015379-x94hbr-6ccd7f378ae819553d37d5f2ee142bd6-0000.au-syd.containers.appdomain.cloud:443/artifactory/generic-local/cp4i/Books_14.bar</a><br>  configurations: [ bar-auth-config  ]<br>  router:<br>    timeout: 120s<br>  designerFlowsOperationMode: disabled<br>  service:<br>    endpointType: http<br>  version: &#39;12.0&#39;<br>  replicas: 1<br>  logFormat: basic</pre><p><strong>Unit Test stage</strong>: This stage performs a simple unit test using a <em>curl</em> command.</p><pre>HOSTNAME=$(oc get route -n ace books-http -ogo-template --template=&#39;{{.spec.host}}&#39;)<br>curl -k http://${HOSTNAME}/api/v1/books | jq -r .</pre><p>Sample output:</p><pre>[<br>  {<br>    &quot;Id&quot;: &quot;1&quot;,<br>    &quot;Title&quot;: &quot;Steve Jobs&quot;,<br>    &quot;ISBN&quot;: &quot;1451648537&quot;,<br>    &quot;Author&quot;: &quot;Walter Isaacson&quot;,<br>    &quot;Published&quot;: &quot;Nov 24, 2011&quot;,<br>    &quot;Language&quot;: &quot;English&quot;,<br>    &quot;Formats&quot;: [<br>      &quot;Hardcover&quot;,<br>      &quot;Paperback&quot;,<br>      &quot;Audiobook CD&quot;,<br>      &quot;Audible&quot;<br>    ]<br>  },<br>  {<br>    &quot;Id&quot;: &quot;2&quot;,<br>    &quot;Title&quot;: &quot;Beautiful Whale&quot;,<br>    &quot;ISBN&quot;: &quot;1419703846&quot;,<br>    &quot;Author&quot;: &quot;Bryant Austin, Sylvia Earle&quot;,<br>    &quot;Published&quot;: &quot;May 02, 2013&quot;,<br>    &quot;Language&quot;: &quot;English&quot;,<br>    &quot;Formats&quot;: [<br>      &quot;Hardcover&quot;<br>    ]<br>  },<br>  {<br>    &quot;Id&quot;: &quot;3&quot;,<br>    &quot;Title&quot;: &quot;A Game of Thrones (A Song of Ice and Fire, Book 1)&quot;,<br>    &quot;ISBN&quot;: &quot;9780553103547&quot;,<br>    &quot;Author&quot;: &quot;George R. R. Martin&quot;,<br>    &quot;Published&quot;: &quot;Sep 01, 1996&quot;,<br>    &quot;Language&quot;: &quot;English&quot;,<br>    &quot;Formats&quot;: [<br>      &quot;Kindle&quot;,<br>      &quot;Hardcover&quot;,<br>      &quot;Paperback&quot;,<br>      &quot;Audiobook CD&quot;,<br>      &quot;Audible&quot;<br>    ]<br>  }<br>]</pre><h3>Conclusion</h3><p>Finally, a video showing how everything hangs together.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FpUW0RJC3sCQ%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DpUW0RJC3sCQ&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FpUW0RJC3sCQ%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="640" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/14921f2748c9ef65b771efe8fc657fa4/href">https://medium.com/media/14921f2748c9ef65b771efe8fc657fa4/href</a></iframe><p><strong>Disclaimer:</strong></p><p><em>All opinions expressed here are very much my own and not of IBM. All codes/scripts/artifacts are provided as-is with no support unless otherwise stated</em><strong><em>.</em></strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=6a1f7dae90e8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Deploy MQ on CP4I using Jenkins]]></title>
            <link>https://khongks.medium.com/deploy-mq-on-cp4i-using-jenkins-82e54f0ac4fe?source=rss-dbd3cf73ac04------2</link>
            <guid isPermaLink="false">https://medium.com/p/82e54f0ac4fe</guid>
            <category><![CDATA[cloud-pak-for-integration]]></category>
            <category><![CDATA[jenkins]]></category>
            <category><![CDATA[cicd]]></category>
            <category><![CDATA[ibm]]></category>
            <category><![CDATA[qms]]></category>
            <dc:creator><![CDATA[Kok Sing Khong]]></dc:creator>
            <pubDate>Fri, 17 Dec 2021 08:57:15 GMT</pubDate>
            <atom:updated>2022-06-24T03:50:10.267Z</atom:updated>
            <content:encoded><![CDATA[<p>Jenkins is a very popular CI/CD tool that allows you to provision applications. In this tutorial, I will show you how to deploy an MQ queue manager, which its configurations to an Red Hat Openshift (using the MQ operators that comes with Cloud Pak for Integration).</p><p>Before you begin, you must have the following setup</p><ul><li>Red Hat OpenShift cluster installed (my version is 4.8.21)</li><li>Cloud Pak for Integration installed on the OpenShift cluster (my version is 2021.3.1)</li><li>Github account</li><li>Clone this repository (<a href="https://github.com/khongks/mq-pipeline.git">https://github.com/khongks/mq-pipeline.git</a>)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VQAXqQgNLQWx8WkFt506yw.png" /><figcaption>MQ Jenkins Pipeline</figcaption></figure><p><strong>Install Jenkins on Red Hat OpenShift (from the Openshift Console)</strong></p><ol><li>Create a project called <strong>jenkins</strong>.</li><li>From the <strong>Operator Hub</strong>, install <strong>jenkins-operator</strong> provided by Red Hat in the <strong>jenkins</strong> namespace. Wait for installation to complete.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/548/1*4kyEVPmRSmJ91DKGtGRqMg.png" /><figcaption>Jenkins Operator tile</figcaption></figure><p>3. From the <strong>jenkins-operator</strong>, create a <strong>Jenkins</strong> instance. Give a name to your instance (e.g. <em>jenkins-kks</em>). Wait for installation to complete.</p><p>4. To access the Jenkins console, get the route using the following command in a terminal.</p><pre>oc get route -n jenkins jenkins-jenkins-kks -ojson | jq -r .spec.host</pre><p>You should have the URL for the Jenkins console that looks like this:</p><pre>jenkins-jenkins-kks-jenkins.&lt;domain-name&gt;</pre><p><strong>Create a credential in Jenkins to store IBM entitlement key (from Jenkins Console)</strong></p><ol><li>Click on <strong>Manage Jenkins &gt; Manage Credentials</strong></li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*qRjahWdlx7x73oYLBJB2bg.png" /><figcaption>Manage Credentials icon</figcaption></figure><p>2. Click on <strong>Jenkins (global) &gt; Global credentials (unrestricted)</strong></p><p>3. Click on <strong>Add Credentials</strong>, with the following setup.</p><ul><li>kind: <em>Secret text</em></li><li>Scope: <em>Global</em></li><li>Secret: <em>(obtained from </em><a href="https://myibm.ibm.com/products-services/containerlibrary"><em>https://myibm.ibm.com/products-services/containerlibrary</em></a><em>)</em></li><li>ID: <em>ibm_entitlement_key</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*muZ_8kZ2ogPITEBnVzF1nA.png" /><figcaption>Add Credentials</figcaption></figure><p>This ID is reference by the Jenkins pipeline to retrieve the value of the <strong>Secret</strong>.</p><p><strong>Enable Jenkins service account to create objects in OpenShift (from terminal)</strong></p><ol><li>Run this command to find the service account in the namespace</li></ol><pre>oc get sa -n jenkins</pre><p>The response should be:</p><pre>NAME                SECRETS AGE<br>builder             2       73m<br>default             2       73m<br>deployer            2       73m<br>jenkins-jenkins-kks 2       54m<br>jenkins-operator    2       56m</pre><p>2. Run this command to assign <em>cluster-admin</em> role to the service account. I assigned <em>cluster-admin </em>role, to simplify the setup; but you can create a custom role with the appropriates to do this.</p><pre>oc adm policy add-cluster-role-to-user cluster-admin system:serviceaccount:jenkins:jenkins-jenkins-kks</pre><p><strong>Configure a pipeline to build MQ queue manager (from Jenkins Console)</strong></p><ol><li>Click on <strong>Dashboard &gt; New Item &gt; Pipeline</strong>. Provide a name (e.g. <em>mq-pipeline</em>) and click <strong>Ok</strong>.</li><li>Go to <strong>Pipeline</strong> section, specify the following and click <strong>Save</strong>.</li></ol><ul><li>Definition: <em>Pipeline script from SCM</em></li><li>SCM: <em>Git</em></li><li>Repository URL: <a href="https://github.com/khongks/mq-pipeline.git"><em>https://github.com/khongks/mq-pipeline.git</em></a></li><li>Branch Specifier: <em>*/main</em></li><li>Script Path: <em>Jenkinsfile</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*leeK5w85sKfmqRN0Dtu95w.png" /><figcaption>Setup the pipeline</figcaption></figure><p><strong>Perform test build (from Jenkins Console)</strong></p><ol><li>Click <strong>Build Now.</strong></li><li>Click <strong>Build History &gt; #1 &gt; Console Output</strong></li><li>When the pipeline is completed, you should see the following output, with the MQ Console URL, with login user and password. It also generates a ccdt.json to access the queue manager.</li></ol><pre>...<br>Installation status: Running<br>MQ console URL: <a href="https://cpd-cp4i.itzroks-3100015379-h4gvux-6ccd7f378ae819553d37d5f2ee142bd6-0000.au-syd.containers.appdomain.cloud/integration/messaging/mq/qm1-ibm-mq">&lt;&lt;M</a>Q_CONSOLE_URL&gt;&gt;<br>User: admin<br>Pass: &lt;&lt;PASSWORD&gt;&gt;<br>{<br>  &quot;channel&quot;: [<br>    {<br>      &quot;name&quot;: &quot;QM1CHL&quot;,<br>      &quot;clientConnection&quot;: {<br>        &quot;connection&quot;: [<br>          {<br>            &quot;host&quot;: &quot;&lt;&lt;HOST&gt;&gt;&quot;,<br>            &quot;port&quot;: 443<br>          }<br>        ],<br>        &quot;queueManager&quot;: &quot;QM1&quot;<br>      },<br>      &quot;transmissionSecurity&quot;: {<br>        &quot;cipherSpecification&quot;: &quot;ANY_TLS12_OR_HIGHER&quot;<br>      },<br>      &quot;type&quot;: &quot;clientConnection&quot;<br>    }<br>  ]<br>}<br>[Pipeline] }<br>[Pipeline] // stage<br>[Pipeline] }</pre><pre>[Pipeline] // withEnv<br>[Pipeline] }<br>[Pipeline] // withCredentials<br>[Pipeline] }<br>[Pipeline] // withEnv<br>[Pipeline] }<br>[Pipeline] // node<br>[Pipeline] End of Pipeline<br>Finished: SUCCESS</pre><p>4. You should see the status of the completed job (#3 as follows).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F-qor5cJqnqPoOZ9mrXy6A.png" /><figcaption>Jenkins build dashboard</figcaption></figure><p><strong>Test the deployed queue manager (from terminal)</strong></p><ol><li>Clone the git repository</li></ol><pre>git clone <a href="https://github.com/khongks/mq-pipeline.git">https://github.com/khongks/mq-pipeline.git</a></pre><p>2. Go to the folder mq-pipeline/test and update the file <em>ccdt.json</em>.</p><p>3. Put a message.</p><pre>./mq-put.sh<br>Sample AMQSPUT0 start<br>target queue is APPQ<br>TESTING</pre><p>4. Get the message</p><pre>./mq-get.sh<br>Sample AMQSGET0 start<br>message &lt;TESTING&gt;</pre><p><strong>Configure Jenkins pipeline to be triggered from GitHub events</strong></p><p><strong><em>(From the Github web)</em></strong></p><ol><li>Go to this Github URL to add a webhook</li></ol><pre>https://github.com/{GIT_ORG}/mq-pipeline/settings/hooks/new</pre><p>2. Configure Payload URL and Content type</p><ul><li>Payload URL: <em>https://&lt;jenkins-route-hostname&gt;/github-webhook. </em>You can obtain this value from previous step</li><li>Content type: <em>application/json</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cZcTamZd08_bYGe31T3yQg.png" /><figcaption>Webhook configuration</figcaption></figure><p>3. Select event types that triggers this weekhook.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/872/1*nPwz9qqgBvMXOiQyC2K7Rw.png" /><figcaption>Webhook events preference</figcaption></figure><ul><li><em>Pushes</em></li><li><em>Pull requests</em></li></ul><p>4. Finally, click on <strong>Add webhook</strong> to create the webhook.</p><p><strong><em>(From Jenkins console)</em></strong></p><p>5. Click <strong>Configure &gt; Build Triggers</strong> and check <strong>GitHub hook trigger for GITScm polling</strong>. Click <strong>Save</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/780/1*InIsdsAkYRdEOf41WiEImA.png" /><figcaption>Github Build Triggers</figcaption></figure><p>6. To test, make a change in the <strong>config.mqsc.tmpl</strong> file and push the changes into Github repository.</p><p>7. Note that build job is triggered in Github.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MU5wzP9foRa5aM3rsRziYA.png" /><figcaption>Github Webhook recent deliveries</figcaption></figure><p>and in Jenkins.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1xTX290l0t7KBQNQ7mR2Rg.png" /><figcaption>Jenkins build dashboard</figcaption></figure><p>Hopeful you enjoy this tutorial. Merry Christmas and Happy New Year!</p><p><strong>Disclaimer:</strong></p><p><em>All opinions expressed here are very much my own and not of IBM. All codes/scripts/artifacts are provided as-is with no support unless otherwise stated</em><strong><em>.</em></strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=82e54f0ac4fe" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Using API Connect Vanity Endpoints running on K8S]]></title>
            <link>https://khongks.medium.com/using-api-connect-vanity-endpoints-running-on-k8s-ba763cf7a089?source=rss-dbd3cf73ac04------2</link>
            <guid isPermaLink="false">https://medium.com/p/ba763cf7a089</guid>
            <dc:creator><![CDATA[Kok Sing Khong]]></dc:creator>
            <pubDate>Sat, 03 Jul 2021 03:04:21 GMT</pubDate>
            <atom:updated>2022-06-24T03:49:30.546Z</atom:updated>
            <content:encoded><![CDATA[<p>This article describes one approach of using vanity API endpoints in API Connect v2018 or v10, specifically on K8S (because this was what I was working on). However, the concepts discussed here is applicable in other deployment, OpenShift or VMware deployment.</p><p>Before I continue, let us understand vanity endpoints in API Connect.</p><ul><li>What is vanity API endpoint?</li><li>Why is it needed?</li><li>How it is implemented?</li></ul><p>From the API Connect documentation, an API has two endpoints</p><ul><li>The gateway endpoint at which the API is invoked.</li><li>The endpoint that is visible to the consumer in the Developer Portal.</li></ul><p>By default, these two endpoints are the same. E.g. if your provider organization is <strong>acme</strong>, your catalog is <strong>public</strong>, your API base path is <strong>/v1/app </strong>and the resource path is <strong>/customers</strong>; then the application will consume the API using this endpoint</p><pre>https://apigateway/acme/public/v1/app/customers</pre><p>However, in most cases, company would like their public APIs to be known differently. Using the example above, they would like to “hide” the provider organization and catalog in API endpoint.</p><pre>https://apigateway/v1/app/customer</pre><p>So, the way to do this in API Connect is using vanity API endpoint, which can be configured in the Catalog. In doing so, this vanity API endpoint will be published to the Developer Portal and is used by the application to invoke the API.</p><p>However, what is not clear in the documentation is you have to handle the traffic routing so that when the application invokes the published vanity API endpoint, it gets routed to the actual API invocation endpoint of the gateway services.</p><p>There are various ways to implement this — and this article describe how this can be done using ingress in K8S. The following is an example of the ingress object.</p><pre>apiVersion: networking.k8s.io/v1beta1<br>kind: Ingress<br>metadata:<br>  annotations:<br>    ingress.kubernetes.io/proxy-read-timeout: &quot;240&quot;<br>    ingress.kubernetes.io/proxy-send-timeout: &quot;240&quot;<br>    ingress.kubernetes.io/ssl-redirect: &quot;true&quot;<br>    ingress.kubernetes.io/rewrite-target: /${porg_name}/${catalog_name}/\$1<br>    ingress.kubernetes.io/ssl-prefer-server-ciphers: &quot;true&quot;<br>    ingress.kubernetes.io/ssl-ciphers: &quot;ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256&quot;<br>    kubernetes.io/ingress.class: nginx<br>    meta.helm.sh/release-name: ${release_name}<br>    meta.helm.sh/release-namespace: ${namespace}<br>    nginx.ingress.kubernetes.io/backend-protocol: HTTPS<br>    nginx.ingress.kubernetes.io/proxy-read-timeout: &quot;240&quot;<br>    nginx.ingress.kubernetes.io/proxy-send-timeout: &quot;240&quot;<br>    nginx.ingress.kubernetes.io/proxy-ssl-server-name: &quot;on&quot;<br>    nginx.ingress.kubernetes.io/ssl-redirect: &quot;true&quot;<br>    nginx.ingress.kubernetes.io/rewrite-target: /${porg_name}/${catalog_name}/\$1<br>    nginx.ingress.kubernetes.io/ssl-prefer-server-ciphers: &quot;true&quot;<br>    nginx.ingress.kubernetes.io/ssl-ciphers: &quot;ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256&quot;<br>  name: ${name}<br>  namespace: ${namespace}<br>spec:<br>  rules:<br>  - host: ${endpoint_name}<br>    http:<br>      paths:<br>      - backend:<br>          serviceName: ${release_name}-dynamic-gateway-service-ingress<br>          servicePort: 9443<br>        path: /(.*)<br>  tls:<br>  - hosts:<br>    - ${endpoint_name}<br>    secretName: ${secret_name}<br>EOF</pre><p>The above ingress does the following</p><ul><li>Terminates the TLS using the server certificate and key defined a secret. In this case, the secret contains the tls.crt and tls.key.</li><li>Defines a list of preferred ciphers</li><li>Rewrite any incoming URI path to /${porg_name}/${catalog_name}/${incoming_uri_path}</li></ul><p>Another variation of this configuration is to terminate MTLS traffic. This ingress object shows how this can be done.</p><pre>apiVersion: networking.k8s.io/v1beta1<br>kind: Ingress<br>metadata:<br>  annotations:<br>    ingress.kubernetes.io/proxy-read-timeout: &quot;240&quot;<br>    ingress.kubernetes.io/proxy-send-timeout: &quot;240&quot;<br>    ingress.kubernetes.io/ssl-redirect: &quot;true&quot;<br>    ingress.kubernetes.io/rewrite-target: /${porg_name}/${catalog_name}/\$1<br>    ingress.kubernetes.io/ssl-prefer-server-ciphers: &quot;true&quot;<br>    ingress.kubernetes.io/ssl-ciphers: &quot;ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256&quot;<br>    ingress.kubernetes.io/auth-tls-verify-client: &quot;on&quot;<br>    ingress.kubernetes.io/auth-tls-secret: &quot;${namespace}/${secret_name}&quot;<br>    ingress.kubernetes.io/auth-tls-verify-depth: &quot;2&quot;<br>    ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: &quot;true&quot;<br>    kubernetes.io/ingress.class: nginx<br>    meta.helm.sh/release-name: ${release_name}<br>    meta.helm.sh/release-namespace: ${namespace}<br>    nginx.ingress.kubernetes.io/backend-protocol: HTTPS<br>    nginx.ingress.kubernetes.io/proxy-read-timeout: &quot;240&quot;<br>    nginx.ingress.kubernetes.io/proxy-send-timeout: &quot;240&quot;<br>    nginx.ingress.kubernetes.io/proxy-ssl-server-name: &quot;on&quot;<br>    nginx.ingress.kubernetes.io/ssl-redirect: &quot;true&quot;<br>    nginx.ingress.kubernetes.io/rewrite-target: /${porg_name}/${catalog_name}/\$1<br>    nginx.ingress.kubernetes.io/ssl-prefer-server-ciphers: &quot;true&quot;<br>    nginx.ingress.kubernetes.io/ssl-ciphers: &quot;ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256&quot;<br>    nginx.ingress.kubernetes.io/auth-tls-verify-client: &quot;on&quot;<br>    nginx.ingress.kubernetes.io/auth-tls-secret: &quot;${namespace}/${secret_name}&quot;<br>    nginx.ingress.kubernetes.io/auth-tls-verify-depth: &quot;2&quot;<br>    nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: &quot;true&quot;<br>  name: ${name}<br>  namespace: ${namespace}<br>spec:<br>  rules:<br>  - host: ${endpoint_name}<br>    http:<br>      paths:<br>      - backend:<br>          serviceName: ${release_name}-dynamic-gateway-service-ingress<br>          servicePort: 9443<br>        path: /(.*)<br>  tls:<br>  - hosts:<br>    - ${endpoint_name}<br>    secretName: ${secret_name}</pre><p>The above ingress does the following</p><ul><li>Terminates the MTLS using the server certificate and key defined a secret, and contains the signer certificate in truststore. In this case, the secret contains the tls.crt, tls.key and ca.crt.</li><li>Defines a list of preferred ciphers</li><li>Pass on the client certificate to downstream application as header ssl-client-cert in URL encoded format. So, if downstream application wants to use the certification, it needs to do URL decode.</li><li>Rewrite any incoming URI path to /${porg_name}/${catalog_name}/${incoming_uri_path}</li><li>Finally, it is important to tune the verify depth parameter you can use the signer certificate to do client certificate verification.</li></ul><p>One benefit of this approach is you can isolate TLS-only APIs from the MTLS-only APIs while sharing the same gateway service. You can publish TLS-only APIs to a TLS-only catalog and MTLS-only APIs to a MTLS-only catalog.</p><p>Let me know what you think in the comment section.</p><p><strong>References</strong></p><p><a href="https://www.ibm.com/docs/en/api-connect/10.0.1.x?topic=catalogs-creating-configuring">https://www.ibm.com/docs/en/api-connect/10.0.1.x?topic=catalogs-creating-configuring</a></p><p><a href="https://chrisphillips-cminion.github.io/apiconnect/2020/05/29/APIC-VanityURL.html">Vanity URLs in APIConnect v2018 and onwards</a></p><p><strong>Disclaimer:</strong></p><p><em>All opinions expressed here are very much my own and not of IBM. All codes/scripts/artifacts are provided as-is with no support unless otherwise stated</em><strong><em>.</em></strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ba763cf7a089" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Part 2 — Enable TLS communications via AMQP]]></title>
            <link>https://khongks.medium.com/part-2-enable-tls-communications-via-amqp-bad1b66cf88b?source=rss-dbd3cf73ac04------2</link>
            <guid isPermaLink="false">https://medium.com/p/bad1b66cf88b</guid>
            <category><![CDATA[qms]]></category>
            <category><![CDATA[amqp]]></category>
            <dc:creator><![CDATA[Kok Sing Khong]]></dc:creator>
            <pubDate>Fri, 01 May 2020 16:05:12 GMT</pubDate>
            <atom:updated>2020-05-01T16:05:12.046Z</atom:updated>
            <content:encoded><![CDATA[<h3>Part 2 — Enable TLS communications via AMQP</h3><p>This is the next installment of the series — to enable TLS communications for the AMQP channel we setup in the previous article. See <a href="https://medium.com/@khongks/part-1-getting-started-on-amqp-using-ibm-mq-99f59851856b">Part 1 here</a>. In this installment, I am going to show you to scenarios:</p><ul><li>Server authentication where the AMQP client checks the server certificate from the MQ queue manger</li><li>Mutual authentication where in addition to server authentication above; there is client authentication where the MQ queue manager checks the client certificate from the AMQP client.</li></ul><h3>Begin I begin</h3><ol><li>To simplify this exercise, I have written a script that generate the keys, certificates, keystores and truststores in the format that we need. In order for the script to run, you need to have the following tools:</li></ol><ul><li>openssl — which is found in most Linux OS</li><li>ikeycmd — which is packaged in the JRE of the MQ installation</li><li>keytool — which is packaged in the JRE of the MQ installation.</li></ul><p>2. Before you run the script, you should configure the variables.</p><ul><li>ROOT_CN — the label of the root certificate authority cert.</li><li>SERVER_CN — the label of the server certificate.</li><li>CLIENT_CN — the label of the client certificate.</li><li>C — the name of the country, e.g. AU</li><li>ST — the name of the state, e.g. VIC (for Victoria)</li><li>L — the name of the locality or city, e.g. Melbourne</li><li>O— the name of the organization, e.g. KKS</li><li>OU — the name of the organization or business unit, e.g. Cloud</li><li>DNS_1 — the DNS name of the MQ server</li><li>IP_1 — the IP address of the MQ server</li><li>PASS — the password for both the server and client keystore (for simplicity)</li><li>IKEYCMD_PATH — the path of ikeyman, e.g. `/opt/mqm/java/jre64/jre/bin`</li><li>KEYTOOL_PATH — the path of keytool, e.g. `/opt/mqm/java/jre64/jre/bin`</li></ul><p>3. The script generates the following that we are going to use. See scripts here (<a href="https://github.com/khongks/amqp-on-mq/blob/master/cert/gen_certs.sh">https://github.com/khongks/amqp-on-mq/blob/master/cert/gen_certs.sh</a>)</p><ul><li><strong>mqclient.crt </strong>— client certificate</li><li><strong>mqclient.key</strong> — client key</li><li><strong>mqclient.p12</strong> — keystore/truststore that contains the client certificate, client key and the root CA certificate in PKCS12 format; this is used by the AMQP client application.</li><li><strong>mqserver.crt</strong> — server certificate</li><li><strong>mqserver.key</strong> — server key</li><li><strong>mqserver.p12</strong> — keystore/truststore that contains the server certificate, server key and the root CA certificate in PKCS12 format; this is not used.</li><li><strong>mqserver.kdb</strong> —key database that stores personal certificates, personal certificate requests, and signer certificates.</li><li><strong>mqserver.rdb</strong> — “request” database file that contains certificate requests that are outstanding and have not yet been received from the CA.</li><li><strong>mqserver.sth</strong> — “stash” file that stores an obfuscated version of the key database password; also stores private keys, if there are any.</li><li><strong>rootca.crt</strong> — the root CA signer certificate</li><li><strong>rootca.key</strong> — the root CA key</li></ul><h3>Step 1: Configure the certificates in the queue manager</h3><ol><li>Inspect the queue manager to find where we should put the key database files. From here, it shows that the key database files should located in the folder /var/mqm/qmgrs/AMQP_SAMPLE_QM/ssl and the file name should be key.kdb.</li></ol><pre>$ runmqsc AMQP_SAMPLE_QM</pre><pre>: DIS QMGR</pre><pre>SSLKEYR(/var/mqm/qmgrs/AMQP_SAMPLE_QM/ssl/key)</pre><p>2. Login as user of mqm group and copy the following files into the folder; and changing the file names. Change the file ownership if you need to</p><pre>cp -p mqserver.kdb /var/mqm/qmgrs/AMQP_SAMPLE_QM/ssl/key.kdb<br>cp -p mqserver.rdb /var/mqm/qmgrs/AMQP_SAMPLE_QM/ssl/key.rdb<br>cp -p mqserver.sth /var/mqm/qmgrs/AMQP_SAMPLE_QM/ssl/key.sth</pre><pre>chown mqm:mqm /var/mqm/qmgrs/AMQP_SAMPLE_QM/ssl/key.kdb<br>chown mqm:mqm /var/mqm/qmgrs/AMQP_SAMPLE_QM/ssl/key.rdb<br>chown mqm:mqm /var/mqm/qmgrs/AMQP_SAMPLE_QM/ssl/key.sth</pre><h3>Step 2: Server authentication</h3><ol><li>Instead of using the same channel, we are creating a new AMQP channel for TLS communications. Create the following MQSC file AMQP.CHL.TLS.mqsc.</li></ol><ul><li>Defines are channel of type AMQP, with the label mqserver that matches the label we used during the creation of the certificate; that listens on port 5671 and specify client authentication SSLCAUTH as OPTIONAL.</li><li>Reload the SSL configuration into the queue manager memory.</li><li>Start the channel.</li></ul><pre>DEF CHL(SAMPLE.AMQP.CHL.TLS) CHLTYPE(AMQP) CERTLABL(&#39;mqserver&#39;) SSLCAUTH(OPTIONAL) PORT(5671) MCAUSER(nobody) SSLCIPH(TLS_RSA_WITH_AES_256_GCM_SHA384)</pre><pre>REFRESH SECURITY TYPE(SSL)<br>START CHL(SAMPLE.AMQP.CHL.TLS)</pre><p>2. Run the MQSC file and make sure there is no error.</p><pre>$ runmqsc AMQP_SAMPLE_QM &lt; SAMPLE.AMQP.CHL.TLS.mqsc</pre><p>3. Copy the root CA certificate into the ./cert folder.</p><p>4. Run the AMQP applications, specifying the following:</p><ul><li>-s URL, --service=URL: amqps://mqserver:5671</li><li>-c FILE, --trust-certificate=FILE: rootca.crt</li></ul><p>a. Start Receive application.</p><pre>java -classpath ./lib/proton-j-0.12.1.jar:./lib/gson-2.2.4.jar:./lib/logback-classic-1.1.2.jar:./lib/logback-core-1.1.2.jar:./lib/netty-all-4.0.21.Final.jar:./lib/slf4j-api-1.7.5.jar:./lib/stateless4j-2.5.0.jar:./mqlight/target/mqlight-api-1.0-SNAPSHOT.jar:./mqlight-samples/target/mqlight-api-samples-1.0-SNAPSHOT.jar com.ibm.mqlight.api.samples.Receive -s amqps://mqserver:5671 -c ./cert/rootca.crt</pre><p>b. Start Send application to send 10 messages.</p><pre>java -classpath ./lib/proton-j-0.12.1.jar:./lib/gson-2.2.4.jar:./lib/logback-classic-1.1.2.jar:./lib/logback-core-1.1.2.jar:./lib/netty-all-4.0.21.Final.jar:./lib/slf4j-api-1.7.5.jar:./lib/stateless4j-2.5.0.jar:./mqlight/target/mqlight-api-1.0-SNAPSHOT.jar:./mqlight-samples/target/mqlight-api-samples-1.0-SNAPSHOT.jar com.ibm.mqlight.api.samples.Send -r 10 -s amqps://mqserver:5671 -c ./cert/rootca.crt</pre><h3>Step 3: Mutual authentication</h3><ol><li>Update the AMQP channel to perform client authentication. Update the previous MQSC file AMQP.CHL.TLS.mqsc.</li></ol><ul><li>Update the AMQP channel with client authentication — SSLCAUTH as REQUIRED.</li><li>Reload the SSL configuration into the queue manager memory.</li><li>Stop and start the channel.</li></ul><pre>ALTER CHL(SAMPLE.AMQP.CHL.TLS) CHLTYPE(AMQP) SSLCAUTH(REQUIRED) </pre><pre>REFRESH SECURITY TYPE(SSL)<br>STOP CHL(SAMPLE.AMQP.CHL.TLS)<br>START CHL(SAMPLE.AMQP.CHL.TLS)</pre><p>2. Run the MQSC file and make sure there is no error.</p><pre>$ runmqsc AMQP_SAMPLE_QM &lt; SAMPLE.AMQP.CHL.TLS.MUTUAL.mqsc</pre><p>3. Copy the client keystore/truststore PKCS12 file into the ./cert folder.</p><p>4. Run the AMQP applications, specifying the following:</p><ul><li>-s URL, --service=URL: amqps://mqserver:5671</li><li>-k FILE, --keystore=FILE: mqclient.p12</li><li>-p PASSPHRASE, --keystore-passphrase=PASSPHRASE: Passw0rd!</li></ul><p>a. Start Receive application.</p><pre>java -classpath ./lib/proton-j-0.12.1.jar:./lib/gson-2.2.4.jar:./lib/logback-classic-1.1.2.jar:./lib/logback-core-1.1.2.jar:./lib/netty-all-4.0.21.Final.jar:./lib/slf4j-api-1.7.5.jar:./lib/stateless4j-2.5.0.jar:./mqlight/target/mqlight-api-1.0-SNAPSHOT.jar:./mqlight-samples/target/mqlight-api-samples-1.0-SNAPSHOT.jar com.ibm.mqlight.api.samples.Receive -s amqps://mqserver:5671 -k ./cert/mqclient.p12 -p Passw0rd!</pre><p>b. Start Send application to send 10 messages.</p><pre>java -classpath ./lib/proton-j-0.12.1.jar:./lib/gson-2.2.4.jar:./lib/logback-classic-1.1.2.jar:./lib/logback-core-1.1.2.jar:./lib/netty-all-4.0.21.Final.jar:./lib/slf4j-api-1.7.5.jar:./lib/stateless4j-2.5.0.jar:./mqlight/target/mqlight-api-1.0-SNAPSHOT.jar:./mqlight-samples/target/mqlight-api-samples-1.0-SNAPSHOT.jar com.ibm.mqlight.api.samples.Send -r 10 -s amqps://mqserver:5671 -k ./cert/mqclient.p12 -p Passw0rd!</pre><p>Alternative, instead of the PKCS12 file, you can run the AMQP applications; specify the following:</p><ul><li>-s URL, --service=URL: amqps://mqserver:5671</li><li>--client-certificate=FILE: mqclient.crt</li><li>--client-key=FILE: mqclient.key</li><li>--client-key-passphrase=PASSPHRASE: Passw0rd!</li><li>-c FILE, --trust-certificate=FILE: rootca.crt</li></ul><p>a. Start Receive application.</p><pre>java -classpath ./lib/proton-j-0.12.1.jar:./lib/gson-2.2.4.jar:./lib/logback-classic-1.1.2.jar:./lib/logback-core-1.1.2.jar:./lib/netty-all-4.0.21.Final.jar:./lib/slf4j-api-1.7.5.jar:./lib/stateless4j-2.5.0.jar:./mqlight/target/mqlight-api-1.0-SNAPSHOT.jar:./mqlight-samples/target/mqlight-api-samples-1.0-SNAPSHOT.jar com.ibm.mqlight.api.samples.Receive -s amqps://mqserver:5671 --client-certificate=./cert/mqclient.crt --client-key=./cert/mqclient.key --client-key-passphrase=Passw0rd! --trust-certificate=./cert/rootca.crt</pre><p>b. Start Send application to send 10 messages.</p><pre>java -classpath ./lib/proton-j-0.12.1.jar:./lib/gson-2.2.4.jar:./lib/logback-classic-1.1.2.jar:./lib/logback-core-1.1.2.jar:./lib/netty-all-4.0.21.Final.jar:./lib/slf4j-api-1.7.5.jar:./lib/stateless4j-2.5.0.jar:./mqlight/target/mqlight-api-1.0-SNAPSHOT.jar:./mqlight-samples/target/mqlight-api-samples-1.0-SNAPSHOT.jar com.ibm.mqlight.api.samples.Send -r 10 -s amqps://mqserver:5671 --client-certificate=./cert/mqclient.crt --client-key=./cert/mqclient.key --client-key-passphrase=Passw0rd! --trust-certificate=./cert/rootca.crt</pre><h3>Finally</h3><p>As with any security type of configuration, it tends to be tedious, hard to debug if you encountered issues. If you have a good understanding of Public Key Infrastructure (PKI) and how TLS/SSL works; you can guess the problems. The most challenging hurdle of this task, for me was really to get the keys, certificates, keystores and truststores generated correctly, and in the right format that is required by the queue manager and the AMQP Java application — trying to figure out how to specify the input paramaters. As you noted, the MQ specific configurations are pretty straight forward. How you find this article useful.</p><p>You can find my script here.</p><p><a href="https://github.com/khongks/amqp-on-mq/blob/master/cert/gen_certs.sh">https://github.com/khongks/amqp-on-mq/blob/master/cert/gen_certs.sh</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=bad1b66cf88b" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Part 1 —  Getting started on AMQP using IBM MQ]]></title>
            <link>https://khongks.medium.com/part-1-getting-started-on-amqp-using-ibm-mq-99f59851856b?source=rss-dbd3cf73ac04------2</link>
            <guid isPermaLink="false">https://medium.com/p/99f59851856b</guid>
            <category><![CDATA[ibm]]></category>
            <category><![CDATA[amqp]]></category>
            <category><![CDATA[qms]]></category>
            <dc:creator><![CDATA[Kok Sing Khong]]></dc:creator>
            <pubDate>Sat, 18 Apr 2020 08:28:18 GMT</pubDate>
            <atom:updated>2022-06-24T03:48:19.337Z</atom:updated>
            <content:encoded><![CDATA[<h3>Part 1 — Getting started on AMQP using IBM MQ</h3><p>A couple of days ago, a customer requested for a Proof of Concept to show how to configure IBM MQ to provide messaging service via AMQP. This feature is not new, but I never gotten around to play with it. I spent a couple of hours fiddling and found that it wasn’t rocket science. I wrote this article so that others can benefit from my journey.</p><p>As it is middle of a lock down due to COVID-19, I do have some spare time; therefore I decided this to be a 4-part series.</p><ul><li>Part 1 — Getting started on AMQP using IBM MQ</li><li>Part 2 — Enable TLS communications via AMQP</li><li>Part 3 — Create a custom Docker image with AMQP configurations</li><li>Part 4 — Deploy Docker image on Red Hat OpenShift</li></ul><h3>Before I begin</h3><p>First of all, let me start by laying out the environment.</p><ul><li>IBM MQ v9.1.0.4</li><li>RedHat v7.7</li><li>OpenJDK v11 to compile and run the sample Java code</li></ul><h3><strong>Step 1: Prepare the AMQP configuration</strong></h3><ol><li>Ensure that you have included the AMQP bundle when installing IBM MQ. To check if you have installed this bundle, run the following command.</li></ol><pre>$ rpm -qa --qf &quot;%{NAME}-%{VERSION}-%{RELEASE}\t%{INSTPREFIXES}\n&quot; | grep MQSeriesAMQP</pre><pre>MQSeriesAMQP-9.1.0-4 /opt/mqm</pre><p>2. Run sample script to create a sample configuration for AMQP. Note that you must run this command using a user that is in the mqmgroup.</p><pre>$ cd /opt/mqm/amqp/samples<br>$ ./SampleMQM.sh</pre><p>This script does the following:</p><ul><li>Creates a queue manager AMQP_SAMPLE_QM.</li><li>Sets authorizations to allow everybody to connect to the queue manager and to publish and subscribe to the base topic SYSTEM.BASE.TOPIC.</li><li>Start the queue manager and the AMQP service SYSTEM.AMQP.SERVICE.</li><li>Defines a AMQP channel with port ranging 1–5672</li><li>Finally starts the channel</li></ul><pre># This script creates an AMQP-enabled Queue manager to allow quick testing.</pre><pre># Get the name of the Queue Manager<br>QMGR=AMQP_SAMPLE_QM</pre><pre># Get the Port number<br>PORT=${1-5672}</pre><pre># Check the queue manager doesn&#39;t exist already<br>dspmq -m $QMGR &gt;/dev/null 2&gt;&amp;1<br>rc=$?<br>if [ $rc -eq 0 ]; then<br>  echo &quot;Queue manager $QMGR already exists.&quot;<br>  exit 1<br>fi</pre><pre>crtmqm $QMGR<br>strmqm $QMGR</pre><pre># Allow user nobody to publish and subscribe on any topic.<br># Note: Allowing the user nobody to do something in MQ, allows all users to do it!<br>setmqaut -m $QMGR -t qmgr -p nobody -all +connect<br>setmqaut -m $QMGR -t topic -n SYSTEM.BASE.TOPIC -p nobody -all +pub +sub</pre><pre># Start the service<br>echo &quot;START SERVICE(SYSTEM.AMQP.SERVICE)&quot; | runmqsc $QMGR</pre><pre># Create and start a channel<br>echo &quot;DEFINE CHANNEL(SAMPLE.AMQP.CHANNEL) CHLTYPE(AMQP) PORT($PORT) MCAUSER(&#39;nobody&#39;)&quot; | runmqsc $QMGR</pre><pre>sleep 2<br>echo &quot;START CHANNEL(SAMPLE.AMQP.CHANNEL)&quot; | runmqsc $QMGR</pre><h3>Step 2: Compile and run a sample Java code</h3><ol><li>Clone the java-mqlight repository from Github</li></ol><pre>$ git clone <a href="https://github.com/mqlight/java-mqlight.git">https://github.com/mqlight/java-mqlight.git</a></pre><p>2. Before you try to compile and generate the JAR file, let’s make a couple of modifications in the pom.xml to save you many heartaches.</p><ul><li>Remove the version here — so that we can use the later version. There is some problems with version 3.0.0.</li></ul><pre>&lt;groupId&gt;org.codehaus.mojo&lt;/groupId&gt;<br>&lt;artifactId&gt;findbugs-maven-plugin&lt;/artifactId&gt;<br>&lt;!-- version&gt;3.0.0&lt;/version --&gt;</pre><ul><li>Remove the plugin maven-javadoc-plugin. This is some issues generating Java documentation</li></ul><pre>&lt;!--<br>        &lt;plugin&gt;<br>          &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;<br>          &lt;artifactId&gt;maven-javadoc-plugin&lt;/artifactId&gt;<br>          &lt;version&gt;2.10.1&lt;/version&gt;<br>          &lt;configuration&gt;<br>            &lt;excludePackageNames&gt;com.ibm.mqlight.api.impl&lt;/excludePackageNames&gt;<br>          &lt;/configuration&gt;<br>          &lt;executions&gt;<br>            &lt;execution&gt;<br>              &lt;id&gt;attach-javadocs&lt;/id&gt;<br>              &lt;goals&gt;<br>                &lt;goal&gt;jar&lt;/goal&gt;<br>              &lt;/goals&gt;<br>            &lt;/execution&gt;<br>          &lt;/executions&gt;<br>        &lt;/plugin&gt;<br>--&gt;</pre><p>3. Now, you can start compile and generate the target JAR files; but remember to skip the test because there are some issues. All we need is the JAR executable is generated.</p><pre>$ cd java-mqlight<br>$ mvn install -Dmaven.test.skip=true</pre><p>5. On build success, you will see this.</p><pre>[INFO] Reactor Summary for com.ibm.mqlight:mqlight-project 1.0-SNAPSHOT:<br>[INFO]<br>[INFO] com.ibm.mqlight:mqlight-project .................... SUCCESS [  0.347 s]<br>[INFO] com.ibm.mqlight:mqlight-api ........................ SUCCESS [  8.752 s]<br>[INFO] com.ibm.mqlight:mqlight-api-samples ................ SUCCESS [  2.572 s]<br>[INFO] com.ibm.mqlight:mqlight-distribution ............... SUCCESS [  0.487 s]<br>[INFO] ------------------------------------------------------------------------<br>[INFO] BUILD SUCCESS<br>[INFO] ------------------------------------------------------------------------<br>[INFO] Total time:  12.726 s<br>[INFO] Finished at: 2020-04-18T17:47:51+10:00<br>[INFO] ------------------------------------------------------------------------</pre><p>6. You will find the following executable JARs generated that you are interested in.</p><ul><li>./mqlight/target/mqlight-api-1.0-SNAPSHOT.jar</li><li>./mqlight-samples/target/mqlight-api-samples-1.0-SNAPSHOT.jar</li></ul><p>7. There is a error in the packaging; a missing dependencies JAR file — <strong>proton-j-0.12.1.jar</strong>. Google and download to the <strong>lib</strong> folder.</p><p>8. Now, try to run the Receive application.</p><pre>java -classpath ./lib/proton-j-0.12.1.jar:./lib/gson-2.2.4.jar:./lib/logback-classic-1.1.2.jar:./lib/logback-core-1.1.2.jar:./lib/netty-all-4.0.21.Final.jar:./lib/slf4j-api-1.7.5.jar:./lib/stateless4j-2.5.0.jar:./mqlight/target/mqlight-api-1.0-SNAPSHOT.jar:./mqlight-samples/target/mqlight-api-samples-1.0-SNAPSHOT.jar com.ibm.mqlight.api.samples.Receive -s amqp://ibmmqserver:5672</pre><p>It shows it is connected and it is subscribed to the public topic.</p><pre>Connected to amqp://ibmmqserver:5672 using client-id AUTO_7e2839f<br>Subscribed to pattern: public</pre><p>9. Open another terminal window, and run the Send application to send 10 messages.</p><pre>java -classpath ./lib/proton-j-0.12.1.jar:./lib/gson-2.2.4.jar:./lib/logback-classic-1.1.2.jar:./lib/logback-core-1.1.2.jar:./lib/netty-all-4.0.21.Final.jar:./lib/slf4j-api-1.7.5.jar:./lib/stateless4j-2.5.0.jar:./mqlight/target/mqlight-api-1.0-SNAPSHOT.jar:./mqlight-samples/target/mqlight-api-samples-1.0-SNAPSHOT.jar com.ibm.mqlight.api.samples.Send -s amqp://[ibmmqserver]:5672 -r 10</pre><p>It shows it is connected and sending 10 messages before exiting</p><pre>Connected to amqp://ibmmqserver:5672 using client-id AUTO_714422f<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Exiting</pre><p>10. Now switch back to the terminal window that is running the Receive application. You will see the messages received.</p><pre>Subscribed to pattern: public<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!<br>Hello World!</pre><h3>Finally</h3><p>OK, there you have it, it was not difficult. The most challenging aspect was trying to get the Java sample code to compile. There were Java incompatibility issues and bundle incompatibility issues. And then, there was a packaging issue (maybe should feedback to the author). Nevertheless, I did some workaround and managed to make it work. It was not perfect, but it works!! Maybe, I should try the Python sample code next round?</p><p><strong>Disclaimer:</strong></p><p><em>All opinions expressed here are very much my own and not of IBM. All codes/scripts/artifacts are provided as-is with no support unless otherwise stated</em><strong><em>.</em></strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=99f59851856b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>