Dockerizing OpenMRS

I noticed on the notes from the recent Scrum of Scrums several implementations are starting to use Docker for production systems. I’m currently working on describing how OpenMRS could be implemented for MSF and was going to recommend use of Docker for simpler deploy, maintenance, upgrades.

I recognize their was a “to do” to set up a moderated discussion on “How to dockerize OpenMRS”. In the meantime, does anyone have some notes or a recipe documented somewhere from which I could draw?

/cc @jdick @pascal @mogoodrich

6 Likes

We’ve done a lot of work on dockerizing eSaude over the past couple of years. @pascal has put together some good documentation around it with the eSaude team here:

@pascal can probably tell you where those need updating or improvements we could be making though. Hope that’s helpful!

3 Likes

The eSaude Platform (i.e. OpenMRS) is Dockerized here: https://github.com/esaude/esaude-platform-docker. The prebuilt compose file and the tomcat and mysql directories contain more info.

Also happy to join the moderated discussion.

3 Likes

Hi @burke,

We are developing our third generation CI/CD platform, simply named “OpenMRS CD” (which in itself will be shipped as a reusable Jenkins Docker container). It rather relates to this specific part:

Our aim is to reuse the same core/fundamental deployment pipelines, regardless of context (development, staging, QA or production servers). We don’t do anything outstanding regarding the underlying OpenMRS Docker container itself though. So if the pipeline-only delivery aspect is of interest, we are happy to be involved as well.

P.S. Note that we hope for this OpenMRS CD to be entirely reusable and configurable so that other groups managing OpenMRS delivery pipelines could adopt it. Not the #1 priority at this stage, but it is worth noting that this custom CD platform is designed & built with this use case in mind.

Cc: @mksrom

1 Like

Let me collect everything I’ve learned deploying Reference Application as docker. Not sure how much it can be applied to other distros.

The OpenMRS SDK has a build-distro goal, and it’s awesome :smiley: It should work with any distro that uses a openmrs-distro.properties file:

mvn openmrs-sdk:build-distro -Ddistro=/path/to/openmrs-distro.properties

You have a lot of different options, including if the distributions plugins will be bundled. The maven goal will not only generate files to build the docker image, but also docker-compose files.

In the reference application maven lifecycle, we have that plugin as part of the default maven lifecycle. In CI, after the mvn deploy, we build the docker image and push to dockerhub as ‘nightly’ tag.

Build config
docker login -u <username> -p <password>
cd docker
docker build -t openmrs/openmrs-reference-application-distro:nightly .
docker push openmrs/openmrs-reference-application-distro:nightly
docker image inspect --format='{{index .RepoDigests 0}}' openmrs/openmrs-reference-application-distro:nightly > docker-image.txt

The last line will store the ID of the image in a file, so later on the pipeline we can deploy the same image with other tags.

We have a different docker tag per environment/server we have, so the version on each one is updated independently.

We are not using the docker-compose files generated by the SDK. Instead, I do have them in an ansible role. We create volumes for /usr/local/tomcat/.OpenMRS/ and database data. The docker compose should expose only openmrs port on the host, and the README file has more information.

To update the servers after a deployment, there are two ways:

I’m using nginx in front of docker:

Nginx vhost config
server {
  listen 80;
  server_name msf.openmrs.org;
  index index.html index.htm;
  return 301 https://$host$request_uri;
} 
server {
    listen 443 ssl;
    server_name msf.openmrs.org;
    index index.html index.htm;
    access_log /var/log/nginx/msf_access.log;
    error_log /var/log/nginx/msf_error.log;
    ssl_certificate /etc/letsencrypt/live/<key>.openmrs.org/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/<key>.openmrs.org/privkey.pem;
    location ^~ /.well-known/acme-challenge/ {
      root /usr/share/nginx/html;
    }
    location / {
      return 301 https://msf.openmrs.org/openmrs;
    }
    location /openmrs {
      proxy_set_header HOST $host;
      proxy_set_header  X-Forwarded-Proto $scheme;
      proxy_pass http://127.0.0.1:8080/openmrs;
    }
}

The acme part relates to letsencrypt certificate. The two set_headers redirect the original host used to reach nginx and the original scheme.

We are deploying all that using ansible.

Hello Pascal, I used your link to build the docker image. I was able to get the openMRS & MySQL images running. But there is a problem. In the yml file, the port assignment is 8080:8080. In my windows OS, I had Apache running in port 8080. I stopped it before I did the compose up command. I am using docker toolbox. The default docker IP is 192.168.99.100. I tried to access openMRS UI at 192.168.99.100:8080/openMRS, but I have connection error. The page refused to open. What might be the problem? And how to solve this issue? Is there an alternative port I should use instead of 8080?

Which link exactly did you use, and what are you trying accomplish?

