Difference between revisions of "Docker"

From Earlham CS Department
Jump to navigation Jump to search
m
 
(5 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
Docker docs found here: [https://docs.docker.com/]
 
Docker docs found here: [https://docs.docker.com/]
 +
 +
Note that for a user to use Docker, they will need to be added to the docker group.
 +
 +
= Docker on Bowie =
 +
 +
Docker is configured to store all of its container data in '''/docker/docker'''.  '''/docker''' is an LV partition that is specifically devoted to storing docker information.  Any files that relate to docker should be stored here.
 +
 +
== Enabling a user to use Docker ==
 +
 +
To allow a user to use Docker without sudo, a sysadmin may run the command '''$sudo usermod -aG docker $USER''' or, for LDAP accounts, run the add-user-to-group script on the LDAP host.
 +
 +
== Building a docker image ==
 +
 +
To build an image, you must have a dockerfile which specifies how the image is to be built (examples of this can be found in the docker docs).  It is recommended that you keep all the files that you are using to build your image in its own directory.  Once you have everything you need, you can run ''' docker build -t [image_name] .''' from that directory, where '''image_name''' is whatever you want to call the image so you can build it later.
 +
 +
== Seeing what images the system has ==
 +
 +
To see what images the system has stored, use '''docker images ls'''
 +
 +
== Starting a container ==
 +
 +
Once you have a built image that you want to run, you can use '''docker run -d [imagename]'''.  The -d option detaches it from your terminal so you can do other things while it runs.  If you omit it, whatever command the container is told to run will run in your terminal instance.  If you
 +
 +
=== Starting a container with a web server ===
 +
 +
To have a web server run in a docker container and also be accessible from the outside world, there are two additional steps you need
 +
1. In DockerFile when you're creating your image, you must include an '''expose''' line, which tells docker which port to expose.  For example, if you are running a server such as Flask that has a default port of 80, you would include '''expose 80'''
 +
2. When running the image, include the '''-p''' option, which follows the format '''-p [port_on_host]:[port_on_container]''' to tell docker to link the port on the host machine you specified to the port you exposed on the container.  From here, you can navigate to that port in whatever fashion your heart desires and see your webserver
 +
 +
== Stopping a container ==
 +
 +
To stop a container, first run '''docker ps''', find your specific container, and note its' name, which is in the rightmost column.  Then run '''docker kill [container]''' to kill the container.
 +
 +
== Other notes ==
 +
 +
If a given image needs more than one container, you can use docker-compose, which is also installed on Bowie.  The docs (https://docs.docker.com/compose/) contain specifics for how to use it, but it is extremely powerful if used correctly.
 +
 +
If a docker container goes into an exit state with an exit code other than 0 (i.e. exits with an error), you may be able to bring it back to life by checking <code>docker ps -a</code> to get the container ID and then running <code>docker start $containerID</code>. (This is a feature you should hopefully not need but will appreciate if-and-when you do.)
 +
 +
You can see containers past and present with <code>docker ps</code>. If you've run a container, you can use <code>docker inspect</code> to get info about it. For example, you can use these commands to get the start and stop times of a container:
 +
<pre>
 +
$ docker inspect -f '{{ .State.StartedAt }}, {{ .State.FinishedAt }}' 7118aad58721
 +
2021-07-07T14:09:14.088885636Z, 2021-07-07T19:02:54.168847268Z
 +
</pre>
 +
 +
== Example ==
 +
 +
This example demonstrates specifically how to build and run an image with a basic Flask server and is adapted from a guide somewhere online that Laurence can't find anymore.  It assumes an empty directory to start.
 +
 +
The resulting files for this example can be found in '''/home/sysadmin/dockerTests/dtest1''' if you wish to follow along with the results
 +
 +
1. Create a file called app.py and put the code to start your server in it.  In this example, we'll be using the following:
 +
 +
<pre>
 +
from flask import Flask
 +
from redis import Redis, RedisError
 +
import os
 +
import socket
 +
 +
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
 +
 +
app = Flask(__name__)
 +
 +
@app.route("/")
 +
def hello():
 +
    try:
 +
        visits = redis.incr("counter")
 +
    except RedisError:
 +
        visits = "<i>cannot connect to Redis, counter disabled</i>"
 +
 +
    html = "<h3>Greetings {name}!</h3>" \
 +
        "<b>Hostname:</b> {hostname}<br/>" \
 +
        "<b>Visits:</b> {visits}"
 +
    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)
 +
 +
if __name__ == "__main__":
 +
    app.run(host='0.0.0.0', port=80)
 +
</pre>
 +
 +
2. Create a file called '''requirements.txt'''.  and put the following text in it:
 +
 +
<pre>
 +
Flask
 +
Redis
 +
</pre>
 +
 +
This step is only necessary if you are using python.  In general, this is where you put the names of all the packages your program needs to pull via pip.
 +
 +
3. Create a file called '''Dockerfile'''.  This is where you want to put all the information docker needs to create your image and will vary between images.  For this example, put the following in it:
 +
 +
<pre>
 +
from python:3
 +
 +
workdir /app
 +
copy . /app
 +
run pip install --trusted-host pypi.python.org -r requirements.txt
 +
expose 80
 +
env NAME World
 +
CMD ["python", "app.py"]
 +
</pre>
 +
 +
Each line does something very specific.  '''workdir''' tells docker to set the work directory in the container to whatever you give it, in this case '''/app'''.  '''copy''' copies the first file or directory from the host machine into the specified directory on the container.  '''run''' tells docker to run the given command inside the container, in this case telling pip to install everything from requirements.txt.  '''expose''' exposes the given port to the host machine, in this case 80.  '''CMD''' specifies the command to be run once a container based on this image is run.
 +
 +
4. Now it is time to build the container.  Run '''docker build -t friendlyhello .''' to build the container.  You can also substitute whatever name you want for friendlyhello.
 +
 +
5. Once the container is done building, we can actually start it.  For the sake of this example, we will be binding the container's port 80 to Bowie's port 9123, but any unused port on Bowie will work fine.  To start it, run '''docker run -dp 9123:80 friendlyhello'''.  You can also run it without the -d option to have the Flask console run from your terminal, but if you perform an interrupt from there, it will kill the container in the process.
 +
 +
6. From here, you can run '''docker ps''' to see all running containers, which should include the one you just ran.  Note the name in the far right, which is randomly generated by default.  You'll need this when you want to kill the container.  For this example, we'll say it's '''goofy_turing'''.
 +
 +
7.  When you want to kill the container, you can run '''docker kill goofy_turing'''.  That will shut down the container.
 +
 +
= Docker on Krasner =
  
 
Docker is set-up on Krasner in the cluster world. Users can be added to the local group docker via '''$sudo usermod -aG docker $USER''' to gain access to docker and allow the user to run docker commands without sudo.
 
Docker is set-up on Krasner in the cluster world. Users can be added to the local group docker via '''$sudo usermod -aG docker $USER''' to gain access to docker and allow the user to run docker commands without sudo.

Latest revision as of 14:23, 7 July 2021

Docker docs found here: [1]

Note that for a user to use Docker, they will need to be added to the docker group.

Docker on Bowie

Docker is configured to store all of its container data in /docker/docker. /docker is an LV partition that is specifically devoted to storing docker information. Any files that relate to docker should be stored here.

Enabling a user to use Docker

To allow a user to use Docker without sudo, a sysadmin may run the command $sudo usermod -aG docker $USER or, for LDAP accounts, run the add-user-to-group script on the LDAP host.

Building a docker image

To build an image, you must have a dockerfile which specifies how the image is to be built (examples of this can be found in the docker docs). It is recommended that you keep all the files that you are using to build your image in its own directory. Once you have everything you need, you can run docker build -t [image_name] . from that directory, where image_name is whatever you want to call the image so you can build it later.

Seeing what images the system has

To see what images the system has stored, use docker images ls

Starting a container

Once you have a built image that you want to run, you can use docker run -d [imagename]. The -d option detaches it from your terminal so you can do other things while it runs. If you omit it, whatever command the container is told to run will run in your terminal instance. If you

Starting a container with a web server

To have a web server run in a docker container and also be accessible from the outside world, there are two additional steps you need 1. In DockerFile when you're creating your image, you must include an expose line, which tells docker which port to expose. For example, if you are running a server such as Flask that has a default port of 80, you would include expose 80 2. When running the image, include the -p option, which follows the format -p [port_on_host]:[port_on_container] to tell docker to link the port on the host machine you specified to the port you exposed on the container. From here, you can navigate to that port in whatever fashion your heart desires and see your webserver

Stopping a container

To stop a container, first run docker ps, find your specific container, and note its' name, which is in the rightmost column. Then run docker kill [container] to kill the container.

Other notes

If a given image needs more than one container, you can use docker-compose, which is also installed on Bowie. The docs (https://docs.docker.com/compose/) contain specifics for how to use it, but it is extremely powerful if used correctly.

If a docker container goes into an exit state with an exit code other than 0 (i.e. exits with an error), you may be able to bring it back to life by checking docker ps -a to get the container ID and then running docker start $containerID. (This is a feature you should hopefully not need but will appreciate if-and-when you do.)

You can see containers past and present with docker ps. If you've run a container, you can use docker inspect to get info about it. For example, you can use these commands to get the start and stop times of a container:

$ docker inspect -f '{{ .State.StartedAt }}, {{ .State.FinishedAt }}' 7118aad58721
2021-07-07T14:09:14.088885636Z, 2021-07-07T19:02:54.168847268Z

Example

This example demonstrates specifically how to build and run an image with a basic Flask server and is adapted from a guide somewhere online that Laurence can't find anymore. It assumes an empty directory to start.

The resulting files for this example can be found in /home/sysadmin/dockerTests/dtest1 if you wish to follow along with the results

1. Create a file called app.py and put the code to start your server in it. In this example, we'll be using the following:

from flask import Flask
from redis import Redis, RedisError
import os
import socket

redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)

app = Flask(__name__)

@app.route("/")
def hello():
    try:
        visits = redis.incr("counter")
    except RedisError:
        visits = "<i>cannot connect to Redis, counter disabled</i>"

    html = "<h3>Greetings {name}!</h3>" \
        "<b>Hostname:</b> {hostname}<br/>" \
        "<b>Visits:</b> {visits}"
    return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname(), visits=visits)

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=80)

2. Create a file called requirements.txt. and put the following text in it:

Flask
Redis

This step is only necessary if you are using python. In general, this is where you put the names of all the packages your program needs to pull via pip.

3. Create a file called Dockerfile. This is where you want to put all the information docker needs to create your image and will vary between images. For this example, put the following in it:

from python:3

workdir /app
copy . /app
run pip install --trusted-host pypi.python.org -r requirements.txt
expose 80
env NAME World
CMD ["python", "app.py"]

Each line does something very specific. workdir tells docker to set the work directory in the container to whatever you give it, in this case /app. copy copies the first file or directory from the host machine into the specified directory on the container. run tells docker to run the given command inside the container, in this case telling pip to install everything from requirements.txt. expose exposes the given port to the host machine, in this case 80. CMD specifies the command to be run once a container based on this image is run.

4. Now it is time to build the container. Run docker build -t friendlyhello . to build the container. You can also substitute whatever name you want for friendlyhello.

5. Once the container is done building, we can actually start it. For the sake of this example, we will be binding the container's port 80 to Bowie's port 9123, but any unused port on Bowie will work fine. To start it, run docker run -dp 9123:80 friendlyhello. You can also run it without the -d option to have the Flask console run from your terminal, but if you perform an interrupt from there, it will kill the container in the process.

6. From here, you can run docker ps to see all running containers, which should include the one you just ran. Note the name in the far right, which is randomly generated by default. You'll need this when you want to kill the container. For this example, we'll say it's goofy_turing.

7. When you want to kill the container, you can run docker kill goofy_turing. That will shut down the container.

Docker on Krasner

Docker is set-up on Krasner in the cluster world. Users can be added to the local group docker via $sudo usermod -aG docker $USER to gain access to docker and allow the user to run docker commands without sudo.