Persistent Data in a MySQL Docker Container

Running MySQL in Docker

In a recent article on Docker in this blog, we presented some basics for dealing with data in containers. This article will present another popular application for Docker: MySQL containers. Running MySQL instances in Docker allows isolating database infrastructure with ease.

Connecting to the Standard MySQL Container

The description of the MySQL docker image provides a lot of useful information how to launch and connect to a MySQL container. The first step is to create standard MySQL container from the latest available image.

sudo docker run \
   -p 3307:3306 

This creates a MySQL container where the root password is set to secret. As the host is already running its own MySQL instance (which has nothing to do with this docker example), the standard port 3306 is already taken. Thus we publish utilise the port 3307 on the host system and forward it to the 3306 standard port from the container.

Connect from the Host

We can then connect from the command line like this:

mysql -uroot -psecret -h -P3307

We could also provide the hostname localhost for connecting to the container, but as the MySQL client per default assumes that a localhost connection is via a socket, this would not work. Thus when using the hostname localhost, we needed to specify the protocol TCP, wo that the client connects via the network interface.

mysql -uroot -psecret -h localhost --protocol TCP -P3307

Connect from other Containers

Connecting from a different container to the MySQL container is pretty straight forward. Docker allows to link two containers and then use the exposed ports between them. The following command creates a new ubuntu container and links to the MySQL container.

sudo docker run -it --name ubuntu-container --link mysql-instance:mysql-link ubuntu:16.10 bash

After this command, you are in the terminal of the Ubuntu container. We then need to install the MySQL client for testing:

# Fetch the package list
root@7a44b3e7b088:/# apt-get update
# Install the client
root@7a44b3e7b088:/# apt-get install mysql-client
# Show environment variables
root@7a44b3e7b088:/# env

The last command gives you a list of environment variables, among which is the IP address and port of the MySQL container.


You can then connect either manually of by providing the variables

mysql -uroot -psecret -h

If you only require a MySQL client inside a container, simply use the MySQL image from docker. Batteries included!

WAMS Containerstandorte in Innsbruck

Der Verein WAMS ist ein Sozialbetrieb mit dem Ziel Arbeitsplätze für Menschen zu schaffen, die aufgrund ihrer besonderen Lebenssituationen im konventionellen Arbeitsmarkt benachteiligt werden. Ein besonderes Augenmerk des Vereins liegt auch auf dem Recyclinggedanken und der Wiederverwertung von Ressourcen. Aus diesem Grund betreut und betreibt der Verein auch Altkleidersammelstellen und verwertet das gespendete Gewand. Eine Liste der Standorte dieser gelben Container befindet sich im Flyer von WAMS, der auf der Vereinshomepage bezogen werden kann. Für all jene, denen die Innsbrucker Straßennamen noch nicht allzu viel sagen oder deren geographisches Gedächtnis lückenhaft ist, habe ich die Standorte auf einer Karte eingetragen.

Der Sourcecode ist auf Github verfügbar und hier beschrieben.

Calling Back: An Example for Google’s Geocoder Service and Custom Markers

I recently moved and naturally there was a lot of clothes which I do not need (read: do not fit in) any more. Throwing them away would be a waste and luckily, there is a social business called WAMS which (besides a lot of other nice projects) supports reuse and recycling. WAMS provides and maintains containers for collecting clothes on many locations in Tirol. Unfortunately, there is not yet a map available to find them easily. I took this as an opportunity for a little side project in Javascript. I am not affiliated with WAMS, but of course the code and data is open sourced here.


The idea was quite simple. I used some of the container addresses I found in the flyer and created a custom Google Map showing the locations of the containers. The final result looks like this and a live demo can be found at the Github page.

Retrieve Geolocation Information

