Skip to content

Instantly share code, notes, and snippets.

@toolness
Last active March 26, 2019 15:21

Revisions

  1. toolness revised this gist Feb 2, 2017. 1 changed file with 8 additions and 4 deletions.
    12 changes: 8 additions & 4 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -159,11 +159,15 @@ Then again, though, non-Dockerized environments have parallel problems: CALC dev
    run *multiple* commands like `pip install -r requirements.txt` and `npm install` to make sure their environment stays up-to-date,
    so perhaps Dockerization is still a net win in this regard.

    ### Using an interactive debugger might be challenging
    ### Using custom development tools can be challenging

    I don't have personal experience with this, but another developer on CALC wanted to use Python's interactive debugger
    on a Docker CALC setup, and ran into some issues. It's definitely *possible*, but unlike local development, it takes
    a little bit of extra work. We're looking into documenting this in [CALC#1300](https://github.com/18F/calc/issues/1300).
    If there's some sort of development or debugging tool that you like using, but which isn't currently part
    of the Docker setup, figuring out how to add it to your setup and using it properly can be harder
    than in a non-Docker environment, as one of our developers found when [trying to use `ipdb` in CALC](https://github.com/18F/calc/issues/1300).

    It can also be challenging to add such a tool to *only* your setup: you can modify your local `Dockerfile`
    or `requirements.txt` to ensure that your favorite debugger is used, but then you have to make sure you
    don't actually commit those changes to the repository.

    ### Docker images can be big

  2. toolness revised this gist Jan 31, 2017. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -130,9 +130,7 @@ the `EXPOSE` directive in dockerfiles, the `ports` directive in docker compose f
    aren't even *exposed* when you run `docker-compose run` instead of `docker-compose up`, unless you pass the `--service-ports`
    option to it...

    Oh, and then you'll *also* want to bind your server to all network interfaces, rather than just the loopback interface...

    Ugggh.
    Oh, and on top of all that you'll *also* want to bind your server to all network interfaces (`0.0.0.0`) rather than just `127.0.0.1`, or else things *still* won't work.

    It's not hard in theory, but it's an annoying chunk of cognitive overhead that one simply doesn't need to
    deal with when they're not using Docker/docker-compose.
  3. toolness revised this gist Jan 31, 2017. 1 changed file with 7 additions and 3 deletions.
    10 changes: 7 additions & 3 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -128,10 +128,14 @@ annoying.
    Argh, I have had so many problems with this and I still barely understand it well enough to explain it to others. There's
    the `EXPOSE` directive in dockerfiles, the `ports` directive in docker compose files, and then the fact that those ports
    aren't even *exposed* when you run `docker-compose run` instead of `docker-compose up`, unless you pass the `--service-ports`
    option to it... It's not hard in theory, but it's an annoying chunk of cognitive overhead that one simply doesn't need to
    deal with when they're not using Docker/docker-compose.
    option to it...

    Oh, and then you'll *also* want to bind your server to all network interfaces, rather than just the loopback interface...

    (Oh, and then there's *also* the fact that if your server is only bound to the loopback interface, none of the above will do any good.)
    Ugggh.

    It's not hard in theory, but it's an annoying chunk of cognitive overhead that one simply doesn't need to
    deal with when they're not using Docker/docker-compose.

    ### Changing python/node/ruby dependencies can be cumbersome

  4. toolness revised this gist Jan 31, 2017. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -131,6 +131,8 @@ aren't even *exposed* when you run `docker-compose run` instead of `docker-compo
    option to it... It's not hard in theory, but it's an annoying chunk of cognitive overhead that one simply doesn't need to
    deal with when they're not using Docker/docker-compose.

    (Oh, and then there's *also* the fact that if your server is only bound to the loopback interface, none of the above will do any good.)

    ### Changing python/node/ruby dependencies can be cumbersome

    Because of the way that dockerfiles work, and the fact that containers are so ephemeral, it can potentially be quite annoying
  5. toolness revised this gist Jan 31, 2017. 1 changed file with 10 additions and 0 deletions.
    10 changes: 10 additions & 0 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -161,6 +161,16 @@ I don't have personal experience with this, but another developer on CALC wanted
    on a Docker CALC setup, and ran into some issues. It's definitely *possible*, but unlike local development, it takes
    a little bit of extra work. We're looking into documenting this in [CALC#1300](https://github.com/18F/calc/issues/1300).

    ### Docker images can be big

    Thanks to [union file systems](https://blog.docker.com/2015/10/docker-basics-webinar-qa/), Docker uses way less
    disk space than a virtual machine; but it's still using more than developing locally without Docker or a VM. This
    can be particularly unfortunate if you need to pull a Docker image and are, say, tethering from a coffee shop.

    Freeing up disk space taken up by Docker can also be a chore, though a recently-introduced
    [`docker system prune`](https://docs.docker.com/engine/reference/commandline/system_prune/) command makes it
    easier than it has been.

    ## References

    * Atul's January 2017 Docker presentation
  6. toolness revised this gist Jan 31, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    # Reflections on Docker-based development

    Note that these reflections are specifically tailored to a conversation about Docker we're having at 18F, and as such they
    Note that these reflections are specifically tailored to a conversation about Docker we're having at [18F](https://18f.gsa.gov/), and as such they
    have a few assumptions:

    * All developers use OS X.
  7. toolness revised this gist Jan 31, 2017. 1 changed file with 13 additions and 13 deletions.
    26 changes: 13 additions & 13 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -9,19 +9,6 @@ have a few assumptions:

    ## Advantages

    ### It encourages dev/prod parity

    Unlike vagrant, a big promise of Docker is that it's not just intended for development purposes--it's also intended for *deployment*,
    because containers are so good for process isolation and resource management. This means that we can ideally have great
    [dev/prod parity](https://12factor.net/dev-prod-parity) *in theory*. In practice, things are a bit more complicated, especially
    since cloud.gov currently calls its Docker support an [experimental feature](https://cloud.gov/docs/apps/experimental/docker/).

    ### It makes dev/CI parity easy

    While we don't do it in CALC, using Docker containers on Travis CI (not sure about CircleCI) is easy and I've
    done it before. This makes it particularly easy to ensure dev/CI parity, so you don't have tests that work
    on your local machines but mysteriously fail in CI.

    ### It obviates an entire class of environment tooling

    Most development tools are built to assume that they are a "singleton" in the context of the system they're installed on.
    @@ -48,6 +35,19 @@ Another nice thing about `docker-compose up` is that it starts all services in a
    output with their container name. This is already a lot more convenient than manually opening a separate terminal window for
    every dependent service, which is what non-Docker setups often make developers do.

    ### It encourages dev/prod parity

    Unlike vagrant, a big promise of Docker is that it's not just intended for development purposes--it's also intended for *deployment*,
    because containers are so good for process isolation and resource management. This means that we can ideally have great
    [dev/prod parity](https://12factor.net/dev-prod-parity) *in theory*. In practice, things are a bit more complicated, especially
    since cloud.gov currently calls its Docker support an [experimental feature](https://cloud.gov/docs/apps/experimental/docker/).

    ### It makes dev/CI parity easy

    While we don't do it in CALC, using Docker containers on Travis CI (not sure about CircleCI) is easy and I've
    done it before. This makes it particularly easy to ensure dev/CI parity, so you don't have tests that work
    on your local machines but mysteriously fail in CI.

    ### It's easy to deploy to AWS sandboxes

    Because we're not allowed to use tools like [ngrok](https://ngrok.com/) to expose our development instances to coworkers at
  8. toolness revised this gist Jan 31, 2017. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -158,7 +158,8 @@ so perhaps Dockerization is still a net win in this regard.
    ### Using an interactive debugger might be challenging

    I don't have personal experience with this, but another developer on CALC wanted to use Python's interactive debugger
    on a Docker CALC setup, and ran into some issues.
    on a Docker CALC setup, and ran into some issues. It's definitely *possible*, but unlike local development, it takes
    a little bit of extra work. We're looking into documenting this in [CALC#1300](https://github.com/18F/calc/issues/1300).

    ## References

  9. toolness revised this gist Jan 31, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -24,7 +24,7 @@ on your local machines but mysteriously fail in CI.

    ### It obviates an entire class of environment tooling

    Most development tools are built to assume that they are a "singleton" in the content of the system they're installed on.
    Most development tools are built to assume that they are a "singleton" in the context of the system they're installed on.

    But as soon as you have two projects that require different versions (or configurations) of that tool, you start needing *another*
    tool that manages the version or configuration of that tool for you, so that each project can use the version or configuration
  10. toolness revised this gist Jan 31, 2017. 1 changed file with 5 additions and 3 deletions.
    8 changes: 5 additions & 3 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -77,10 +77,12 @@ Thinking of containers as "lightweight VMs" is a good way to get started with Do
    doesn't work very well, especially once you need to start debugging certain kinds of problems.

    It's easier to understand how containers work when your Docker host is a Linux system; however, on OS X, there's a
    hypervisor running a Linux VM in the way (yes, even on Docker Native for OS X), along with a variety of other
    tricks that might make it a bit harder to develop a good mental model for how they work.
    hypervisor running a Linux VM in the way (yes, even on Docker Native for OS X), along with a variety of
    [other tricks](https://www.youtube.com/watch?v=7da-B3rY9V4) that might make it a bit harder to develop a good
    mental model for how they work.

    That said, developing a solid mental model for how containers work, especially how they work *under the hood*, is
    That said, developing a solid mental model for how containers work, especially how they work
    [under the hood](https://ericchiang.github.io/post/containers-from-scratch/), is
    valuable knowledge that can help one in a wide variety of problem areas that go far beyond setting up development
    environments. Even if one doesn't ever use chroot, cgroups, or namespaces on their own, understanding what they *do*
    improves one's understanding of the foundational plumbing that underlies *any* application, irrespective of implementation
  11. toolness revised this gist Jan 31, 2017. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -9,20 +9,20 @@ have a few assumptions:

    ## Advantages

    ### Dev/prod parity ... sort of
    ### It encourages dev/prod parity

    Unlike vagrant, a big promise of Docker is that it's not just intended for development purposes--it's also intended for *deployment*,
    because containers are so good for process isolation and resource management. This means that we can ideally have great
    [dev/prod parity](https://12factor.net/dev-prod-parity) *in theory*. In practice, things are a bit more complicated, especially
    since cloud.gov currently calls its Docker support an [experimental feature](https://cloud.gov/docs/apps/experimental/docker/).

    ### Dev/CI parity
    ### It makes dev/CI parity easy

    While we don't do it in CALC, using Docker containers on Travis CI (not sure about CircleCI) is easy and I've
    done it before. This makes it particularly easy to ensure dev/CI parity, so you don't have tests that work
    on your local machines but mysteriously fail in CI.

    ### Obviates an entire class of environment tooling
    ### It obviates an entire class of environment tooling

    Most development tools are built to assume that they are a "singleton" in the content of the system they're installed on.

    @@ -35,7 +35,7 @@ Containers get rid of this problem entirely--but not without introducing *new* c
    understand. At least one benefit of the new overhead, though, is it's generic enough to apply to all kinds of problems,
    rather than being specialized to a particular type of development tool.

    ### Reduces setup time
    ### It reduces setup time

    Installing Docker on OS X is easy, and as the [CALC docker instructions](https://github.com/18F/calc#using-docker-optional) attest,
    setup largely boils down to `git clone` followed by `docker-compose up`, peppered with a few manual tasks.
    @@ -48,7 +48,7 @@ Another nice thing about `docker-compose up` is that it starts all services in a
    output with their container name. This is already a lot more convenient than manually opening a separate terminal window for
    every dependent service, which is what non-Docker setups often make developers do.

    ### Ease of one-off deployment to the cloud
    ### It's easy to deploy to AWS sandboxes

    Because we're not allowed to use tools like [ngrok](https://ngrok.com/) to expose our development instances to coworkers at
    18F, being able to conveniently deploy our work to a temporary Amazon EC2 instance becomes important. Fortunately, thanks
  12. toolness revised this gist Jan 31, 2017. 1 changed file with 7 additions and 1 deletion.
    8 changes: 7 additions & 1 deletion docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -80,6 +80,12 @@ It's easier to understand how containers work when your Docker host is a Linux s
    hypervisor running a Linux VM in the way (yes, even on Docker Native for OS X), along with a variety of other
    tricks that might make it a bit harder to develop a good mental model for how they work.

    That said, developing a solid mental model for how containers work, especially how they work *under the hood*, is
    valuable knowledge that can help one in a wide variety of problem areas that go far beyond setting up development
    environments. Even if one doesn't ever use chroot, cgroups, or namespaces on their own, understanding what they *do*
    improves one's understanding of the foundational plumbing that underlies *any* application, irrespective of implementation
    language.

    ### Volume mounts on OS X native might still be really slow

    I'm not sure if it's still the case, but when Docker Native for OS X was first released, mounting a directory on one's
    @@ -94,7 +100,7 @@ make it fast but more complicated. Argh.

    ### Dealing with filesystem permissions on volume mounts can be frustrating

    If your Docker containers never write new files to volume mounts, this generally isn't a problem.
    If your Docker containers never write new files to mounted volumes, this generally isn't a problem.

    However, if they do--e.g. if your static asset build pipeline is running in a container--then by default, those files
    are owned by `root`. This means that deleting them from your Docker host becomes annoying.
  13. toolness revised this gist Jan 31, 2017. 1 changed file with 4 additions and 1 deletion.
    5 changes: 4 additions & 1 deletion docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -103,13 +103,16 @@ To work around this, I've had to add an entrypoint script that creates a user in
    owner of the project's root directory. I've literally written this script in [JS](https://github.com/toolness/p5.js-docker/blob/master/p5-website-bridge/entrypoint.js), [Ruby](https://github.com/exercism/exercism.io/blob/master/docker/entrypoint.rb), and [Python](https://github.com/18F/calc/blob/develop/docker_django_management.py) at this point, and it's really
    annoying.

    That said, I started following this pattern in late 2015, and it's possible that Docker/docker-compose may have evolved
    new functionality to obviate the need for this.

    ### Dealing with race conditions on dependent services can be annoying

    Because `docker-compose up` starts up all of a project's services at once, but because it has no way to detect when a service
    is actually *ready*, it's easy for race conditions to exist between dependent services.

    To work around this, I've had to add an entrypoint script that waits for a project's database to be ready before running
    any commands. I've written this script in [Ruby](https://github.com/exercism/exercism.io/blob/master/docker/entrypoint.rb), and [Python](https://github.com/18F/calc/blob/develop/docker_django_management.py) at this point, and it's kind of
    any commands. I've written this script in [Ruby](https://github.com/exercism/exercism.io/blob/master/docker/entrypoint.rb) and [Python](https://github.com/18F/calc/blob/develop/docker_django_management.py) at this point, and it's kind of
    annoying.

    ### Exposing ports is complicated and confusing
  14. toolness revised this gist Jan 31, 2017. 1 changed file with 20 additions and 0 deletions.
    20 changes: 20 additions & 0 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -92,6 +92,26 @@ layer of abstraction, because one now needs to use `docker-machine` to develop l
    If this problem hasn't yet been fixed, it presents one with a frustrating trade-off: make development slow but less complicated, or
    make it fast but more complicated. Argh.

    ### Dealing with filesystem permissions on volume mounts can be frustrating

    If your Docker containers never write new files to volume mounts, this generally isn't a problem.

    However, if they do--e.g. if your static asset build pipeline is running in a container--then by default, those files
    are owned by `root`. This means that deleting them from your Docker host becomes annoying.

    To work around this, I've had to add an entrypoint script that creates a user in the container with the same UID as the
    owner of the project's root directory. I've literally written this script in [JS](https://github.com/toolness/p5.js-docker/blob/master/p5-website-bridge/entrypoint.js), [Ruby](https://github.com/exercism/exercism.io/blob/master/docker/entrypoint.rb), and [Python](https://github.com/18F/calc/blob/develop/docker_django_management.py) at this point, and it's really
    annoying.

    ### Dealing with race conditions on dependent services can be annoying

    Because `docker-compose up` starts up all of a project's services at once, but because it has no way to detect when a service
    is actually *ready*, it's easy for race conditions to exist between dependent services.

    To work around this, I've had to add an entrypoint script that waits for a project's database to be ready before running
    any commands. I've written this script in [Ruby](https://github.com/exercism/exercism.io/blob/master/docker/entrypoint.rb), and [Python](https://github.com/18F/calc/blob/develop/docker_django_management.py) at this point, and it's kind of
    annoying.

    ### Exposing ports is complicated and confusing

    Argh, I have had so many problems with this and I still barely understand it well enough to explain it to others. There's
  15. toolness revised this gist Jan 31, 2017. 1 changed file with 26 additions and 0 deletions.
    26 changes: 26 additions & 0 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -71,6 +71,27 @@ to add new developer tooling. For example, in CALC, we were able to [trivially a

    ## Challenges

    ### Understanding containers can be hard, especially on OS X

    Thinking of containers as "lightweight VMs" is a good way to get started with Docker, but sometimes that abstraction
    doesn't work very well, especially once you need to start debugging certain kinds of problems.

    It's easier to understand how containers work when your Docker host is a Linux system; however, on OS X, there's a
    hypervisor running a Linux VM in the way (yes, even on Docker Native for OS X), along with a variety of other
    tricks that might make it a bit harder to develop a good mental model for how they work.

    ### Volume mounts on OS X native might still be really slow

    I'm not sure if it's still the case, but when Docker Native for OS X was first released, mounting a directory on one's
    Docker host to a volume on a container was *really* slow. As in, tests took 10 times longer to run.

    I ended up using a third-party tool called [dinghy](https://github.com/codekitchen/dinghy), which works a bit like
    the old Docker Toolbox for OS X, to speed things up. However, like the old Docker Toolbox, it also introduces an extra
    layer of abstraction, because one now needs to use `docker-machine` to develop locally.

    If this problem hasn't yet been fixed, it presents one with a frustrating trade-off: make development slow but less complicated, or
    make it fast but more complicated. Argh.

    ### Exposing ports is complicated and confusing

    Argh, I have had so many problems with this and I still barely understand it well enough to explain it to others. There's
    @@ -103,6 +124,11 @@ Then again, though, non-Dockerized environments have parallel problems: CALC dev
    run *multiple* commands like `pip install -r requirements.txt` and `npm install` to make sure their environment stays up-to-date,
    so perhaps Dockerization is still a net win in this regard.

    ### Using an interactive debugger might be challenging

    I don't have personal experience with this, but another developer on CALC wanted to use Python's interactive debugger
    on a Docker CALC setup, and ran into some issues.

    ## References

    * Atul's January 2017 Docker presentation
  16. toolness revised this gist Jan 31, 2017. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -79,11 +79,11 @@ aren't even *exposed* when you run `docker-compose run` instead of `docker-compo
    option to it... It's not hard in theory, but it's an annoying chunk of cognitive overhead that one simply doesn't need to
    deal with when they're not using Docker/docker-compose.

    ### Changing dependencies can be cumbersome
    ### Changing python/node/ruby dependencies can be cumbersome

    Because of the way that dockerfiles work, and the fact that containers are so ephemeral, it can potentially be quite annoying
    to change the dependencies in one's projects. Often just editing a `requirements.txt` or `package.json`
    file, as one would do in a non-Docker environment, causes *all* the packages listed in said file to be re-retrieved from the
    to change the dependencies in one's projects. Often just editing a `requirements.txt`/`package.json`/`Gemfile`, as one would
    do in a non-Docker environment, causes *all* the packages listed in said file to be re-retrieved from the
    internet and installed, which starts taking a very long time once you've got lots of dependencies.

    There's various ways to work around this; for instance, if I'm just tinkering with a dependency, I'll temporarily add a
  17. toolness revised this gist Jan 31, 2017. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -63,6 +63,12 @@ one decides not to use Docker, they can still consult those files to figure out
    This transparency also means that it wouldn't be too hard for us to migrate from Docker to a different containerization
    technology, if that ever becomes a need. It's the opposite of vendor lock-in.

    ### Adding new developer tooling is easy

    The incredibly low cost of adding new containers to a docker-based project means that it becomes very easy
    to add new developer tooling. For example, in CALC, we were able to [trivially add mailcatcher support](https://github.com/18F/calc/pull/1218) during development, despite the fact that it's ruby-based
    (and CALC is a Python project).

    ## Challenges

    ### Exposing ports is complicated and confusing
  18. toolness revised this gist Jan 31, 2017. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -16,6 +16,12 @@ because containers are so good for process isolation and resource management. Th
    [dev/prod parity](https://12factor.net/dev-prod-parity) *in theory*. In practice, things are a bit more complicated, especially
    since cloud.gov currently calls its Docker support an [experimental feature](https://cloud.gov/docs/apps/experimental/docker/).

    ### Dev/CI parity

    While we don't do it in CALC, using Docker containers on Travis CI (not sure about CircleCI) is easy and I've
    done it before. This makes it particularly easy to ensure dev/CI parity, so you don't have tests that work
    on your local machines but mysteriously fail in CI.

    ### Obviates an entire class of environment tooling

    Most development tools are built to assume that they are a "singleton" in the content of the system they're installed on.
  19. toolness revised this gist Jan 31, 2017. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -78,10 +78,9 @@ There's various ways to work around this; for instance, if I'm just tinkering wi
    `RUN npm install foo` to the end of my `Dockerfile`. We're discussing this more in-depth in [CALC#1230](https://github.com/18F/calc/issues/1230) but the point is that it's something that can become non-trivial once you move
    to Docker, and that can be annoying.

    ### Connecting to the docker host from a docker container can be annoying
    ### Running Selenium/WebDriver tests can be really complicated

    This isn't needed often, but it is if you want to run Selenium/WebDriver tests using your desktop browser against an
    app in a container. And it is really annoying to set up; see [CALC's `selenium.md`](https://github.com/18F/calc/blob/develop/selenium.md#example-docker-on-os-x) for more details.
    See [CALC's `selenium.md`](https://github.com/18F/calc/blob/develop/selenium.md#example-docker-on-os-x) for more details.

    ### Knowing when/whether to re-run "docker-compose build" can be confusing

  20. toolness revised this gist Jan 31, 2017. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -80,6 +80,9 @@ to Docker, and that can be annoying.

    ### Connecting to the docker host from a docker container can be annoying

    This isn't needed often, but it is if you want to run Selenium/WebDriver tests using your desktop browser against an
    app in a container. And it is really annoying to set up; see [CALC's `selenium.md`](https://github.com/18F/calc/blob/develop/selenium.md#example-docker-on-os-x) for more details.

    ### Knowing when/whether to re-run "docker-compose build" can be confusing

    This is something that our non-technical folks in particular frequently get tripped up on, but more experienced devs can too.
  21. toolness revised this gist Jan 31, 2017. 1 changed file with 45 additions and 0 deletions.
    45 changes: 45 additions & 0 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -34,6 +34,10 @@ rather than being specialized to a particular type of development tool.
    Installing Docker on OS X is easy, and as the [CALC docker instructions](https://github.com/18F/calc#using-docker-optional) attest,
    setup largely boils down to `git clone` followed by `docker-compose up`, peppered with a few manual tasks.

    Without Docker, the more dependent services your project has, the harder it's generally going to be for someone to configure
    and start up a development environment. With Docker, this often isn't the case: as we've added redis, worker and scheduler
    processes to CALC, developers haven't had to change their environment, because `docker-compose up` does everything for them.

    Another nice thing about `docker-compose up` is that it starts all services in a single terminal window and prefixes their
    output with their container name. This is already a lot more convenient than manually opening a separate terminal window for
    every dependent service, which is what non-Docker setups often make developers do.
    @@ -44,6 +48,47 @@ Because we're not allowed to use tools like [ngrok](https://ngrok.com/) to expos
    18F, being able to conveniently deploy our work to a temporary Amazon EC2 instance becomes important. Fortunately, thanks
    to `docker-machine`, this isn't hard; see [CALC's guide to deploying to cloud environments](https://github.com/18F/calc#deploying-to-cloud-environments) for more details.

    ### It's self-documenting

    Once one learns the fairly straightforward syntax of dockerfiles and docker compose files, `Dockerfile` and `docker-compose.yml`
    become handy "recipes" on how to reliably set up a development (or even production) environment from scratch. So even if
    one decides not to use Docker, they can still consult those files to figure out how everything is configured and connected.

    This transparency also means that it wouldn't be too hard for us to migrate from Docker to a different containerization
    technology, if that ever becomes a need. It's the opposite of vendor lock-in.

    ## Challenges

    ### Exposing ports is complicated and confusing

    Argh, I have had so many problems with this and I still barely understand it well enough to explain it to others. There's
    the `EXPOSE` directive in dockerfiles, the `ports` directive in docker compose files, and then the fact that those ports
    aren't even *exposed* when you run `docker-compose run` instead of `docker-compose up`, unless you pass the `--service-ports`
    option to it... It's not hard in theory, but it's an annoying chunk of cognitive overhead that one simply doesn't need to
    deal with when they're not using Docker/docker-compose.

    ### Changing dependencies can be cumbersome

    Because of the way that dockerfiles work, and the fact that containers are so ephemeral, it can potentially be quite annoying
    to change the dependencies in one's projects. Often just editing a `requirements.txt` or `package.json`
    file, as one would do in a non-Docker environment, causes *all* the packages listed in said file to be re-retrieved from the
    internet and installed, which starts taking a very long time once you've got lots of dependencies.

    There's various ways to work around this; for instance, if I'm just tinkering with a dependency, I'll temporarily add a
    `RUN npm install foo` to the end of my `Dockerfile`. We're discussing this more in-depth in [CALC#1230](https://github.com/18F/calc/issues/1230) but the point is that it's something that can become non-trivial once you move
    to Docker, and that can be annoying.

    ### Connecting to the docker host from a docker container can be annoying

    ### Knowing when/whether to re-run "docker-compose build" can be confusing

    This is something that our non-technical folks in particular frequently get tripped up on, but more experienced devs can too.
    The safest approach is simply to re-run `docker-compose build` every time you `git pull` but this can be hard to remember.

    Then again, though, non-Dockerized environments have parallel problems: CALC devs who aren't using Docker actually have to
    run *multiple* commands like `pip install -r requirements.txt` and `npm install` to make sure their environment stays up-to-date,
    so perhaps Dockerization is still a net win in this regard.

    ## References

    * Atul's January 2017 Docker presentation
  22. toolness revised this gist Jan 31, 2017. 1 changed file with 22 additions and 0 deletions.
    22 changes: 22 additions & 0 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,12 @@
    # Reflections on Docker-based development

    Note that these reflections are specifically tailored to a conversation about Docker we're having at 18F, and as such they
    have a few assumptions:

    * All developers use OS X.
    * Production deployments will be done via [cloud.gov](https://cloud.gov).
    * Developers have access to [AWS sandbox accounts](https://pages.18f.gov/before-you-ship/infrastructure/sandbox/).

    ## Advantages

    ### Dev/prod parity ... sort of
    @@ -22,6 +29,21 @@ Containers get rid of this problem entirely--but not without introducing *new* c
    understand. At least one benefit of the new overhead, though, is it's generic enough to apply to all kinds of problems,
    rather than being specialized to a particular type of development tool.

    ### Reduces setup time

    Installing Docker on OS X is easy, and as the [CALC docker instructions](https://github.com/18F/calc#using-docker-optional) attest,
    setup largely boils down to `git clone` followed by `docker-compose up`, peppered with a few manual tasks.

    Another nice thing about `docker-compose up` is that it starts all services in a single terminal window and prefixes their
    output with their container name. This is already a lot more convenient than manually opening a separate terminal window for
    every dependent service, which is what non-Docker setups often make developers do.

    ### Ease of one-off deployment to the cloud

    Because we're not allowed to use tools like [ngrok](https://ngrok.com/) to expose our development instances to coworkers at
    18F, being able to conveniently deploy our work to a temporary Amazon EC2 instance becomes important. Fortunately, thanks
    to `docker-machine`, this isn't hard; see [CALC's guide to deploying to cloud environments](https://github.com/18F/calc#deploying-to-cloud-environments) for more details.

    ## References

    * Atul's January 2017 Docker presentation
  23. toolness created this gist Jan 31, 2017.
    30 changes: 30 additions & 0 deletions docker-thoughts.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,30 @@
    # Reflections on Docker-based development

    ## Advantages

    ### Dev/prod parity ... sort of

    Unlike vagrant, a big promise of Docker is that it's not just intended for development purposes--it's also intended for *deployment*,
    because containers are so good for process isolation and resource management. This means that we can ideally have great
    [dev/prod parity](https://12factor.net/dev-prod-parity) *in theory*. In practice, things are a bit more complicated, especially
    since cloud.gov currently calls its Docker support an [experimental feature](https://cloud.gov/docs/apps/experimental/docker/).

    ### Obviates an entire class of environment tooling

    Most development tools are built to assume that they are a "singleton" in the content of the system they're installed on.

    But as soon as you have two projects that require different versions (or configurations) of that tool, you start needing *another*
    tool that manages the version or configuration of that tool for you, so that each project can use the version or configuration
    that it needs. This is how tools like `nvm` (for node), `rvm` (for ruby), `virtualenv`/`pyenv` (for python) and such come
    into existence. It adds a lot of cognitive overhead to the development process.

    Containers get rid of this problem entirely--but not without introducing *new* cognitive overhead that developers need to
    understand. At least one benefit of the new overhead, though, is it's generic enough to apply to all kinds of problems,
    rather than being specialized to a particular type of development tool.

    ## References

    * Atul's January 2017 Docker presentation
    * [GitHub](https://github.com/18F/atul-docker-presentation)
    * [Slides](http://federalist.18f.gov.s3-website-us-east-1.amazonaws.com/site/18F/atul-docker-presentation/#/)
    * Video (coming soon!)