worksofliam / blog

Blog
28 stars 5 forks source link

Deploying a Node.js + Db2 for i app using Docker (from a Codespace!) #59

Open worksofliam opened 2 years ago

worksofliam commented 2 years ago

Building an app that uses ODBC to talk to Db2 for i takes some work these days. You need ODBC, the chosen driver (Db2 for i / iaccess) and unixodbc if you're not on Windows.

Up until recently, it's taken some work to get all these pieces. You could easily install unixodbc, but the driver has usually been downloaded from the IBM website behind a signup. Then there is node-odbc which needs to be built on unsupported platforms (where pre-built binaries have not been provided) - luckily, all the major archs (Windows x86, OSX Darwin, Linux, etc) now have pre-built binaries!

Luckily, for all those pieces, they are so easy to get now. Putting all the work into a Dockerfile is the next logical step to make an awesome pipeline.

The latest big change is that IBM now allow you to install iaccess (the Db2 for i ODBC driver) through a package manager on Linux (apt for example). Kevin Adler wrote about that on his blog. Previously, people who were automating this were using their own way to install it.. like making the deb available through their own service.

This guide will take an existing Node.js app (a basic one) and show you how to deploy it using Docker with a Dockerfile onto Heroku - though it should work with pretty much any cloud services.

Codespaces

I am going to do all this using a GitHub Codespace. I like Codespaces a lot. I can write all my Node.js code, use ODBC and iaccess on a Codespace like I can on my local machine.. except I can move between devices and have the same environment.

For this guide, you do need docker installed on whatever machine you use. We will use docker to test our build of the image, and of course you can run the app locally using docker if you wanted.

B03DB2D1-1BC1-4047-AE9D-32ADE0A86A26

Repo

You can find the repo I used for this demo on my GitHub. I took a basic Node.js + node-odbc example and basically added a Dockerfile - easy.

Checking it works

Open the repo up into VS Code - either on your local machine or in your Codespace. From the Terminal, make sure docker is working. You should see all the help text appear.

@worksofliam ➜ /workspaces/node-odbc-express (main) $ docker

Usage:  docker [OPTIONS] COMMAND

D3FDD6DF-F8B0-4D1A-9E22-B3C4A2EBC48F

Creating a Dockerfile

A Dockerfile is used to determine how to build the image and run the app. Here is the contents of the Dockerfile for our demo app.. and I am more than sure it will apply to lots of apps outside of this.

FROM node:16.7.0

USER root

COPY . /nodeapp
WORKDIR /nodeapp

RUN curl https://public.dhe.ibm.com/software/ibmi/products/odbc/debs/dists/1.1.0/ibmi-acs-1.1.0.list | tee /etc/apt/sources.list.d/ibmi-acs-1.1.0.list

RUN apt update
RUN apt -y install ibm-iaccess

ENV PORT=$PORT
ENV DB_CONNSTR=$DB_CONNSTR

CMD npm run start

There are some important parts to note here:

Testing build

Before we can deploy our image, we need to test that it will build. This checks it can run all the commands, etc, provided in the Dockerfile.

@worksofliam ➜ /workspaces/node-odbc-express (main ✗) $ docker build --no-cache -t tmp_image .
[+] Building 14.0s (11/11) FINISHED                                                                                                                                                          
 => [internal] load build definition from Dockerfile                                                                                                                                    0.1s
 => => transferring dockerfile: 411B                                                                                                                                                    0.0s
 => [internal] load .dockerignore                                                                                                                                                       0.1s
 => => transferring context: 2B                                                                                                                                                         0.0s
 => [internal] load metadata for docker.io/library/node:16.7.0                                                                                                                          0.2s
 => CACHED [1/6] FROM docker.io/library/node:16.7.0@sha256:d75b1663c035a5e9ed48ad54041aff3067d6a66104d32d07901314e573393d2a                                                             0.0s
 => [internal] load build context                                                                                                                                                       0.1s
 => => transferring context: 82.96kB                                                                                                                                                    0.0s
 => [2/6] COPY . /nodeapp                                                                                                                                                               0.4s
 => [3/6] WORKDIR /nodeapp                                                                                                                                                              0.3s
 => [4/6] RUN curl https://public.dhe.ibm.com/software/ibmi/products/odbc/debs/dists/1.1.0/ibmi-acs-1.1.0.list | tee /etc/apt/sources.list.d/ibmi-acs-1.1.0.list                        1.0s
 => [5/6] RUN apt update                                                                                                                                                                2.9s 
 => [6/6] RUN apt -y install ibm-iaccess                                                                                                                                                5.6s 
 => exporting to image                                                                                                                                                                  3.2s 
 => => exporting layers                                                                                                                                                                 3.1s 
 => => writing image sha256:2560006c2f00708ec3201374eadb9a5226abfdf5b61661be33b262899cd68436                                                                                            0.0s 
 => => naming to docker.io/library/tmp_image                                                                                                                                            0.0s 

If it failed, you will know.

Deploying to Heroku

You can use any service you want. Digital Ocean, AWS, Azure, and others, all have their own app services-type infrastructure for you to run apps in the cloud. I have used Heroku before, so I am using it again for this demo.

We will use both Heroku UI and Heroku CLI to deploy our app.

  1. Install the Heroku CLI. You will need it in order to deploy an app that uses Docker to Heroku.
  2. Sign up and create a new app (not pipeline) in Heroku. It's free!
  3. Head over to the Deploy tab, and select 'Container Registry' as the deployment method.
  4. It should show a set of instructions using the Heroku CLI to deploy your app. Let's do that!

