Tag Archives: EN

Kubernetes Persistent Storage Hell

We've started to work on a rather complex application recently with my team at Red Hat. We all agreed it'll be best to use containers, Kubernetes and Vagrant to make our development (and testing) environment easy to setup (and to be cool, obviously).

Our application consists of multiple components where those important for the post are MongoDB and something we can call worker. The reason for MongoDB is clear - we are working with JSONs and need to store them somewhere. Worker takes data, does some works on them and writes to DB. There are multiple types of workers and they need to share some data. We also need to be able to scale (That's why we use containers!) which also requires shared storage. We want both storages to be local path (for Vagrant use case especially).

Sounds easy, right? But it's not. Here is the config objects situation:


The way you work with volumes i Kubernetes is that you define a PersistentVolume object stating capacity, access mode and host path (still talking about local storage). Then you define PersistentVolumeClaim with access mode and capacity. Kubernetes then automagically map these two - i.e. randomly match claim and volume where volume provides correct mode and enough capacity.

You might be able to see the problem now, but if not, here it is: If you have 2 volumes and 2 claims (as we have) there is no way you can be sure which claim will get which volume. You might not care when you first start your app, because the directories you provided for volumes will be probably empty. But what if you restart the app? Or the Vagrant box (and thus the app)? You cannot be sure which volume will be assigned to which claim.

This leads to an inconsistent state where your MongoDB storage can be assigned to your worker storage and vice versa.

I've found 2 related issues on github https://github.com/.../issues/14908 and https://github.com/.../pull/17056 which, if implemented and solved, should fix it. But is there a workaround?

Hell yeah! And it's pretty simple. Instead of defining PersistentVolumeClaim object and using persistentVolumeClaim key in a replication controller, you can use hostPath directly in the RC. This is how the patch looked like:

diff --git a/kubernetes/mongodb-controller.yaml b/kubernetes/mongodb-controller.yaml
index ffdd5f3..9d7bbe2 100644
--- a/kubernetes/mongodb-controller.yaml
+++ b/kubernetes/mongodb-controller.yaml
@@ -23,5 +23,5 @@ spec:
 mountPath: /data/db
 - name: mongo-persistent-storage
- persistentVolumeClaim:
- claimName: myclaim-1
+ hostPath:
+ path: "/media/mongo-data"
diff --git a/kubernetes/worker-controller.yaml b/kubernetes/worker-controller.yaml
index 51181df..f62df47 100644
--- a/kubernetes/worker-controller.yaml
+++ b/kubernetes/worker-controller.yaml
@@ -44,5 +44,6 @@ spec:
 mountPath: /data
 - name: worker-persistent-storage
- persistentVolumeClaim:
- claimName: myclaim-2
+ hostPath:
+ path: "/media/worker-data"

The important bits of Kubernetes config then looks like:

     - name: mongo-persistent-storage
       mountPath: /data/db
   - name: mongo-persistent-storage
       path: "/media/mongo-data"

What the hell does Nulecule try to solve?

There are some statements on the Project Atomic website about Nulecule. There is also some information in the Nulecule Github repository. I've spent big portion of DockerCon explaining Nulecule to various people and here is what my explanation boiled down to:

1. Parameterization

As a deployer of multi-container application, I want to have simple way how to parameterize orchestration manifests

  •  f.e. if you look at kubernetes/examples, you can see "change this, and that in the JSON configs to make this app working in your environment" in every other example.

2. Reusability

As a developer of a multi-container application I want to use existing components (like databases) in my application so that I don't have to burn my time on something that already exists.

  • f.e. as someone creating a voting app (borrowing from DockerCon:) ) I want to use Redis and Postgresql components and only add frontend and worker to the equation.

3. Multiple Orchestrations - providers

As a developer of a multi-container application I want enable deployment to multiple orchestration providers for my application so that users can easily migrate.

4. Distribution

As an enterprise consumer of a multi-container application I want to avoid any out-of-band transport layer for the application and it's metadata

  • f.e. I use Docker images and have a private registry set up. Instead of having to setup another authenticated webserver and figure out how to verify what I pull as tarballs or plain text, I will package every piece of puzzle into a Docker image and distribute it through registry.

The next and very valid question is: "How well did we tackled down these challenges?" That's up to you to figure out and tell us and ideally help us fix bits that you struggle with.

Fedora Developer Portal – how to contribute

The great thing about working at Red Hat is being part of the Fedora community and as a part of this group of enthusiastic people you get close to cool, interesting, awesome, innovative, important... projects. And you get close to them while they are at the beginning and you can influence where they go.

