Docker OpenEMR Swarm

Hi,

I’ve been playing around with getting OpenEMR to work with Docker Swarm in case any folks are interested.

Was finally able to get a OpenEMR Docker Swarm working:

ID                  NAME                         MODE                REPLICAS            IMAGE                             PORTS
6ftch7xebtok        demo_openemr                 replicated          1/1                 openemr/openemr:5.0.2             
lho762jthyv1        demo_mysql                   replicated          1/1                 mariadb:10.2                      
qsn6gv1kdc5h        demo_phpmyadmin              replicated          1/1                 phpmyadmin/phpmyadmin:latest      *:8081->80/tcp
rqcslkwxm09l        demo_nginx                   replicated          3/3                 openemr/dev-nginx:swarm-example   *:8080->80/tcp
vxoypilgq84i        demo_redis                   replicated          1/1                 redis:latest                      
ykopp1bpuk2k        demo_dev-php-fpm-7-2-redis   replicated          3/3                 openemr/dev-php-fpm:7.2-redis

The docker-compose.yml I used is for this:

services:
  redis:
    image: redis
    deploy:
      replicas: 1
  mysql:
    image: mariadb:10.2
    command: ['mysqld','--character-set-server=utf8']
    environment:
      MYSQL_ROOT_PASSWORD: root
    deploy:
      replicas: 1
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    ports:
    - 8081:80
    environment:
      PMA_HOSTS: mariadb
    deploy:
      replicas: 1
  openemr:
    image: openemr/openemr:5.0.2
    volumes:
    - websitevolume:/var/www/localhost/htdocs/openemr
    environment:
      MYSQL_HOST: mysql
      MYSQL_ROOT_PASS: root
      MYSQL_USER: openemr
      MYSQL_PASS: openemr
      OE_USER: admin
      OE_PASS: pass
    depends_on:
    - mysql
    deploy:
      replicas: 1
  nginx:
    image: openemr/dev-nginx:swarm-example
    ports:
    - 8080:80
    volumes:
    - websitevolume:/usr/share/nginx/html/openemr
    depends_on:
    - openemr
    - dev-php-fpm-7-2-redis
    deploy:
      replicas: 3
  dev-php-fpm-7-2-redis:
    image: openemr/dev-php-fpm:7.2-redis
    volumes:
    - websitevolume:/usr/share/nginx/html/openemr
    depends_on:
    - openemr
    deploy:
      replicas: 3
volumes:
  websitevolume: {}

It is load balancing 3 nginx containers and 3 php-fpm containers (the openemr container is simply a data container with a shared volume) (php-fpm all share the redis container for session sharing). So far just have it running on one node. The difficulty in getting it into more than 1 node is the shared volume, since then need to use a plugin to use as a volume driver.

Note I am only use the official OpenEMR docker as a data container for now (that also autoinstalls, though) and am using the nginx/php-fpm dockers to actually serve OpenEMR (thank you @gutiersa for making this even possible) since needed the solution to work with a redis docker. Next plan to get the OpenEMR official docker to support redis, so can also have a solution with standard apache/php docker serving OpenEMR on the Docker Swarm.

Anyways, this is really just the beginning and I barely know what the heck I am doing here, but the main goal here is to make OpenEMR as friendly as possible with container orchestration suites.

-brady

1 Like

@brady.miller
My pleasure.
I am moving, but as soon as I get a chance I will look into it. I think openemr images is actuallyl a great idea.

Hi,

Here’s a docker swarm example that is using apache/php.

ID                  NAME                 MODE                REPLICAS            IMAGE                          PORTS
7x72by1t0byt        demo_mysql           replicated          1/1                 mariadb:10.2                   
8bipwptfialg        demo_redis           replicated          1/1                 redis:latest                   
k42ukjb1763k        demo_openemr-serve   replicated          5/5                 openemr/openemr:flex           *:8080->80/tcp
m0vmhk4up5j8        demo_openemr         replicated          1/1                 openemr/openemr:5.0.2          
vnlgtd9awyun        demo_phpmyadmin      replicated          1/1                 phpmyadmin/phpmyadmin:latest   *:8081->80/tcp

