diff --git a/labs/docker-101/1.md b/labs/docker-101/1.md index 6b9434a..a8ac8cf 100644 --- a/labs/docker-101/1.md +++ b/labs/docker-101/1.md @@ -1,8 +1,8 @@ # Docker 101 - ## Objective -This Learning Lab introduces Docker, a tool suite for building, sharing, and deploying containers. For more information about containers, see the [Containers-101](https://developer.cisco.com/learning/lab/containers-101/step/1) Lab. Use this Learning Lab to build, deploy, and optionally share your first Docker container. +This Learning Lab introduces Docker, a tool suite for building, sharing, and deploying containers. Use this Learning Lab to build, deploy, and optionally share your first Docker container. For more information about containers, see the [Containers-101](https://developer.cisco.com/learning/lab/containers-101/step/1) Lab. +Further reading is available in the excellent Docker introduction at [imapex.io](https://github.com/imapex-training/mod_adv_docker/blob/master/README.md). ## For best results This is a hands-on Lab, but each example builds on the previous and explains why you run the commands. If you just skip to each command to run, without reading the text in between, you will not learn anything. @@ -14,10 +14,6 @@ This is a hands-on Lab, but each example builds on the previous and explains why * System Architects and Engineers * IT teams addressing developer needs for Docker and Containers -## Content Notice - -Thanks to the Cisco Live EU 2017 workshop "Introduction to Containers" for portions of this Learning Lab. Further reading is available in the excellent docker introduction at [imapex.io](https://github.com/imapex-training/mod_adv_docker/blob/master/README.md). - ## Prerequisite * Install Docker on your system. @@ -69,7 +65,7 @@ The play-with-docker.com site provides access to a full VM running Docker direct The simplest way to use Docker is to run an existing public image that's available from [Docker Hub](https://hub.docker.com/). -Docker Hub is a public exchange for sharing Docker containers. Other Docker sharing sites are available, but we'll take advantage of the fact that Docker's command-line interface searches DockerHub by default. +Docker Hub is a public exchange for sharing Docker containers. Other Docker sharing sites are available, but we'll take advantage of the fact that Docker's command-line interface searches Docker Hub by default. To run a publicly-available Docker Container, follow these steps: @@ -79,7 +75,7 @@ To run a publicly-available Docker Container, follow these steps: ![docker search hello-world](assets/images/dockersearch.png) - Docker searches the public DockerHub repositories and finds the "hello-world" image. + Docker searches the public Docker Hub repositories and finds the "hello-world" image. You can see that Docker has found the "hello-world" image. Let's run it. 2. Execute the following command to run the hello-world: @@ -88,7 +84,7 @@ To run a publicly-available Docker Container, follow these steps: ![docker run hello-world](assets/images/dockerrun1.png) - Docker first checks to see whether the "hello-world" image is available locally. If not, Docker automatically downloads it from DockerHub. Docker sets up the container to run locally, ensuring its isolation from other processes. Once the preparations are made, Docker runs the image. + Docker first checks to see whether the "hello-world" image is available locally. If not, Docker automatically downloads it from Docker Hub. Docker sets up the container to run locally, ensuring its isolation from other processes. Once the preparations are made, Docker runs the image. Congratulations! You just ran your first Docker container! diff --git a/labs/docker-101/2.md b/labs/docker-101/2.md index edf7d86..ef438e8 100644 --- a/labs/docker-101/2.md +++ b/labs/docker-101/2.md @@ -1,6 +1,6 @@ # Get or create a Docker image -How did the author of "hello-world" create the container image? Because it's available on the public DockerHub repository, we can find out by inspecting the files. +How did the author of "hello-world" create the container image? Because it's available on the public Docker Hub repository, we can find out by inspecting the files. Browse to [the "hello world" web page](https://hub.docker.com/_/hello-world/) to see details describing the Docker image. @@ -14,7 +14,7 @@ Among those details is a link to the __Dockerfile__, the file that defines the i Every Docker image, from a simple one like "hello-world" to a complex application, is defined by a __Dockerfile__. The Dockerfile is a text file that lists the programs and resources that become part of the Docker image and which instructs Docker what to do when the container runs. An author creates a Docker image by assembling application source code and other resource files and writing a Dockerfile that turns them into a working container image. -To create the container image, the author executes the `docker build` command from the directory that contains the Dockerfile. Docker reads the Dockerfile and follows the instructions in it to build the container image. Once the Docker image is built, the author can push it to the public repository on DockerHub, making it available to everyone. +To create the container image, the author executes the `docker build` command from the directory that contains the Dockerfile. Docker reads the Dockerfile and follows the instructions in it to build the container image. Once the Docker image is built, the author can push it to the public repository on Docker Hub, making it available to everyone. Most container authors store their Dockerfiles in a version-control repository along with the files used in building their images. Storing a Dockerfile along with the files that it uses to build a container simplifies both the Dockerfile itself and the process of building the container image. @@ -72,13 +72,13 @@ On the one hand, building a whole userspace into a container means that the cont On the other hand, it means that even a complex application with many dependencies can be delivered in the form of a container image. The container can even include operating-system package-management software like APT or YUM for use in configuring optional dependencies. -Suppose you want to build a container image that includes the whole Ubuntu system. Begin by searching DockerHub for a suitable container to start with: +Suppose you want to build a container image that includes the whole Ubuntu system. Begin by searching Docker Hub for a suitable container to start with: ``` docker search ubuntu ``` -We're in luck; DockerHub has an existing Ubuntu container. +We're in luck; Docker Hub has an existing Ubuntu container. Run the container: @@ -86,11 +86,11 @@ Run the container: docker run -ti ubuntu ``` -The example command downloads and runs the Ubuntu container from DockerHub. The command-line flags "-ti" tell Docker that we want to interact with a shell in the running image. As soon as the image finishes launching it dutifully presents us with a shell: +The example command downloads and runs the Ubuntu container from Docker Hub. The command-line flags "-ti" tell Docker that we want to interact with a shell in the running image. As soon as the image finishes launching it dutifully presents us with a shell: ![Ubuntu shell](assets/images/ubuntu1.png) -# Testing Isolation. +# Testing Isolation The processes that run in a Docker container are completely isolated from the outside world. Files and processes on the host machine are invisible to the application in the container. The container application can't create or interact with any files or other resources outside the container. @@ -125,7 +125,7 @@ It's important to remember that changes to a running Docker container do not sur # The Ubuntu Dockerfile -Let's look at the Dockerfile that built the Ubuntu image. You can find an Ubuntu Dockerfile at [DockerHub](https://github.com/tianon/docker-brew-ubuntu-core/blob/7a8f63add8a1003a6f77bbcf00e4d408ea96ca1b/bionic/Dockerfile). +Let's look at the Dockerfile that built the Ubuntu image. You can find an Ubuntu Dockerfile at [Docker Hub](https://github.com/tianon/docker-brew-ubuntu-core/blob/7a8f63add8a1003a6f77bbcf00e4d408ea96ca1b/bionic/Dockerfile). Click the link to the Dockerfile just as we did with the "hello-world" image. The Ubuntu DockerFile is more complex, as we would expect, but the concepts are exactly the same: diff --git a/labs/docker-101/3.md b/labs/docker-101/3.md index bc4f8ea..a677116 100644 --- a/labs/docker-101/3.md +++ b/labs/docker-101/3.md @@ -1,132 +1,130 @@ # Building a Docker Image -Next we'll build our own Ubuntu Docker image instead of using the one from DockerHub. +Next we'll build our own Ubuntu Docker image instead of using the one from Docker Hub. -1. __Download the files__. Begin by downloading the Ubuntu Dockerfile and its dependencies. +1. Download the Ubuntu Dockerfile and its dependencies. ``` git clone --single-branch --branch dist-amd64 https://github.com/tianon/docker-brew-ubuntu-core.git ``` -2. __Check the Dockerfile__. Change directory to the cloned repository and ensure that the Dockerfile is present. +2. Change directory to the cloned repository and ensure that the Dockerfile is present. ``` cd docker-brew-ubuntu-core/xenial ls . ``` -3. __Build a new image using Docker and the Dockerfile__. +3. Build a new image using Docker and the Dockerfile. ``` docker build . ``` Docker prints progress messages as it builds the Ubuntu image. Once it finishes building the image, Docker assigns it a randomly-chosen name. -4. __Run the command `docker images`__. Docker lists all the images on your system, including both the newly-built one and any that you previously downloaded. You can tell which image is the one you just created by examining the list; it's the only image that isn't associated with a repository: +4. Run the command `docker images`. + Docker lists all the images on your system, including both the newly-built one and any that you previously downloaded. You can tell which image is the one you just created by examining the list; it's the only image that isn't associated with a repository: ![Docker Images](assets/images/images1.png) -5. __Run the new image__. Run the newly created docker image by giving the randomly-chosen ID to Docker: +5. Run the newly created Docker image by giving the randomly-chosen ID to Docker: ``` docker run -ti ``` - The newly-created image behaves exactly the same way as the Ubuntu image from Dockerhub because was built from the same Dockerfile. You now have a bash root prompt. Enter ``ls`` to confirm standard Ubuntu directories are installed. + The newly-created image behaves exactly the same way as the Ubuntu image from Dockerhub, because it is built from the same Dockerfile. You now have a bash root prompt. + + 6. Enter ``ls`` to confirm standard Ubuntu directories are installed. # Building a Custom Cisco Learning Labs Container -To modify the image that we just built, all we have to do is change the Dockerfile and ensure that any needed resources are available in the repository. Let's make an image that's more specific to our application's needs. +To modify the image that we just built, all we have to do is change the Dockerfile and ensure that all required resources are available in the repository. Let's make an image that's more specific to our application's needs. -I'm currently sitting in at Cisco LIVE! Europe 2017 in the wonderful -city of Berlin, so let's change the image to say that when it runs: +Let's change the image to display the following message: -![Custom Docker Output](assets/images/hellocustom1.png) + ``` + Hello from DevNet! + ``` -To make the image display that message we will: +To make the image display the above message we will: 1. Create a new Python script. 2. Edit the Dockerfile to include that script in the container build. -3. Change the Dockerfile to install python in the container (remember, -all dependencies must be present in the container). +3. Change the Dockerfile to install Python in the container (remember, all dependencies must be present in the container). 4. Build and test the new container. -You have a choice young Jedi: -You can either +To update the image, follow the below instructions: -* Copy and paste following Dockerfile commands -* Type them into the file manually -* Download the Github repository that contains them +1. Clone the Github repository that contains the Dockerfile for this section using the following command: -To clone the Github repository that contains the Dockerfile for this -section using the following command: + ``` + git clone https://github.com/CiscoDevNet/container-intro-devnet.git + cd container-intro-devnet + ``` -``` -git clone https://github.com/CiscoDevNet/container-intro-devnet.git -cd container-intro-devnet -``` + The cloned repository contains these files: -The cloned repository contains two files: + * hellodevnet.py + * Dockerfile -* hellodevnet.py -* Dockerfile + The "hellodevnet.py" file is our custom application. It contains the following Python code: -The "hellodevnet.py" file is our custom application. It contains the -following Python code: + ``` python + #!/usr/bin/env python + print("Hello from DevNet!") + ``` -``` python -#!/usr/bin/env python + The Dockerfile contains the instructions required to build the custom image: -print("Hello from DevNet!") -``` + ``` + FROM ubuntu + RUN apt-get update + RUN apt-get -y install python + COPY hellodevnet.py /hellodevnet.py + RUN ["chmod", "+x", "/hellodevnet.py"] + CMD ["/hellodevnet.py"] + ``` -The Dockerfile contains the instructions needed to build the custom -image: + This Dockerfile says: -``` -FROM ubuntu -RUN apt-get update -RUN apt-get -y install python -ADD hellodevnet.py /hellodevnet.py -CMD ["/hellodevnet.py"] -``` + 1. `FROM ubuntu` + Extend the existing ubuntu public Docker image. Our previous examples built an image from scratch. In this case we begin with a previously-built container image and extend with our own customisations. -This Dockerfile says: + 2. `RUN apt-get update` + Ensure the package-management tools in the base Ubuntu container are updated to use the latest software. -1. `FROM ubuntu` - Extend the existing ubuntu public docker image. Our previous - examples built an image from scratch. In this case we begin with a - previously-built container image and extend with our own - customisations. + 3. `RUN apt-get -y install python` + Use apt-get to install Python and all its dependencies in the container. The reason to build this container on an existing Ubuntu image is that we could use apt-get to install needed software. -2. `RUN apt-get update` - Ensure the package-management tools in the base Ubuntu container - are updated to use the latest software. + 4. `COPY hellodevnet.py /hellodevnet.py` + Copy the Python program from the local directory into the container as `/hellodevnet.py`. + + 5. `RUN ["chmod", "+x", "/hellodevnet.py"]` + Grant permission to execute the `/hellodevnet.py` file + + 6. `CMD ["/hellodevnet.py"]` + Run the Python program when the container starts up. + + >**Note:** Instead of cloning this GitHub repository, you can also add the above mentioned Python code in the hellodevnet.py file and Dockerfile commands in the Dockerfile using the `vi` command in the terminal and continue with step 2. + +2. Build the Docker image using the following command: -3. `RUN apt-get -y install python` - Use apt-get to install Python and all its dependencies in the - container. The reason to build this container on an existing Ubuntu - image was so that we could use apt-get to install needed software. + ``` + docker build . + ``` + Docker prints progress messages as it builds the Ubuntu image. Once it finishes building the image, Docker displays `Succesfully built `. + Make note of the newly built container ID so that you can use it in the next step. + +3. Run the new container using the following command. + Use the container ID that you recieved from the `docker build .` command output. -4. `ADD hellodevnet.py /hellodevnet.py` - Copy our Python program from the local directory into the container - as `/hellodevnet.py`. + ``` + docker run + ``` + The "Hello from DevNet!" message is displayed in the container terminal. + + ![](assets/images/docker-image-new.png) -5. `CMD ["/hellodevnet.py"]` - Run our Python program when the container starts up. +Congratulations, you've just built and run a custom Docker image! -That's all there is to it! Now let's actually build the new container image. - -``` -docker build . -``` - -![Custom Docker Build](assets/images/dockerbuildcustom.png) - -After the Docker build completes you can run the new Container. When -you do, you should see the "hello" message displayed in the container -terminal. - -Congratulations, you've just built and run a custom docker image! - -Now let's build a container image that does something more useful: how -about a container that runs a web server? +Now let's build a container image that does something more useful: how about a container that runs a web server? diff --git a/labs/docker-101/4.md b/labs/docker-101/4.md index 7a4be8d..b4ec55f 100644 --- a/labs/docker-101/4.md +++ b/labs/docker-101/4.md @@ -1,135 +1,116 @@ -# Building w web server container +# Building a web server container -A Docker container image can run any application you like. Let's build -one that runs a web server. The web server will run whenever the -container image starts up. +A Docker container image can run any application you like. Let's build one that runs a web server. The web server will run whenever the container image starts up. -The following python command creates and starts a simple web server: +The following Python command creates and starts a simple web server: ``` python -m SimpleHTTPServer 8000 ``` -To build a container that runs this web server we need only change the -`CMD` line of the Dockerfile—the line that controls the program -that runs when the container starts. +To build a container that runs this web server we need to change the `CMD` line of the Dockerfile, the line that controls the program that runs when the container starts. -The new Dockerfile looks like this: +1. Change to new directory and update the following commands in the Dockerfile: -``` -FROM ubuntu -RUN apt-get update -RUN apt-get -y install python -EXPOSE 8000 -ENTRYPOINT ["python", "-m", "SimpleHTTPServer", "8000"] -``` + ``` + FROM ubuntu + RUN apt-get update + RUN apt-get -y install python + EXPOSE 8000 + ENTRYPOINT ["python", "-m", "SimpleHTTPServer", "8000"] + ``` -The first three lines are familiar. The last two introduce new -Dockerfile options. + The first three lines are familiar. The last two lines introduce the new Dockerfile options. -* EXPOSE 8000 - The EXPOSE command allows us as developers to "build in" documentation of - what ports our application uses. Running this container in future with `-P` - will automatically map any `EXPOSE` ports in the Dßockerfile to a dynamic port - on our hosts real IP, allowing real remote connections to our service if necessary. - You can see what port has been mapped by using the `docker ps` command as below: + * EXPOSE 8000 + The EXPOSE command allows us as developers to "build in" documentation of what ports our application uses. Running this container in future with `-P` will automatically map any `EXPOSE` ports in the Dockerfile to a dynamic port on our hosts real IP, allowing real remote connections to our service if necessary. You can see what port has been mapped by using the `docker ps` command as below: - ``` - docker run -P 86edbfe17927 & - [1] 18291 + ``` + docker run -P 86edbfe17927 & + [1] 18291 - docker ps - CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES - 7edf98bc653b 86edbfe17927 "/app/myApp.py" 3 seconds ago Up 2 seconds 0.0.0.0:32768->5000/tcp jolly_mestorf + docker ps + CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES + 7edf98bc653b 86edbfe17927 "/app/myApp.py" 3 seconds ago Up 2 seconds 0.0.0.0:32768->5000/tcp jolly_mestorf - curl localhost:32768 - 172.17.0.1 - - [18/Jan/2019 12:40:17] "GET / HTTP/1.1" 200 - - Hello Cisco - ``` + curl localhost:32768 + 172.17.0.1 - - [18/Jan/2019 12:40:17] "GET / HTTP/1.1" 200 - + Hello Cisco + ``` * ENTRYPOINT [“python”, “-m”, “SimpleHTTPServer”, “8000”] - Like CMD, the ENTRYPOINT command runs a program, but it also does - something else: it enables us to pass arguments to the program. We - use this feature to pass arguments to Python to start the web server. + Like CMD, the ENTRYPOINT command runs a program, but it also does something else: it enables us to pass arguments to the program. We use this feature to pass arguments to Python to start the web server. -Save the Dockerfile in a new directory and build the new web server -container image: +2. Build and run the new web server container image using the following command: -``` -docker build . -docker run -P & -``` + ``` + docker build . + docker run -P & + ``` -Why don't we see any output? + Why don't we see any output? -Every time before when we started a container we saw output from the -container's application. The reason we see no output this time is that -our application, a web server, doesn't print any. So how do we know -whether it's running correctly? + Every time before when we started a container we saw output from the container's application. The reason we see no output this time is that our application, a web server, doesn't print any message. So how do we know whether it's running correctly? -Run the following Docker command: +3. Run the following Docker command to check if the new web server image is running: -``` -docker ps -``` + ``` + docker ps + ``` -The command lists all running containers—including the new -web server image that we created: + The command lists all running containers including the new web server image that we created: -![docker ps](assets/images/dockerpsweb.png) + ![docker ps](assets/images/dockerpsweb.png) -The web server is running. Now how do we connect to it? + The web server is running. Now how do we connect to it? -By default Docker gives each container an internal IP address on the -host. We can find out our container's IP address by running `docker -inspect `. Running this command displays a great deal of -information about the container. Included in the output is the -container's address, identified as "IPAddress": + By default Docker gives each container an internal IP address on the host. + Make note of the container ID of the new web server image so that you can use it in the next step. + +4. Run the following command to find out the container's IP address. + You can use the container ID of the new web server image that is received from the `docker ps` command output. -![Docker Inspect](assets/images/dockerinspect.png) + ``` + docker inspect + ``` + Running this command displays a great deal of information about the container. Included in the output is the container's address, identified as "IPAddress". + + ![Docker Inspect](assets/images/dockerinspect.png) -Now that we know the IP address and port on which the web server can be -reached, we can make a connection. + Now that we know the IP address and port on which the web server can be reached, we can make a connection. + Make note of the IP address of the container so that you can use it in the next step. + +5. Run the following command to make the connection. + You can use the IP address of the container that is received from the `docker inspect ` command output. -``` -curl http://:8000 -``` + ``` + curl http://:8000 + ``` -The built-in Python web server by default serves the contents of its -working directory. Because our Dockerfile copied the Python script to -the root of the container, that's the directory that the web server -displays: + The built-in Python web server by default serves the contents of its working directory. Because the Dockerfile copied the Python script to the root of the container, that's the directory that the web server displays: -![Success](assets/images/success.png) + ![Success](assets/images/success.png) -Success! We can see the web server running in the container that we -created, and when we connect to the web server it shows a list of the -files in the container's root directory. +Success! We can see the web server running in the container that we created, and when we connect to the web server it shows a list of the files in the container's root directory. ## Extra credit -You now know how to `ADD` files to the Docker build process. If you -create a file named "index.html", add some HTML text to it, then use -the Dockerfile to add it to the root of the container, guess what the -new web server container will serve instead of the directory listing? +You now know how to `ADD` files to the Docker build process. If you create a file named "index.html", add some HTML text to it, then use the Dockerfile to add it to the root of the container, guess what the new web server container will serve instead of the directory listing? Give it a try! # Summary -In this learning lab we have: +In this Learning Lab we have: -* Understood how Docker images are built using Dockerfiles +* Understood how Docker images are built using Dockerfiles. -* Understood how publicly-available Docker images are built by viewing - their Dockerfiles +* Understood how publicly-available Docker images are built by viewing their Dockerfiles. -* Built and ran our own Docker images +* Built and ran our own Docker images. -* Connected to a web server running in a custom Docker container that - we built +* Connect to a web server running in a custom Docker container that we built. -Give yourself a pat on the back, grab a coffee and enjoy the related -Labs. +Give yourself a pat on the back, grab a coffee and enjoy the related Labs. That's all folks! diff --git a/labs/docker-101/assets/images/docker-image-new.png b/labs/docker-101/assets/images/docker-image-new.png new file mode 100644 index 0000000..e92e0cc Binary files /dev/null and b/labs/docker-101/assets/images/docker-image-new.png differ diff --git a/labs/docker-101/byod.html b/labs/docker-101/byod.html index 03f2e66..cd7fa9c 100644 --- a/labs/docker-101/byod.html +++ b/labs/docker-101/byod.html @@ -1,2 +1 @@ -< div > -

No additional configuration required.

+

No additional configuration required.