How to setup a docker development environment.
-
to have nice clean environment to work on array of different projects without cluttering the main machine with a host of different conflicting dependancies.
-
An alternative is to use a bunch of VM's but they use a lot of memory, slower to startup and aren't as amenable to being run in production.
-
My personal feeling is that dev containers should be similar, but not actual production containers. So the end product, an uberjar or natively compiled binary and then can be packaged and deployed as desired.
-
Basically dev time should have build tools, runtime should not
-
Today I will be focusing on just the dev time setup
The docker tools on mac take care of file permission issues. Compose seems to work a bit better On linux, my preference is for the make based startup.
- docker has had major changes and updates recently. Please be sure to use the very latest tooling.
- Basic usage of docker
- Remove old containers after they are run (use --rm)
- Sharing the files on main computer with the container (volumes)
- Mapping ports from the contain to the host
- All files created by container are owned by root (linux)
- Reloading of all app dependancies from repo on each container startup
- Your editor/ide/debugger does not work correctly when not "inside" the container
docker images
docker ps -a
Let's build a dev image
- Choose a base image (https://hub.docker.com/_/openjdk/) * I used openjdk:8-jdk instead of 8-jdk-alpine because I wanted terminal inside docker. probably would deploy uberjar on openjdk:8-alpine
- Write a Dockerfile (see basic/Dockerfile)
docker build -t basicapp .
docker images
docker run -it basicapp
docker ps -a
docker run -it basicapp
docker ps -a
docker rm the_container_name
docker run --rm -it basicapp
docker ps -a
Use the -v
option
docker run --rm -it -v ~/work/meetup/docker-dev/basic/project:/project basicapp
- Even though you expose the container port you should also map it, otherwise docker will assign it a random port number on the host.
docker ps -a
docker run --rm -it -v ~/work/meetup/docker-dev/basic/project:/project -p 8080:8080 basicapp
- doesn't seem to be an issue in windows/mac on recent versions, only an issue on linux
- we will inject your current user into the running container
- We will see a solution to this in the make-dev solution.
- Store the dependencies on the host and share as a volume.
- For instance with java maven we have the .m2 folder which will shared as volume.
- the solution is to use SSHFS
- install ssh in the container
- use SSHFS to mount to the root of the container
- do some special simlink fixes
- you should be able to use the file system as normal.
- see reference links below for more details.
- I won't be attempting to show this today
Why compose? Because it can start up multiple linked containers easily.
- Go over compose-dev/docker-compose.yml
- Go over compose-dev/web/Dockerfile
cd compose-dev
docker-compose build
docker-compose up
Connect to web instance from another terminal
docker exec -it composedev_web_1 bash
lein version
lein new hello1
set the REPL options in project clj to listen on right port and host
(defproject hello1 "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.8.0"]]
:repl-options {:host "0.0.0.0" :port 9090})
start a REPL
lein repl
connect to the REPL inside the docker container from atom and execute some code
cmd + shift + p => search repl remote => enter port
Open a clojure source file and execute some expressions. cmd + alt + b
shutdown the compose instances
docker-compose down
Why make instead of compose? Because it allows us more fine grained control and to pass current user information to containsers as environment variables. It doesn't however start up multiple containers. It should also work well with other container systems such as rocket.
- Go over make-dev/Dockerfile
- Go over make-dev/startup.sh
- Go over make-dev/Makefile
cd make-dev/web
docker build -t makedev_web .
docker images
make shell
We should now have a terminal with java/lein, and user should be host user.
lein new hello2
Set the REPL options
(defproject hello2 "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.8.0"]]
:repl-options {:host "0.0.0.0" :port 9090})
Now start a REPL
cd hello2
lein repl
connect to the REPL inside the docker container from atom and execute some code
cmd + shift + p => search repl remote => enter port
Open a clojure source file and execute some expressions. cmd + alt + b
https://github.com/markmandel/wrapping-clojure-tooling-in-containers https://www.youtube.com/watch?v=FtkHgQSSb3c
xx