and here is the docker-compose.yml:

version: '3.1'
services:
  redis:
    image: redis
    deploy:
      replicas: 1
  mysql:
    image: mariadb:10.2
    command: ['mysqld','--character-set-server=utf8']
    environment:
      MYSQL_ROOT_PASSWORD: root
    deploy:
      replicas: 1
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    ports:
    - 8081:80
    environment:
      PMA_HOSTS: mariadb
    deploy:
      replicas: 1
  openemr:
    image: openemr/openemr:5.0.2
    volumes:
    - websitevolume:/var/www/localhost/htdocs/openemr
    environment:
      MYSQL_HOST: mysql
      MYSQL_ROOT_PASS: root
      MYSQL_USER: openemr
      MYSQL_PASS: openemr
      OE_USER: admin
      OE_PASS: pass
    depends_on:
    - mysql
    deploy:
      replicas: 1
  openemr-serve:
    image: openemr/openemr:flex
    ports:
    - 8080:80
    volumes:
    - websitevolume:/var/www/localhost/htdocs/openemr
    environment:
      REDIS_SERVER: redis
      EMPTY: "yes"
    depends_on:
    - openemr
    deploy:
      replicas: 5
volumes:
  websitevolume: {}

Note this basically uses the openemr/openemr:5.0.2(openemr) container as a self installing data container. And the openemr/openemr:flex(openemr-serve) container is what actually serves it (and this can be safely replicated and in this case has 5 replicated instances that are load balanced). The next goal is to make it so the flex container is not needed.

-brady

1 Like

ok,

After some docker sorcery, it appears we now can get the openemr/openemr:5.0.2 docker to be the primary openemr docker in a swarm (no longer need the flex docker crutch as did above).

Here’s a rundown of how things look (note that both the http port 8080 and https port 8090 work well):

[23:52][brady2@brady2-gaz:~/docker/swarm-example-3]$ docker swarm init --advertise-addr 192.168.1.192

[23:52][brady2@brady2-gaz:~/docker/swarm-example-3]$ docker stack deploy -c docker-compose.yml demo

[23:54][brady2@brady2-gaz:~/docker/swarm-example-3]$ docker service ls
ID                  NAME                MODE                REPLICAS            IMAGE                          PORTS
eoplt7ywm3b0        demo_phpmyadmin     replicated          1/1                 phpmyadmin/phpmyadmin:latest   *:8081->80/tcp
kps04sx96erb        demo_redis          replicated          1/1                 redis:latest                   
uol4286im0ya        demo_openemr        replicated          5/5                 openemr/openemr:5.0.2          *:8080->80/tcp,*:8090->443/tcp
x8j4drxjg93r        demo_mysql          replicated          1/1                 mariadb:10.2                   

[23:56][brady2@brady2-gaz:~/docker/swarm-example-3]$ docker ps -a
CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS              PORTS               NAMES
293c5575a8f0        redis:latest                   "docker-entrypoint..."   3 minutes ago       Up 3 minutes        6379/tcp            demo_redis.1.chb98mcar8olege8gqm62b2w3
18d43016283f        openemr/openemr:5.0.2          "./run_openemr.sh"       3 minutes ago       Up 3 minutes        80/tcp, 443/tcp     demo_openemr.1.g7ihrygcy2bu27spuun2ec0qt
c1340511625c        openemr/openemr:5.0.2          "./run_openemr.sh"       3 minutes ago       Up 3 minutes        80/tcp, 443/tcp     demo_openemr.5.vjfi45hzxac90haowy8ak2p03
801146e94132        openemr/openemr:5.0.2          "./run_openemr.sh"       3 minutes ago       Up 3 minutes        80/tcp, 443/tcp     demo_openemr.2.s7tz8zzqouz5rtmnryyyh41um
8b4f32dcbc9b        openemr/openemr:5.0.2          "./run_openemr.sh"       3 minutes ago       Up 3 minutes        80/tcp, 443/tcp     demo_openemr.4.rtkcnkh5o8kr22oecp0rgde4r
293209556cef        openemr/openemr:5.0.2          "./run_openemr.sh"       3 minutes ago       Up 3 minutes        80/tcp, 443/tcp     demo_openemr.3.qq7ubjn2t5crwnfjig1h8h5jr
39fa81522994        phpmyadmin/phpmyadmin:latest   "/run.sh superviso..."   3 minutes ago       Up 3 minutes        80/tcp, 9000/tcp    demo_phpmyadmin.1.wzrmipbe1dou5nd5c3yazpnrj
11cb5f53df68        mariadb:10.2                   "docker-entrypoint..."   3 minutes ago       Up 3 minutes        3306/tcp            demo_mysql.1.ymflx1sg3t2e1dorxqjbc2uuz

