diff --git a/docs/Dockerfile b/docs/Dockerfile index 5f32dc4d..b16d0d2c 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -10,6 +10,7 @@ RUN svn checkout https://github.com/docker/kitematic/trunk/docs /docs/content/ki RUN svn checkout https://github.com/docker/toolbox/trunk/docs /docs/content/toolbox RUN svn checkout https://github.com/docker/opensource/trunk/docs /docs/content/project + ENV PROJECT=compose # To get the git info for this repo COPY . /src diff --git a/docs/compose-file.md b/docs/compose-file.md index 97b8ba51..ffa73f98 100644 --- a/docs/compose-file.md +++ b/docs/compose-file.md @@ -59,6 +59,14 @@ optionally [dockerfile](#dockerfile) and [args](#args). args: buildno: 1 +If you specify `image` as well as `build`, then Compose tags the built image +with the tag specified in `image`: + + build: ./dir + image: webapp + +This will result in an image tagged `webapp`, built from `./dir`. + > **Note**: In the [version 1 file format](#version-1), `build` is different in > two ways: > @@ -95,13 +103,13 @@ specified. > **Note**: In the [version 1 file format](#version-1), `dockerfile` is > different in two ways: -> -> - It appears alongside `build`, not as a sub-option: -> -> build: . -> dockerfile: Dockerfile-alternate -> - Using `dockerfile` together with `image` is not allowed. Attempting to do -> so results in an error. + + * It appears alongside `build`, not as a sub-option: + + build: . + dockerfile: Dockerfile-alternate + + * Using `dockerfile` together with `image` is not allowed. Attempting to do so results in an error. #### args @@ -195,6 +203,11 @@ Simple example: db: image: postgres +> **Note:** `depends_on` will not wait for `db` and `redis` to be "ready" before +> starting `web` - only until they have been started. If you need to wait +> for a service to be ready, see [Controlling startup order](startup-order.md) +> for more on this problem and strategies for solving it. + ### dns Custom DNS servers. Can be a single value or a list. @@ -340,13 +353,22 @@ An entry with the ip address and hostname will be created in `/etc/hosts` inside ### image -Tag or partial image ID. Can be local or remote - Compose will attempt to -pull if it doesn't exist locally. +Specify the image to start the container from. Can either be a repository/tag or +a partial image ID. - image: ubuntu - image: orchardup/postgresql + image: redis + image: ubuntu:14.04 + image: tutum/influxdb + image: example-registry.com:4000/postgresql image: a4bc65fd +If the image does not exist, Compose attempts to pull it, unless you have also +specified [build](#build), in which case it builds it using the specified +options and tags it with the specified tag. + +> **Note**: In the [version 1 file format](#version-1), using `build` together +> with `image` is not allowed. Attempting to do so results in an error. + ### labels Add metadata to containers using [Docker labels](https://docs.docker.com/engine/userguide/labels-custom-metadata/). You can use either an array or a dictionary. diff --git a/docs/django.md b/docs/django.md index e616d0e1..fb1fa214 100644 --- a/docs/django.md +++ b/docs/django.md @@ -10,10 +10,9 @@ weight=4 -# Quickstart: Compose and Django +# Quickstart: Docker Compose and Django -This quick-start guide demonstrates how to use Compose to set up and run a -simple Django/PostgreSQL app. Before starting, you'll need to have +This quick-start guide demonstrates how to use Docker Compose to set up and run a simple Django/PostgreSQL app. Before starting, you'll need to have [Compose installed](install.md). ## Define the project components @@ -119,12 +118,23 @@ In this step, you create a Django started project by building the image from the -rwxr-xr-x 1 root root manage.py -rw-rw-r-- 1 user user requirements.txt - The files `django-admin` created are owned by root. This happens because - the container runs as the `root` user. + If you are running Docker on Linux, the files `django-admin` created are owned + by root. This happens because the container runs as the root user. Change the + ownership of the the new files. -4. Change the ownership of the new files. + sudo chown -R $USER:$USER . - sudo chown -R $USER:$USER . + If you are running Docker on Mac or Windows, you should already have ownership + of all files, including those generated by `django-admin`. List the files just + verify this. + + $ ls -l + total 32 + -rw-r--r-- 1 user staff 145 Feb 13 23:00 Dockerfile + drwxr-xr-x 6 user staff 204 Feb 13 23:07 composeexample + -rw-r--r-- 1 user staff 159 Feb 13 23:02 docker-compose.yml + -rwxr-xr-x 1 user staff 257 Feb 13 23:07 manage.py + -rw-r--r-- 1 user staff 16 Feb 13 23:01 requirements.txt ## Connect the database @@ -171,6 +181,8 @@ In this section, you set up the database connection for Django. Docker host. If you are using a Docker Machine VM, you can use the `docker-machine ip MACHINE_NAME` to get the IP address. + ![Django example](images/django-it-worked.png) + ## More Compose documentation - [User guide](index.md) diff --git a/docs/extends.md b/docs/extends.md index bceb0257..9ecccd8a 100644 --- a/docs/extends.md +++ b/docs/extends.md @@ -290,31 +290,17 @@ replaces the old value. # result command: python otherapp.py -In the case of `build` and `image`, using one in the local service causes -Compose to discard the other, if it was defined in the original service. - -Example of image replacing build: - - # original service - build: . - - # local service - image: redis - - # result - image: redis - - -Example of build replacing image: - - # original service - image: redis - - # local service - build: . - - # result - build: . +> **Note:** In the case of `build` and `image`, when using +> [version 1 of the Compose file format](compose-file.md#version-1), using one +> option in the local service causes Compose to discard the other option if it +> was defined in the original service. +> +> For example, if the original service defines `image: webapp` and the +> local service defines `build: .` then the resulting service will have +> `build: .` and no `image` option. +> +> This is because `build` and `image` cannot be used together in a version 1 +> file. For the **multi-value options** `ports`, `expose`, `external_links`, `dns` and `dns_search`, Compose concatenates both sets of values: diff --git a/docs/faq.md b/docs/faq.md index 73596c18..45885255 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -15,7 +15,13 @@ weight=90 If you don’t see your question here, feel free to drop by `#docker-compose` on freenode IRC and ask the community. -## Why do my services take 10 seconds to stop? + +## Can I control service startup order? + +Yes - see [Controlling startup order](startup-order.md). + + +## Why do my services take 10 seconds to recreate or stop? Compose stop attempts to stop a container by sending a `SIGTERM`. It then waits for a [default timeout of 10 seconds](./reference/stop.md). After the timeout, @@ -40,6 +46,12 @@ in your Dockerfile. * If you are able, modify the application that you're running to add an explicit signal handler for `SIGTERM`. +* Set the `stop_signal` to a signal which the application knows how to handle: + + web: + build: . + stop_signal: SIGINT + * If you can't modify the application, wrap the application in a lightweight init system (like [s6](http://skarnet.org/software/s6/)) or a signal proxy (like [dumb-init](https://github.com/Yelp/dumb-init) or @@ -84,30 +96,6 @@ specify the filename to use, for example: docker-compose -f docker-compose.json up ``` -## How do I get Compose to wait for my database to be ready before starting my application? - -Unfortunately, Compose won't do that for you but for a good reason. - -The problem of waiting for a database to be ready is really just a subset of a -much larger problem of distributed systems. In production, your database could -become unavailable or move hosts at any time. The application needs to be -resilient to these types of failures. - -To handle this, the application would attempt to re-establish a connection to -the database after a failure. If the application retries the connection, -it should eventually be able to connect to the database. - -To wait for the application to be in a good state, you can implement a -healthcheck. A healthcheck makes a request to the application and checks -the response for a success status code. If it is not successful it waits -for a short period of time, and tries again. After some timeout value, the check -stops trying and report a failure. - -If you need to run tests against your application, you can start by running a -healthcheck. Once the healthcheck gets a successful response, you can start -running your tests. - - ## Should I include my code with `COPY`/`ADD` or a volume? You can add your code to the image using `COPY` or `ADD` directive in a diff --git a/docs/gettingstarted.md b/docs/gettingstarted.md index 36577f07..60482bce 100644 --- a/docs/gettingstarted.md +++ b/docs/gettingstarted.md @@ -12,7 +12,7 @@ weight=-85 # Getting Started -On this page you build a simple Python web application running on Compose. The +On this page you build a simple Python web application running on Docker Compose. The application uses the Flask framework and increments a value in Redis. While the sample uses Python, the concepts demonstrated here should be understandable even if you're not familiar with it. diff --git a/docs/images/django-it-worked.png b/docs/images/django-it-worked.png new file mode 100644 index 00000000..75769754 Binary files /dev/null and b/docs/images/django-it-worked.png differ diff --git a/docs/images/rails-welcome.png b/docs/images/rails-welcome.png new file mode 100644 index 00000000..51512dbd Binary files /dev/null and b/docs/images/rails-welcome.png differ diff --git a/docs/images/wordpress-files.png b/docs/images/wordpress-files.png new file mode 100644 index 00000000..4762935b Binary files /dev/null and b/docs/images/wordpress-files.png differ diff --git a/docs/images/wordpress-lang.png b/docs/images/wordpress-lang.png new file mode 100644 index 00000000..f0bd864e Binary files /dev/null and b/docs/images/wordpress-lang.png differ diff --git a/docs/images/wordpress-welcome.png b/docs/images/wordpress-welcome.png new file mode 100644 index 00000000..c9ba2036 Binary files /dev/null and b/docs/images/wordpress-welcome.png differ diff --git a/docs/overview.md b/docs/overview.md index bb3c5d71..2efb715a 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -24,11 +24,14 @@ CI workflows. You can learn more about each case in Using Compose is basically a three-step process. -1. Define your app's environment with a `Dockerfile` so it can be -reproduced anywhere. -2. Define the services that make up your app in `docker-compose.yml` so -they can be run together in an isolated environment. -3. Lastly, run `docker-compose up` and Compose will start and run your entire app. +1. Define your app's environment with a `Dockerfile` so it can be reproduced +anywhere. + +2. Define the services that make up your app in `docker-compose.yml` +so they can be run together in an isolated environment. + +3. Lastly, run +`docker-compose up` and Compose will start and run your entire app. A `docker-compose.yml` looks like this: @@ -37,16 +40,16 @@ A `docker-compose.yml` looks like this: web: build: . ports: - - "5000:5000" + - "5000:5000" volumes: - - .:/code - - logvolume01:/var/log + - .:/code + - logvolume01:/var/log links: - - redis - redis: - image: redis - volumes: - logvolume01: {} + - redis + redis: + image: redis + volumes: + logvolume01: {} For more information about the Compose file, see the [Compose file reference](compose-file.md) @@ -80,14 +83,12 @@ The features of Compose that make it effective are: ### Multiple isolated environments on a single host -Compose uses a project name to isolate environments from each other. You can use -this project name to: +Compose uses a project name to isolate environments from each other. You can make use of this project name in several different contexts: -* on a dev host, to create multiple copies of a single environment (ex: you want - to run a stable copy for each feature branch of a project) +* on a dev host, to create multiple copies of a single environment (e.g., you want to run a stable copy for each feature branch of a project) * on a CI server, to keep builds from interfering with each other, you can set the project name to a unique build number -* on a shared host or dev host, to prevent different projects which may use the +* on a shared host or dev host, to prevent different projects, which may use the same service names, from interfering with each other The default project name is the basename of the project directory. You can set @@ -148,9 +149,7 @@ started guide" to a single machine readable Compose file and a few commands. An important part of any Continuous Deployment or Continuous Integration process is the automated test suite. Automated end-to-end testing requires an environment in which to run tests. Compose provides a convenient way to create -and destroy isolated testing environments for your test suite. By defining the full -environment in a [Compose file](compose-file.md) you can create and destroy these -environments in just a few commands: +and destroy isolated testing environments for your test suite. By defining the full environment in a [Compose file](compose-file.md) you can create and destroy these environments in just a few commands: $ docker-compose up -d $ ./run_tests @@ -159,9 +158,7 @@ environments in just a few commands: ### Single host deployments Compose has traditionally been focused on development and testing workflows, -but with each release we're making progress on more production-oriented features. -You can use Compose to deploy to a remote Docker Engine. The Docker Engine may -be a single instance provisioned with +but with each release we're making progress on more production-oriented features. You can use Compose to deploy to a remote Docker Engine. The Docker Engine may be a single instance provisioned with [Docker Machine](https://docs.docker.com/machine/) or an entire [Docker Swarm](https://docs.docker.com/swarm/) cluster. diff --git a/docs/rails.md b/docs/rails.md index 8b7b4fd9..a8fc383e 100644 --- a/docs/rails.md +++ b/docs/rails.md @@ -9,9 +9,9 @@ weight=5 +++ -## Quickstart: Compose and Rails +## Quickstart: Docker Compose and Rails -This Quickstart guide will show you how to use Compose to set up and run a Rails/PostgreSQL app. Before starting, you'll need to have [Compose installed](install.md). +This Quickstart guide will show you how to use Docker Compose to set up and run a Rails/PostgreSQL app. Before starting, you'll need to have [Compose installed](install.md). ### Define the project @@ -30,7 +30,9 @@ Dockerfile consists of: RUN bundle install ADD . /myapp -That'll put your application code inside an image that will build a container with Ruby, Bundler and all your dependencies inside it. For more information on how to write Dockerfiles, see the [Docker user guide](https://docs.docker.com/engine/userguide/dockerimages/#building-an-image-from-a-dockerfile) and the [Dockerfile reference](https://docs.docker.com/engine/reference/builder/). +That'll put your application code inside an image that will build a container +with Ruby, Bundler and all your dependencies inside it. For more information on +how to write Dockerfiles, see the [Docker user guide](https://docs.docker.com/engine/userguide/dockerimages/#building-an-image-from-a-dockerfile) and the [Dockerfile reference](https://docs.docker.com/engine/reference/builder/). Next, create a bootstrap `Gemfile` which just loads Rails. It'll be overwritten in a moment by `rails new`. @@ -41,7 +43,11 @@ You'll need an empty `Gemfile.lock` in order to build our `Dockerfile`. $ touch Gemfile.lock -Finally, `docker-compose.yml` is where the magic happens. This file describes the services that comprise your app (a database and a web app), how to get each one's Docker image (the database just runs on a pre-made PostgreSQL image, and the web app is built from the current directory), and the configuration needed to link them together and expose the web app's port. +Finally, `docker-compose.yml` is where the magic happens. This file describes +the services that comprise your app (a database and a web app), how to get each +one's Docker image (the database just runs on a pre-made PostgreSQL image, and +the web app is built from the current directory), and the configuration needed +to link them together and expose the web app's port. version: '2' services: @@ -64,22 +70,38 @@ using `docker-compose run`: $ docker-compose run web rails new . --force --database=postgresql --skip-bundle -First, Compose will build the image for the `web` service using the -`Dockerfile`. Then it'll run `rails new` inside a new container, using that -image. Once it's done, you should have generated a fresh app: +First, Compose will build the image for the `web` service using the `Dockerfile`. Then it'll run `rails new` inside a new container, using that image. Once it's done, you should have generated a fresh app: - $ ls - Dockerfile app docker-compose.yml tmp - Gemfile bin lib vendor - Gemfile.lock config log - README.rdoc config.ru public - Rakefile db test + $ ls -l + total 56 + -rw-r--r-- 1 user staff 215 Feb 13 23:33 Dockerfile + -rw-r--r-- 1 user staff 1480 Feb 13 23:43 Gemfile + -rw-r--r-- 1 user staff 2535 Feb 13 23:43 Gemfile.lock + -rw-r--r-- 1 root root 478 Feb 13 23:43 README.rdoc + -rw-r--r-- 1 root root 249 Feb 13 23:43 Rakefile + drwxr-xr-x 8 root root 272 Feb 13 23:43 app + drwxr-xr-x 6 root root 204 Feb 13 23:43 bin + drwxr-xr-x 11 root root 374 Feb 13 23:43 config + -rw-r--r-- 1 root root 153 Feb 13 23:43 config.ru + drwxr-xr-x 3 root root 102 Feb 13 23:43 db + -rw-r--r-- 1 user staff 161 Feb 13 23:35 docker-compose.yml + drwxr-xr-x 4 root root 136 Feb 13 23:43 lib + drwxr-xr-x 3 root root 102 Feb 13 23:43 log + drwxr-xr-x 7 root root 238 Feb 13 23:43 public + drwxr-xr-x 9 root root 306 Feb 13 23:43 test + drwxr-xr-x 3 root root 102 Feb 13 23:43 tmp + drwxr-xr-x 3 root root 102 Feb 13 23:43 vendor -The files `rails new` created are owned by root. This happens because the -container runs as the `root` user. Change the ownership of the new files. +If you are running Docker on Linux, the files `rails new` created are owned by +root. This happens because the container runs as the root user. Change the +ownership of the the new files. - sudo chown -R $USER:$USER . + sudo chown -R $USER:$USER . + +If you are running Docker on Mac or Windows, you should already have ownership +of all files, including those generated by `rails new`. List the files just to +verify this. Uncomment the line in your new `Gemfile` which loads `therubyracer`, so you've got a Javascript runtime: @@ -132,6 +154,14 @@ Finally, you need to create the database. In another terminal, run: That's it. Your app should now be running on port 3000 on your Docker daemon. If you're using [Docker Machine](https://docs.docker.com/machine/), then `docker-machine ip MACHINE_VM` returns the Docker host IP address. +![Rails example](images/rails-welcome.png) + +>**Note**: If you stop the example application and attempt to restart it, you might get the +following error: `web_1 | A server is already running. Check +/myapp/tmp/pids/server.pid.` One way to resolve this is to delete the file +`tmp/pids/server.pid`, and then re-start the application with `docker-compose +up`. + ## More Compose documentation diff --git a/docs/startup-order.md b/docs/startup-order.md new file mode 100644 index 00000000..c67e1829 --- /dev/null +++ b/docs/startup-order.md @@ -0,0 +1,88 @@ + + +# Controlling startup order in Compose + +You can control the order of service startup with the +[depends_on](compose-file.md#depends-on) option. Compose always starts +containers in dependency order, where dependencies are determined by +`depends_on`, `links`, `volumes_from` and `network_mode: "service:..."`. + +However, Compose will not wait until a container is "ready" (whatever that means +for your particular application) - only until it's running. There's a good +reason for this. + +The problem of waiting for a database (for example) to be ready is really just +a subset of a much larger problem of distributed systems. In production, your +database could become unavailable or move hosts at any time. Your application +needs to be resilient to these types of failures. + +To handle this, your application should attempt to re-establish a connection to +the database after a failure. If the application retries the connection, +it should eventually be able to connect to the database. + +The best solution is to perform this check in your application code, both at +startup and whenever a connection is lost for any reason. However, if you don't +need this level of resilience, you can work around the problem with a wrapper +script: + +- Use a tool such as [wait-for-it](https://github.com/vishnubob/wait-for-it) + or [dockerize](https://github.com/jwilder/dockerize). These are small + wrapper scripts which you can include in your application's image and will + poll a given host and port until it's accepting TCP connections. + + Supposing your application's image has a `CMD` set in its Dockerfile, you + can wrap it by setting the entrypoint in `docker-compose.yml`: + + version: "2" + services: + web: + build: . + ports: + - "80:8000" + depends_on: + - "db" + entrypoint: ./wait-for-it.sh db:5432 + db: + image: postgres + +- Write your own wrapper script to perform a more application-specific health + check. For example, you might want to wait until Postgres is definitely + ready to accept commands: + + #!/bin/bash + + set -e + + host="$1" + shift + cmd="$@" + + until psql -h "$host" -U "postgres" -c '\l'; do + >&2 echo "Postgres is unavailable - sleeping" + sleep 1 + done + + >&2 echo "Postgres is up - executing command" + exec $cmd + + You can use this as a wrapper script as in the previous example, by setting + `entrypoint: ./wait-for-postgres.sh db`. + + +## Compose documentation + +- [Installing Compose](install.md) +- [Get started with Django](django.md) +- [Get started with Rails](rails.md) +- [Get started with WordPress](wordpress.md) +- [Command line reference](./reference/index.md) +- [Compose file reference](compose-file.md) diff --git a/docs/wordpress.md b/docs/wordpress.md index 62aec251..62f50c24 100644 --- a/docs/wordpress.md +++ b/docs/wordpress.md @@ -10,88 +10,133 @@ weight=6 -# Quickstart: Compose and WordPress +# Quickstart: Docker Compose and WordPress -You can use Compose to easily run WordPress in an isolated environment built -with Docker containers. +You can use Docker Compose to easily run WordPress in an isolated environment built +with Docker containers. This quick-start guide demonstrates how to use Compose to set up and run WordPress. Before starting, you'll need to have +[Compose installed](install.md). ## Define the project -First, [Install Compose](install.md) and then download WordPress into the -current directory: +1. Create an empty project directory. - $ curl https://wordpress.org/latest.tar.gz | tar -xvzf - + You can name the directory something easy for you to remember. This directory is the context for your application image. The directory should only contain resources to build that image. -This will create a directory called `wordpress`. If you wish, you can rename it -to the name of your project. + This project directory will contain a `Dockerfile`, a `docker-compose.yaml` file, along with a downloaded `wordpress` directory and a custom `wp-config.php`, all of which you will create in the following steps. -Next, inside that directory, create a `Dockerfile`, a file that defines what -environment your app is going to run in. For more information on how to write -Dockerfiles, see the -[Docker user guide](https://docs.docker.com/engine/userguide/dockerimages/#building-an-image-from-a-dockerfile) and the -[Dockerfile reference](https://docs.docker.com/engine/reference/builder/). In -this case, your Dockerfile should be: +2. Change directories into your project directory. - FROM orchardup/php5 - ADD . /code + For example, if you named your directory `my_wordpress`: -This tells Docker how to build an image defining a container that contains PHP -and WordPress. + $ cd my-wordpress/ -Next you'll create a `docker-compose.yml` file that will start your web service -and a separate MySQL instance: +3. Create a `Dockerfile`, a file that defines the environment in which your application will run. - version: '2' - services: - web: - build: . - command: php -S 0.0.0.0:8000 -t /code - ports: - - "8000:8000" - depends_on: - - db - volumes: - - .:/code - db: - image: orchardup/mysql - environment: - MYSQL_DATABASE: wordpress + For more information on how to write Dockerfiles, see the [Docker Engine user guide](https://docs.docker.com/engine/userguide/dockerimages/#building-an-image-from-a-dockerfile) and the [Dockerfile reference](https://docs.docker.com/engine/reference/builder/). -A supporting file is needed to get this working. `wp-config.php` is -the standard WordPress config file with a single change to point the database -configuration at the `db` container: + In this case, your Dockerfile should include these two lines: - + +7. Verify the contents and structure of your project directory. + + + ![WordPress files](images/wordpress-files.png) ### Build the project -With those four files in place, run `docker-compose up` inside your WordPress -directory and it'll pull and build the needed images, and then start the web and -database containers. If you're using [Docker Machine](https://docs.docker.com/machine/), then `docker-machine ip MACHINE_VM` gives you the machine address and you can open `http://MACHINE_VM_IP:8000` in a browser. +With those four new files in place, run `docker-compose up` from your project directory. This will pull and build the needed images, and then start the web and database containers. + +If you're using [Docker Machine](https://docs.docker.com/machine/), then `docker-machine ip MACHINE_VM` gives you the machine address and you can open `http://MACHINE_VM_IP:8000` in a browser. + +At this point, WordPress should be running on port `8000` of your Docker Host, and you can complete the "famous five-minute installation" as a WordPress administrator. + +![Choose language for WordPress install](images/wordpress-lang.png) + +![WordPress Welcome](images/wordpress-welcome.png) + ## More Compose documentation