One of those projects is Fedora Developer Portal which will help developers to start their projects on Fedora. It will help you figure out what languages, frameworks, or databases are available in our distribution. How to use Docker, Vagrant or Copr build system to package, distribute and deploy your projects. There is already content ready for you to help you with setting things up for Arduino. Much of other content is in preparations and even more is waiting for you to come and join the project!

My contribution to the project so far has been making it easy for you to contribute. I helped guys with contribution guidelines and I created a Docker image which will let you run the website locally so that you can review your contributions.

This is what you can also find in a README.md for the website project:

$ sudo docker run -it --rm developerportal/devel
[sudo] password for vpavlin: 
Previous HEAD position was 702f2a3... move logo to static directory
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
Already up-to-date.
Configuration file: /opt/developerportal/website/_config.yml
/home/dp/.gem/ruby/gems/jekyll-lunr-js-search-0.3.0/lib/jekyll_lunr_js_search/version.rb:3: warning: already initialized constant Jekyll::LunrJsSearch::VERSION
/opt/developerportal/website/_plugins/jekyll_lunr_js_search.rb:245: warning: previous definition of VERSION was here
 Source: /opt/developerportal/website
 Destination: /opt/developerportal/website/_site
 Lunr: Creating search index...
 Build Warning: Layout 'page' requested in content/fedora_features/Fedora23_Self_contained_Changes.md does not exist.
 Build Warning: Layout 'page' requested in content/fedora_features/Fedora23_System_Wide_Changes.md does not exist.
 Lunr: Index ready (lunr.js v0.4.5)
 Auto-regeneration: enabled for '/opt/developerportal/website'
Configuration file: /opt/developerportal/website/_config.yml
 Server address:
 Server running... press ctrl-c to stop.

You can see a server address - that's what you need to copy to your browser to view the page.

Screenshot from 2015-09-02 09-39-51

Now you have the local dev instance running. What if you want to display your changes? First, you clone the content repository.

$ git clone https://github.com/developer-portal/content

Then you will have to modify the run command a bit - specifically, add a volume mount (replace $PWD/content with the path to the cloned content repository):

$ sudo docker run -it --rm -v $PWD/content:/opt/developerportal/website/content developerportal/devel

Ok, now what if you don't want to contribute to content of the portal but rather to help guys making the website awesome? The approach is the same as above. First, you clone the website repository.

$ git clone https://github.com/developer-portal/website

Then you run the container just with the mount for website instead of content.

$ sudo docker run -it --rm -v $PWD/website:/opt/developerportal/website developerportal/devel

Jekyll is used to render the website and it's content and it's set up in the way that whenever you edit any file the website re-renders itself and you can simply refresh the browser when it's finished.

The rest is easy - you change whatever you want, push to your fork on Github, submit a pull request. Once it's reviewed, your changes will appear on the web. Yay!

Ok, my job is done here. Now it's your turn to contribute and promote it further!:)

How to (be a) man on Atomic Host

One major thing missing on the Atomic Host are manual pages. Not a terrible thing - you can always google for them, right? But what if you cannot? Then there is the Fedora Tools Docker image. Try this:

-bash-4.3$ alias man="sudo atomic run vpavlin/fedora-tools man"
-bash-4.3$ man systemd

You should see a manual page for systemd. Thinking about it, that's it. Nothing more you need to now about it. Simple:)


Running git on Atomic Host with Fedora Tools image

I added the Fedora Tools image to Fedora-Dockerfiles repository, as you might know from my earlier post. I'd like to introduce you to one use case for this image - git.

When I started to work more on Docker images, I started using Atomic Host(s) for testing as they boot faster and are easier to set up than classic installations. Problem was to get data in those VMs running Atomic Host as git was not present. That's where I first really appreciated the tools image.

bash-4.3# yum
bash: yum: command not found
bash-4.3# git
bash: git: command not found
bash-4.3# atomic run fedora/tools
[root@localhost /]# cd /host/home/vagrant/
[root@localhost vagrant]# git clone https://github.com/fedora-cloud/Fedora-Dockerfiles
Cloning into 'Fedora-Dockerfiles'...
remote: Counting objects: 2189, done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 2189 (delta 3), reused 0 (delta 0), pack-reused 2180
Receiving objects: 100% (2189/2189), 915.13 KiB | 901.00 KiB/s, done.
Resolving deltas: 100% (1014/1014), done.
Checking connectivity... done.
[root@localhost vagrant]# exit
bash-4.3# ls
Fedora-Dockerfiles sync

It's simple, right? You can see there is neither yum/dnf, nor git on the host, but still, I was able to clone the repository from Github very easily. The important thing to notice is the path I cd'ed to: /host/home/vagrant. You can see /host prefix there. That's where the host's filesystem is mounted and where I can access it and modify it.

You can review the docker run command for the tools image f.e. with this command:

bash-4.3# docker inspect --format='{{.Config.Labels.RUN}}' vpavlin/fedora-tools
docker run -it --name NAME --privileged --ipc=host --net=host --pid=host -e HOST=/host -e NAME=NAME -e IMAGE=IMAGE -v /run:/run -v /var/log:/var/log -v /etc/localtime:/etc/localtime -v /:/host IMAGE

Obviously, you can do more, not just clone the repo - you can run commit, push, checkout or anything else the same way.

Taskwarrior in a Docker container

So I heard about great tool - Taskwarrior. Cool, let's try it. Well, sure, but why should I install another bunch of RPMs to my laptop? Not that it matters a lot, but I hate to have my system bloated with unused packages which are installed as dependencies, but stay there when I remove the "root" package. Let's go crazy and create a simple Taskwarrior container.

I started with plain Dockerfile.

FROM fedora
MAINTAINER Vaclav Pavlin <vpavlin@redhat.com>
RUN dnf -y install task
VOLUME /task_data


That was not ideal because the final container missed very important settings - data location. So I added 2 lines which initialized ~/.taskrc and changed the data location to a well known path. I also added man command to the mix so that I can display manual pages for Taskwarrior. Final Dockerfile follows

FROM fedora
MAINTAINER Vaclav Pavlin <vpavlin@redhat.com>
RUN dnf -y install task man
VOLUME /task_data
RUN yes | task || true
RUN sed -i 's#\(data.location=\).*#\1/task_data#' ~/.taskrc

Still pretty simple, isn't it? Now, how to run this image? Just call the following command, there is an image ready for you on Docker Hub:

docker run -it --rm -v $HOME/.task:/task_data vpavlin/task

The command above will start a container which will initialize few files in $HOME/.task directory and print output like this:

[task next]
No matches.

You can try some fancy stuff with Taskwarrior itself now:

Screenshot from 2015-08-18 16-40-32Well, it works. But also is pretty ugly. Let's make the user experience nicer and smoother. You can simply create an alias for docker run command. For example like this one:

$ alias task="docker run -it --rm -v $HOME/.task:/task_data vpavlin/task"
$ task
[task next]

ID Age Project Tag Description Urg 
 1 6s vpavlin.eu blog today This is a test taks for my blog post 1.9

1 task

Then, when you call task, you will get the same output as if Taskwarrior was installed on you machine. Also your data will be stored locally so you don't have to be afraid of losing them when you remove container/image.

I also wrote a simple task function which you can paste in your ~/.bash_aliases file which lets you either use Taskwarrior as with the alias above, or you can do

task CMD man task

Note CMD in the command - that will let the bash function know to run different command than the one specified in Dockerfile - f.e. view the man pages.

I also strongly suggest to set the data location (i.e. the volume mount, or $data_dir variable in the function) to a backed up folder. I, for example, use Dropbox, so that I can access and modify my tasks from any machine (basically just by pulling and running the Docker image).



My Docker Helpers

I work with Docker almost all the time in my job at Red Hat. Building, running, inspecting containers... Writing same long commands every time you want to run a container or get it's IP starts to annoy you quickly. That's why I started writing small helpers in the form of bash functions which are loaded through .bashrc and thus can be used from cmd line easily.

You can find them in my docker-tools repository but let me introduce them a bit.


If you load/import/build images often, it happens that you end up having a bunch of <none> named images in your docker images output. The above commands removes them all.


I use this mostly in VMs where I am limited in terms of disk space - every container, especially when you test f.e. if yum install works, eats some space and this command lets you remove them all quickly.

dr fedora
docker run --name tmp0 -it --rm fedora bash
dr fedora cat /etc/os-release 
docker run --name tmp0 -it --rm fedora cat /etc/os-release

This dr command is probably my favourite. It runs bash in the given image with arguments I use the most. You can also specifiy a command to run if you wish so.


Simple alias for docker load command with the advantage of being able to load from default directory so you can just give it a file name and it looks in the predefined folder.


The most awesome thing about using functions instead of just aliases is that you can add whatever logic you like. So my de command (representing docker exec) can be called with a container id/name and command  - same as docker exec. But it can also be called without command which then defaults to bash and also without container id/name which default to the last entry in docker ps output. If you want to skip specifying container, but still want to use different cmd than bash, use following syntax:

de "" rpm -qa

I don't use next command as often as those above but I still like it a lot - it let's you print IP address of any container. If container id/name is not specified it uses the same logic as de.


Last command I have on my list at the moment is dk and you could maybe guess - yes, it's docker kill and it also provides the same logic as the two above.


Do you have more aliases/ideas? Let me know I am happy to make my list richer!

Delete an Image from Private Docker Registry