[23:56][brady2@brady2-gaz:~/docker/swarm-example-3]$ cat docker-compose.yml 
version: '3.1'
services:
  redis:
    image: redis
    deploy:
      replicas: 1
  mysql:
    image: mariadb:10.2
    command: ['mysqld','--character-set-server=utf8']
    environment:
      MYSQL_ROOT_PASSWORD: root
    deploy:
      replicas: 1
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    ports:
    - 8081:80
    environment:
      PMA_HOSTS: mariadb
    deploy:
      replicas: 1
  openemr:
    image: openemr/openemr:5.0.2
    ports:
    - 8080:80
    - 8090:443
    volumes:
    - websitevolume:/var/www/localhost/htdocs/openemr/sites
    - sslvolume:/etc/ssl
    - letsencryptvolume:/etc/letsencrypt
    environment:
      SWARM_MODE: "yes"
      REDIS_SERVER: redis
      MYSQL_HOST: mysql
      MYSQL_ROOT_PASS: root
      MYSQL_USER: openemr
      MYSQL_PASS: openemr
      OE_USER: admin
      OE_PASS: pass
    depends_on:
    - mysql
    deploy:
      replicas: 5
volumes:
  websitevolume: {}
  sslvolume: {}
  letsencryptvolume: {}
1 Like

Hey Brady,

The better bet might be Redhat’s OpenShift, which is essentially enterprise Kubernetes and Docker. Redhat is a major contributor to both. I ran kompose.io against your Docker file from Docker Hub, however, it seems like it still needs some tweaking to get it running fully in OpenShift.

kompose convert --provider=openshift
INFO OpenShift file "openemr-service.yaml" created 
INFO OpenShift file "mysql-deploymentconfig.yaml" created 
INFO OpenShift file "mysql-imagestream.yaml" created 
INFO OpenShift file "databasevolume-persistentvolumeclaim.yaml" created 
INFO OpenShift file "openemr-deploymentconfig.yaml" created 
INFO OpenShift file "openemr-imagestream.yaml" created 
INFO OpenShift file "logvolume01-persistentvolumeclaim.yaml" created 
INFO OpenShift file "sitevolume-persistentvolumeclaim.yaml" created 

I then run kompose up to deploy OpenEMR to our OpenShift cluster.

kompose up
INFO We are going to create Kubernetes Deployments, Services and PersistentVolumeClaims for your Dockerized application. If you need different kind of resources, use the 'kompose convert' and 'kubectl create -f' commands instead. 
 
INFO Deploying application in "openemr" namespace 
INFO Successfully created Service: openemr        
INFO Successfully created Deployment: mysql       
INFO Successfully created PersistentVolumeClaim: databasevolume of size 100Mi. If your cluster has dynamic storage provisioning, you don't have to do anything. Otherwise you have to create PersistentVolume to make PVC work 
INFO Successfully created Deployment: openemr     
INFO Successfully created PersistentVolumeClaim: logvolume01 of size 100Mi. If your cluster has dynamic storage provisioning, you don't have to do anything. Otherwise you have to create PersistentVolume to make PVC work 
INFO Successfully created PersistentVolumeClaim: sitevolume of size 100Mi. If your cluster has dynamic storage provisioning, you don't have to do anything. Otherwise you have to create PersistentVolume to make PVC work 

