At BetterDoc we’re currently in the process of step by step replacing an old monolithic application with a microservice landscape. Sometime in early January 2019 we talked over lunch we asked ourselves “What could be a crazy language in which we could implement one of our microservices just to prove that it can be done?”. I’m not really sure whose idea it was but one of us said “What about COBOL?”.
Of course it was meant as a joke, I mean who would start a new COBOL project in the 21st century? But I thought to myself “What the heck, why not?”. I’ve never really looked into COBOL so it sounded like a nice challenge to pick up. So I said actually tried it.
Having never had contact with COBOL before the first steps for me to be able to do anything useful were to look for a COBOL compiler and a tutorial on how to get a “Hello World!” program written and run on a Mac.
In the end for a COBOL application to be runnable in our microservice architecture all I needed to accomplish was to have a COBOL application running inside a Docker container listening for incoming HTTP requests.
Thanks to the internet it didn’t took long to assemble the basic infrastructure. Actually it was way simpler than I thought.
First I needed to install GNU Cobol which didn’t take more than executing
$ brew install gnu-cobol
The famous “Hello World” in COBOL I copied from the web was this:
IDENTIFICATION DIVISION. PROGRAM-ID. HelloWorld. PROCEDURE DIVISION. DISPLAY "Hello World!". STOP RUN.
It took me some time to figure out the right compiler flags for turning this into a program binary but this did the trick:
cobc -x -free helloworld.cob
Voila, that’s it!
Now to have that as a microservice I needed to wrap it into a Docker container.
Interestingly for the first time since studying computer science I had to deal with platform specific binaries. I spent most of my professional time developing Java application, so a JAR file generated by a compiler on one platform could easily be packaged and run on another platform. The same was true for an interpreted language like Ruby.
But COBOL was a different beast: The executable I had created on my local Mac couldn’t be simply packaged inside a Docker container and run inside that container, as Docker is based on Linux as a platform.
So instead of building the application and then simply adding the artifacts created to a runtime in a Docker container I chose to perform the build process inside the target Docker container during the container creation process.
For a real world application I would have chosen a more elaborate setup by having a special build container (based on Linux) spawn by a Continuous Integration server, have that container build a Linux library and then package that binary into a runtime container. But since this is more a proof-of-concept I decided to go the easy way and build the application during the container creation.
So let’s take a look at the Dockerfile:
FROM ubuntu:latest RUN apt-get update && apt-get install -y open-cobol gcc COPY *.cob /cobol/ WORKDIR /cobol RUN cobc -x -free *.cob
To verify that everything works correctly I can build and run this locally:
$ docker build -t example/cobolservice . $ docker run example/cobolservice
The output - as expected - is:
Interestingly enough after doing some more research on the web I found out that COBOL really doesn’t support web development as we know it today, especially that there are no real frameworks or libraries out there that allow a COBOL applications to function as webservers.
The canonical solution for such a usecase seems to be to use a COBOL application as target for a CGI script or expose the output of that script via HTTP through any other means.
For the sake of my example I found a nice little tool called “shell2http” that does exactly that: Expose a shell command via an HTTP port.
So let’s add this to our docker file:
FROM ubuntu:latest RUN apt-get update && apt-get install -y open-cobol gcc wget unzip RUN mkdir /shell2http WORKDIR /shell2http RUN wget https://github.com/msoap/shell2http/releases/download/1.7/\ shell2http-1.7.linux.386.zip RUN unzip shell2http-1.7.linux.386.zip COPY *.cob /cobol/ WORKDIR /cobol RUN cobc -x -free *.cob CMD ["/shell2http/shell2http", "-port", "80", "/helloworld",\ "/cobol/helloworld"]
Putting everything together we can spin up the container and test whether everything works:
$ docker build -t example/cobolservice . $ docker run -p 8088:80 example/cobolservice
Now I can access the application from the browser
Of course I knew from the very beginning that this would never be a real option for creating one of our services (nor was it ever intended to become one). But it was a nice experiment to see what could be done and what hoops you have to jump through in 2019 to get a COBOL application up and running in a modern setup. Looks like there are ways to isolate that old COBOL code and integrate it into some sort of modern environment.
I also got quite an appreciation (or perhaps compassion would be a better word) for my fellow developers out there working with COBOL these days. It also helps me appreciate the tools and frameworks we have today that allow us to work blazingly fast while at the same time enjoying what we do.