The Google API allows to retrieve latitude and longitude data from any given address. If the address was found in Google’s database, the Server returns a GeocoderResult object containing the geometry information about the found object. This GeocoderGeometry contains the latitude and longitude data of the address. The first step retrieves the data from Google’s API by using the Geocoder class. To do so, the following JSON structure is iterated and the addresses are being fed to the Geocoding service.

                "containerStandorte": [
                        "id": "1",
                        "name": "Pfarre Allerheiligen",
                        "address": "St.-Georgs-Weg 15, 6020, Innsbruck, Austria",
                        "latitude": "",
                        "longitude: "":
                        "id": "2",
                        "name": "Endhaltestelle 3er Linie Amras",
                        "address": "Philippine-Welser-Straße 49, 6020, Innsbruck, Austria",
                        "latitude": "",
                        "longitude": ""

The Javascript code for obtaining the data is shown in the following listing:

window.onload = function() {

    // Data
    var wamsData =
 '{ "containerStandorte" : [' +
    '{ "id":"1", "name":"Pfarre Allerheiligen" , "address":"St.-Georgs-Weg 15, 6020, Innsbruck, Austria" , "latitude":"", "longitude":"" },' +
    '{ "id":"2", "name":"Endhaltestelle 3er Linie Amras" , "address":"Philippine-Welser-Straße 49, 6020, Innsbruck, Austria" , "latitude":"", "longitude":"" },' +
    '{ "id":"3", "name":"DEZ Einkaufszentrum Parkgarage" , "address":"Amraser-See-Straße 56a,6020 Innsbruck, Austria" , "latitude":"", "longitude":"" },' +
    '{ "id":"4", "name":"Wohnanlage Neue Heimat" , "address":"Geyrstraße 27-29, 6020 Innsbruck, Austria" , "latitude":"", "longitude":"" },' +
    '{ "id":"5", "name":"MPREIS Haller Straße" , "address":"Hallerstraße 212, 6020 Innsbruck, Austria" , "latitude":"", "longitude":"" },' +
    '{ "id":"6", "name":"Recyclinginsel Novapark" , "address":"Arzlerstraße 43, 6020 Innsbruck, Austria" , "latitude":"", "longitude":"" },' +
    '{ "id":"7", "name":"Höhenstraße / Hungerburg (neben Spar)" , "address":"Höhenstraße 125,6020 Innsbruck, 6020, Innsbruck, Austria" , "latitude":"", "longitude":"" },' +
    '{ "id":"8", "name":"Recyclinginsel Schneeburggasse" , "address":"Schneeburggasse 116, 6020 Innsbruck, Austria" , "latitude":"", "longitude":"" },' +
    '{ "id":"9", "name":"MPreis Fischerhäuslweg 31" , "address":"Fischerhäuslweg 31, 6020 Innsbruck, Austria" , "latitude":"", "longitude":"" },' +
    '{ "id":"10", "name":"Pfarre Petrus Canisius" , "address":"Santifallerstraße 5,6020 Innsbruck Austria" , "latitude":"", "longitude":"" },' +
    '{ "id":"11", "name":"MPreis Bachlechnerstraße" , "address":"Bachlechnerstraße 46, 6020 Innsbruck" , "latitude":"", "longitude":"" }'
    +' ]}';

    // Google Geocoder Library
    var geocoder = new google.maps.Geocoder();
    // Parse the JSON string into a javascript object.
    var wamsJSON = JSON.parse(wamsData);

        Iterate over containers and retrieve the geo location for their address.
    function processContainers(){
        // Store amount of containers
        var amountOfContainers = wamsJSON.containerStandorte.length;
        // Iterate over all containers
        for (var i=0;i<amountOfContainers;i++){
            var container = wamsJSON.containerStandorte[i];
            // Encode the address of the container
            geocodeAddress(container, processContainerLocationCallback);

        Process the results
    function processContainerLocationCallback(container,lat,long){
        wamsJSON = updateJSON(container,lat,long, printJSONCallback);

        Update the JSON object and store the latitude and longitude information
    function updateJSON(container,lat,long,printJSONCallback){
        // Store amount of containers
        var amountOfContainers = wamsJSON.containerStandorte.length;
        // Iterate over containers
        for (var i=0;i<amountOfContainers;i++){
            // Pick the correct id and store the data
        // When the update is done, call the displayCallback
        return wamsJSON;

        Google's Geocoder function takes and address as input and retrieves
        (among other data) the latitude and longitude of the provided address.
        Note that this is an asynchronous call, the response may take some time.
        Also remember that the processContainerLocationCallback which is given as
        an input parameter is just a variable. A variable which happens to be a function.

    function geocodeAddress(container, processContainerLocationCallback){
        var address = container.address;
        geocoder.geocode( { 'address': address}, function(results, status) {
            // Anonymous function to process results.
            if (status == google.maps.GeocoderStatus.OK) {
                // When the results have been retrieved,process them in the function processContainerLocationCallback
                processContainerLocationCallback(container, lat,long);
            } else {
                alert("Geocode was not successful for the following reason: " + status);

    // Print the result
    function printJSONCallback(){
        var jsonString = JSON.stringify(wamsJSON, null,4);
        document.getElementById("jsonOutput").innerHTML = jsonString;

    // Start processing

As the calls to the Google Services asynchronously, we need to use callbacks which are called when the function before has finished. Callbacks can be tricky and are a bit of a challenge to understand the first time. Especially the Google Geocoder methods require to work with several callbacks, which is often referred to as callback hell. The code above does the following things:

  1. Iterate over the JSON structure process each container individually -> function processContainers()
  2. For each container, call Google’s Geocoder and resolve the address to a location -> geocodeAddress(container, processContainerLocationCallback)
  3. After the result has been obtained, process the result. -> processContainerLocationCallback(container,lat,long)
  4. Update the JSON object by looping over all records and search for the correct id. Once the id was found, update latitude and longitude information. -> updateJSON(container,lat,long,printJSONCallback)
  5. Write the result to the Web page -> printJSONCallback()

The missing latitude and longitude values are retrieved and the JSON gets updated. The final result looks like this:

                "containerStandorte": [
                        "id": "1",
                        "name": "Pfarre Allerheiligen",
                        "address": "St.-Georgs-Weg 15, 6020, Innsbruck, Austria",
                        "latitude": 47.2680316,
                        "longitude": 11.355563999999958
                        "id": "2",
                        "name": "Endhaltestelle 3er Linie Amras",
                        "address": "Philippine-Welser-Straße 49, 6020, Innsbruck, Austria",
                        "latitude": 47.2589929,
                        "longitude": 11.42600379999999

Now that we have the data ready, we can proceed with the second step.

Placing the Markers

I artistically created a custom marker image which we will use to indicate the location of a clothes container from WAMS.

This image replaces the Google standard marker. Now all that is left is that we iterate over the updated JSON object, which now contains also the latitude and longitude data and place a marker for each container. Note that hovering over the image displays the address of the container on the Map.

// Data for container locations
        var wamsData = '{"containerStandorte":[{"id":"1","name":"Pfarre Allerheiligen",
"address":"St.-Georgs-Weg 15, 6020, Innsbruck, Austria","latitude":47.2680316,"longitude":11.355563999999958},
{"id":"2","name":"Endhaltestelle 3er Linie Amras","address":"Philippine-Welser-Straße 49, 6020, Innsbruck, Austria","latitude":47.2589929,"longitude":11.42600379999999},
{"id":"3","name":"DEZ Einkaufszentrum Parkgarage","address":"Amraser-See-Straße 56a,6020 Innsbruck, Austria","latitude":47.2625925,"longitude":11.430842299999995},
{"id":"4","name":"Wohnanlage Neue Heimat","address":"Geyrstraße 27-29, 6020 Innsbruck, Austria","latitude":47.2614899,"longitude":11.426765700000033},
{"id":"5","name":"MPREIS Haller Straße","address":"Hallerstraße 212, 6020 Innsbruck, Austria","latitude":47.2769524,"longitude":11.442559599999981},
{"id":"6","name":"Recyclinginsel Novapark","address":"Arzlerstraße 43, 6020 Innsbruck, Austria","latitude":47.2833947,"longitude":11.424273299999982},
{"id":"7","name":"Höhenstraße / Hungerburg (neben Spar)","address":"Höhenstraße 125,6020 Innsbruck, 6020, Innsbruck, Austria","latitude":47.2841353,"longitude":11.394666799999982},
{"id":"8","name":"Recyclinginsel Schneeburggasse","address":"Schneeburggasse 116, 6020 Innsbruck, Austria","latitude":47.2695889,"longitude":11.364059699999984},
{"id":"9","name":"MPreis Fischerhäuslweg 31","address":"Fischerhäuslweg 31, 6020 Innsbruck, Austria","latitude":47.261875,"longitude":11.364496700000018},
{"id":"10","name":"Pfarre Petrus Canisius","address":"Santifallerstraße 5,6020 Innsbruck Austria","latitude":47.2635626,"longitude":11.380990800000063},
{"id":"11","name":"MPreis Bachlechnerstraße","address":"Bachlechnerstraße 46, 6020 Innsbruck","latitude":47.2645067,"longitude":11.376220800000056}]}';

        function initialize() {
          var innsbruck = { lat: 47.2656733, lng: 11.3941983 };
          var map = new google.maps.Map(document.getElementById('map'), {
            zoom: 14,
            center: innsbruck

          // Load Google Geocoder Library
          var geocoder = new google.maps.Geocoder();
          // Parse the data into a JSON
          var wamsJSON = JSON.parse(wamsData);
          // Iterate over all containers
          for(var i =0; i < wamsJSON.containerStandorte.length;i++){
              var container = wamsJSON.containerStandorte[i];
              placeMarkerOnMap(geocoder, map, container);

    // Custom marker
    var wamsLogo = {
      url: 'images/wams.png',
      // This marker is 20 pixels wide by 32 pixels high.
      size: new google.maps.Size(64, 64),
      // The origin for this image is (0, 0).
      origin: new google.maps.Point(0, 0),
      // The anchor for this image is the base of the flagpole at (0, 32).
      anchor: new google.maps.Point(64, 70)

    // Define the shape for the marker
    var shape = {
      coords: [1, 1, 1, 64, 64, 64, 64, 1],
      type: 'poly'

    // Place marker on the map
    function placeMarkerOnMap(geocoder, resultsMap, container) {
        // Create Google position object with latitude and longitude from the container object
        var positionLatLng = new google.maps.LatLng(parseFloat(container.latitude),parseFloat(container.longitude));
        // Create marker with the position, logo and address
        var marker = new google.maps.Marker({
          map: resultsMap,
          position: positionLatLng,
          icon: wamsLogo,
          shape: shape,
          title: container.address,
          animation: google.maps.Animation.DROP
    // Place marker on the map
    google.maps.event.addDomListener(window, 'load', initialize);

Hosting the Result

Github offers a great feature for hosting simple static Web pages. All is needed is a new orphan branch of your project, which is named gh-pages, as described here. This branch serves as the Web directory for all your files and allows to host Web pages for public projects for free. You can see the result of the project above here.