First, we need to log into Heroku from the CLI.

@worksofliam ➜ /workspaces/node-odbc-express (main) $ heroku login -i
heroku: Enter your login credentials
Email: barry@me.com
Password: ************************************
Logged in as barry@me.com

Before you continue, this is a good time to setup your environment variables for your app instance in Heroku. You can do this under Config Vars in settings:

E051C80E-ECE6-4C78-87F0-9DCE41657A3E

Next, connect to the the container registry:

@worksofliam ➜ /workspaces/node-odbc-express (main) $ heroku container:login
Login Succeeded

Now it's time to build your image on Heroku! Notice I am using the -a parameter to specify the app.

@worksofliam ➜ /workspaces/node-odbc-express (main) $ heroku container:push web -a odbc-docker-example
=== Building web (/workspaces/node-odbc-express/Dockerfile)
[+] Building 15.4s (12/12) FINISHED                                                                                                                                                          
 => [internal] load build definition from Dockerfile                                                                                                                                    0.2s
 => => transferring dockerfile: 407B                                                                                                                                                    0.0s
 => [internal] load .dockerignore                                                                                                                                                       0.3s
 => => transferring context: 48B                                                                                                                                                        0.0s
 => [internal] load metadata for docker.io/library/node:16.7.0                                                                                                                          0.3s
 => [auth] library/node:pull token for registry-1.docker.io                                                                                                                             0.0s
 => CACHED [1/6] FROM docker.io/library/node:16.7.0@sha256:d75b1663c035a5e9ed48ad54041aff3067d6a66104d32d07901314e573393d2a                                                             0.0s
 => [internal] load build context                                                                                                                                                       1.3s
 => => transferring context: 18.04MB                                                                                                                                                    1.1s
 => [2/6] COPY . /nodeapp                                                                                                                                                               0.5s
 => [3/6] WORKDIR /nodeapp                                                                                                                                                              0.2s
 => [4/6] RUN curl https://public.dhe.ibm.com/software/ibmi/products/odbc/debs/dists/1.1.0/ibmi-acs-1.1.0.list | tee /etc/apt/sources.list.d/ibmi-acs-1.1.0.list                        1.1s
 => [5/6] RUN apt update                                                                                                                                                                2.8s
 => [6/6] RUN apt -y install ibm-iaccess                                                                                                                                                5.6s 
 => exporting to image                                                                                                                                                                  3.2s 
 => => exporting layers                                                                                                                                                                 3.1s 
 => => writing image sha256:ca723cc9385b592a5231129f8fb3f57136fa7ddd306c41d8e269ec9d4437eae6                                                                                            0.0s 
 => => naming to registry.heroku.com/odbc-docker-example/web                                                                                                                            0.0s 
=== Pushing web (/workspaces/node-odbc-express/Dockerfile)                                                                                                                                   
Using default tag: latest                                                                                                                                                                    
The push refers to repository [registry.heroku.com/odbc-docker-example/web]
69bf5b2a57a5: Pushed 
latest: digest: sha256:a4b8a915ceb7492750cef34cd7b7ff52e5164c935bd5ddcc24e64239001da677 size: 3261
Your image has been successfully pushed. You can now release it with the 'container:release' command.

Finally, deploy the app:

@worksofliam ➜ /workspaces/node-odbc-express (main) $ heroku container:release web -a odbc-docker-example
Releasing images web to odbc-docker-example... done

Here is the /employee endpoint from my sample being returned from my Heroku app running on a container!

27785C48-A416-44EF-9C6C-5F151EB227DD

mdgozza commented 2 years ago

Really love your work @worksofliam 😍

We have this automated where I worked, but never thought to share like you have!

It’s nice to see that driver make its way to the package managers, it was always a pain!!

cole-maxwell1 commented 2 years ago

This is REALLY cool! I have this pie-in-the-sky idea of using docker-compose with docker db2 in a docker dev container for testing new things without even having to touch anything on IBM i. Do you think something like that might work? Frameworks like Laravel have really good database seeding tools that might make this viable...

I am very new to the platform in general, but things like this post and Merlin are getting me excited!

worksofliam commented 2 years ago

@cole-maxwell1 Cool idea! I guess if you can get node-odbc to work with Db2 LUW then that's a good start! My next worry is differences in how data is returned, connection strings, SQL syntax differences. I'd be interested in seeing a single app run with two different databases, though (Db2 LUW and Db2 for i)

cole-maxwell1 commented 2 years ago

I wanted to link to this blog post "CONTINUOUS INTEGRATION FOR PHP EXTENSIONS" over at Seiden Group by Calvin Buckley. They are actually using the db2 docker container for their CI tests on ibm_db2 and PDO_IBM PHP projects. Interesting stuff!

beckhamrryyaann commented 2 years ago

Thanks for the post! I did not realize you could install the odbc driver now from the package manager! I have written a Rest API in NodeJS connecting to our IBM i that is containerized with Docker for an Android App I developed. I use docker compose to create multiple instances of the app running on our linux vm. (see image below of my current docker file) So now going forward i should be able to use apt install after i've updated the repository list???

I am very excited about this MerLin technology coming. Now i just go to figure out how to get my other colleagues still writing in fixed format RPG to use it !!! :-)

image

kraudy commented 5 months ago

It is quite amazing that this was written 2 yeasrs ago