Last active
January 18, 2017 11:01
-
-
Save RickyCook/31cb4b8a8b4ea2f7f9bf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# Create a Docker machine\n", | |
| "\n", | |
| "- Docker machine is a wrapper around virtualization software\n", | |
| "- Uses boot2docker, which is a thin OS with just Docker on it\n", | |
| "- There's also `docker-machine upgrade docker-training` which will download a new boot2docker iso, and keep your data" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 1, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Forcibly halting docker-training...\r\n", | |
| "Deleting docker-training...\r\n", | |
| "Successfully removed docker-training\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine kill docker-training\n", | |
| "docker-machine rm docker-training" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 2, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Creating SSH key...\r\n", | |
| "Creating VM...\r\n", | |
| "Starting docker-training...\r\n", | |
| "Waiting for VM to come online...\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "MACHINE_DRIVER=$([ -e '/Applications/VMware Fusion.app' ] && echo vmwarefusion || echo virtualbox)\n", | |
| "docker-machine create --driver $MACHINE_DRIVER --engine-storage-driver overlay docker-training" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 3, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Regenerating TLS certificates\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine regenerate-certs -f docker-training" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "-" | |
| } | |
| }, | |
| "source": [ | |
| "Docker machine is a little bit awful, so we do this ourself\n", | |
| "\n", | |
| "- Generates a new CA, and signing a pub/priv TLS key pair for the Docker engine\n", | |
| "- Docker uses TLS client authentication too\n", | |
| "- TLS isn't necessary, but Docker machine adds it by default" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# Using the Docker machine" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 4, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "An error occurred trying to connect: Get http://debian.local:2375/v1.22/info: dial tcp: lookup debian.local: no such host\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker info" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 5, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "export DOCKER_TLS_VERIFY=\"1\"\r\n", | |
| "export DOCKER_HOST=\"tcp://172.16.34.134:2376\"\r\n", | |
| "export DOCKER_CERT_PATH=\"/Users/rickycook/.docker/machine/machines/docker-training\"\r\n", | |
| "export DOCKER_MACHINE_NAME=\"docker-training\"\r\n", | |
| "# Run this command to configure your shell: \r\n", | |
| "# eval \"$(docker-machine env docker-training)\"\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine env docker-training\n", | |
| "eval \"$(docker-machine env docker-training)\"" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "-" | |
| } | |
| }, | |
| "source": [ | |
| "Sets up environment variables that tell the `docker` command to:\n", | |
| "- Verify TLS host name\n", | |
| "- Connect to the VM on the right IP\n", | |
| "- Use the machine's CA, and client certs" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "These things can be overridden on the CLI as well, but it's annoying to type `docker -H tcp://...` all the time" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 6, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "-" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| " -H, --host=[] Daemon socket(s) to connect to\r\n", | |
| " --tls Use TLS; implied by --tlsverify\r\n", | |
| " --tlscacert=~/.docker/machine/machines/docker-training/ca.pem Trust certs signed only by this CA\r\n", | |
| " --tlscert=~/.docker/machine/machines/docker-training/cert.pem Path to TLS certificate file\r\n", | |
| " --tlskey=~/.docker/machine/machines/docker-training/key.pem Path to TLS key file\r\n", | |
| " --tlsverify=true Use TLS and verify the remote\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker --help | grep -E '(--host)|(--tls)'" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 7, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Containers: 0\r\n", | |
| " Running: 0\r\n", | |
| " Paused: 0\r\n", | |
| " Stopped: 0\r\n", | |
| "Images: 0\r\n", | |
| "Server Version: 1.10.2\r\n", | |
| "Storage Driver: overlay\r\n", | |
| " Backing Filesystem: extfs\r\n", | |
| "Execution Driver: native-0.2\r\n", | |
| "Logging Driver: json-file\r\n", | |
| "Plugins: \r\n", | |
| " Volume: local\r\n", | |
| " Network: host bridge null\r\n", | |
| "Kernel Version: 4.1.18-boot2docker\r\n", | |
| "Operating System: Boot2Docker 1.10.2 (TCL 6.4.1); master : 611be10 - Mon Feb 22 22:47:06 UTC 2016\r\n", | |
| "OSType: linux\r\n", | |
| "Architecture: x86_64\r\n", | |
| "CPUs: 1\r\n", | |
| "Total Memory: 996 MiB\r\n", | |
| "Name: docker-training\r\n", | |
| "ID: 6KLY:LL2E:MFTX:U6UC:UG5W:RVNG:IXD6:KWY3:KXUP:WYZB:IPS4:DX2O\r\n", | |
| "Debug mode (server): true\r\n", | |
| " File Descriptors: 10\r\n", | |
| " Goroutines: 21\r\n", | |
| " System Time: 2016-03-03T00:59:09.322774983Z\r\n", | |
| " EventsListeners: 0\r\n", | |
| " Init SHA1: \r\n", | |
| " Init Path: /usr/local/bin/docker\r\n", | |
| " Docker Root Dir: /mnt/sda1/var/lib/docker\r\n", | |
| "Username: thatpanda\r\n", | |
| "Registry: https://index.docker.io/v1/\r\n", | |
| "Labels:\r\n", | |
| " provider=vmwarefusion\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker info" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "## You can SSH into the machine" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 8, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "-" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Linux docker-training 4.1.18-boot2docker #1 SMP Sat Feb 20 08:24:27 UTC 2016 x86_64 GNU/Linux\r\n", | |
| "Docker version 1.10.2, build c3959b1\r\n", | |
| "Docker version 1.10.2, build c3959b1\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training 'uname -a'\n", | |
| "docker-machine ssh docker-training 'docker -v'\n", | |
| "docker -v" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "## `/Users/<you>` is mounted into the VM" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 62, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "total 49\r\n", | |
| "drwxr-xr-x 1 501 20 1496 Mar 2 01:13 .\r\n", | |
| "drwxr-xr-x 1 501 20 2448 Mar 3 02:47 ..\r\n", | |
| "-rw-r--r-- 1 501 20 8196 Dec 16 03:22 .DS_Store\r\n", | |
| "drwxr-xr-x 1 501 20 1292 Oct 23 04:31 Portus\r\n", | |
| "drwxr-xr-x 1 501 20 238 Oct 14 02:38 aliaskeepr\r\n", | |
| "drwxr-xr-x 1 501 20 272 Sep 18 06:49 alpine-tini\r\n", | |
| "drwxr-xr-x 1 501 20 918 Jan 21 23:17 asset-wala\r\n", | |
| "drwxr-xr-x 1 501 20 476 Dec 1 05:44 aws\r\n", | |
| "drwxr-xr-x 1 501 20 544 Dec 31 01:10 baxter\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training \"[ -e '$HOME' ] || sudo mount -o bind /mnt/hgfs/Users /Users\" # mine isn't working :(\n", | |
| "docker-machine ssh docker-training \"ls -la '$HOME/src'\" | head" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "This becomes more useful later, because it means that you can have Docker containers that read and write to your user directory!" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# Some `docker`!\n", | |
| "\n", | |
| "Let's start with a simple command:" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 10, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Unable to find image 'debian:jessie' locally\r\n", | |
| "Pulling repository docker.io/library/debian\r\n", | |
| "\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "a582cd499e0f: Pulling image (jessie) from docker.io/library/debian \r", | |
| "\u001b[0B\u001b[1A\u001b[2K\r", | |
| "a582cd499e0f: Pulling image (jessie) from docker.io/library/debian, endpoint: https://registry-1.docker.io/v1/ \r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "a582cd499e0f: Pulling dependent layers \r", | |
| "\u001b[1B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "d8bd0657b25f: Pulling metadata \r", | |
| "\u001b[0B\u001b[2A\u001b[2K\r", | |
| "a582cd499e0f: Pulling metadata \r", | |
| "\u001b[2B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Pulling fs layer \r", | |
| "\u001b[1B\u001b[2A\u001b[2K\r", | |
| "a582cd499e0f: Pulling fs layer \r", | |
| "\u001b[2B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Pulling fs layer \r", | |
| "\u001b[1B\u001b[2A\u001b[2K\r", | |
| "a582cd499e0f: Pulling fs layer \r", | |
| "\u001b[2B\u001b[2A\u001b[2K\r", | |
| "a582cd499e0f: Download complete \r", | |
| "\u001b[2B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 539.6 kB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 1.08 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 1.621 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 2.162 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 2.702 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 3.243 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 3.784 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 4.324 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 4.865 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 5.406 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 5.946 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 6.487 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 7.028 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 7.568 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 8.109 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 8.65 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 9.19 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 9.731 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 10.27 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 10.81 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 11.35 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 11.89 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 12.43 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 12.98 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 13.52 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 14.06 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 14.6 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 15.14 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 15.68 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 16.22 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 16.76 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 17.3 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 17.84 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 18.38 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 18.92 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 19.46 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 20 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 20.54 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 21.08 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 21.63 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 22.17 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 22.71 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 23.25 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 23.79 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 24.33 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 24.87 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 25.41 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 25.95 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 26.49 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 27.03 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 27.57 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 28.11 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 28.65 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 29.19 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 29.74 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 30.28 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 30.82 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 31.36 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 31.9 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 32.44 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 32.98 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 33.52 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 34.06 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 34.6 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 35.14 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 35.68 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 36.22 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 36.76 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 37.29 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 37.83 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 38.37 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 38.91 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 39.45 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 39.99 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 40.53 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 41.07 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 41.61 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 42.15 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 42.7 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 43.24 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 43.78 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 44.32 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 44.86 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 45.4 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 45.94 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 46.48 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 47.02 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 47.56 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 48.1 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 48.64 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 49.18 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 49.72 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 50.27 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 50.81 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Downloading 51.35 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Download complete \r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 557.1 kB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 1.114 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 1.671 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 2.228 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 2.785 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 3.342 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 3.899 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 4.456 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 5.014 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 5.571 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 6.128 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 6.685 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 7.242 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 7.799 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 8.356 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 8.913 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 9.47 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 10.03 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 10.58 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 11.14 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 11.7 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 12.26 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 12.81 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 13.37 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 13.93 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 14.48 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 15.04 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 15.6 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 16.15 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 16.71 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 17.27 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 17.83 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 18.38 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 18.94 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 19.5 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 20.05 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 20.61 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 21.17 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 21.73 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 22.28 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 22.84 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 23.4 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 23.95 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 24.51 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 25.07 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 25.62 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 26.18 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 26.74 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 27.3 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 27.85 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 28.41 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 28.97 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 29.52 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 30.08 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 30.64 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 31.2 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 31.75 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 32.31 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 32.87 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 33.42 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 33.98 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 34.54 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 35.09 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 35.65 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 36.21 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 36.77 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 37.32 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 37.88 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 38.44 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 38.99 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 39.55 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 40.11 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 40.67 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 41.22 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 41.78 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 42.34 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 42.89 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 43.45 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 44.01 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 44.56 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 45.12 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 45.68 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 46.24 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 46.79 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 47.35 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 47.91 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 48.46 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 49.02 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 49.58 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 50.14 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 50.69 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 51.25 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Extracting 51.37 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Pull complete \r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d8bd0657b25f: Pull complete \r", | |
| "\u001b[1B\u001b[2A\u001b[2K\r", | |
| "a582cd499e0f: Extracting 32 B\r", | |
| "\u001b[2B\u001b[2A\u001b[2K\r", | |
| "a582cd499e0f: Pull complete \r", | |
| "\u001b[2B\u001b[2A\u001b[2K\r", | |
| "a582cd499e0f: Pull complete \r", | |
| "\u001b[2BStatus: Downloaded newer image for debian:jessie\r\n", | |
| "docker.io/library/debian: this image was pulled from a legacy registry. Important: This registry version will not be supported in future versions of docker.\r\n", | |
| "Debian GNU/Linux 8 \\n \\l\r\n", | |
| "\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker run -i --rm debian:jessie cat /etc/issue" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "source": [ | |
| "What did we just do?\n", | |
| "\n", | |
| "- `run` the run command in Docker creates a container, then starts it. It is shorthand for `docker create` followed by `docker start`\n", | |
| "- `-i` interactive mode provides a standard input to the container (and by default, attaches your stdin to it)\n", | |
| " - Another helpful switch for interacting with containers from the terminal is `-t`, which creates a TTY for the container (that way things like tabs and arrows work in bash)\n", | |
| "- `--rm` when the command exits, remove the container (it's good to get into the habit of doing this, because it's annying to clean up later)\n", | |
| "- `debian:jessie` this is the base image that we use for our root filesystem. This debian image comes from https://hub.docker.com/_/debian/. The part after the `:` is the tag, which is similar to a git tag\n", | |
| "- Everything after the image is the command to run" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "## Dockerfile\n", | |
| "\n", | |
| "https://docs.docker.com/engine/reference/builder/\n", | |
| "\n", | |
| "A Dockerfile is just a file that Docker uses to automatically assemble Docker images. Here's an example Dockerfile, with its build and run output" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 11, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [] | |
| } | |
| ], | |
| "source": [ | |
| "OLDPWD=\"$(pwd)\"\n", | |
| "NEWPWD=\"$(mktemp -d -t docker-training)\"\n", | |
| "cd \"$NEWPWD\"" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 12, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [] | |
| } | |
| ], | |
| "source": [ | |
| "cat <<END > script.sh\n", | |
| "#!/bin/sh\n", | |
| "echo 'our script'\n", | |
| "cat /etc/issue\n", | |
| "\n", | |
| "END\n", | |
| "\n", | |
| "cat <<END > Dockerfile\n", | |
| "\n", | |
| "FROM alpine:3.2\n", | |
| "COPY script.sh /script.sh\n", | |
| "RUN chmod +x /script.sh\n", | |
| "\n", | |
| "END" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "- [`FROM`](https://docs.docker.com/engine/reference/builder/#from) gives the base image that we use for the root, just like the `docker run` command\n", | |
| "- [`COPY`](https://docs.docker.com/engine/reference/builder/#copy) copies a file from the build context into a new layer, and uses this as the base for the next command\n", | |
| " - There's also the [`ADD`](https://docs.docker.com/engine/reference/builder/#add) command that does some extra things. It will download external URLs, and extract local tar/gz/bz2/xz archives automatically\n", | |
| "- [`RUN`](https://docs.docker.com/engine/reference/builder/#run) is an arbitrary command to run. Docker will create a new layer, run the command, and uses this as the base for the next command" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 13, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Sending build context to Docker daemon 3.072 kB\r", | |
| "\r", | |
| "\r\n", | |
| "Step 1 : FROM alpine:3.2\r\n", | |
| "3.2: Pulling from library/alpine\r\n", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "e49bb2b1d8f0: Pulling fs layer \r", | |
| "\u001b[0B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 32.26 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 64.62 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 97.41 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 130.2 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 162.9 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 195.7 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 229.5 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 261.3 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 296.5 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 326.8 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 359.6 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 392.3 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 425.1 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 457.9 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 490.6 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 517.7 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 542.7 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 574.1 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 606.8 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 633.8 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 670.9 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 711.4 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 736.4 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 768.4 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 801.9 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 834.7 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 867.5 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 900.2 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 932.6 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 965.4 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 998.5 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.031 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.061 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.093 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.13 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.162 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.195 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.228 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.261 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.292 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.326 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.359 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.392 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.425 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.457 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.49 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.523 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.556 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.588 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.621 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.654 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.687 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.719 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.752 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.785 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.818 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.85 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.883 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.916 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.949 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 1.982 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.014 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.047 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.08 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.113 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.145 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.178 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.211 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.244 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.276 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.309 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.342 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.375 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.408 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.44 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Downloading 2.473 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Verifying Checksum \r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Download complete \r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 32.77 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 65.54 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 131.1 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 196.6 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 262.1 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 327.7 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 393.2 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 458.8 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 524.3 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 557.1 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 622.6 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 688.1 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 753.7 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 819.2 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 884.7 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 950.3 kB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.016 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.081 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.147 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.212 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.278 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.343 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.409 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.475 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.54 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.606 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.671 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.737 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.802 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.868 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.933 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 1.999 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 2.064 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 2.13 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 2.195 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 2.261 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 2.327 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 2.392 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 2.458 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 2.49 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Extracting 2.492 MB/2.492 MB\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Pull complete \r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "e49bb2b1d8f0: Pull complete \r", | |
| "\u001b[1BDigest: sha256:4f2d8bbad359e3e6f23c0498e009aaa3e2f31996cbea7269b78f92ee43647811\r\n", | |
| "Status: Downloaded newer image for alpine:3.2\r\n", | |
| " ---> 342c0650e86b\r\n", | |
| "Step 2 : COPY script.sh /script.sh\r\n", | |
| " ---> 5a3acdd7dd43\r\n", | |
| "Removing intermediate container 9464af1fbbd1\r\n", | |
| "Step 3 : RUN chmod +x /script.sh\r\n", | |
| " ---> Running in ebb8061312b9\r\n", | |
| " ---> e6d852e914a4\r\n", | |
| "Removing intermediate container ebb8061312b9\r\n", | |
| "Successfully built e6d852e914a4\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker build -t docker-training-1 ." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "- `build` command tells Docker to tar the current directory (called the \"build context), and send it to the Docker engine to build. The Docker engine untars the directory, finds the Dockerfile, and runs the commands\n", | |
| "- `-t docker-training-1` tags the output image with a real name, so that we can reference it later. If we don't provide a tag, we get an auto-assigned ID like `56db960b43f7`\n", | |
| "- `.` the location of the Dockerfile in the build context. We could have said something like `myspecial.Dockerfile` if we had a Dockerfile called that" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 14, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "our script\r\n", | |
| "Welcome to Alpine Linux 3.2\r\n", | |
| "Kernel \\r on an \\m (\\l)\r\n", | |
| "\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker run -i --rm docker-training-1 /script.sh" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "### Build cache\n", | |
| "\n", | |
| "Because Docker works with layers, it has a tree stucture that means it can reuse layers that haven't changed" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 15, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Sending build context to Docker daemon 3.072 kB\r", | |
| "\r", | |
| "\r\n", | |
| "Step 1 : FROM alpine:3.2\r\n", | |
| " ---> 342c0650e86b\r\n", | |
| "Step 2 : COPY script.sh /script.sh\r\n", | |
| " ---> Using cache\r\n", | |
| " ---> 5a3acdd7dd43\r\n", | |
| "Step 3 : RUN chmod +x /script.sh\r\n", | |
| " ---> Using cache\r\n", | |
| " ---> e6d852e914a4\r\n", | |
| "Step 4 : RUN echo \"echo $(date)\" >> /script.sh\r\n", | |
| " ---> Running in 1ab7365e14bc\r\n", | |
| " ---> 7d94903d5c34\r\n", | |
| "Removing intermediate container 1ab7365e14bc\r\n", | |
| "Successfully built 7d94903d5c34\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "echo 'RUN echo \"echo $(date)\" >> /script.sh' >> Dockerfile\n", | |
| "docker build -t docker-training-2 ." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 16, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "our script\r\n", | |
| "Welcome to Alpine Linux 3.2\r\n", | |
| "Kernel \\r on an \\m (\\l)\r\n", | |
| "\r\n", | |
| "Thu Mar 3 01:01:21 UTC 2016\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker run -i --rm docker-training-2 /script.sh" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "This is really handy for OS dependencies, because it means that you don't have to reinstall Ruby/etc every time you make a change to your code. To take advantage of this, the usual rule is to put things that take longest, and change the least at the top of the Dockerfile. Things that change often and don't take long go toward the bottom of the Dockerfile.\n", | |
| "\n", | |
| "- The build cache is broken when:\n", | |
| " - A command in the Dockerfile is changed\n", | |
| " - A file copied in is changed" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "It is NOT broken from the output of a `RUN` command. The `$(date)` above will be cached on subsequent runs" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 17, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "-" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Sending build context to Docker daemon 3.072 kB\r", | |
| "\r", | |
| "\r\n", | |
| "Step 1 : FROM alpine:3.2\r\n", | |
| " ---> 342c0650e86b\r\n", | |
| "Step 2 : COPY script.sh /script.sh\r\n", | |
| " ---> Using cache\r\n", | |
| " ---> 5a3acdd7dd43\r\n", | |
| "Step 3 : RUN chmod +x /script.sh\r\n", | |
| " ---> Using cache\r\n", | |
| " ---> e6d852e914a4\r\n", | |
| "Step 4 : RUN echo \"echo $(date)\" >> /script.sh\r\n", | |
| " ---> Using cache\r\n", | |
| " ---> 7d94903d5c34\r\n", | |
| "Successfully built 7d94903d5c34\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker build -t docker-training-2 ." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "This becomes a little tricky when using things like `Gemfile.lock`, because people usually do something like:\n", | |
| "\n", | |
| "```\n", | |
| "COPY . /code\n", | |
| "RUN gem install bundler && bundle install\n", | |
| "```\n", | |
| "\n", | |
| "This has the negative effect of needing to install gems every time you change any code. To get around this, you'd usually do something like this:\n", | |
| "\n", | |
| "```\n", | |
| "RUN mkdir -p /code\n", | |
| "\n", | |
| "COPY package.json /code/package.json\n", | |
| "RUN npm install\n", | |
| "\n", | |
| "COPY Gemfile.lock /code/Gemfile.lock\n", | |
| "RUN gem install bundler && bundle install\n", | |
| "\n", | |
| "COPY . /code\n", | |
| "```" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": { | |
| "collapsed": true, | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [], | |
| "source": [ | |
| "cd \"$OLDPWD\"\n", | |
| "rm -rf \"$NEWPWD\"" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 18, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Untagged: docker-training-1:latest\r\n", | |
| "Untagged: docker-training-2:latest\r\n", | |
| "Deleted: sha256:7d94903d5c34794d3b619b6588904d95c0f882e5fbd05fb7e15eb1b2473216a5\r\n", | |
| "Deleted: sha256:5a6a75cc510e0380287e5ca7068064ba658e6fede46ae93556823f860798a946\r\n", | |
| "Deleted: sha256:e6d852e914a410414df9c36f750f6943c8d732adb3778bbbae603b4a0bd4ffc5\r\n", | |
| "Deleted: sha256:f433d79c59ab4ef1b5284f619756fad390e87480694f835a5642a2478c9b5fa2\r\n", | |
| "Deleted: sha256:5a3acdd7dd430d0b60258e168a5896d0b98429006e869e9c6c865e7358e0470d\r\n", | |
| "Deleted: sha256:832e0d848455399462efc8c96f020ba6299968024b61d0564eee0a039069e1fa\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker rmi docker-training-1\n", | |
| "docker rmi docker-training-2" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "As a quick note, `docker rm` is to remove containers (we didn't need to, because we added `--rm` to our `run` invokation), and `docker rmi` is to remove images. You can also use `docker rm -f` which stops, and removes a container. You shouldn't, however, use `docker rmi -f`, because this can get you into some weird states that are hard to recover from.\n", | |
| "\n", | |
| "Also note that it said that it untagged `docker-training-1:latest`. Named Docker images always have both a \"repository\", and a \"tag\". If no `:` is added, Docker assumes that you have given the repository and will automatically tag the image as `latest` for that repository. The same thing happens if you `pull`, `run`, or reference via `FROM` in a Dockerfile." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "## Volumes\n", | |
| "\n", | |
| "https://docs.docker.com/engine/userguide/containers/dockervolumes/\n", | |
| "\n", | |
| "Running commands in a container is... Pretty boring on its own.\n", | |
| "\n", | |
| "Volumes allow you to use data from the host OS (in this case, our `docker-training` VM that we created with Docker machine). By default, these are read-writable, but you can add `:ro` to make them read-only." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 19, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Capfile\r\n", | |
| "Dockerfile\r\n", | |
| "Gemfile\r\n", | |
| "Gemfile.lock\r\n", | |
| "Guardfile\r\n", | |
| "Procfile\r\n", | |
| "README.md\r\n", | |
| "Rakefile\r\n", | |
| "app\r\n", | |
| "config\r\n", | |
| "config.ru\r\n", | |
| "custom_plan.rb\r\n", | |
| "data\r\n", | |
| "db\r\n", | |
| "deploy\r\n", | |
| "doc\r\n", | |
| "ey.yml\r\n", | |
| "features\r\n", | |
| "frontend\r\n", | |
| "knapsack_cucumber_report.json\r\n", | |
| "knapsack_rspec_report.json\r\n", | |
| "lib\r\n", | |
| "log\r\n", | |
| "package.json\r\n", | |
| "public\r\n", | |
| "reports\r\n", | |
| "script\r\n", | |
| "spec\r\n", | |
| "test\r\n", | |
| "tmp\r\n", | |
| "zeus.json\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker run -i --rm -v ~/src/redbubble:/app debian:jessie ls /app | head" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "source": [ | |
| "In this case, you should be aware that this works in a kind of round-about way. Bash on your Mac is expanding `~` into `/Users/<you>`, so Docker is seeing `/Users/<you>/src/redbubble`. Remember that Docker machine mounts `/Users` into the VM in the same place? That's how that magically appears there.\n", | |
| "\n", | |
| "This can be confusing to understand where, and how Docker is doing things if you don't know that this is happening." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# Docker magic unmagic'd\n", | |
| "\n", | |
| "To get started with understanding exactly what Docker is doing, we will start off with a more simplified example: a `chroot`. This stands for \"changed root\". A similar process to what we're about to do forms the basis of what most people know about Docker: it's ability to run different OSes." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "## Chroot\n", | |
| "\n", | |
| "First, we'll set up a chroot. A chroot simply changes your root directory to a different one. I this case, we're creating a directory `./docker-training-chroot`, mounting in the host's `bin`, and `lib` directories, and adding a new file to show that it's what we created." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 20, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Boot2Docker version 1.10.2, build master : 611be10 - Mon Feb 22 22:47:06 UTC 2016\r\n", | |
| "Docker version 1.10.2, build c3959b1\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training <<'END'\n", | |
| "mkdir -p \"docker-training-chroot/bin\" \"docker-training-chroot/lib\"\n", | |
| "\n", | |
| "sudo mount -o bind /bin \"docker-training-chroot/bin\" # get bin from the host\n", | |
| "sudo mount -o bind /lib \"docker-training-chroot/lib\" # get lib from the host\n", | |
| "\n", | |
| "touch \"docker-training-chroot/this-is-our-new-root\"\n", | |
| "END" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "Here's the host's root directory" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 21, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "total 261\r\n", | |
| "drwxr-xr-x 17 tc staff 440 Mar 3 2016 .\r\n", | |
| "drwxr-xr-x 17 tc staff 440 Mar 3 2016 ..\r\n", | |
| "drwxr-xr-x 1 root 80 170 Aug 28 2015 Users\r\n", | |
| "drwxr-xr-x 2 root root 1500 Mar 3 2016 bin\r\n", | |
| "drwxrwxr-x 14 root staff 4400 Mar 3 2016 dev\r\n", | |
| "-rw-r--r-- 1 root root 262144 Mar 3 2016 device_test_file\r\n", | |
| "drwxr-xr-x 11 root root 1040 Mar 3 00:58 etc\r\n", | |
| "drwxrwxr-x 3 root staff 60 Mar 3 2016 home\r\n", | |
| "-rwxr-xr-x 1 root root 496 Feb 22 22:47 init\r\n", | |
| "drwxr-xr-x 5 root root 860 Mar 3 2016 lib\r\n", | |
| "lrwxrwxrwx 1 root root 3 Mar 3 2016 lib64 -> lib\r\n", | |
| "lrwxrwxrwx 1 root root 11 Mar 3 2016 linuxrc -> bin/busybox\r\n", | |
| "drwxr-xr-x 6 root root 120 Mar 3 2016 mnt\r\n", | |
| "drwxrwsr-x 2 root staff 180 Mar 3 2016 opt\r\n", | |
| "dr-xr-xr-x 165 root root 0 Mar 3 2016 proc\r\n", | |
| "drwxrwxr-x 2 root staff 80 Mar 3 2016 root\r\n", | |
| "drwxrwxr-x 4 root staff 80 Mar 3 2016 run\r\n", | |
| "drwxrwxr-x 2 root root 1400 Mar 3 2016 sbin\r\n", | |
| "dr-xr-xr-x 13 root root 0 Mar 3 2016 sys\r\n", | |
| "lrwxrwxrwx 1 root root 13 Mar 3 2016 tmp -> /mnt/sda1/tmp\r\n", | |
| "drwxr-xr-x 7 root root 140 Mar 3 2016 usr\r\n", | |
| "drwxrwxr-x 9 root staff 200 Mar 3 2016 var\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training 'ls -la /'" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "And here, we will chroot and list the new root directory" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 22, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Boot2Docker version 1.10.2, build master : 611be10 - Mon Feb 22 22:47:06 UTC 2016\r\n", | |
| "Docker version 1.10.2, build c3959b1\r\n", | |
| "total 0\r\n", | |
| "drwxr-sr-x 4 1000 50 100 Mar 3 01:01 .\r\n", | |
| "drwxr-sr-x 4 1000 50 100 Mar 3 01:01 ..\r\n", | |
| "drwxr-xr-x 2 0 0 1500 Mar 3 2016 bin\r\n", | |
| "drwxr-xr-x 5 0 0 860 Mar 3 2016 lib\r\n", | |
| "-rw-r--r-- 1 1000 50 0 Mar 3 01:01 this-is-our-new-root\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training <<'END'\n", | |
| "sudo chroot \"docker-training-chroot\" ls -la /\n", | |
| "END" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "Notice that we had to mount in the `bin`, and `lib` directories from the host? This is because everything is looked up relative to `/`, which now doesn't include anything on the host!\n", | |
| "\n", | |
| "If we were to copy (for example) the entire root directory of a Debian install, then we would have all the libraries and binaries that make up Debian available to us. This is essentially all that makes up any specific Linux distro; just different binaries and libraries.\n", | |
| "\n", | |
| "Given that we haven't done anything particularly interesting, you might not be surprised to hear that if you run processes in the chroot, you can also see them on the host (but since Jupyter is not able to parallelize, you'll just have to trust me for now)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "source": [ | |
| "*Ignore this; it's just clean up*" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 23, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Boot2Docker version 1.10.2, build master : 611be10 - Mon Feb 22 22:47:06 UTC 2016\r\n", | |
| "Docker version 1.10.2, build c3959b1\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training <<'END'\n", | |
| "sudo umount \"docker-training-chroot/bin\"\n", | |
| "sudo umount \"docker-training-chroot/lib\"\n", | |
| "rm -rf \"docker-training-chroot\"\n", | |
| "END" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "## CGroups\n", | |
| "\n", | |
| "> (abbreviated from control groups) is a Linux kernel feature that\n", | |
| "> limits, accounts for, and isolates the resource usage (CPU, memory,\n", | |
| "> disk I/O, network, etc.) of a collection of processes.\n", | |
| ">\n", | |
| "> -- <cite>https://en.wikipedia.org/wiki/Cgroups</cite>\n", | |
| "\n", | |
| "So, if you start an application (eg bash) in a CGroup with a memory limit of 500mb, then that process and all children have a hard limit of 500mb of RAM, even if the process gets orphined (which means that its parent becomes PID 1).\n", | |
| "\n", | |
| "Docker uses this in multiple ways:\n", | |
| "\n", | |
| "1. Track processes that are running in a container\n", | |
| "1. Track resource usage of a container\n", | |
| "1. Limit CPU/RAM/etc that a container can use\n", | |
| "1. Namespaces (below)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "### Namespaces\n", | |
| "\n", | |
| "The other feature of CGroups worth noting is called \"namespaces\". This allows you to apply kind of a lens to the processes in the CGroups (the isolation mentioned above)." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "An easy to understand namespace is the PID namespace. Here we see the processes running on the host:" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 24, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "-" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "PID USER COMMAND\r\n", | |
| " 1 root init\r\n", | |
| " 195 root /sbin/udevd --daemon\r\n", | |
| " 1325 root /sbin/udevd --daemon\r\n", | |
| " 1326 root /sbin/udevd --daemon\r\n", | |
| " 2007 root crond -f -d 8\r\n", | |
| " 2031 root /usr/local/sbin/sshd\r\n", | |
| " 2035 root /usr/local/sbin/acpid\r\n", | |
| " 2048 root /sbin/udhcpc -b -i eth0 -x hostname boot2docker -p /var/run/udhcpc.eth0.pid\r\n", | |
| " 2050 root ntpd -d -n -p 0.boot2docker.pool.ntp.org -p 1.boot2docker.pool.ntp.org -p 2.boot2docker.pool.ntp.org -p 3.boot2docker.pool.ntp.org\r\n", | |
| " 2105 root /usr/local/bin/vmhgfs-fuse -o allow_other .host:/ /mnt/hgfs\r\n", | |
| " 2112 root /usr/local/bin/vmtoolsd\r\n", | |
| " 2137 root -sh\r\n", | |
| " 2139 root /sbin/getty -l /usr/local/bin/autologin 9600 ttyS0 vt100\r\n", | |
| " 2140 root /sbin/getty -l /usr/local/bin/autologin 9600 ttyS1 vt100\r\n", | |
| " 2264 root sshd: docker [priv]\r\n", | |
| " 2266 docker sshd: docker@notty\r\n", | |
| " 2335 root /usr/local/bin/docker daemon -D -g /var/lib/docker -H unix:// -H tcp://0.0.0.0:2376 --label provider=vmwarefusion --tlsverify --tlscacert=/var/lib/boot2docker/ca.pem --tlscert=/var/lib/boot2docker/server.pem --tlskey=/var/lib/boot2docker/server-key.pem -s overlay\r\n", | |
| " 2570 docker sh -c ps aux\r\n", | |
| " 2571 docker ps aux\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training ps aux | awk '$3 ~ /^[^[]/ { print }' # filter out kernel processes" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "And in a container" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 25, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "-" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "PID USER TIME COMMAND\r\n", | |
| " 1 root 0:00 ps aux\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker run -i --rm alpine:3.2 ps aux" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "As you can see, there are plenty of things running no the host, but the CGroup doesn't let the container see any of it" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "Just to prove that this is all running directly on the host, we can do another ps on the host" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 26, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training ps aux | grep ping || true" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 27, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| " 2580 root /bin/busybox ping 8.8.8.8\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker run -d --name docker-training-ping alpine:3.2 ping 8.8.8.8 >/dev/null\n", | |
| "docker-machine ssh docker-training ps aux | grep ping\n", | |
| "docker rm -f docker-training-ping >/dev/null" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "Note that, confusingly, the command here (`/bin/busybox`) doesn't actually point to the `/bin/busybox` on the host; it's the `/bin/busybox` in the container, even though we're listing from the host!\n", | |
| "\n", | |
| "This can get really confusing when you might have 5 processes in different containers with the same invokation." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "### Networking namespace\n", | |
| "\n", | |
| "Docker uses other namespaces, like the network namespace to ensure that containers can't access the host's networking. Rather, it provides virtual interfaces for containers so that it can do some nice software defined networking between containers." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 28, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default \r\n", | |
| " link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\r\n", | |
| "2: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default \r\n", | |
| " link/ether ca:24:5f:0e:af:2b brd ff:ff:ff:ff:ff:ff\r\n", | |
| "3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000\r\n", | |
| " link/ether 00:0c:29:7e:a9:0c brd ff:ff:ff:ff:ff:ff\r\n", | |
| "4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default \r\n", | |
| " link/ether 02:42:bc:a5:6d:e1 brd ff:ff:ff:ff:ff:ff\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training ip link" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 29, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN \r\n", | |
| " link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\r\n", | |
| "21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP \r\n", | |
| " link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker run -it --rm alpine:3.2 ip link" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "## No magic\n", | |
| "\n", | |
| "So, as you can hopefully see, there's really nothing too magic that's happening at the core. All that's happening is that we're getting a directory with an OS in it, and telling Linux to start a process using that filesystem, and isolate it's PIDs, networking, etc from everything else on the host.\n", | |
| "\n", | |
| "The great thing about this is that it's got a very similar resource consumption to just running the command on the host (because it is, albeit with a little extra setup and teardown)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "## Filesystem layers\n", | |
| "\n", | |
| "One of the other major things that Docker does, is it has its base OS filesystem in layers. Though in production, we mostly use things like BTRFS subvolumes to do this, we can replicate it with AuFS (which was originally the only storage driver available for Docker).\n", | |
| "\n", | |
| "AuFS allows us to combine multiple directories into 1, where the top level directory may contain all writes (so others are read only)." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "Below, we will create directories:\n", | |
| "\n", | |
| "- `docker-training-layer-rw` (where writes to root will go)\n", | |
| "- `docker-training-layer-1` (first read only layer)\n", | |
| "- `docker-training-layer-2` (second read only layer)\n", | |
| "- `docker-training-layer-root` (the mount point)\n", | |
| "\n", | |
| "We add marker files into the read-only directories so that we can see what happens\n", | |
| "\n", | |
| "And then mount it with AuFS" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 30, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Boot2Docker version 1.10.2, build master : 611be10 - Mon Feb 22 22:47:06 UTC 2016\r\n", | |
| "Docker version 1.10.2, build c3959b1\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training <<'END'\n", | |
| "\n", | |
| "for i in 1 2; do\n", | |
| " mkdir docker-training-layer-$i\n", | |
| " echo \"Layer $i\" > docker-training-layer-$i/from-layer-$i\n", | |
| "done\n", | |
| "\n", | |
| "mkdir docker-training-layer-rw\n", | |
| "mkdir docker-training-layer-root\n", | |
| "\n", | |
| "sudo mount -t aufs -o br=docker-training-layer-rw:docker-training-layer-1:docker-training-layer-2 none docker-training-layer-root\n", | |
| "END" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 31, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "total 8\r\n", | |
| "drwxr-sr-x 4 docker staff 100 Mar 3 01:04 .\r\n", | |
| "drwxr-sr-x 9 docker staff 280 Mar 3 01:04 ..\r\n", | |
| "-rw-r--r-- 1 docker staff 8 Mar 3 01:04 from-layer-1\r\n", | |
| "-rw-r--r-- 1 docker staff 8 Mar 3 01:04 from-layer-2\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training 'ls -la docker-training-layer-root'" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "As you can see, by listing the root directory, we have the files from both RO dirs we created.\n", | |
| "\n", | |
| "Writes to the root directory are copy on write" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 32, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training 'echo \"changed\" > docker-training-layer-root/from-layer-1'\n", | |
| "docker-machine ssh docker-training 'rm docker-training-layer-root/from-layer-2'" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 33, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Layer 1\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training 'cat docker-training-layer-1/from-layer-1'" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 34, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Layer 2\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training 'cat docker-training-layer-2/from-layer-2'" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "As you can see, the content change and deletion didn't change anything in the RO layers.\n", | |
| "\n", | |
| "This has important implications for `docker build`, because it means that something like this:\n", | |
| "\n", | |
| "```\n", | |
| "RUN apt-get install -y nodejs\n", | |
| "RUN apt-get purge nodejs\n", | |
| "```\n", | |
| "\n", | |
| "Will not actually save you any space, because they are each on separate layers, so nothing is actually deleted. In fact, you will use *more* space than without the purge command.\n", | |
| "\n", | |
| "This can be a security issue too. Remember: **never add private data to a Docker container you intend to push**. You can *not* delete it!" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 35, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "total 4\r\n", | |
| "drwxr-sr-x 4 docker staff 140 Mar 3 01:04 .\r\n", | |
| "drwxr-sr-x 9 docker staff 280 Mar 3 01:04 ..\r\n", | |
| "-r--r--r-- 2 root staff 0 Mar 3 01:04 .wh..wh.aufs\r\n", | |
| "drwx--S--- 2 root staff 40 Mar 3 01:04 .wh..wh.orph\r\n", | |
| "drwx--S--- 2 root staff 40 Mar 3 01:04 .wh..wh.plnk\r\n", | |
| "-r--r--r-- 2 root staff 0 Mar 3 01:04 .wh.from-layer-2\r\n", | |
| "-rw-r--r-- 1 docker staff 8 Mar 3 01:04 from-layer-1\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training 'ls -la docker-training-layer-rw'" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 36, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "changed\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training 'cat docker-training-layer-rw/from-layer-1'" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "In the RW directory, we have some metadata for the deletion, and the updated `from-layer-1` file" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "This is how Docker treats its OS images. It has layers that make up (for example) the Debian root filesystem that are read-only, and containers create a read-write layer, and a root mount that forms the root of the `chroot` for the container.\n", | |
| "\n", | |
| "This allows us to have as many RW directories and root mounts as we like, while taking up minimal disk space because the OS itself isn't cloned multiple times. If you don't make any changes in the container, there's only a little bit of metadata that Docker stores, so you don't have `OS x Ncontainers` space used, unlike VMs." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 37, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Boot2Docker version 1.10.2, build master : 611be10 - Mon Feb 22 22:47:06 UTC 2016\r\n", | |
| "Docker version 1.10.2, build c3959b1\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker-machine ssh docker-training <<'END'\n", | |
| "sudo umount docker-training-layer-root\n", | |
| "sudo rm -rf docker-training-layer-*\n", | |
| "END" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# Utility pattern\n", | |
| "\n", | |
| "Other than building and running servers, Docker has another particularly useful pattern, which involves installing tools in a container. This means that you don't have to worry as much about differing versions of things, because you can just say `docker run -it --rm my-sass-compiler:3.4.2` or `docker run -it --rm my-sass-compiler:2.2.0`." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 55, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [] | |
| } | |
| ], | |
| "source": [ | |
| "OLDPWD=\"$(pwd)\"\n", | |
| "NEWPWD=\"$(mktemp -d -t docker-sass)\"\n", | |
| "cd \"$NEWPWD\"" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 56, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Sending build context to Docker daemon 2.048 kB\r", | |
| "\r", | |
| "\r\n", | |
| "Step 1 : FROM ruby:alpine\r\n", | |
| "Pulling repository docker.io/library/ruby\r\n", | |
| "\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "d69211ce1b82: Pulling image (alpine) from docker.io/library/ruby \r", | |
| "\u001b[0B\u001b[1A\u001b[2K\r", | |
| "d69211ce1b82: Pulling image (alpine) from docker.io/library/ruby, endpoint: https://registry-1.docker.io/v1/ \r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "d69211ce1b82: Pulling dependent layers \r", | |
| "\u001b[1B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "2a250d324882: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "168d6480f3ac: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "5e9a2174bca3: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "bb57d65427db: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "a58f5c2aa27c: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "6e171e12770f: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "bf840a81de99: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "3667ee957458: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "0f6a3222db0b: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "33e692c74de5: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "592ba6bdf6b0: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "40c1903d7955: Pulling metadata \r", | |
| "\u001b[0B\r\n", | |
| "\u001b[0A\u001b[2K\r", | |
| "8e9407868fd2: Pulling metadata \r", | |
| "\u001b[0B\u001b[14A\u001b[2K\r", | |
| "d69211ce1b82: Pulling metadata \r", | |
| "\u001b[14B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Pulling fs layer \r", | |
| "\u001b[13B\u001b[12A\u001b[2K\r", | |
| "168d6480f3ac: Pulling fs layer \r", | |
| "\u001b[12B\u001b[11A\u001b[2K\r", | |
| "5e9a2174bca3: Pulling fs layer \r", | |
| "\u001b[11B\u001b[10A\u001b[2K\r", | |
| "bb57d65427db: Pulling fs layer \r", | |
| "\u001b[10B\u001b[9A\u001b[2K\r", | |
| "a58f5c2aa27c: Pulling fs layer \r", | |
| "\u001b[9B\u001b[8A\u001b[2K\r", | |
| "6e171e12770f: Pulling fs layer \r", | |
| "\u001b[8B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Pulling fs layer \r", | |
| "\u001b[7B\u001b[6A\u001b[2K\r", | |
| "3667ee957458: Pulling fs layer \r", | |
| "\u001b[6B\u001b[5A\u001b[2K\r", | |
| "0f6a3222db0b: Pulling fs layer \r", | |
| "\u001b[5B\u001b[4A\u001b[2K\r", | |
| "33e692c74de5: Pulling fs layer \r", | |
| "\u001b[4B\u001b[3A\u001b[2K\r", | |
| "592ba6bdf6b0: Pulling fs layer \r", | |
| "\u001b[3B\u001b[2A\u001b[2K\r", | |
| "40c1903d7955: Pulling fs layer \r", | |
| "\u001b[2B\u001b[1A\u001b[2K\r", | |
| "8e9407868fd2: Pulling fs layer \r", | |
| "\u001b[1B\u001b[14A\u001b[2K\r", | |
| "d69211ce1b82: Pulling fs layer \r", | |
| "\u001b[14B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Pulling fs layer \r", | |
| "\u001b[13B\u001b[12A\u001b[2K\r", | |
| "168d6480f3ac: Pulling fs layer \r", | |
| "\u001b[12B\u001b[11A\u001b[2K\r", | |
| "5e9a2174bca3: Pulling fs layer \r", | |
| "\u001b[11B\u001b[10A\u001b[2K\r", | |
| "bb57d65427db: Waiting \r", | |
| "\u001b[10B\u001b[9A\u001b[2K\r", | |
| "a58f5c2aa27c: Waiting \r", | |
| "\u001b[9B\u001b[8A\u001b[2K\r", | |
| "6e171e12770f: Waiting \r", | |
| "\u001b[8B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Waiting \r", | |
| "\u001b[7B\u001b[6A\u001b[2K\r", | |
| "3667ee957458: Waiting \r", | |
| "\u001b[6B\u001b[5A\u001b[2K\r", | |
| "0f6a3222db0b: Waiting \r", | |
| "\u001b[5B\u001b[4A\u001b[2K\r", | |
| "33e692c74de5: Waiting \r", | |
| "\u001b[4B\u001b[3A\u001b[2K\r", | |
| "592ba6bdf6b0: Waiting \r", | |
| "\u001b[3B\u001b[2A\u001b[2K\r", | |
| "40c1903d7955: Waiting \r", | |
| "\u001b[2B\u001b[1A\u001b[2K\r", | |
| "8e9407868fd2: Waiting \r", | |
| "\u001b[1B\u001b[14A\u001b[2K\r", | |
| "d69211ce1b82: Waiting \r", | |
| "\u001b[14B\u001b[12A\u001b[2K\r", | |
| "168d6480f3ac: Download complete \r", | |
| "\u001b[12B\u001b[10A\u001b[2K\r", | |
| "bb57d65427db: Pulling fs layer \r", | |
| "\u001b[10B\u001b[11A\u001b[2K\r", | |
| "5e9a2174bca3: Download complete \r", | |
| "\u001b[11B\u001b[9A\u001b[2K\r", | |
| "a58f5c2aa27c: Pulling fs layer \r", | |
| "\u001b[9B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Downloading 539.9 kB\r", | |
| "\u001b[13B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Downloading 1.081 MB\r", | |
| "\u001b[13B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Downloading 1.621 MB\r", | |
| "\u001b[13B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Downloading 2.162 MB\r", | |
| "\u001b[13B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Download complete \r", | |
| "\u001b[13B\u001b[8A\u001b[2K\r", | |
| "6e171e12770f: Pulling fs layer \r", | |
| "\u001b[8B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Extracting 557.1 kB\r", | |
| "\u001b[13B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Extracting 1.114 MB\r", | |
| "\u001b[13B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Extracting 1.671 MB\r", | |
| "\u001b[13B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Extracting 2.228 MB\r", | |
| "\u001b[13B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Extracting 2.32 MB\r", | |
| "\u001b[13B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Pull complete \r", | |
| "\u001b[13B\u001b[13A\u001b[2K\r", | |
| "2a250d324882: Pull complete \r", | |
| "\u001b[13B\u001b[12A\u001b[2K\r", | |
| "168d6480f3ac: Extracting 198 B\r", | |
| "\u001b[12B\u001b[12A\u001b[2K\r", | |
| "168d6480f3ac: Pull complete \r", | |
| "\u001b[12B\u001b[12A\u001b[2K\r", | |
| "168d6480f3ac: Pull complete \r", | |
| "\u001b[12B\u001b[11A\u001b[2K\r", | |
| "5e9a2174bca3: Extracting 32 B\r", | |
| "\u001b[11B\u001b[11A\u001b[2K\r", | |
| "5e9a2174bca3: Pull complete \r", | |
| "\u001b[11B\u001b[11A\u001b[2K\r", | |
| "5e9a2174bca3: Pull complete \r", | |
| "\u001b[11B\u001b[9A\u001b[2K\r", | |
| "a58f5c2aa27c: Download complete \r", | |
| "\u001b[9B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Pulling fs layer \r", | |
| "\u001b[7B\u001b[10A\u001b[2K\r", | |
| "bb57d65427db: Download complete \r", | |
| "\u001b[10B\u001b[6A\u001b[2K\r", | |
| "3667ee957458: Pulling fs layer \r", | |
| "\u001b[6B\u001b[10A\u001b[2K\r", | |
| "bb57d65427db: Extracting 32 B\r", | |
| "\u001b[10B\u001b[10A\u001b[2K\r", | |
| "bb57d65427db: Pull complete \r", | |
| "\u001b[10B\u001b[10A\u001b[2K\r", | |
| "bb57d65427db: Pull complete \r", | |
| "\u001b[10B\u001b[9A\u001b[2K\r", | |
| "a58f5c2aa27c: Extracting 32 B\r", | |
| "\u001b[9B\u001b[9A\u001b[2K\r", | |
| "a58f5c2aa27c: Pull complete \r", | |
| "\u001b[9B\u001b[9A\u001b[2K\r", | |
| "a58f5c2aa27c: Pull complete \r", | |
| "\u001b[9B\u001b[6A\u001b[2K\r", | |
| "3667ee957458: Download complete \r", | |
| "\u001b[6B\u001b[5A\u001b[2K\r", | |
| "0f6a3222db0b: Pulling fs layer \r", | |
| "\u001b[5B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 539.8 kB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 1.068 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 1.608 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 2.149 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 2.69 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 3.23 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 3.771 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 4.312 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 4.852 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 5.393 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 5.934 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 6.474 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 7.015 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 7.556 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 8.096 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 8.637 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 9.178 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 9.718 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 10.26 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 10.8 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 11.34 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 11.88 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 12.42 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 12.96 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 13.5 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 14.04 MB\r", | |
| "\u001b[7B\u001b[8A\u001b[2K\r", | |
| "6e171e12770f: Download complete \r", | |
| "\u001b[8B\u001b[4A\u001b[2K\r", | |
| "33e692c74de5: Pulling fs layer \r", | |
| "\u001b[4B\u001b[8A\u001b[2K\r", | |
| "6e171e12770f: Extracting 32 B\r", | |
| "\u001b[8B\u001b[5A\u001b[2K\r", | |
| "0f6a3222db0b: Download complete \r", | |
| "\u001b[5B\u001b[3A\u001b[2K\r", | |
| "592ba6bdf6b0: Pulling fs layer \r", | |
| "\u001b[3B\u001b[8A\u001b[2K\r", | |
| "6e171e12770f: Pull complete \r", | |
| "\u001b[8B\u001b[8A\u001b[2K\r", | |
| "6e171e12770f: Pull complete \r", | |
| "\u001b[8B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 14.58 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 15.13 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 15.67 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 16.21 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 16.75 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 17.29 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 17.83 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 18.37 MB\r", | |
| "\u001b[7B\u001b[4A\u001b[2K\r", | |
| "33e692c74de5: Download complete \r", | |
| "\u001b[4B\u001b[2A\u001b[2K\r", | |
| "40c1903d7955: Pulling fs layer \r", | |
| "\u001b[2B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 18.91 MB\r", | |
| "\u001b[7B\u001b[3A\u001b[2K\r", | |
| "592ba6bdf6b0: Download complete \r", | |
| "\u001b[3B\u001b[1A\u001b[2K\r", | |
| "8e9407868fd2: Pulling fs layer \r", | |
| "\u001b[1B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 19.45 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 19.99 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 20.53 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 21.07 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 21.61 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 22.15 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 22.69 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 23.24 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 23.78 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 24.32 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 24.86 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 25.4 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 25.94 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 26.48 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 27.02 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 27.56 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 28.1 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 28.64 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 29.18 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 29.72 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 30.26 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 30.8 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 31.35 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 31.89 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 32.43 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 32.97 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 33.51 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 34.05 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Downloading 34.59 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Download complete \r", | |
| "\u001b[7B\u001b[14A\u001b[2K\r", | |
| "d69211ce1b82: Pulling fs layer \r", | |
| "\u001b[14B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 557.1 kB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 1.114 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 1.671 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 2.228 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 2.785 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 3.342 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 3.899 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 4.456 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 5.014 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 5.571 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 6.128 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 6.685 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 7.242 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 7.799 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 8.356 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 8.913 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 9.47 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 10.03 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 10.58 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 11.14 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 11.7 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 12.26 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 12.81 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 13.37 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 13.93 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 14.48 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 15.04 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 15.6 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 16.15 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 16.71 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 17.27 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 17.83 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 18.38 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 18.94 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 19.5 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 20.05 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 20.61 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 21.17 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 21.73 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 22.28 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 22.84 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 23.4 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 23.95 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 24.51 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 25.07 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 25.62 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 26.18 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 26.74 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 27.3 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 27.85 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 28.41 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 28.97 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 29.52 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 30.08 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 30.64 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 31.2 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 31.75 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 32.31 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 32.87 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 33.42 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 33.98 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 34.54 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 35.09 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Extracting 35.1 MB\r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Pull complete \r", | |
| "\u001b[7B\u001b[7A\u001b[2K\r", | |
| "bf840a81de99: Pull complete \r", | |
| "\u001b[7B\u001b[6A\u001b[2K\r", | |
| "3667ee957458: Extracting 32 B\r", | |
| "\u001b[6B\u001b[6A\u001b[2K\r", | |
| "3667ee957458: Pull complete \r", | |
| "\u001b[6B\u001b[6A\u001b[2K\r", | |
| "3667ee957458: Pull complete \r", | |
| "\u001b[6B\u001b[5A\u001b[2K\r", | |
| "0f6a3222db0b: Extracting 522.8 kB\r", | |
| "\u001b[5B\u001b[5A\u001b[2K\r", | |
| "0f6a3222db0b: Pull complete \r", | |
| "\u001b[5B\u001b[5A\u001b[2K\r", | |
| "0f6a3222db0b: Pull complete \r", | |
| "\u001b[5B\u001b[4A\u001b[2K\r", | |
| "33e692c74de5: Extracting 32 B\r", | |
| "\u001b[4B\u001b[4A\u001b[2K\r", | |
| "33e692c74de5: Pull complete \r", | |
| "\u001b[4B\u001b[4A\u001b[2K\r", | |
| "33e692c74de5: Pull complete \r", | |
| "\u001b[4B\u001b[3A\u001b[2K\r", | |
| "592ba6bdf6b0: Extracting 32 B\r", | |
| "\u001b[3B\u001b[3A\u001b[2K\r", | |
| "592ba6bdf6b0: Pull complete \r", | |
| "\u001b[3B\u001b[3A\u001b[2K\r", | |
| "592ba6bdf6b0: Pull complete \r", | |
| "\u001b[3B\u001b[14A\u001b[2K\r", | |
| "d69211ce1b82: Download complete \r", | |
| "\u001b[14B\u001b[2A\u001b[2K\r", | |
| "40c1903d7955: Download complete \r", | |
| "\u001b[2B\u001b[2A\u001b[2K\r", | |
| "40c1903d7955: Extracting 32 B\r", | |
| "\u001b[2B\u001b[1A\u001b[2K\r", | |
| "8e9407868fd2: Download complete \r", | |
| "\u001b[1B\u001b[2A\u001b[2K\r", | |
| "40c1903d7955: Pull complete \r", | |
| "\u001b[2B\u001b[2A\u001b[2K\r", | |
| "40c1903d7955: Pull complete \r", | |
| "\u001b[2B\u001b[1A\u001b[2K\r", | |
| "8e9407868fd2: Extracting 154 B\r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "8e9407868fd2: Pull complete \r", | |
| "\u001b[1B\u001b[1A\u001b[2K\r", | |
| "8e9407868fd2: Pull complete \r", | |
| "\u001b[1B\u001b[14A\u001b[2K\r", | |
| "d69211ce1b82: Extracting 32 B\r", | |
| "\u001b[14B\u001b[14A\u001b[2K\r", | |
| "d69211ce1b82: Pull complete \r", | |
| "\u001b[14B\u001b[14A\u001b[2K\r", | |
| "d69211ce1b82: Pull complete \r", | |
| "\u001b[14BStatus: Downloaded newer image for ruby:alpine\r\n", | |
| "docker.io/library/ruby: this image was pulled from a legacy registry. Important: This registry version will not be supported in future versions of docker.\r\n", | |
| " ---> cf8cf45c67be\r\n", | |
| "Step 2 : ARG version\r\n", | |
| " ---> Running in 6c6f0000c0aa\r\n", | |
| " ---> cb50b10feabf\r\n", | |
| "Removing intermediate container 6c6f0000c0aa\r\n", | |
| "Step 3 : RUN gem install sass -v $version\r\n", | |
| " ---> Running in 85866c497a87\r\n", | |
| "Successfully installed sass-3.4.21\r\n", | |
| "1 gem installed\r\n", | |
| " ---> aa53eb2474e2\r\n", | |
| "Removing intermediate container 85866c497a87\r\n", | |
| "Successfully built aa53eb2474e2\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "SASS_VERSION=\"3.4.21\"\n", | |
| "\n", | |
| "cat <<'END' > Dockerfile\n", | |
| "FROM ruby:alpine\n", | |
| "ARG version\n", | |
| "RUN gem install sass -v $version\n", | |
| "END\n", | |
| "docker build -t \"docker-sass:$SASS_VERSION\" --build-arg version=\"$SASS_VERSION\" ." | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "- `--build-arg VERSION=\"$SASS_VERSION\"` provides the `VERSION` env var to the Dockerfile, making it easy to reuse for multiple versions\n", | |
| " - Note that this is different to the Dockerfile directive `ENV`, as it doesn't automatically make the variable available to running containers" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 57, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "body {\r\n", | |
| " font: 100% Helvetica, sans-serif;\r\n", | |
| " color: #333; }\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker run -i --rm \"docker-sass:$SASS_VERSION\" scss <<'END'\n", | |
| "$font-stack: Helvetica, sans-serif;\n", | |
| "$primary-color: #333;\n", | |
| "\n", | |
| "body {\n", | |
| " font: 100% $font-stack;\n", | |
| " color: $primary-color;\n", | |
| "}\n", | |
| "END" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "You can even create an alias so that it looks the same" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 58, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "rbenv: scss: command not found\r\n", | |
| "\r\n", | |
| "The `scss' command exists in these Ruby versions:\r\n", | |
| " 1.9.3-p484\r\n", | |
| " 2.2.3\r\n", | |
| "\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "unalias scss\n", | |
| "scss ~/src/redbubble/app/assets/stylesheets/admin/purchase_order.css.scss | head" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 59, | |
| "metadata": { | |
| "collapsed": false | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "#address_change_container {\r\n", | |
| " box-sizing: border-box;\r\n", | |
| " width: 360px;\r\n", | |
| " height: 100%;\r\n", | |
| " position: fixed;\r\n", | |
| " right: 0;\r\n", | |
| " top: 0;\r\n", | |
| " background-color: #454545;\r\n", | |
| " color: #CCC;\r\n", | |
| " padding: 20px;\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "alias scss=\"docker run -i --rm -v /Users:/Users 'docker-sass:$SASS_VERSION' scss\"\n", | |
| "scss ~/src/redbubble/app/assets/stylesheets/admin/purchase_order.css.scss | head" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "source": [ | |
| "This pattern becomes particularly helpful with more complex utilities, such as the golang compiler. In fact, it's so useful that using Docker to compile golang is their suggested method!" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 60, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [] | |
| } | |
| ], | |
| "source": [ | |
| "rm -rf \"$NEWPWD\"\n", | |
| "cd \"$OLDPWD\"" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# Docker networks\n", | |
| "\n", | |
| "Docker also provides an SDN interface to connect containers. All contaners started on the same network are referrable by their container ID, container name, and \"container name.network name\".\n", | |
| "\n", | |
| "Note that if you've done much Docker before, you would have used the `--link` argument to make contaniers able to talk to each other. This has been deprecated in favour of networks." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 46, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "NETWORK ID NAME DRIVER\r\n", | |
| "35703b333fc9 bridge bridge \r\n", | |
| "f02273f9c232 none null \r\n", | |
| "54f37e6b29df host host \r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker network ls" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 47, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "47ad3d2a61713055444d7b2b4b0e940abecf6162dc805635ff1a0be97858a6be\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker network create docker-training" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 48, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "fragment" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "NETWORK ID NAME DRIVER\r\n", | |
| "47ad3d2a6171 docker-training bridge \r\n", | |
| "35703b333fc9 bridge bridge \r\n", | |
| "f02273f9c232 none null \r\n", | |
| "54f37e6b29df host host \r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker network ls" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 49, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "ca6d14f4c98db4725711ad63ae06d02adfd89e9cd0f16534feff9d0013eee744\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker run -di --name ping-target debian:jessie bash -c read" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "- `-d` daemonize, meaning that we don't attach our std{in,out,err}\n", | |
| "- `-i` interactive, meaning provide stdin for the container\n", | |
| "- `--name` name the contanier so that we can easily remove it later. This will also be the name that we connect to on the network\n", | |
| "- `sh read` read from stdin (in this case, pause and don't do anything until killed)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 50, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker run --rm --net docker-training alpine:3.2 ping -c 2 ping-target" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "We can't ping the container, because it's not on the same network. Note the `--net` argument that automatically connects a container to a network." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 51, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "subslide" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "PING ping-target (172.18.0.2): 56 data bytes\r\n", | |
| "64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.420 ms\r\n", | |
| "64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.085 ms\r\n", | |
| "\r\n", | |
| "--- ping-target ping statistics ---\r\n", | |
| "2 packets transmitted, 2 packets received, 0% packet loss\r\n", | |
| "round-trip min/avg/max = 0.085/0.252/0.420 ms\r\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "docker network connect docker-training ping-target\n", | |
| "docker run --rm --net docker-training alpine:3.2 ping -c 2 ping-target" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "- Connect the `ping-target` container to the `docker-training` network (while it's running)\n", | |
| "- Try, and succeed with the ping" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 52, | |
| "metadata": { | |
| "collapsed": false, | |
| "slideshow": { | |
| "slide_type": "skip" | |
| } | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [] | |
| } | |
| ], | |
| "source": [ | |
| "docker rm -f ping-target >/dev/null\n", | |
| "docker network rm docker-training" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# Compose\n", | |
| "\n", | |
| "> Compose is a tool for defining and running multi-container Docker\n", | |
| "> applications. With Compose, you use a Compose file to configure\n", | |
| "> your application’s services. Then, using a single command, you\n", | |
| "> create and start all the services from your configuration.\n", | |
| ">\n", | |
| "> -- <cite>https://docs.docker.com/compose/overview/</cite>\n", | |
| "\n", | |
| "Put simply, Compose is CloudFormation, or Puppet for Docker. For example, a compose file for Redbubble looks like this:\n", | |
| "\n", | |
| "```yaml\n", | |
| "app:\n", | |
| " build: .\n", | |
| " ports: ['8080:8080']\n", | |
| " links:\n", | |
| " - mysql\n", | |
| " restart: on-failure\n", | |
| " volumes:\n", | |
| " - .:/var/www\n", | |
| " environment:\n", | |
| " DB_MIGRATE: true\n", | |
| "mysql:\n", | |
| " image: 'mysql:5.5'\n", | |
| " environment:\n", | |
| " MYSQL_DATABASE: redbubble\n", | |
| " MYSQL_USER: redbubble\n", | |
| " MYSQL_PASSWORD: letmein\n", | |
| " MYSQL_RANDOM_ROOT_PASSWORD: 1\n", | |
| "```" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "slideshow": { | |
| "slide_type": "slide" | |
| } | |
| }, | |
| "source": [ | |
| "# Swarm\n", | |
| "\n", | |
| "> Docker Swarm is native clustering for Docker. It turns a pool of\n", | |
| "> Docker hosts into a single, virtual Docker host. Because Docker\n", | |
| "> Swarm serves the standard Docker API, any tool that already\n", | |
| "> communicates with a Docker daemon can use Swarm to transparently\n", | |
| "> scale to multiple hosts.\n", | |
| ">\n", | |
| "> -- <cite>https://docs.docker.com/swarm/overview/</cite>\n", | |
| "\n", | |
| "This means that you can use the same Docker commands that you've been using, but it will \"load balance\", and aggregate across multiple hosts. Swarm also integrates with tools like Compose, so you can have a compose file that you start and run across hosts.\n", | |
| "\n", | |
| "Swarm utilizes Docker's networking to create inter-host communication in a way that is transparent to the apps (it's just like using a container on the same host, but with added latency)." | |
| ] | |
| } | |
| ], | |
| "metadata": { | |
| "celltoolbar": "Slideshow", | |
| "kernelspec": { | |
| "display_name": "Bash", | |
| "language": "bash", | |
| "name": "bash" | |
| }, | |
| "language_info": { | |
| "codemirror_mode": "shell", | |
| "file_extension": ".sh", | |
| "mimetype": "text/x-sh", | |
| "name": "bash" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 0 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment