Using Docker in Vagrant for a Ghost blog behind NGINX
Vagrant in Docker can be used more usefully to simulate traditional setups such as an application behind a load balancer or a reverse proxy. We've already set up NGINX, so what about using it as a front reverse proxy with a blog engine such as Ghost behind it? We'll end up by showing how to do something similar with docker-compose.
Getting ready
To step through this recipe, you will need the following:
- A working Vagrant installation (no hypervisor needed)
- A working Docker installation and basic Docker knowledge
- An Internet connection
How to do it…
The previous example allows only one container to be launched simultaneously, which is sad considering the power of Docker. Let's define multiple containers and start by creating a front container (our previous NGINX):
config.vm.define "front" do |front|
front.vm.provider "docker" do |docker|
docker.image = "nginx:stable"
docker.ports = ['80:80']
docker.volumes = ["#{Dir.pwd}/src:/usr/share/nginx/html"]
end
endNow how about creating an application container, maybe a blog engine such as Ghost? Ghost publishes a ready-to-use container on the Docker Hub, so let's use that (version 0.9.0 at the time of writing) and expose on TCP/8080 the application container listening on TCP/2368:
config.vm.define "app" do |app|
app.vm.provider "docker" do |docker|
docker.image = "ghost:0.9.0"
docker.ports = ['8080:2368']
end
endCheck if you can access the blog on http://localhost:8080 and NGINX on http://localhost:
$ curl -IL http://localhost:8080 HTTP/1.1 200 OK X-Powered-By: Express […] $ curl -IL http://localhost HTTP/1.1 200 OK Server: nginx/1.10.1
Now let's use NGINX for what it's for—serving the application. Configuring NGINX as a reverse proxy is beyond the scope of this book, so just use the following simple configuration for the nginx.conf file at the root of your working folder:
server {
listen 80;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://app:2368;
}
}Change the configuration of the front container in Vagrant to use this configuration, remove the old index.html as we're not using it anymore, and link this container to the app container:
config.vm.define "front" do |front|
front.vm.provider "docker" do |docker|
docker.image = "nginx:stable"
docker.ports = ['80:80']
docker.volumes = ["#{Dir.pwd}/nginx.conf:/etc/nginx/conf.d/default.conf"]
docker.link("app:app")
end
endLinking the app container makes it available to the front container, so now there's no need to expose the Ghost blog container directly, let's make it simpler and more secure behind the reverse proxy:
config.vm.define "app" do |app|
app.vm.provider "docker" do |docker|
docker.name = "app"
docker.image = "ghost:0.9.0"
end
endWe're close! But this setup will eventually fail for a simple reason: our systems are too fast, and Vagrant parallelizes the startup of virtual machines by default, and also does this for containers. Containers start so fast that the app container may not be ready for NGINX when it's started. To ensure sequential startup, use the VAGRANT_NO_PARALLEL environment variable at the top of the Vagrantfile:
ENV['VAGRANT_NO_PARALLEL'] = 'true'
Now you can browse to http://localhost/admin and start using your Ghost blog in a container, behind a NGINX reverse proxy container, with the whole thing managed by Vagrant!
There's more…
You can access the containers logs directly using Vagrant:
$ vagrant docker-logs --follow ==> app: > ghost@0.9.0 start /usr/src/ghost ==> app: > node index ==> app: Migrations: Creating tables... […] ==> front: 172.17.0.1 - - [21/Aug/2016:10:55:08 +0000] "GET / HTTP/1.1" 200 1547 "-" "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:48.0) Gecko/20100101 Firefox/48.0" "-" ==> app: GET / 200 113.120 ms - - […]
A Docker Compose equivalent
Docker Compose is a tool to orchestrate multiple containers and manage Docker features from a single YAML file. So if you're more familiar with Docker Compose, or if you'd like to do something similar with this tool, here's what the code would look like in the docker-compose.yml file:
version: '2'
services:
front:
image: nginx:stable
volumes:
- "./nginx.conf:/etc/nginx/conf.d/default.conf"
restart: always
ports:
- "80:80"
depends_on:
- app
links:
- app
app:
image: ghost:0.9.0
restart: alwaysNote
Remember that with Vagrant, you can mix virtual machines and Docker containers, while you can't with docker-compose.