DockerInAction-Running software in containers
来源:互联网 发布:ubuntu glib 安装 编辑:程序博客网 时间:2024/06/09 17:46
Getting help with the Docker command line
docker help
gives you only high-level information about what commands are available. To get detailed information about a specific command, include the command in the COMMAND argument.
docker help cp
That will display a usage pattern for docker cp
, a general description of what the command does, and a detailed breakdown of its arguments.
Controlling containers: building a website monitor
This example uses three containers. The first will run NGINX; the second will run a program called a mailer. Both of these will run as detached containers. Detached
means that the container will run in the background, without being attached to any input or output stream. A third program, called an agent, will run in an interactive container.
Creating and starting a new container
docker run --detach \ --name web nginx:latest # Note the detach flag
When you run this command, Docker will install nginx:latest from the NGINX repository hosted on Docker Hub and run the software.
Running detached containers is a perfect fit for programs that sit quietly in the background. That type of program is called a daemon
.
docker run -d \ --name mailer \ # Start detached
This command uses the short form of the --detach
flag to start a new container named mailer in the background.
Running interactive containers
docker run --interactive --tty \ --link web:web \ --name web_test \ busybox:latest /bin/sh # Create a virtual terminal and bin stdin
The command uses two flags on the run
command: –interactive (or -i) and –-tty (or –t). First, the --interactive
option tells Docker to keep the standard input stream (stdin) open for the container even if no terminal is attached. Second, the --tty
option tells Docker to allocate a virtual terminal for the container, which will allow you to pass signals to the container.
To finish the work for your client, you need to start an agent. This is a monitoring agent that will test the web server as you did in the last example and send a message with the mailer if the web server stops.
docker run -it \ --name agent \ --link web:insideweb \ --link mailer:insidemailer \ dockerinaction/ch2_agent # Create a virtual terminal and bind stdin
Listing, stopping, restarting, and viewing output of containers
docker ps
Running the command will display the following information about each running container:
- The container ID
- The image used
- The command executed in the container
- The time since the container was created
- The duration that the container has been running
- The network ports exposed by the container
- The name of the container
At this point you should have three running containers with names: web, mailer, and agent.
Choose the appropriate ones to restart the containers that were missing from the list of running containers.
docker restart webdocker restart mailerdocker restart agent
Examine the logs for each container. Start with the web container:
docker logs web
That should display a long log with several lines that contain this substring:
"GET / HTTP/1.0" 200
Examine the log output for mailer and agent as well:
docker logs mailerdocker logs agent
The docker logs
command has a flag, --follow
or -f
, that will display the logs and then continue watching and updating the display with changes to the log as they occur.
The docker stop
command tells the program with PID #1 in the container to halt.
docker stop web # Stop the web server by stopping the containerdocker logs mailer # Wait a couple seconds and check the mailer logs
Look for a line at the end of the mailer logs that reads like:
“Sending email: To: admin@work Message: The service is down!”
Solved problems and the PID namespace
docker run -d --name namespaceA \ busybox:latest /bin/sh -c "sleep 30000"docker run -d --name namespaceB \ busybox:latest /bin/sh -c "nc -l -p 0.0.0.0:80"docker exec namespaceA ps # 1docker exec namespaceB ps # 2
Command 1 above should generate a process list similar to the following:
PID USER COMMAND 1 root /bin/sh -c sleep 30000 5 root sleep 30000 6 root ps
Command 2 above should generate a slightly different process list:
PID USER COMMAND 1 root /bin/sh -c nc -l -p 0.0.0.0:80 7 root nc -l -p 0.0.0.0:80 8 root ps
Without a PID namespace, the processes running inside a container would share the same ID space as those in other containers or on the host. A container would be able to determine what other processes were running on the host machine. Worse, namespaces transform many authorization decisions into domain decisions. That means processes in one container might be able to control processes in other containers.
Like most Docker isolation features, you can optionally create containers without their own PID namespace. You can try this yourself by setting the --pid
flag on docker create
or docker run
and setting the value to host.
docker run --pid host busybox:latest ps # Should list all processes running on the computer
This is a basic software conflict example. You can see it in action by trying to run two copies of NGINX in the same container:
docker run –d --name webConflict nginx:latestdocker logs webConflict # The output should be emptydocker exec webConflict nginx -g 'daemon off;' # Start a second nginx process in the same container
The last command should display output like:
2015/03/29 22:04:35 [emerg] 10#0: bind() to 0.0.0.0:80 failed (98:Address already in use)nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)...
Run each in a different container, like this:
docker run -d --name webA nginx:latest # Start the first nginx instancedocker logs webA # Verify that it is working, should be emptydocker run -d --name webB nginx:latest # Start the second instancedocker logs webB # Verify that it is working, should be empty
Eliminating metaconflicts: building a website farm
Flexible container identification
docker run -d --name webid nginx # Create a container named "webid"docker run -d --name webid nginx # Create another container named "webid"
The second command here will fail with a conflict error:
FATA[0000] Error response from daemon: Conflict. The name "webid" isalready in use by container 2b5958ba6a00. You have to delete (or rename)that container to be able to reuse that name.
By default Docker assigns a unique (human-friendly) name to each container it creates. You can always rename the container with the docker rename
command:
docker rename webid webid-old # Rename the current web container to "webid-old"docker run -d --name webid nginx # Create another container named "webid"
In addition to the name, Docker assigns a unique identifier that was mentioned in the first example. These are hex-encoded 1024-bit numbers and look something like this:
7cb5d2b9a7eab87f07182b5bf58936c9947890995b1b94f412912fa822a9ecb5
You can use these identifiers in place of the container name with any command that needs to identify a specific container. For example, you could use the previous ID with a stop
or exec
command:
docker exec \ 7cb5d2b9a7eab87f07182b5bf58936c9947890995b1b94f412912fa822a9ecb5 \psdocker stop \ 7cb5d2b9a7eab87f07182b5bf58936c9947890995b1b94f412912fa822a9ecb5
In most Docker interfaces, you’ll see container IDs truncated to their first 12 characters. So the previous two commands could be written like this:
docker exec 7cb5d2b9a7ea psdocker stop 7cb5d2b9a7ea
When a new container is started in detached mode, the container ID will be written to the terminal (stdout).
docker create nginx
The result should be a line like:
b26a631e536d3caae348e9fd36e7661254a11511eb2274fb55f9f7c788721b0d
You can simply assign that result to a shell variable and use it again later:
CID=$(docker create nginx:latest) # This will work on POSIX-compliant shellsecho $CID
Both the docker run
and docker create
commands provide another flag to write the ID of a new container to a known file:
docker create --cidfile /tmp/web.cid nginx # Create a new stopped containercat /tmp/web.cid # Inspect the file
For example, if you want to get the truncated ID of the last created container, you can use this:
CID=$(docker ps --latest --quiet) # This will work on POSIX-compliant shellsecho $CIDCID=$(docker ps -l –q) # Run again with the short-form flagsecho $CID
If you want to get the full container ID, you can use the --no-trunc
option on the docker ps
command.
Container state and dependencies
MAILER_CID=$(docker run -d dockerinaction/ch2_mailer) # Make sure mailer from first example is runningWEB_CID=$(docker create nginx)AGENT_CID=$(docker create --link $WEB_CID:insideweb \ --link $MAILER_CID:insidemailer \ dockerinaction/ch2_agent)
Neither of the new containers you started appears in the list of containers because docker ps shows only running containers by default. Those containers were specifically created with docker create
and never started (the exited state). To see all the containers (including those in the exited state), use the -a
option:
docker ps -a
Now that you’ve verified that both of the containers were created, you need to start
them. For that you can use the docker start
command:
docker start $AGENT_CIDdocker start $WEB_CID
Docker reported a message like this one:
Error response from daemon: Cannot start container 03e65e3c6ee34e714665a8dc4e33fb19257d11402b151380ed4c0a5e38779d0a: Cannot link to a non running container: /clever_wright AS /modest_hopper/ insidewebFATA[0000] Error: failed to start one or more containers
You need to start the web container first:
docker start $WEB_CIDdocker start $AGENT_CID
The link mechanism
injects IP addresses into dependent containers, and containers that aren’t running don’t have IP addresses.
Whether you’re using docker run
or docker create
, the resulting containers need to be started in the reverse order of their dependency chain.
At this point you can put everything together into one concise script that looks like the following:
MAILER_CID=$(docker run -d dockerinaction/ch2_mailer)WEB_CID=$(docker run -d nginx)AGENT_CID=$(docker run -d \ --link $WEB_CID:insideweb \ --link $MAILER_CID:insidemailer \ dockerinaction/ch2_agent)
Building environment-agnostic systems
Docker has three specific features to help build environment-agnostic systems:
- Read-only file systems
- Environment variable injection
- Volumes
Read-only file systems
Using the --read-only
flag:
docker run -d --name wp --read-only wordpress:4docker inspect --format "{{.State.Running}}" wp
The docker inspect
command will display all the metadata (a JSON document) that Docker maintains for a container.
In this case, the container isn’t running. To determine why, examine the logs for the container:
docker logs wp
That should output something like:
error: missing WORDPRESS_DB_HOST and MYSQL_PORT_3306_TCP environment variablesDid you forget to --link some_mysql_container:mysql or set an external db with -e WORDPRESS_DB_HOST=hostname:port?
You can install MySQL using Docker just like WordPress:
docker run -d --name wpdb \ -e MYSQL_ROOT_PASSWORD=ch2demo \ mysql:5
Once that is started, create a different WordPress container that’s linked to this new database container:
docker run -d --name wp2 \ # Use a unique name --link wpdb:mysql \ # Create a link to the database -p 80 --read-only \ wordpress:4
Check one more time that WordPress is running correctly:
docker inspect --format "{{.State.Running}}" wp2
You can tell that WordPress failed to start again. Examine the logs to determine the cause:
docker logs wp2
There should be a line in the logs that is similar to the following:
... Read-only file system: AH00023: Couldn't create the rewrite-map mutex(file /var/lock/apache2/rewrite-map.1)
You need to use a volume to make that exception.
# Start the container with specific volumes for read only exceptionsdocker run -d --name wp3 --link wpdb:mysql -p 80 \ -v /run/lock/apache2/ \ # Create specific volumes for writeable space -v /run/apache2/ \ --read-only wordpress:4
An updated version of the script you’ve been working on should look like this:
SQL_CID=$(docker create -e MYSQL_ROOT_PASSWORD=ch2demo mysql:5)docker start $SQL_CIDMAILER_CID=$(docker create dockerinaction/ch2_mailer)docker start $MAILER_CIDWP_CID=$(docker create --link $SQL_CID:mysql -p 80 \ -v /run/lock/apache2/ -v /run/apache2/ \ --read-only wordpress:4)docker start $WP_CIDAGENT_CID=$(docker create --link $WP_CID:insideweb \ --link $MAILER_CID:insidemailer \ dockerinaction/ch2_agent)docker start $AGENT_CID
Environment variable injection
docker run --env MY_ENVIRONMENT_VAR="this is a test" \ # Inject an environment variable busybox:latest \ env # Execute the env command inside the container
The --env
flag or -e
for short—can be used to inject any environment variable.
You’ll need to use environment variable injection to set the database name for each independent site:
docker create --link wpdb:mysql \ -e WORDPRESS_DB_NAME=client_a_wp wordpress:4 # For client Adocker create --link wpdb:mysql \ -e WORDPRESS_DB_NAME=client_b_wp wordpress:4 # For client B
First, set the computer to run only a single MySQL container:
DB_CID=$(docker run -d -e MYSQL_ROOT_PASSWORD=ch2demo mysql:5)MAILER_CID=$(docker run -d dockerinaction/ch2_mailer)
Then the site provisioning script would be this:
if [ ! -n "$CLIENT_ID" ]; then # Assume $CLIENT_ID variable is set as input to script echo "Client ID not set” exit 1fiWP_CID=$(docker create \ --link $DB_CID:mysql \ # Create link using DB_CID --name wp_$CLIENT_ID \ -p 80 \ -v /run/lock/apache2/ -v /run/apache2/ \ -e WORDPRESS_DB_NAME=$CLIENT_ID \ --read-only wordpress:4)docker start $WP_CIDAGENT_CID=$(docker create \ --name agent_$CLIENT_ID \ --link $WP_CID:insideweb \ --link $MAILER_CID:insidemailer \ dockerinaction/ch2_agent)docker start $AGENT_CID
Building durable containers
Automatically restarting containers
Using the --restart
flag at container-creation time, you can tell Docker to do any of the following:
- Never restart (default)
- Attempt to restart when a failure is detected
- Attempt for some predetermined time to restart when a failure is detected
- Always restart the container regardless of the condition
Docker uses an exponential backoff strategy for timing restart attempts.
docker run -d --name backoff-detector --restart always busybox date
Then after a few seconds use the trailing logs feature to watch it back off and restart:
docker logs -f backoff-detector
Keeping containers running with supervisor and startup processes
A supervisor process, or init process, is a program that’s used to launch and maintain the state of other programs. On a Linux system, PID #1 is an init process. It starts all the other system processes and restarts them in the event that they fail unexpectedly.
Using a supervisor process inside your container will keep the container running in the event that the target process—a web server, for example—fails and is restarted.
Start an example container:
docker run -d -p 80:80 --name lamp-test tutum/lampdocker top lamp-test
The top subcommand will show the host PID for each of the processes in the container.
To get that list, run the following exec subcommand:
docker exec lamp-test ps
The process list generated will have listed apache2 in the CMD column:
PID TTY TIME CMD1 ? 00:00:00 supervisord433 ? 00:00:00 mysqld_safe835 ? 00:00:00 apache2842 ? 00:00:00 ps
docker exec lamp-test kill <PID>
Running this command will run the Linux kill program inside the lamp-test container and tell the apache2 process to shut down. The container logs will clearly show these events:
...... exited: apache2 (exit status 0; expected)... spawned: 'apache2' with pid 820... success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
A common alternative to the use of init or supervisor programs is using a startup script
that at least checks the preconditions for successfully starting the contained software. These are sometimes used as the default command for the container. For example, the WordPress containers that you’ve created start by running a script to validate and set default environment variables before starting the WordPress process. You can view this script by overriding the default command and using a command to view the contents of the startup script:
docker run wordpress:4 cat /entrypoint.sh
Running that command will result in an error messages like:
error: missing WORDPRESS_DB_HOST and MYSQL_PORT_3306_TCP environment variables...
Entrypoints are perfect places to put code that validates the preconditions of a con- tainer.
docker run --entrypoint="cat" \ # Use "cat" as the entrypoint wordpress:4 /entrypoint.sh # Pass /entrypoint.sh as the argument to cat
Cleaning up
To remove a container from your computer, use the docker rm
command.
docker rm wp
If you try to remove a container that’s running, paused, or restarting, Docker will display a message like the following:
Error response from daemon: Conflict, You cannot remove a running container. Stop the container before attempting removal or use -f FATA[0000] Error: failed to remove one or more containers
The processes running in a container should be stopped before the files in the con- tainer are removed. You can do this with the docker stop command or by using the -f
flag on docker rm
. The key difference is that when you stop a process using the -f flag, Docker sends a SIG_KILL
signal, which immediately terminates the receiving process. In contrast, using docker stop
will send a SIG_HUP
signal.
You can avoid the cleanup burden by specifying –rm on the command. Doing so will automatically remove the container as soon as it enters the exited state.
docker run --rm --name auto-exit-test busybox:latest echo Hello Worlddocker ps -a
You should also use the -v flag for reasons.The docker CLI makes it is easy to compose a quick cleanup command:
docker rm -vf $(docker ps -a -q)
- DockerInAction-Running software in containers
- DockerInAction-Packaging software in images
- DockerInAction-Software installation simplified
- Running ASP.NET 5 applications in Linux Containers with Docker
- Containers in depth笔记
- Managing Data in Containers
- Managing Data in Containers
- Manage Data in Containers
- 3 sequence containers in STL
- Containers
- aking public containers in Swift (OpenStack)
- Containers In Memory: How Big Is Big?
- Privileged containers provisioning by Kubernetes in Ubuntu
- Running neutron in apache2
- Running Nutch in Eclipse
- Running cinder in apache2
- ethereum Running in Docker
- thinking in software
- unity 脚本
- Android 扫描SD卡中的所有视频文件
- jmp指令
- 《CLR via C#》读书笔记-线程同步(四)
- Error setting TTL index on collection : sessions
- DockerInAction-Running software in containers
- 蓝桥杯 杨辉三角
- maven笔记
- webstorm快捷键大全
- react-native-android-guide
- 在IOS中使用多线程
- IDA6.8F5结果不正确
- Hibernate+MySQL连接超时解决办法
- 回文串判定 (sdut oj)