dap6000 / docker_playground

Where I play around with Docker

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Docker Playground

This is where I'm keeping my experiments with Docker, for now at least. As projects grow I may spin things out to individual repos. For now I reached a point where not having source control for the versions of my LAMP stack dockerfile seemed like a bad idea. And I wasn't sure the scope of that project justified its own repo.

Of course, as I write this the LAMP container is the only project here. And LAMP is a bit of a misnomer 'cos there's no MySQL element in it yet. And may not be. Or maybe I should do MySQL as it's own container and compose them?

I won't claim to be any sort of Docker expert. But if documenting my process and failures here can help ease the learning curve for anyone else out there I'll consider that a win.

Advice and Lessons Learned

Be warned, this is a brain dump with little to no organization behind it. I'll try to iterate on it and make it suck less over time.

Even after a couple of months of dabbling in Docker I still find myself occasionally conflating images and containers. If you look at the documentation you'll often see multiple syntax for the same command. For example see https://docs.docker.com/engine/reference/commandline/create/ vs https://docs.docker.com/engine/reference/commandline/container_create/. I've learned to lean on the more verbose version if only to reinforce the key terms. A container is created from an image. And an image is built from a dockerfile (and build context). There are shortcuts. For example docker run… builds an image then creates a container from it then starts that container then optionally issues a command to it. That's where a lot of tutorials start. If your brain works like mine you may wanna slow down and do things the more verbose, multi-step, easier to reason about and debug way. Maybe someday I'll welcome the shortcuts. But I haven't reached that point yet.

If you're running Docker on Mac, like me, then there's several important special cases to be aware of.

  • Due to file system difference, the directories available for Docker to use for Volumes is limited. This can be configured. But it is important to know about as out of the box behavior. See https://docs.docker.com/docker-for-mac/osxfs/ for more info.
  • A lot of the internals are different on a Mac. Usually these differences are inconsequential to the end user. But unexpected behavior is possible in edge cases. See https://docs.docker.com/docker-for-mac/docker-toolbox/ and be prepared to sink extra time into debugging if things go wonky.
  • Publishing ports from the container to the host machine works essentially the same on a Mac as on other platforms. But getting the container to discover services running on the host (for example, a MySQL instance) requires the special Mac only docker.for.mac.localhost address. Other aspects of container networking are also different in important ways. See https://docs.docker.com/docker-for-mac/networking/.

Official images are great and can be a huge time saver. But you may not be able to find exactly what you are looking for from an official source. For example, when I started working on my local development container the official image once went up to PHP 7.1 as a release candidate. I didn't want to build from source so I ended up needing about 30 lines of apt-get related code in my dockerfile. Since PHP 7.1.8 came out on August 3rd the official image now supports that. But the 7.1 branch was quite out of date when I needed it. And if I'm reading this right there tags between 7.1.0 and 7.1.8 aren't currently available (and may never be). https://hub.docker.com/_/php/

That being said, don't be afraid to try to build your image from scratch even if an official image is available. I learned a hell of a lot using Ubuntu as my base image rather than running with an official PHP image. And even with the official image supporting a tag for PHP 7.1.8 now I don't think I'll go back and recreate my dockerfile to use it.

Building images, or fetching them from Docker Hub, can take a while. It's essentially a compile step. Creating and starting containers from locally available images is quick and relatively painless. I recommend fearlessly tearing down and rebuilding images while learning. Some types of munged internal state can be fixed by stopping and restarting a container. Others need to stop and remove the botched container and spin up a new container from the same base image. But if the source of the problem is something in the dockerfile or build context fix it there and rebuild the image (tagging a new version if you want). That can fix just about anything. And if you're tracking the state of your dockerfile and build context in source control there's really no misstep you can't recover from.

I think one thing that's held me back from learning more sysadmin / ops stuff is the perceived cost of making a mistake. I sure as hell don't wanna screw anything up in production. And recovering from a mistake on my local development environment can easily cost a few hours. So better to stick with the devil I know, right? The ability to roll back and even hard reset the state of my development server has dropped the friction associated with experimenting. In fact, it's introduced the sort of playfulness I found appealing in web development many years ago.

Initially I misunderstood the idea that containers are ephemeral. At first I thought that meant the internal state was completely reset on each launch, aside from whatever data may be allowed to persist inside a volume. I learned that is not the case while debugging a hung PID file from a less than graceful Apache exit. A container will retain much of its internal state from a previous run upon relaunch. So ephemeral by design isn't so much about wiping the slate clean on every container launch. It's more about lowering the cost / friction around the process of launching new instances of a container. Or building a new iteration of a base image. And the fearlessness that introduces into ops work. Some of you may be able to approach this stuff fearlessly anyway. But to someone like me — carrying around a lot of baggage about the costs of sysadmin screw ups (some justified some not) in any environment — it's a breath of fresh air.

The command docker container exec… is your friend. https://docs.docker.com/edge/engine/reference/commandline/container_exec/ But keep in mind that common Unix tools / commands may not be available in your image by default. Especially if you're intentionally going for a slim build, you may not have access to curl or some such. You could add it in your dockerfile and rebuild. I guess you could even call apt-get via docker container exec although I haven't tried that yet myself.

About

Where I play around with Docker