My compose scripts are not really the official way to get OpenMRS up and running. You should probably be using either the official downloads at openmrs.org, or if you are a developer you should the OpenMRS SDK.

However, if you share your Docker logs I don’t mind taking a look. What do you see at http://localhost:8080/openmrs?

Hello Pascal, I used the link you posted on 2017-11: https://github.com/esaude/esaude-platform-docker My goal is to log into openMRS UI.

I reran the whole process in these 3 steps: 1/ git clone https://github.com/esaude/esaude-platform-docker.git 2/ cd esaude-platform-docker 3/ docker-compose up -d

192.168.99.100 is my docker IP address. Then I opened up Chrome and type in: 192 168 100:8080/openmrs

I got an error This site can’t be reached 192.168.99.100 refused to connect. Search Google for 192 168 100 8080 openmrs ERR_CONNECTION_REFUSED

I noticed this time something is not right (differ from a few hours ago). MySQL hung. The only container (Tomcat) that is running is:

fe04e014f1c8 esaude_esaude-platform-tomcat “/bin/sh -c 'dockeri” 5 minutes ago Up 42 second 0.0.0.0:8080->8080/tcp esaude-platform-tomcat 91ac9a74e86a esaude_esaude-platform-mysql “docker-entrypoint.s” 5 minutes ago Restarting (127) 49 seconds ago esaude-platform-mysql

The log file for tomcat is as follow: PS C:\Users\fortuna\esaude-platform-docker> docker logs fe04e014f1c8 2018/09/19 04:12:05 Waiting for host: tcp://esaude-platform-mysql:3306 2018/09/19 04:17:05 Timeout after 5m0s waiting on dependencies to become available: [tcp://esaude-platform-mysql:3306] 2018/09/19 04:17:06 Waiting for host: tcp://esaude-platform-mysql:3306

There is no log file for MySQL as I mentioned above, it is trying to restart non-stop (& w/o succeeding).

I am going to run another compose command in the link you provide soon to see what happened.

docker-compose -f docker-compose-prebuilt.yml up -d

Because earlier, I got both Tomcat & MySQL running but have the same error loggin in.

Do you see something wrong that I did?

Thanks in advance.

Those Docker containers specifically set up the eSaude Distribution. Are you sure that’s what you want to do? If so, then it’s better to use the eSaude Communication Tools for support.

Is there a good reason that you’re using Docker Toolbox and not Docker for Windows?

As you can see from the logs, Tomcat waits for MySQL to start, so if your MySQL fails, you will not be able to access Tomcat in the browser.

It will be helpful to see the full output of docker-compose up (note the absence of -d).

Thanks for response.

First: I am using Win8 as my workhorse. I looked at the yml file last evening. I saw it uses V3.0. Then it dawn on me then maybe I need to do this on Win10 pro (which supports Docker for Windows).

Second: You are correct. The problem is with MySQL. Another evident is in the above link your mentioned in 2017/11: https://github.com/esaude/esaude-platform-docker

There is another way to start openMRS and that is to run openMRS:

docker-compose -f docker-compose-prebuilt.yml up -d

When I ran this, the containers (Tomcat, MySQL) were running in the background and the logs from both containers were constantly pumping out errors. That was why I suspect the problem is with the obsolete Docker Toolbox (aka Win8)

Third (Most Importantly): I just want to build a openMRS using docker. I failed to build it using the distro version from the official DockerHub site for openMRS. Yesterday, I went to the chat box for openMRS to look for help. They recommended me to look at this link which has your post on it. And so I followed up with you.

So do you know what I should do now (where is the proper docker image for openMRS for Windows OS ) since I just want to build openMRS using docker?

I will wait for your response first before I pull out my Win10 Pro (aka Docker For Windows). Thanks in advance.

I recommend not spending any more effort trying to set up the eSaude Distribution if that is not what you specifically want. So, do not use my images or Docker Compose file.

If you want to get the same thing running as you see at demo.openmrs.org, then you must run the OpenMRS Reference Application Distribution.

To do that, you can follow the instructions on this page. Alternatively, if you want to use the exact same Docker Compose file used to run demo.openmrs.org, you can use this one.

@Pascal. Thanks again for the quick response.

I did use the official page of openMRS you mentioned: https://wiki.openmrs.org/display/docs/Installing+OpenMRS+on+Docker

It failed. But now, I think the failure was likely due to using Docker Toolbox. I am going to switch to Docker For Windows later this evening.

Thanks for the link to yml file. It gives me control on what I want to do. I will try that first this evening.

Again appreciate for your help. Hope I get this over with OK & not returning begging for help :frowning:

1 Like

No problem. This forum is for help, and the discussions we have here helps everyone reading in the future :+1:

