Deploying to Digital Ocean¶
While there are multiple ways one can deploy to Digital Ocean, for this guide we’re choosing to use Docker Swarm (installed as a one-click app). This choice was made because it is easy to get started with on Digital Ocean, and makes for a good foundation for small production applications due to its convenience and feature set.
For this guide, we’re going to assume you have a single VM you wish to deploy to.
Tip
You should be familiar with how to build a Docker image with your app, see the Working With Docker guide first if you are not sure how to do so.
Prerequisites¶
You will need to have the following prerequisites checked off:
- Know how to build a Docker image containing your application
- Be familiar with Docker Compose (this guide uses it, see Working With Docker)
- Know how to create a “one-click app” droplet
- Know how to SSH to a Digital Ocean droplet
- Know how to publish an image to Docker Hub (covered below)
- Have published your app’s Docker image to Docker Hub (covered below)
Docker Compose¶
We will be using Docker Compose in conjunction with Docker Swarm - and to do so
we need to make some adjustments to the docker-compose.yml
file we created in
Working With Docker.
First, define a network, by adding the following to the top-level of the file:
1 2 3 4 5 6 7 | networks:
webnet:
driver: overlay
attachable: true # Needed in order to run custom commands in the container
services:
# snip..
|
We then need to use that network with our web
service, and add a deploy
configuration section:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | services: web: image: "myapp:latest" depends_on: - db deploy: replicas: 1 restart_policy: condition: on-failure ports: - "80:4000" env_file: - config/docker.env networks: - webnet |
Likewise, our db
service needs some adjustment:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | db: image: postgres:10-alpine deploy: replicas: 1 placement: constraints: [node.role == manager] restart_policy: condition: on-failure volumes: - "./volumes/postgres:/var/lib/postgresql/data" ports: - "5432:5432" env_file: - config/docker.env networks: - webnet |
Now we’re all set!
Publishing to Docker Hub¶
If you aren’t sure how to publish an image to Docker Hub, you’re in luck! It’s very simple - first, create an account here.
Then, click “Create Repository” from the dashboard while logged in, set the name of the repository to the name of the image you have created, give it a description, and set the visibility to either public or private.
Warning
If you set visibility to private
, you will need to login to Docker on the
server in order to pull images. If you set it to public
, anyone call pull
your images, so if they contain sensitive information, do not do this!
Once your account is created, you will need to log in with the Docker CLI:
1 | $ docker login |
Then, once you have built your image, publish it like so:
1 | $ docker push username/$APP_NAME:$APP_VSN |
Warning
Make sure you update the tags you are building with to include the full
repository name, i.e. username/myapp:0.1.0
, not just myapp:0.1.0
. If you
were following the Working With Docker guide,
adjust your Makefile
by adding the username/
prefix, where username
should be your Docker Hub username.
Assuming APP_NAME=myapp
and APP_VSN=0.1.0
, this will check for a local image
with the tag myapp:0.1.0
, and if it exists, push it to the Docker Hub repository.
Setting up the droplet¶
On Digital Ocean, click on “one-click apps” and choose Docker. It will create a new droplet for you with Docker pre-installed.
SSH into the new droplet, and upgrade it:
1 | $ apt-get upgrade -y |
Next, create a directory for configuration files:
1 | $ mkdir -p /etc/myapp/config |
Now that the directory has been created, copy up the docker-compose.yml
and
docker.env
files you have created (if you didn’t follow the Working With
Docker guide, I recommend reviewing it to see what is
in these files):
1 2 | $ scp ./config/docker.env root@<droplet host>:/etc/myapp/config/docker.env $ scp ./docker-compose.yml root@<droplet host>:/etc/myapp/docker-compose.yml |
If you set the visibility of your image repository to private
, login to Docker
with docker login
.
The final step needed to set up our droplet is to initialize Docker Swarm:
1 | $ docker swarm init --advertise-addr <ip address of droplet> --listen-addr <ip address of droplet> |
We now have everything in place to run our application!
Deploying the application¶
All that is needed now to run our application is to deploy a new stack:
1 | $ docker stack deploy -c /etc/myapp/docker-compose.yml myapp |
Note
This command is run on the droplet, not your local machine.
Deploying new versions of the application¶
To deploy an update to your application, first publish a new version of your image to Docker Hub.
Now, SSH to your droplet, and run a service update:
1 | $ docker service update --image username/myapp:0.2.0 myapp |
The above assumes we set APP_NAME=myapp
and APP_VSN=0.2.0
in previous steps.
Warning
If you are tagging images with latest
and deploying that tag instead (not
recommended), deploying an update this way may not work, as the image will not
be refreshed if it has already been pulled. You can force an upgrade like so
1 2 | $ docker pull username/myapp:latest $ docker service update --image username/myapp:latest --force myapp |
Wrap up¶
As you can see, deploying an application to Digital Ocean can be very simple when we make use of some convenient automation tools like Docker Compose and Docker Swarm.
This is a great way to get an application up fast and be able to experiment with things without having to do a lot of tedious work by hand. For more complex applications, or orchestration for all of an organization’s services, I recommend looking at Kubernetes; but Docker Swarm is a great fit when you can keep things simple.