Have you ever wondered how to remove repositories/tags from your private Docker registry? It's simple according to Docker registry API specs. So let's try this

yum -y install docker-registry
sudo systemctl start docker-registry
docker pull fedora:21
docker tag fedora:21 localhost:5000/fedora:21 
curl localhost:5000/v1/repositories/fedora/tags/21

You should see an image id printed to your terminal. Now let's delete the image...

$ curl -X DELETE localhost:5000/v1/repositories/fedora/tags/21

To be clear - it does not remove the image/layers data - it just removes the reference from fedora:21 tag to the image id (i.e. data). If there is any other tag referencing the data, they will still be accessible.

Anyway, in some cases it is useful to be able to remove this reference. I run a private registry with 337 images (multiplied by few tags for every image) and I sometimes found myself in a situation where I pushed an image with wrong tag or I just wanted to stop people from pulling a specific image. I wrote a small bash script for these occasions - drrm.sh. The usage is simple

drrm.sh NAME[:TAG]

Which means for our fedora example

$ ./drrm.sh localhost:5000/fedora:21
Do you really want to untag "834629358fe214f210b0ed606fba2c17827d7a46dd74bd3309afc2a103ad0e89"? [y/N]: y
Image library/fedora:21 removed from localhost:5000

Firstly it checks if the image exists, then it asks for confirmation of removal and then it calls the previously shown curl command to delete the reference. I also have a simple "Docker Registry Garbage Collector" under development which goes through the docker-registry directory and moves unreferenced layers away (where you can delete them later). But that's going to be a topic next time:).

Why have I backed Pebble Time?

News! Awesome news! Pebble, the best smart watch maker in the world, announced new version of the watch yesterday. The name Time perfectly fits and I am proud and happy to be one of the first (thousands) backers.

I've been very interested in Pebble since their announcement on Kickstarter in 2012. I wanted to back Pebble back then but was not convinced enough. Two years later I caught myself browsing Pebble's web and hitting Buy button for basic black watch.

They arrived and I happily used them for few weeks. Then display died. I was sad so I asked Pebble what to do about it and the result was new replacement watch in a week on my hand. Awesome customer care, thank you Pebble!

Snímek z 2015-02-24 23:02:32

And here we are at the dawn of the year 2015 and I am finally backing their cool new product again on Kickstarter (Back to the roooots!) and I can't wait till May when they plan to start shipping Pebble Time. I don't need new watch, sure, but they hit the right note - color display, thinner design, new UI, possible hardware extensions... I was not thinking a single minute of switching to Android Wear from my Pebble a single minute and similarly, it took me a minute to figure out I'll back new Pebble Time. And from the numbers at Kickstarter, I was not the only one.

Running services with docker and systemd

I have described how to run systemd in a Docker container on Fedora in previous article but didn't give you any "real" example of how to actually use it. I guess you find it easy to figure out your own examples but let me show you mine.

WordPress & MariaDB

I like to use WP and MariaDB as example applications when I give a talk about containers. It's quite simple setup and at the same time uses some nice features of docker (f.e. links or port mapping). If you just want to see my Dockerfiles, please go to this github repository. If want more babbling, read on.

The MariaDB Dockerfile is forked from Fedora-Dockerfiles and I guess it will be "merged" there soon:). First few lines are quite boring - yum update/install. Next line I really like. How to start MariaDB properly..hmm...hey, let's use what packagers came up with - mariadb.service file.

RUN systemctl enable mariadb.service

This really presents the beauty of using systemd inside containers. Single line tells the init that we want to start the service on the container start. Easy, clean, awesome. Then some "stuff" follows. I let it up to you to figure out what it actually does - everybody likes homeworks, right?

You can also check my WordPress Dockerfile in the same repository. It's a bit longer but the most important line for this case is again enablement of the service - in this case httpd.

RUN systemctl enable httpd.service

If you build those two images...

docker build -t vpavlin/mariadb mariadb/
docker build -t vpavlin/wordpress wordpress/

You can run them with these commands

docker run -it --rm -v /sys/fs/cgroup:/sys/fs/cgroup --name mariadb vpavlin/mariadb
docker run -it --rm -v /sys/fs/cgroup:/sys/fs/cgroup -p 80:80 --name wordpress --link mariadb:mariadb vpavlin/wordpress

To describe these commands I'd say: Run a container with stdin and out attached to my tty, volume mount /sys/fs/cgroup for systemd, name containers mariadb and wordpress (respectively) and link mariadb to wordpress (which basically mean tell WP how to connect to mariadb). Oh, and map port 80 of WP container to host's port 80.

When you hit http://localhost in your browser, you should see a WP installation page.

Snímek z 2015-02-24 23:35:53

Any questions?:)