@Pascal, I ran into some errors using the yml files. But I am working on to identify and fixing those errors. Have an unrelated basic docker question. I ran into this openMRS module in dockerhub (https://hub.docker.com/r/jmbabazi/openmrs/). Images (mysql, openmrs) were pull & built w/o any issues.

So, now I have 2 images (MySQL & openMRS). Each images has its own image ids. Here are my elementary docker questions:

1/ To run MySQL image as a daemon in the background using an existing image, I can issue command such as this:

docker run --name=myDB -e MYSQL_ROOT_PASSWORD=abc123 -e MYSQL_DATABASE=openmrs -p 3306:3306 -d mysql

What command I should issue in order to run such generic openmrs image in docker?

The above jmbabazi/openmrs in Dockerhub site does not have the instruction how to run these images once they are generated. It only tells what URL to access once the containers are running?

2/ In general, does openMRS demand a certain name for a MySQL table to setup first and MySQL to run in the background first before the openMRS container can run? Do you have info what is the name of this MySQL table openMRS is expecting?

I’m just using “openmrs” as a placeholder in my above MySQL run script.

Thanks in advance.

Please use the official OpenMRS Docker Image. The image you found is three years old and I don’t know if it works. I can pull the relevant images as follows:

C:\> docker pull openmrs/openmrs-reference-application-distro:2.8.0
C:\> docker pull mysql:5.6

The compose file shows which environment variables OpenMRS needs.

I am able to get OpenMRS running using the following three commands:

1. Create Network :earth_africa:

C:\> docker network create openmrs-network

2. Run Database :floppy_disk:

C:\> docker run --name=mysql \
       -e MYSQL_DATABASE=openmrs \
       -e MYSQL_ROOT_PASSWORD=root \
       -e MYSQL_USER=openmrs \
       -e MYSQL_PASSWORD=openmrs \
       --network=openmrs-network \
       -p 3306:3306 \
       -d mysql:5.6 --character-set-server=utf8 --collation-server=utf8_general_ci

3. Run Web App :man_health_worker:t2:

C:\> docker run --name=openmrs \
       -e DB_DATABASE=openmrs \
       -e DB_HOST=mysql \
       -e DB_USERNAME=openmrs \
       -e DB_PASSWORD=openmrs \
       -e DB_CREATE_TABLES=true \
       -e DB_AUTO_UPDATE=false \
       -e MODULE_WEB_ADMIN=true \
       --network=openmrs-network \
       -p 8081:8080 \
       -d openmrs/openmrs-reference-application-distro:2.8.0

Then, after a few minutes I’m able to log in at http://localhost:8081/openmrs with username admin, password Admin123.

Note that if you want data to persist between Docker runs, you will have to attach a Docker volume (see here).

When I ran your 2nd command (aka run database), I got an error. The error said:

At line:6 char:10

  •    --network=openmrs-network \
    
  •      ~
    

Missing expression after unary operator ‘–’. At line:6 char:10

  •    --network=openmrs-network \
    
  •      ~~~~~~~~~~~~~~~~~~~~~~~
    

Unexpected token ‘network=openmrs-network’ in expression or statement. + CategoryInfo : ParserError: (:slight_smile: [], ParentContainsErrorRecordException + FullyQualifiedErrorId : MissingExpressionAfterOperator

Looks like my docker engine does not like the network assignment. Do you know why it is so?

PS: My OS is Win10Pro and running Docker For Window

Does it work if you remove all the backslashes and put everything on one line?

Edit: The other thing you can try is replacing openmrs-network with openmrsnetwork in all three commands.

This is strange. I got a different error if I ran the command input all in one line:

PS C:\Users\Sorcerer> docker run --name=mysql -e MYSQL_DATABASE=openmrs -e MYSQL_ROOT_PASSWORD=root -e MYSQL_USER=openmrs -e MYSQL_PASSWORD=openmrs --network=openmrs-network -p 3306:3306 -d mysql:5.6 --character-set-server=utf8 --collation-server=utf8_general_ci

cb5a0e70b731bfc6e1684e760aeea1ca6b312b0f6c8562a4901e5e637abce6b7 docker : C:\Program Files\Docker\Docker\Resources\bin\docker.exe: Error response from daemon: driver failed programming external connectivity on endpoint mysql (7c35270302f6b7c503d61689af0cd5701a75f33e4242ea23474a3e5ea2b99752): Error starting userland proxy: mkdir /port/tcp:0.0.0.0:3306:tcp:172.20.0.2:3306: input/output error. At line:1 char:1

  • docker run --name=mysql -e MYSQL_DATABASE=openmrs -e MYSQL_ROOT_PASSW …
  •   + CategoryInfo          : NotSpecified: (C:\Program File...t/output error.:String) [], RemoteException
      + FullyQualifiedErrorId : NativeCommandError

Wait. It is working. I googled the latest error. Found this: https://github.com/docker/for-win/issues/573 I restart Docker. No error anymore. openMRS installation wizard is now running. Hope it works.

Installation success. I’m in! Thanks Pascal.

1 Like