Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save qw3r/14687e3131b66ea6ce22 to your computer and use it in GitHub Desktop.
Save qw3r/14687e3131b66ea6ce22 to your computer and use it in GitHub Desktop.

Revisions

  1. @tonypujals tonypujals revised this gist Jan 11, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,5 @@
    Quick Start for getting acquainted with Docker for Node.js developers
    =====================================================================
    Docker quick start for Node.js developers
    =========================================

    Install Dependencies
    --------------------
  2. @tonypujals tonypujals revised this gist Jan 11, 2016. 1 changed file with 10 additions and 0 deletions.
    10 changes: 10 additions & 0 deletions docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -395,6 +395,16 @@ Remove it

    $ docker rm demo

    ### Steamlining the developer session workflow

    During a development session, it can be time-consuming to continuously rebuild the image every time the sources are modified. The Dockerfile for the base node image configured the Node process in a running container to start in the `/usr/src/app` directory where the source files and modules under `node_modules` were copied in the image.

    Using Docker's volume mapping feature, the current directory of your development system can be mapped to the `/usr/src/app` directory of a container so that the Node process running in the container uses the sources being edited.

    $ docker run -d -t -p 49100:3000 --name demo -v $PWD:/usr/src/app demo-app

    Using this technique, when a container is launched from the image and the Node process starts, it will be accessing `/usr/src/app` in a volume that has been mapped from the developer's system. There is no need to rebuild the image until the developer has tested the changes and is ready to publish a new image.

    ## Mongo example

    Create a Docker data volume container
  3. @tonypujals tonypujals revised this gist Oct 13, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -304,7 +304,7 @@ You will need to create an account on Docker Hub, then login from the command li

    $ docker login

    Only official images (such as iojs) can have simple names. To push your own image, you will need to change the name of the image. Instead of demo-app, you will need to create the image using your login name. Mine is 'subfuzion' so my docker build and docker push commands would look like this:
    Only official images (such as node) can have simple names. To push your own image, you will need to change the name of the image. Instead of demo-app, you will need to create the image using your login name. Mine is 'subfuzion' so my docker build and docker push commands would look like this:

    $ docker build -t subfuzion/demo-app .

    @@ -344,7 +344,7 @@ console.log('listening on port ' + port);
    And update Dockerfile

    ```
    FROM iojs:onbuild
    FROM node:onbuild
    expose 3000
    ```

  4. @tonypujals tonypujals revised this gist Oct 7, 2015. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -159,7 +159,7 @@ This downloads latest image to your machine.

    ### Run the node shell in a container and execute some JavaScript.

    $ docker -it --rm node
    $ docker run -it --rm node
    > console.log('hello')
    hello

    @@ -180,7 +180,7 @@ CMD [ "node" ]

    Override the default CMD by supplying a command after the name of the `node` image.

    $ docker -it --rm node node -v
    $ docker run -it --rm node node -v
    v4.0.0

    $ docker run -it --rm node npm -v
  5. @tonypujals tonypujals revised this gist Sep 23, 2015. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,6 @@
    Quick Start for getting acquainted with Docker for Node.js developers
    =====================================================================

    Install Dependencies
    --------------------

  6. @tonypujals tonypujals revised this gist Sep 22, 2015. 1 changed file with 0 additions and 5 deletions.
    5 changes: 0 additions & 5 deletions docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,3 @@
    ContainerNode Meetup
    ====================

    http://www.meetup.com/ContainerNode/events/225045748/

    Install Dependencies
    --------------------

  7. @tonypujals tonypujals revised this gist Sep 16, 2015. 1 changed file with 4 additions and 2 deletions.
    6 changes: 4 additions & 2 deletions docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    ContainerNode Demo
    ==================
    ContainerNode Meetup
    ====================

    http://www.meetup.com/ContainerNode/events/225045748/

    Install Dependencies
    --------------------
  8. @tonypujals tonypujals revised this gist Sep 16, 2015. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -466,4 +466,3 @@ https://docs.docker.com/articles/dockerfile_best-practices/

    Node, Docker, and Microservices
    http://blog.codefresh.io/node-docker-and-microservices/

  9. @tonypujals tonypujals revised this gist Sep 16, 2015. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -458,6 +458,9 @@ https://www.youtube.com/watch?v=xwj44dAvdYo&feature=youtu.be
    Docker Machine Drivers
    https://docs.docker.com/machine/drivers/

    Linking Containers
    https://docs.docker.com/userguide/dockerlinks/

    Best practices for writing Dockerfiles
    https://docs.docker.com/articles/dockerfile_best-practices/

  10. @tonypujals tonypujals revised this gist Sep 16, 2015. 1 changed file with 10 additions and 1 deletion.
    11 changes: 10 additions & 1 deletion docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -447,11 +447,20 @@ In your app, you can create a connection URL to the Mongo `test` collection as s
    ## Links

    Docker Machine reference
    https://docs.docker.com/machine/reference/
    https://docs.docker.com/machine/

    Docker Machine basics
    http://blog.codefresh.io/docker-machine-basics/

    Machine presentation (Nathan LeClaire)
    https://www.youtube.com/watch?v=xwj44dAvdYo&feature=youtu.be

    Docker Machine Drivers
    https://docs.docker.com/machine/drivers/

    Best practices for writing Dockerfiles
    https://docs.docker.com/articles/dockerfile_best-practices/

    Node, Docker, and Microservices
    http://blog.codefresh.io/node-docker-and-microservices/

  11. @tonypujals tonypujals revised this gist Sep 16, 2015. 1 changed file with 36 additions and 2 deletions.
    38 changes: 36 additions & 2 deletions docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -403,11 +403,11 @@ Create a Docker data volume container

    Start mongo

    (without data volume container)
    -without data volume container

    $ docker run --name mongo -v /data/db -d mongo

    **with data volume container**
    -with data volume container

    $ docker run -d --name mongo --volumes-from dbdata mongo

    @@ -421,3 +421,37 @@ Backup database

    $ docker-machine scp -r dev:~/test .

    ## Node app container linking to mongo container

    $ docker run -p 49100:3000 --link mongo:mongo demo-app

    When launching your app container, Docker dynamically adds a `mongo` entry to the container's `etc/hosts` file and sets a number of convenient mongo-related environment variables, eliminating the need for you to have to provide configuration information. Here are all the environment variables that Docker created related to the mongo dependency in the previous command:

    ```
    MONGO_ENV_MONGO_MAJOR=3.0
    MONGO_PORT=tcp://172.17.0.89:27017
    MONGO_ENV_MONGO_VERSION=3.0.3
    MONGO_PORT_27017_TCP=tcp://172.17.0.89:27017
    MONGO_PORT_27017_TCP_PROTO=tcp
    MONGO_PORT_27017_TCP_ADDR=172.17.0.89
    MONGO_NAME=/xapp/mongo
    MONGO_PORT_27017_TCP_PORT=27017
    ```

    In your app, you can create a connection URL to the Mongo `test` collection as simple as the following:

    var mongoUrl = util.format('mongodb://mongo:%s/test', process.env.MONGO_PORT_27017_TCP_PORT);



    ## Links

    Docker Machine reference
    https://docs.docker.com/machine/reference/

    Docker Machine Drivers
    https://docs.docker.com/machine/drivers/

    Best practices for writing Dockerfiles
    https://docs.docker.com/articles/dockerfile_best-practices/

  12. @tonypujals tonypujals revised this gist Sep 16, 2015. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@ ContainerNode Demo
    Install Dependencies
    --------------------

    ### Install VirtualBox
    ### Install Docker Toolbox

    For Mac and Windows users, just install Docker Toolbox. It provides what you need to get started, including:

  13. @tonypujals tonypujals revised this gist Sep 16, 2015. 1 changed file with 29 additions and 4 deletions.
    33 changes: 29 additions & 4 deletions docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,6 @@
    ContainerNode Demo
    ==================

    http://www.meetup.com/ContainerNode/events/225045748/


    Install Dependencies
    --------------------

    @@ -179,7 +176,9 @@ FROM buildpack-deps:jessie
    CMD [ "node" ]
    ```

    ### Run an alternate shell command in the node container. Override the default CMD by supplying a command after the name of the `node` image.
    ### Run an alternate shell command in the node container

    Override the default CMD by supplying a command after the name of the `node` image.

    $ docker -it --rm node node -v
    v4.0.0
    @@ -395,4 +394,30 @@ Stop it
    Remove it

    $ docker rm demo

    ## Mongo example

    Create a Docker data volume container

    $ docker create --name dbdata -v /dbdata mongo /bin/true

    Start mongo

    (without data volume container)

    $ docker run --name mongo -v /data/db -d mongo

    **with data volume container**

    $ docker run -d --name mongo --volumes-from dbdata mongo

    Connect with client container

    $ docker run -it --link mongo:mongo --rm mongo sh -c 'exec mongo "$MONGO_PORT_27017_TCP_ADDR:$MONGO_PORT_27017_TCP_PORT/test"'

    Backup database

    $ docker run --rm --link mongo:mongo -v /root:/backup mongo bash -c 'mongodump --out /backup --host $MONGO_PORT_27017_TCP_ADDR'

    $ docker-machine scp -r dev:~/test .

  14. @tonypujals tonypujals created this gist Sep 16, 2015.
    398 changes: 398 additions & 0 deletions docker-orientation-for-node-developers.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,398 @@
    ContainerNode Demo
    ==================

    http://www.meetup.com/ContainerNode/events/225045748/


    Install Dependencies
    --------------------

    ### Install VirtualBox

    For Mac and Windows users, just install Docker Toolbox. It provides what you need to get started, including:

    * Docker Machine - for creating Docker hosts ("machines")
    * Docker Client - for communicating with docker hosts
    * VirtualBox - to create docker hosts in a Linux-based (boot2docker) virtual machine

    https://www.docker.com/toolbox


    Working with Docker Machine
    ---------------------------

    ### List Docker machines

    $ docker-machine ls
    NAME ACTIVE DRIVER STATE URL SWARM
    default virtualbox Running tcp://192.168.99.100:2376

    ### Create a new machine

    $ docker-machine create --driver virtualbox dev
    Creating VirtualBox VM...
    Creating SSH key...
    Starting VirtualBox VM...
    Starting VM...
    To see how to connect Docker to this machine, run: docker-machine env dev


    Now list machines

    $ docker-machine ls
    NAME ACTIVE DRIVER STATE URL SWARM
    default virtualbox Running tcp://192.168.99.100:2376
    dev virtualbox Running tcp://192.168.99.101:2376


    ### Tell the Docker client to use the new machine

    $ eval "$(docker-machine env dev)"

    This command evaluates the command `docker-machine env dev`, which results in updating
    environment variables used by the Docker client to communicate with a machine.

    This means that any `docker` commands you issue will be executed for the docker machine named `dev`.

    ### Stop a machine

    $ docker-machine stop dev

    ### Start a machine

    $ docker-machine start dev
    Starting VM...
    Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.

    ### Get the machine host IP

    $ docker-machine ip dev
    192.168.99.101

    ### ssh into the machine

    $ docker-machine ssh dev
    ## .
    ## ## ## ==
    ## ## ## ## ## ===
    /"""""""""""""""""\___/ ===
    ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
    \______ o __/
    \ \ __/
    \____\_______/
    _ _ ____ _ _
    | |__ ___ ___ | |_|___ \ __| | ___ ___| | _____ _ __
    | '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|
    | |_) | (_) | (_) | |_ / __/ (_| | (_) | (__| < __/ |
    |_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_|
    Boot2Docker version 1.8.1, build master : 7f12e95 - Thu Aug 13 03:24:56 UTC 2015
    Docker version 1.8.1, build d12ea79
    docker@dev:~$

    ### Create a machine using other provider drivers

    https://docs.docker.com/machine/drivers/

    #### DigitalOcean example

    Make sure to create a personal access token: https://cloud.digitalocean.com/settings/applications

    Add the access token to your environment:

    export DIGITALOCEAN_ACCESS_TOKEN='...'

    Create a machine

    $ docker-machine create --driver digitalocean demo
    Creating SSH key...
    Creating Digital Ocean droplet...
    To see how to connect Docker to this machine, run: docker-machine env demo

    List the machine

    $ docker-machine ls
    NAME ACTIVE DRIVER STATE URL SWARM
    default virtualbox Running tcp://192.168.99.100:2376
    demo digitalocean Running tcp://107.170.201.137:2376
    dev virtualbox Running tcp://192.168.99.102:2376

    Set `docker` client environment to use, just like any other machine

    $ eval "$(docker-machine env demo)"

    You can also log into your DigitalOcean console and see that the machine has been created.

    Remove the machine if you won't need it

    $ docker-machine rm demo
    Successfully removed demo


    Working with Docker
    -------------------

    Launch a container to run a command, such as the bash builtin `echo` command. The container will be created using the BusyBox image (https://registry.hub.docker.com/_/busybox/). BusyBox is just
    a single executable that defines many common UNIX utilities. It's very small, so it's convenient
    to use for demonstration purposes. You can substitute `ubuntu` or another Linux distribution.


    $ docker run --rm busybox echo hello
    hello

    Launch a BusyBox container and run an interactive shell

    $ docker run --rm -it busybox sh




    Working with Node
    -----------------

    Docker Hub Node repository

    https://hub.docker.com/_/node/


    ### Pull node image

    $ docker pull node

    This downloads latest image to your machine.

    ### Run the node shell in a container and execute some JavaScript.

    $ docker -it --rm node
    > console.log('hello')
    hello


    This runs the node REPL (read-evaluate-print-loop shell) in a container created from the node image.

    It runs a REPL because the container runs the default command as defined by the node image CMD, as defined here:

    https://github.com/nodejs/docker-node/blob/c2a8075f1e3155577c071bf1178c59370bb76d1a/4.0/Dockerfile#L26

    ```
    FROM buildpack-deps:jessie
    ...
    CMD [ "node" ]
    ```

    ### Run an alternate shell command in the node container. Override the default CMD by supplying a command after the name of the `node` image.

    $ docker -it --rm node node -v
    v4.0.0

    $ docker run -it --rm node npm -v
    2.14.2


    ### Run bash in the container

    This will put us into a bash shell in the container

    $ docker run -it --rm node bash
    root@d72e494e756a:/#

    In the bash shell in the node container

    # node -v
    v4.0.0

    # npm -v
    2.14.2


    ### Create a simple node app

    In a new directory...

    Create a package.json file

    ```
    {
    "name": "simple-docker-node-demo",
    "version": "1.0.0",
    "scripts": {
    "start": "node app.js"
    }
    }
    ```

    Create app.js

    console.log('hello world!');


    Create a `Dockerfile`

    ```
    FROM node:onbuild
    ```

    Build an image:

    ```
    $ docker build -t demo-app .
    Sending build context to Docker daemon 4.096 kB
    Step 0 : FROM node:onbuild
    onbuild: Pulling from library/node
    843e2bded498: Already exists
    8c00acfb0175: Already exists
    ...
    # Executing 3 build triggers
    Trigger 0, COPY package.json /usr/src/app/
    Step 0 : COPY package.json /usr/src/app/
    Trigger 1, RUN npm install
    Step 0 : RUN npm install
    ---> Running in 85dc900dbab9
    npm ...
    npm info ok
    Trigger 2, COPY . /usr/src/app
    Step 0 : COPY . /usr/src/app
    ---> e90767b20603
    ...
    Successfully built e90767b20603
    ```

    Docker created an image based on the Dockerfile in the current directory and named it `demo-app-1`. As part of creating the image, it ran instructions triggered from the 'onbuild' base image that we specified in our Dockerfile that included copying the contents of the current directory to /usr/src/app/ and running npm install.

    You can see what the instructions look like here:

    https://github.com/nodejs/docker-node/blob/e763a1065077c580aab4d73945597c0b160b4ee2/4.0/onbuild/Dockerfile

    The triggers are the `ONBUILD` statements. These will be run when
    the image is built that referenced this `Dockerfile` in its `FROM` statement.

    ```
    FROM node:4.0.0
    RUN mkdir -p /usr/src/app
    WORKDIR /usr/src/app
    ONBUILD COPY package.json /usr/src/app/
    ONBUILD RUN npm install
    ONBUILD COPY . /usr/src/app
    CMD [ "npm", "start" ]
    ```

    ### Run the demo app in a container

    $ docker run --rm demo-app-1
    npm info it worked if it ends with ok
    npm info using [email protected]
    npm info using [email protected]
    npm info prestart [email protected]
    npm info start [email protected]

    > [email protected] start /usr/src/app
    > node app.js

    hello world
    npm info poststart [email protected]
    npm info ok


    The node app is trivial, but the mechanics of how this works is the same for more complicated examples. One thing you will probably want to do is export a port for accessing your node application, which we cover in the next section.

    ### Pushing your image

    Save your image for spinning up your app in a node container to Docker repository. You can use Docker Hub.

    You will need to create an account on Docker Hub, then login from the command line:

    $ docker login

    Only official images (such as iojs) can have simple names. To push your own image, you will need to change the name of the image. Instead of demo-app, you will need to create the image using your login name. Mine is 'subfuzion' so my docker build and docker push commands would look like this:

    $ docker build -t subfuzion/demo-app .

    Or when you build, give it a tag:

    $ docker build -t subfuzion/demo-app:1.0 .

    Or if you forget, tag it after:

    $ docker tag <image-id> subfuzion:/demo-app:v1

    Then push the image to Docker Hub

    $ docker push subfuzion/demo-app


    ## Create Express API app and expose a port

    Modify the demo to make it an express app. Install express:

    $ npm install --save express

    Update app.js to start an express server

    ```
    const app = require('express')();
    const port = process.env.PORT || 3000;
    app.use('/', function(req, res) {
    res.json({ message: 'hello world' });
    });
    app.listen(port);
    console.log('listening on port ' + port);
    ```

    And update Dockerfile

    ```
    FROM iojs:onbuild
    expose 3000
    ```

    Rebuild the image

    $ docker build -t demo-app:v2 .


    Now we can run it, but we want to map port 3000 inside the container to a port we can access from our system. We'll pick port 49100:

    $ docker run --rm -t -p 49100:3000 demo-app:v2

    This won't be an interactive session, so no need for `-i`, but the `-t` allows us to send signals from our client, like `CTRL-C`. As usual, `--rm` will remove the container for us when it is stopped.

    Now we can access the app via port 49100, which will be mapped to port 3000 in the container.

    If you're using Docker on a Mac, the port is actually mapped to the Docker host virtual machine. To determine the IP address, enter this at the command line:

    $ docker-machine ip dev
    192.168.99.102

    You should be able to test http://192.168.99.102:49100/ in your browser.

    The app looks for the environment variable PORT to be set, otherwise it defaults to 3000. We could specify an alternate port via the environment from the command line like this:

    $ docker run --rm -t -p 49100:8080 -e "PORT=8080" demo-app

    You will still access the app using the external port 49100, but it is now mapped to port 8080, which is what the app is listening to since the environment variable PORT was set.

    Run it as a daemon

    $ docker run -d -t -p 49100:3000 --name demo demo-app
    dea4768765c176b679d1cb944fdf84466be17be7db0f749b47f5ab32a3ff2bc7


    Naming containers is always a good idea, especially for daemons.

    List it

    $ docker ps


    Stop it

    $ docker stop demo

    Remove it

    $ docker rm demo