Your application has been deployed to Kubernetes. You can run 'kubectl get deployment,svc,pods,pvc' for details.

Unfortunately, the main images won’t deploy, and the logs say: /bin/sh: can't open './run_openemr.sh'

Hi @Ryan_Nix ,

Very cool to see somebody else working on this stuff. I just tried to get it going via these instructions(via minikube and kompose):
http://kompose.io/getting-started/
(btw, very cool to see how easily it is to get Kubernetes up and going)

The error I ran into was that OpenEMR containers were not working because of issues with the persistent volumes, which are mission critical for the openemr containers. This is also something plan to spend more time on the above Docker Swarm solution (the solution above only works on 1 Docker Swarm node since is using local shared volumes) to get it working with nfs shared volumes. Then maybe will have more luck when try to translate it over to minikube/kompose.

-brady

btw, here’s how things look on my command line along with screen shots from my post above:

[00:43][brady2@brady2-gaz:~/docker/swarm-example-3/kubernets-go]$ minikube start
Starting local Kubernetes v1.10.0 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.
[00:45][brady2@brady2-gaz:~/docker/swarm-example-3/kubernets-go]$ kompose convert
INFO Kubernetes file "openemr-service.yaml" created 
INFO Kubernetes file "phpmyadmin-service.yaml" created 
INFO Kubernetes file "mysql-deployment.yaml" created 
INFO Kubernetes file "openemr-deployment.yaml" created 
INFO Kubernetes file "websitevolume-persistentvolumeclaim.yaml" created 
INFO Kubernetes file "sslvolume-persistentvolumeclaim.yaml" created 
INFO Kubernetes file "letsencryptvolume-persistentvolumeclaim.yaml" created 
INFO Kubernetes file "phpmyadmin-deployment.yaml" created 
INFO Kubernetes file "redis-deployment.yaml" created 
[00:45][brady2@brady2-gaz:~/docker/swarm-example-3/kubernets-go]$ kompose up
INFO We are going to create Kubernetes Deployments, Services and PersistentVolumeClaims for your Dockerized application. If you need different kind of resources, use the 'kompose convert' and 'kubectl create -f' commands instead. 
 
INFO Deploying application in "default" namespace 
INFO Successfully created Service: openemr        
INFO Successfully created Service: phpmyadmin     
INFO Successfully created Deployment: mysql       
INFO Successfully created Deployment: openemr     
INFO Successfully created PersistentVolumeClaim: websitevolume of size 100Mi. If your cluster has dynamic storage provisioning, you don't have to do anything. Otherwise you have to create PersistentVolume to make PVC work 
INFO Successfully created PersistentVolumeClaim: sslvolume of size 100Mi. If your cluster has dynamic storage provisioning, you don't have to do anything. Otherwise you have to create PersistentVolume to make PVC work 
INFO Successfully created PersistentVolumeClaim: letsencryptvolume of size 100Mi. If your cluster has dynamic storage provisioning, you don't have to do anything. Otherwise you have to create PersistentVolume to make PVC work 
INFO Successfully created Deployment: phpmyadmin  
INFO Successfully created Deployment: redis       

Your application has been deployed to Kubernetes. You can run 'kubectl get deployment,svc,pods,pvc' for details.

[00:21][brady2@brady2-gaz:~/docker/swarm-example-3/kubernets-go]$ minikube dashboard




Sweet! Not sure why the PVC didn’t get created as there is a YAML file in there for a volume claim. I’ll keep chipping away at it. In any case, Kubernetes is pretty impressive. The CEO of Redhat said in an earnings call that they aren’t seeing a lot of demand for Docker by itself. I can see why. OpenShfit seems to offer a complete solution for running and scaling containerized applications.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  creationTimestamp: null
  labels:
    io.kompose.service: logvolume01
  name: logvolume01
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 100Mi
status: {}
1 Like