├── Dockerfile ├── README.md ├── docker-compose.yml └── images ├── database_missing.png ├── elixir_install.png ├── paydirt.png └── phoenix.png /Dockerfile: -------------------------------------------------------------------------------- 1 | # Elixir 1.3.2: https://hub.docker.com/_/elixir/ 2 | FROM elixir:1.3.2 3 | ENV DEBIAN_FRONTEND=noninteractive 4 | 5 | # Install hex 6 | RUN mix local.hex --force 7 | 8 | # Install rebar 9 | RUN mix local.rebar --force 10 | 11 | # Install the Phoenix framework itself 12 | RUN mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez --force 13 | 14 | # Install NodeJS 6.x and the NPM 15 | RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - 16 | RUN apt-get install -y -q nodejs 17 | 18 | # Set /app as workdir 19 | RUN mkdir /app 20 | ADD . /app 21 | WORKDIR /app 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Phoenix Dockerized 2 | (Pulled from a blog article I wrote [here](http://echobind.com/blog)) 3 | 4 | --- 5 | title: Starting a Phoenix Project with Docker 6 | date: 2016-08-11 7 | tags: phoenix, docker 8 | author: beene 9 | --- 10 | Before I setup a new Dockerfile for a new technology stack, I like to map out how I would do this without Docker. How would I set this up if I didn't mind muddying my host OS with a given technology? READMORE 11 | 12 | ![Phoenix](images/phoenix.png) 13 | 14 | A brief word on Docker. Docker is a virtualization approach to infrastructure. Imagine being able to ensure that every developer was running the same version of each item in the technology stack. Database, redis, memcache - any piece of the stack can be setup by a couple Docker related files. No more issues because someone developed on the wrong version of Postgres. No more wondering if you're mirroring production. You can. You can do it with Docker. 15 | 16 | Let's do this first so we can see how we map from [local install](http://www.phoenixframework.org/docs/installation) to Docker installation. 17 | 18 | #### Installing Phoenix 19 | 20 | To install Phoenix, we must first have [elixir](http://elixir-lang.org/install.html). We're going to be using Ubuntu for our base image in Docker, but use the appropriate instructions for your local operating system. For OS X, the following command will do the trick if you have [homebrew](http://brew.sh/) installed. 21 | 22 | ![elixir](images/elixir_install.png) 23 | 24 | #### OS X 25 | 26 | ```shell 27 | brew install elixir 28 | ``` 29 | 30 | #### Ubuntu 31 | ```shell 32 | wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb && sudo dpkg -i erlang-solutions_1.0_all.deb 33 | sudo apt-get update 34 | sudo apt-get install esl-erlang 35 | sudo apt-get install elixir 36 | ``` 37 | 38 | Once this is installed we'll have access to the mix command. 39 | 40 | > Mix is a build tool that ships with Elixir that provides tasks for creating, compiling, testing your application, managing its dependencies and much more. 41 | 42 | ##### Other Dependencies 43 | 44 | We'll need to install hex (a package manager) and rebar (used to build Erlang packages) 45 | 46 | ```shell 47 | mix local.hex 48 | mix local.rebar 49 | ``` 50 | 51 | ##### Phoenix 52 | Finally, we can install Phoenix. 53 | 54 | ```shell 55 | mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez 56 | ``` 57 | 58 | ##### Hello World 59 | We can start a new project by running the follow command to generate an app called "hello_phoenix". 60 | 61 | ```shell 62 | mix phoenix.new hello_phoenix 63 | ``` 64 | 65 | This will generate the basic framework of an application. At completion, you'll be prompted on whether or not to install dependencies which would run the following. 66 | 67 | ```shell 68 | mix deps.get 69 | ``` 70 | 71 | This will also compile your assets using [Brunch.io](brunch.io) which uses npm. This means this is also a requirement if you don't specify --no-brunch when creating your application. 72 | 73 | ```shell 74 | mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez --no-brunch 75 | ``` 76 | 77 | For our purposes, we'll keep with the defaults and use brunch. 78 | 79 | Finally, we'll create our database and then run our application. If you see the following, then you forgot the database creation. 80 | 81 | ![database missing](images/database_missing.png) 82 | 83 | ```shell 84 | mix ecto.create # database creation 85 | mix phoenix.server 86 | ``` 87 | 88 | If all goes well, you should see the following at [http://localhost:4000]. 89 | 90 | ![Paydirt](images/paydirt.png) 91 | 92 | #### Dockerize It! 93 | Great. Now you're up and running with a local installation of Phoenix. Now how do we do that with Docker? 94 | 95 | > Docker ensures all environments and developers are operating on the same versions of every dependency. 96 | 97 | This article assumes you've already installed Docker for your local machine. 98 | 99 | * [OS X](https://docs.docker.com/docker-for-mac/) 100 | * [Windows](https://docs.docker.com/engine/installation/windows/#/docker-for-windows) 101 | * [Linux](https://docs.docker.com/engine/installation/#/on-linux) 102 | 103 | > No more issues because someone developed on the wrong version of Postgres. No more wondering if you're mirroring production. You can. You can do it with Docker. 104 | 105 | Once installed, we can start building out our Dockerfile. What's a Dockerfile though? 106 | 107 | > A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession. [Reference](https://docs.docker.com/engine/reference/builder/#dockerfile-reference) 108 | 109 | One important benefit of Docker is the ability to build off existing images. Phoenix is no different as the Elixir project has their own official base images. We'll start there. 110 | 111 | Open a new file named 'Dockerfile' and add the following contents: 112 | 113 | ```docker 114 | # Elixir 1.3.2.: https://hub.docker.com/_/elixir/ 115 | FROM elixir:1.3.2 116 | ``` 117 | 118 | Next, we'll want to set an environment variable that will skip post-install steps. 119 | 120 | ```docker 121 | ENV DEBIAN_FRONTEND=noninteractive 122 | ``` 123 | 124 | ##### Install hex package manager 125 | 126 | ```docker 127 | RUN mix local.hex --force 128 | ``` 129 | 130 | ##### Install rebar (Erlang build tool) 131 | 132 | ```docker 133 | # Install rebar 134 | RUN mix local.rebar --force 135 | ``` 136 | 137 | This should all seem very familiar. We're just continuing to add our steps that we performed locally into the Dockerfile. Think of it as a recipe of repeatable steps to ensure every one is running the same environment. 138 | 139 | ##### Install Phoenix 140 | 141 | ```docker 142 | # Install the Phoenix framework itself 143 | RUN mix archive.install --force https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez 144 | ``` 145 | 146 | ##### Install Node and NPM for Brunch 147 | 148 | ```docker 149 | # Install NodeJS 6.x and the NPM 150 | RUN curl -sL https://deb.nodesource.com/setup_6.x | bash - 151 | RUN apt-get install -y -q nodejs 152 | ``` 153 | 154 | Finally, for Docker we have to specify our work directory 155 | 156 | ```docker 157 | WORKDIR /app 158 | ADD . /app 159 | ``` 160 | 161 | > The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile. If the WORKDIR doesn’t exist, it will be created even if it’s not used in any subsequent Dockerfile instruction. 162 | 163 | > The ADD instruction copies new files, directories or remote file URLs from and adds them to the filesystem of the container at the path . 164 | 165 | With this setup, we'll have a Docker container that has Phoenix installed and ready to go. Of course, we still need a database and to setup the initial application. This is where Docker Compose comes in. 166 | 167 | #### Docker Compose 168 | 169 | Docker Compose allows Docker to mix multiple images together. No modern web framework lives on its own. Docker Compose orchestrates the databases, cache layers, search...anything that you need in one package. Let's see what a simple example would look like with Phoenix. 170 | 171 | ```yml 172 | version: '2' 173 | services: 174 | db: 175 | image: postgres 176 | web: 177 | build: . 178 | command: mix phoenix.server 179 | volumes: 180 | - .:/app 181 | ports: 182 | - "4000:4000" 183 | depends_on: 184 | - db 185 | 186 | ``` 187 | If you're a Rubyist, you probably recognize this yml format. Here's the breakdown. 188 | 189 | Docker Compose is on its 2nd version. 190 | Services represent the various containers that will run. We can name the next level anything we want but this will be important when the containers communicate with each other. For example, we could have named db "postgres" instead. Image tells docker which image to use to build that container. 191 | 192 | Web is where the interesting things happen. It is our phoenix app. To build it, we use the current directory's Dockerfile. That is why we see this line. 193 | 194 | ```yml 195 | build: . 196 | ``` 197 | 198 | The command to run on successful launch is indicated in the "command" line. 199 | Volumes connects the current directory with the /app directory. 200 | Ports maps port 4000 on localhost to port 4000 on the container. 201 | depends_on links this container to the db. This is where the names have to match. 202 | 203 | > **Containers must reference each other by their service name** 204 | 205 | Now that we have this file in place, we can begin setting things in motion. 206 | 207 | ##### Build 208 | 209 | ```shell 210 | docker-compose up -d 211 | docker-compose run web mix phoenix.new hello_world 212 | mv hello_world/* ./ 213 | mv hello_world/.gitignore ./ 214 | rm -rf hello_world 215 | # don't forget to rename your database hostname, you remember this step - right? 216 | docker-compose run web mix ecto.create 217 | docker-compose restart web 218 | ``` 219 | 220 | > Did you get an error when creating the database? I purposefully left out a step. Remember the hostname needs to match the names of your containers. If you look inside the new phoenix application, you'll find a file `config\dev.exs`. At the bottom of this file, it gives `localhost` for the hostname of the database server. In the land of docker, we're calling it `db`. Make that change and try to create the database again. 221 | 222 | If all goes well, go to localhost:4000. 223 | 224 | With this setup, you can get up and running on any machine running docker and know your environment is exactly the same. In development, qa, and production - you can keep everything in lock step. For production, you'll want to consult with your devops team to ensure the configuration is in line with what they want. Consider this a starting point. 225 | 226 | > Want to get started without typing all this out? Fork my project [here](https://github.com/rbeene/phoenix-with-docker) and give it a whirl. Just make sure you have Docker installed! 227 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | db: 4 | image: postgres 5 | web: 6 | build: . 7 | command: mix phoenix.server 8 | volumes: 9 | - .:/app 10 | ports: 11 | - "4000:4000" 12 | depends_on: 13 | - db 14 | -------------------------------------------------------------------------------- /images/database_missing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbeene/phoenix-with-docker/cb9b462a7ee70063d5258db54637915725c25f77/images/database_missing.png -------------------------------------------------------------------------------- /images/elixir_install.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbeene/phoenix-with-docker/cb9b462a7ee70063d5258db54637915725c25f77/images/elixir_install.png -------------------------------------------------------------------------------- /images/paydirt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbeene/phoenix-with-docker/cb9b462a7ee70063d5258db54637915725c25f77/images/paydirt.png -------------------------------------------------------------------------------- /images/phoenix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rbeene/phoenix-with-docker/cb9b462a7ee70063d5258db54637915725c25f77/images/phoenix.png --------------------------------------------------------------------------------