{"id":307,"date":"2018-10-16T08:42:07","date_gmt":"2018-10-16T08:42:07","guid":{"rendered":"https:\/\/www.appservgrid.com\/paw93\/?p=307"},"modified":"2018-10-16T20:51:57","modified_gmt":"2018-10-16T20:51:57","slug":"containerizing-sql-db-changes-with-flyway-kubernetes-and-openshift","status":"publish","type":"post","link":"https:\/\/www.appservgrid.com\/paw93\/index.php\/2018\/10\/16\/containerizing-sql-db-changes-with-flyway-kubernetes-and-openshift\/","title":{"rendered":"Containerizing SQL DB changes with Flyway, Kubernetes, and OpenShift"},"content":{"rendered":"<p>&nbsp;<\/p>\n<h2>Containerizing SQL DB changes with Flyway, Kubernetes, and OpenShift<\/h2>\n<p>&nbsp;<\/p>\n<p>By\u00a0<a href=\"https:\/\/developers.redhat.com\/blog\/author\/elvadasnono\/\">Elvadas Nono<\/a> January 10, 2018January 9, 2018<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/developers.redhat.com\/blog\/wp-content\/uploads\/2017\/08\/openshift-logo-121c2a0c397c2a0121.jpeg\" alt=\"\" width=\"121\" height=\"121\" \/><\/p>\n<p>In DevOps projects, you are sometimes haunted by the practices inherited from the monolithic world. In a previous project, we were checking how to simply apply SQL updates and changes to a relational database management system (RDBMS) database in an <a href=\"https:\/\/www.redhat.com\/en\/technologies\/cloud-computing\/openshift?sc_cid=70160000000QiULAA0\">OpenShift<\/a> Cluster.<\/p>\n<p>Micro database schema evolution patterns are perfectly described by Edson Yanaga in his brilliant free book: <a href=\"https:\/\/developers.redhat.com\/promotions\/migrating-to-microservice-databases\/\">Migrating to Microservice Databases: From Relational Monolith to Distributed Data. <\/a> A video presentation of these patterns is also available <a href=\"https:\/\/www.youtube.com\/watch?v=tRteUhd9eAI\">on youtube<\/a>.<\/p>\n<p>In this blog post series we will show a simple approach to implement the described patterns in your Continuous Integration and Continuous Delivery (CI\/CD) pipelines on OpenShift. The series is split in two parts:<\/p>\n<ul>\n<li>This post shows how to handle SQL update automation using Flyway, Dockerfiles, and Kubernetes on OpenShift.<\/li>\n<li>A future post will showcase application migration patterns, including database migration stages using OpenShift Jenkins2 pipelines.<\/li>\n<\/ul>\n<p>The approach uses docker containers, <a href=\"https:\/\/flywaydb.org\/\">Flyway<\/a> and <a href=\"https:\/\/kubernetes.io\/\">Kubernetes Objects<\/a> to automate SQL updates\/patches on a micro database running on OpenShift.<\/p>\n<h2>Create your Micro Database<\/h2>\n<p>To keep it simple We will rely on a <a href=\"https:\/\/hub.docker.com\/r\/jbossdevguidebook\/beosbank_posgres_db_europa\/\">docker image<\/a> that provides a simple <a href=\"https:\/\/en.wikipedia.org\/wiki\/PostgreSQL\">Postgres<\/a> database with a custom prebuilt data set, but you can build a custom database service to follow this demo.<\/p>\n<p>The database is hosted on Openshift, and we assume you have a basic knowledge of Openshift, Kubernetes, and docker containers. You can install a simple Minishift\/CDK Cluster <a href=\"https:\/\/developers.redhat.com\/products\/cdk\/overview\/\">using these instructions:<\/a><\/p>\n<p>Once you have your OpenShift\/minishift installation running, connect as admin using the oc CLI command:<\/p>\n<p>$ oc login https:\/\/192.168.99.100:8443 -u developer -p developer<br \/>\n$ oc new-project ocp-flyway-db-migration<\/p>\n<p>Grant anyuid scc to the default service account in order to run docker images<\/p>\n<p>$ oc adm policy add-scc-to-user anyuid -z default<br \/>\n$ oc new-app &#8211;docker-image=jbossdevguidebook\/beosbank_posgres_db_europa:latest &#8211;name=beosbank-posgres-db-europa<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/developers.redhat.com\/blog\/wp-content\/uploads\/2018\/01\/img_5a5506663ba34.gif\" alt=\"\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/developers.redhat.com\/blog\/wp-content\/uploads\/2017\/12\/beosbank-db-pod.png\" alt=\"Openshift view: Beosbank pod\" width=\"2856\" height=\"1210\" \/><\/p>\n<p>OpenShift view: Beosbank pod<\/p>\n<p>Determine the database pod name, and connect to the database.. Then you can explore the database content:<\/p>\n<p>$ oc get pods<br \/>\nNAME READY STATUS RESTARTS AGE<br \/>\nbeosbank-posgres-db-europa-1-p16bx 1\/1 Running 1 22h<\/p>\n<p>$ oc rsh beosbank-posgres-db-europa-1-p16bx<br \/>\n# psql -U postgres<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/developers.redhat.com\/blog\/wp-content\/uploads\/2018\/01\/img_5a55066646b59.gif\" alt=\"\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/developers.redhat.com\/blog\/wp-content\/uploads\/2018\/01\/beosbank-pod-dbcontent.png\" alt=\"\" width=\"1652\" height=\"1558\" \/><\/p>\n<p>Now that the RDBMS is up and running, we may ask how to perform automatic SQL updates on the database.<\/p>\n<p>From monolithic processes, we have various options to do it, including SQL batches with Flyway runtimes. In the next section we will see how to containerize a Flyway update first, and then automate it with Kubernetes.<\/p>\n<h2>Containerizing SQL updates with Flyway runtimes<\/h2>\n<p>The purpose behind the Flyway process containerization is to provide on-the-fly a container that can connect to the database container using Java Database Connectivity (JDBC) protocol in order to perform SQL updates.<\/p>\n<p>From DockerHub you can find a lot of custom images for Flyway. The following Dockerfile can be used to procure a more suitable one in the OpenShift context:<\/p>\n<p>FROM alpine<br \/>\nMAINTAINER &#8220;Nono Elvadas&#8221;<\/p>\n<p>ENV FLYWAY_VERSION=4.2.0<\/p>\n<p>ENV FLYWAY_HOME=\/opt\/flyway\/$FLYWAY_VERSION<br \/>\nFLYWAY_PKGS=&#8221;https:\/\/repo1.maven.org\/maven2\/org\/flywaydb\/flyway-commandline\/$\/flyway-commandline-$.tar.gz&#8221;<\/p>\n<p>LABEL com.redhat.component=&#8221;flyway&#8221;<br \/>\nio.k8s.description=&#8221;Platform for upgrading database using flyway&#8221;<br \/>\nio.k8s.display-name=&#8221;DB Migration with flyway &#8221;<br \/>\nio.openshift.tags=&#8221;builder,sql-upgrades,flyway,db,migration&#8221;<\/p>\n<p>RUN apk add &#8211;update<br \/>\nopenjdk8-jre<br \/>\nwget<br \/>\nbash<\/p>\n<p>#Download flyway<br \/>\nRUN wget &#8211;no-check-certificate $FLYWAY_PKGS &amp;&amp;<br \/>\nmkdir -p $FLYWAY_HOME &amp;&amp;<br \/>\nmkdir -p \/var\/flyway\/data &amp;&amp;<br \/>\ntar -xzf flyway-commandline-$FLYWAY_VERSION.tar.gz -C $FLYWAY_HOME &#8211;strip-components=1<\/p>\n<p>VOLUME \/var\/flyway\/data<\/p>\n<p>ENTRYPOINT cp -f \/var\/flyway\/data\/*.sql $FLYWAY_HOME\/sql\/ &amp;&amp;<br \/>\n$FLYWAY_HOME\/flyway baseline migrate info -user=$ -password=$ -url=$<\/p>\n<p>The Dockerfile installs wget, bash and a Java runtime environment, then downloads a specific version of Flyway binaries. Flyway binaries are installed. A volume is created on \/var\/flyway\/data to hold SQL files we want to be executed on the database.<\/p>\n<p>By default, Flyway will check the SQL file in the $FLYWAY_HOME\/sql\/ folder.<\/p>\n<p>We first copy all of the provided SQL files from the data volume to $FLYWAY_HOME\/sql\/ and start a migration script. Database url and credentials should be provided as environment variables.<\/p>\n<p>Note: Originally the idea was to tell Flyway to read SQL files from the volume without copying or moving them to the container home directory. However, we faced an issue with this configuration: <a href=\"https:\/\/github.com\/flyway\/flyway\/issues\/1807\"><br \/>\n(See flyway issue 1807 on github)<\/a>. Indeed the Flyway engine will recursively read the volume, including the hidden subfolder. There is a Request for Enhancement to customize this behavior and prevent Flyway from reading meta data files in the volume mount folder.<\/p>\n<p>Build the image using the command:<\/p>\n<p>$ docker build -t &#8211;no-cache jbossdevguidebook\/flyway:v1.0.4-rhdblog .<\/p>\n<p>&#8230;<\/p>\n<p>2018-01-07 13:48:43 (298 KB\/s) &#8211; &#8216;flyway-commandline-4.2.0.tar.gz&#8217; saved [13583481\/13583481]<br \/>\n&#8212;&gt; 095befbd2450<br \/>\nRemoving intermediate container 8496d11bf4ae<br \/>\nStep 8\/9 : VOLUME \/var\/flyway\/data<br \/>\n&#8212;&gt; Running in d0e012ece342<br \/>\n&#8212;&gt; 4b81dfff398b<br \/>\nRemoving intermediate container d0e012ece342<br \/>\nStep 9\/9 : ENTRYPOINT cp -f \/var\/flyway\/data\/*.sql $FLYWAY_HOME\/sql\/ &amp;&amp; $FLYWAY_HOME\/flyway baseline migrate info -user=$ -password=$ -url=$<br \/>\n&#8212;&gt; Running in ff2431eb1c26<br \/>\n&#8212;&gt; 0a3721ff4863<br \/>\nRemoving intermediate container ff2431eb1c26<br \/>\nSuccessfully built 0a3721ff4863<br \/>\nSuccessfully tagged jbossdevguidebook\/flyway:v1.0.4-rhdblog<\/p>\n<p>The database client is now available as a docker image. In the next section, we will see how to combine Kubernetes objects in OpenShift to automate SQL updates for this database.<\/p>\n<h2>Kubernetes in action<\/h2>\n<p>Kubernetes provides various deployment objects and patterns we can rely on to apply live SQL updates from containers created on top of the \u201cjbossdevguidebook\/flyway:v1.0.4-rhdblog\u201d image:<\/p>\n<ul>\n<li>Deployment Config<\/li>\n<li>Job<\/li>\n<li>CronJob\/ScheduledJob<\/li>\n<li>InitContainer; Sidecar<\/li>\n<\/ul>\n<p>In the following section we will illustrate how a single Kubernetes job object can be used to perform live SQL updates. SQL files will be provided to the container through a volume and a configMap.<\/p>\n<h3>Create a configMap from provided SQL files<img decoding=\"async\" src=\"https:\/\/developers.redhat.com\/blog\/wp-content\/uploads\/2018\/01\/img_5a5506677cbe5.gif\" alt=\"\" \/><\/h3>\n<p>$ cd ocp-flyway-db-migration\/sql<br \/>\n$ oc create cm sql-configmap &#8211;from-file=.<br \/>\nconfigmap &#8220;sql-configmap&#8221; created<\/p>\n<h3>Create a Job to update the DB.<\/h3>\n<p>The job spec is provided. To keep it simple we are not going in deep details of the customization. Files are available on my github repo.<\/p>\n<ul>\n<li>Include secrets to keep db user and password credentials<\/li>\n<li>Manage job history limits; restart policy according to the desired policy<\/li>\n<\/ul>\n<p>$ oc create -f https:\/\/raw.githubusercontent.com\/nelvadas\/ocp-flyway-db-migration\/master\/beosbank-flyway-job.yaml<\/p>\n<p>Check that the job was created in OpenShift:<\/p>\n<p>$ oc get jobs<br \/>\nNAME DESIRED SUCCESSFUL AGE<br \/>\nbeosbank-dbupdater-job 1 1 2d<\/p>\n<p>Check the pods. Once the job is created, it generates a job instance that is executed by a new pod.<\/p>\n<p>$ oc get pods<br \/>\nNAME READY STATUS RESTARTS AGE<br \/>\nbeosbank-dbupdater-job-wzk9q 0\/1 Completed 0 2d<br \/>\nbeosbank-posgres-db-europa-1-p16bx 1\/1 Running 2 6d<img decoding=\"async\" src=\"https:\/\/developers.redhat.com\/blog\/wp-content\/uploads\/2018\/01\/img_5a55066857f97.gif\" alt=\"\" \/><\/p>\n<p>The job instance completed successfully according to the log, and the migration steps have been applied.<\/p>\n<p>$ oc logs beosbank-dbupdater-job-wzk9q<br \/>\nFlyway 4.2.0 by Boxfuse<br \/>\nDatabase: jdbc:postgresql:\/\/beosbank-posgres-db-europa\/beosbank-europa (PostgreSQL 9.6)<br \/>\nCreating Metadata table: &#8220;public&#8221;.&#8221;schema_version&#8221;<br \/>\nSuccessfully baselined schema with version: 1<br \/>\nSuccessfully validated 5 migrations (execution time 00:00.014s)<br \/>\nCurrent version of schema &#8220;public&#8221;: 1<br \/>\nMigrating schema &#8220;public&#8221; to version 1.1 &#8211; UpdateCountry<br \/>\nMigrating schema &#8220;public&#8221; to version 2.2 &#8211; UpdateCountry2<br \/>\nMigrating schema &#8220;public&#8221; to version 2.3 &#8211; UpdateZip<br \/>\nMigrating schema &#8220;public&#8221; to version 3.0 &#8211; UpdateStreet<br \/>\nSuccessfully applied 4 migrations to schema &#8220;public&#8221; (execution time 00:00.046s).<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;+<br \/>\n| Version | Description | Installed on | State |<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;+<br \/>\n| 1 | &lt;&lt; Flyway Baseline &gt;&gt; | 2018-01-05 04:35:16 | Baselin |<br \/>\n| 1.1 | UpdateCountry | 2018-01-05 04:35:16 | Success |<br \/>\n| 2.2 | UpdateCountry2 | 2018-01-05 04:35:16 | Success |<br \/>\n| 2.3 | UpdateZip | 2018-01-05 04:35:16 | Success |<br \/>\n| 3.0 | UpdateStreet | 2018-01-05 04:35:16 | Success |<br \/>\n+&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;+<\/p>\n<h3>Check the updated DB<\/h3>\n<p>$ oc rsh beosbank-posgres-db-europa-1-p16bx<br \/>\n# psql -U postgres<br \/>\npsql (9.6.2)<br \/>\nType &#8220;help&#8221; for help.<\/p>\n<p>postgres=# connect beosbank-europa<br \/>\nbeosbank-europa=# select * from eu_customer;<br \/>\nid | city | country | street | zip | birthdate |firstname | lastname<br \/>\n&#8212;-+&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8212;&#8212;&#8211;+&#8212;&#8212;&#8212;&#8212;+<br \/>\n1 | Berlin | Germany | brand burgStrasse | 10115 | 1985-06-20 |Yanick | Modjo<br \/>\n2 | Bologna | Italy | place Venice | 40100 | 1984-11-21 |Mirabeau | Luc<br \/>\n3 | Paris | France | Bld DeGaule | 75001 | 2000-02-07 |Noe | Nono<br \/>\n4 | Chatillon | France | Avenue JFK | 55 | 1984-02-19 |Landry | Kouam<br \/>\n5 | Douala | Cameroon | bld Liberte | 1020 | 1996-04-21 |Ghislain | Kamga<br \/>\n6 | Yaounde | Cameroon | Hypodrome | 1400 | 1983-11-18 |Nathan | Brice<br \/>\n7 | Bruxelles | Belgium | rue Van Gogh | 1000 | 1980-09-06 |Yohan | Pieter<br \/>\n9 | Bamako | Mali | Rue Modibo Keita | 30 | 1979-05-17 |Mohamed | Diallo<br \/>\n10 | Cracovie | Pologne | Avenue Vienne | 434 | 1983-05-17 |Souleymann | Njifenjou<br \/>\n11 | Chennai | Red Hat Training | Gandhi street | 600001 | 1990-02-13 |Anusha | Mandalapu<br \/>\n12 | Sao Polo | Open Source | samba bld | 75020 | 1994-02-13 |Adriana | Pinto<br \/>\n8 | Farnborough | UK | 200 Fowler Avenue | 208 | 1990-01-01 |John | Doe<br \/>\n(12 rows)<\/p>\n<p>beosbank-europa=#<\/p>\n<p>If the batch is rerun with same migration scripts, as the database is already aware of the modifications, a warning is displayed in your log and no update is performed:<\/p>\n<p>Current version of schema &#8220;public&#8221;: 3.0<br \/>\nSchema &#8220;public&#8221; is up to date. No migration necessary.<\/p>\n<p>This concludes the article. Hope you learn something that will help you during your container journey.<\/p>\n<p>The full source is available from my Github repository:<br \/>\n<a href=\"https:\/\/github.com\/nelvadas\/ocp-flyway-db-migration\">https:\/\/github.com\/nelvadas\/ocp-flyway-db-migration<\/a><\/p>\n<p><a href=\"https:\/\/developers.redhat.com\/blog\/2018\/01\/10\/flyway-containerized-db-changes\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Containerizing SQL DB changes with Flyway, Kubernetes, and OpenShift &nbsp; By\u00a0Elvadas Nono January 10, 2018January 9, 2018 In DevOps projects, you are sometimes haunted by the practices inherited from the monolithic world. In a previous project, we were checking how to simply apply SQL updates and changes to a relational database management system (RDBMS) &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.appservgrid.com\/paw93\/index.php\/2018\/10\/16\/containerizing-sql-db-changes-with-flyway-kubernetes-and-openshift\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Containerizing SQL DB changes with Flyway, Kubernetes, and OpenShift&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-307","post","type-post","status-publish","format-standard","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/307","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/comments?post=307"}],"version-history":[{"count":1,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/307\/revisions"}],"predecessor-version":[{"id":413,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/posts\/307\/revisions\/413"}],"wp:attachment":[{"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/media?parent=307"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/categories?post=307"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.appservgrid.com\/paw93\/index.php\/wp-json\/wp\/v2\/tags?post=307"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}