DockerInAction-Build automation and advanced image considerations
来源:互联网 发布:精通matlab最优化计算 编辑:程序博客网 时间:2024/05/22 00:16
Packaging Git with a Dockerfile
# An example Dockerfile for installing Git on UbuntuFROM ubuntu:latestMAINTAINER "dockerinaction@allingeek.com"RUN apt-get install -y gitENTRYPOINT ["git"]
Before dissecting this example, build a new image from it with the docker build command from the same directory containing the Dockerfile. Tag the new image with auto:
docker build --tag ubuntu-git:auto .
Outputs several lines about steps and output from apt-get and will finally display a message like this:
Successfully built 0bca8436849b
View the list of all your ubuntu-git images and test the newest one with this command:
docker images
The new build tagged “auto” should now appear in the list:
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZEubuntu-git auto 0bca8436849b 10 seconds ago 225.9 MBubuntu-git latest 826c66145a59 10 minutes ago 226.6 MBubuntu-git removed 826c66145a59 10 minutes ago 226.6 MBubuntu-git 1.9 3e356394c14e 41 hours ago 226 MB
The first instruction must be FROM
. If you’re starting from an empty image and your software has no dependencies, or you’ll provide all the dependencies, then you can start from a special empty repository named scratch
.
The builder validated that the image specified by the FROM instruction was installed as the first step of the build. If it were not, Docker would have automatically tried to pull the image.
The output will show which steps the builder was able to skip in favor of cached results:
Sending build context to Docker daemon 2.048 kBSending build context to Docker daemonStep 0 : FROM ubuntu:latest ---> b39b81afc8caStep 1 : MAINTAINER "dockerinaction@allingeek.com" ---> Using cache ---> 80a695671201Step 2 : RUN apt-get install -y git ---> Using cache # Note use of cache ---> 1c20f8970532Step 3 : ENTRYPOINT git ---> Using cache # Note use of cache ---> 89d726cf3514Step 4 : RUN This will not work ---> Running in f68f0e0418b5/bin/sh: 1: This: not foundINFO[0001] The command [/bin/sh -c This will not work] returned a non-zerocode: 127
A Dockerfile primer
Metadata instructions
Create a new file named .dockerignore and copy in the following lines:
.dockerignoremailer-base.dfmailer-logging.dfmailer-live.df
Create a new file named mailer-base.df and add the following lines:
FROM debian:wheezyMAINTAINER Jeff Nickoloff "dia@allingeek.com"RUN groupadd -r -g 2200 example && \ useradd -rM -g example -u 2200 exampleENV APPROOT="/app" \ APP="mailer.sh" \ VERSION="0.6"LABEL base.name="Mailer Archetype" \ base.version="${VERSION}"WORKDIR $APPROOTADD . $APPROOTENTRYPOINT ["/app/mailer.sh"]EXPOSE 33333# Do not set the default user in the base otherwise# implementations will not be able to update the image# USER example:example
The -f flag tells the builder which filename to use as input:
docker build -t dockerinaction/mailer-base:0.6 -f mailer-base.df .
ENV
sets environment variables for an image similar to the –env flag on docker run or docker create.- The
LABEL
instruction is used to define key/value pairs that are recorded as additional metadata for an image or container. This mirrors the –label flag on docker run and docker create. - The result of the
WORKDIR
instruction will be an image with the default working directory set to /app. Setting WORKDIR to a location that doesn’t exist will create that location just like the command-line option. - The
EXPOSE
command creates a layer that opens TCP port 33333. - The
FROM
instruction sets the layer stack to start from the debian:wheezy image. Any new layers built will be placed on top of that image. - The
MAINTAINER
instruction sets the Author value in the image metadata. - The
ENTRYPOINT
instruction sets the executable to be run at container startup. - The last commented line is a metadata instruction
USER
. It sets the user and group for all further build steps and containers created from the image.
You’ll need to inspect the image:
docker inspect dockerinaction/mailer-base:0.6
The relevant lines are these:
"Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "APPROOT=/app","APP=mailer.sh","VERSION=0.6"],..."Labels": { "base.name": "Mailer Archetype","base.version": "0.6" },..."WorkingDir": "/app"
File system instructions
A file named mailer-logging.df:
FROM dockerinaction/mailer-base:0.6COPY ["./log-impl", "${APPROOT}"]RUN chmod a+x ${APPROOT}/${APP} && \ chown example:example /var/logUSER example:exampleVOLUME ["/var/log"]CMD ["/var/log/mailer.log"]
- The
COPY
instruction will copy files from the file system where the image is being built into the build container. - The second new instruction is
VOLUME
. This behaves exactly as you’d expect if you understand what the –volume flag does on a call to docker run or docker create. - The
CMD
command represents an argument list for the entrypoint. The default entrypoint for a container is /bin/sh.
Create a directory at ./log-impl
. Inside that directory create a file named mailer.sh
and copy the following script into the file:
#!/bin/shprintf "Logging Mailer has started.\n"while truedo MESSAGE=$(nc -l -p 33333) printf "[Message]: %s\n" "$MESSAGE" > $1 sleep 1done
This script will start a mailer daemon on port 33333 and write each message that it receives to the file specified in the first argument to the program.
Build and run the container:
docker build -t dockerinaction/mailer-logging -f mailer-logging.df .docker run -d --name logging-mailer dockerinaction/mailer-logging
Name this file mailer-live.df:
FROM dockerinaction/mailer-base:0.6ADD ["./live-impl", "${APPROOT}"]RUN apt-get update && \ apt-get install -y curl python && \ curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py" && \ python get-pip.py && \ pip install awscli && \ rm get-pip.py && \ chmod a+x "${APPROOT}/${APP}"RUN apt-get install -y netcatUSER example:exampleCMD ["mailer@dockerinaction.com", "pager@dockerinaction.com"]
The ADD instruction will
* Fetch remote source files if a URL is specified
* Extract the files of any source determined to be an archive file
Next, create a new subdirectory named live-impl
under the location containing mailer-live.df. Add the following script to a file in that directory named mailer.sh
:
#!/bin/shprintf "Live Mailer has started.\n"while truedo MESSAGE=$(nc -l -p 33333) aws ses send-email --from $1 \ --destination {\"ToAddresses\":[\"$2\"]} \ --message "{\"Subject\":{\"Data\":\"Mailer Alert\"},\ \"Body\":{\"Text\":{\"Data\":\"$MESSAGE}\"}}}"sleep 1 done
It will wait for connections on port 33333, take action on any received messages, and then sleep for a moment before waiting for another message.
Build and run the container:
docker build -t dockerinaction/mailer-live -f mailer-live.df .docker run -d --name live-mailer dockerinaction/mailer-live
Injecting downstream build-time behavior
The ONBUILD
instruction defines instructions to execute if the resulting image is used as a base for another build.
The upstream Dockerfile would use a set of instructions like this:
ONBUILD COPY [".", "/var/myapp"]ONBUILD RUN go build /var/myapp
The instructions following ONBUILD instructions aren’t executed when their containing Dockerfile is built. Instead, those instructions are recorded in the resulting image’s metadata under ContainerConfig.OnBuild. The previous instructions would result in the following metadata inclusions:
"ContainerConfig": { "OnBuild": [ "COPY [\".\", \"/var/myapp\"]", "RUN go build /var/myapp"]}
When a downstream Dockerfile uses the upstream image(the one with the ONBUILD instructions) in a FROM instruction, those ONBUILD instructions are executed after the FROM instruction and before the next instruction in a Dockerfile.
Using startup scripts and multiprocess containers
Environmental preconditions validation
That script validates that the container context is set in a way that’s compatible with the contained version of WordPress. If any required condition is unmet (a link is undefined or a variable is unset), then the script will exit before starting WordPress, and the container will stop unexpectedly.
This type of startup script is generally use-case specific. If you’re packaging a specific piece of software in an image, you’ll need to write the script yourself. Your script should validate as much of the assumed context as possible. This should include the following:
- Presumed links (and aliases)
- Environment variables
- Network access
- Network port availability
- Root file system mount parameters (read-write or read-only)
- Volumes
- Current user
At container startup, this script enforces that either another container has been linked to the web alias and has exposed port 80 or the WEB_HOST environment variable has been defined:
#!/bin/bashset -eif [ -n "$WEB_PORT_80_TCP" ]; then if [ -z "$WEB_HOST" ]; then WEB_HOST='web' else echo >&2 '[WARN]: Linked container, "web" overridden by $WEB_HOST.' echo >&2 "===> Connecting to WEB_HOST ($WEB_HOST)" fifiif [ -z "$WEB_HOST" ]; then echo >&2 '[ERROR]: specify a linked container, "web" or WEB_HOST environ- ment variable' exit 1fiexec "$@" # run the default command
Initialization processes
Using an init process is the best way to launch multiple programs, clean up orphaned processes, monitor processes, and automatically restart any failed processes.
When evaluating any init program for use in a container, consider these factors:
- Additional dependencies the program will bring into the image
- File sizes
- How the program passes signals to its child processes (or if it does)
- Required user access
- Monitoring and restart functionality (backoff-on-restart features are a bonus)
- Zombie process cleanup features
Building hardened application images
Hardening an image
is the process of shaping it in a way that will reduce the attack surface inside any Docker containers based on it.
A general strategy for hardening an application image is to minimize the software included with it.
There are three things that you can do to harden an image beyond that general strategy. First, you can enforce that your images are built from a specific image. Second, you can make sure that regardless of how containers are built from your image, they will have a sensible default user. Last, you should eliminate a common path for root user escalation.
- DockerInAction-Build automation and advanced image considerations
- STM and MVCC considerations
- Xamarin.Android + Build/Test Cloud TFS Automation - Issues and Workground
- DockerInAction-Persistent storage and shared state with volumes
- Pragmatic Project Automation: How to Build, Deploy, and Monitor Java Apps
- Performance Considerations for Direct3D9 and WPF Interoperability
- Broadcasts -----Security considerations and best practices
- Automation and Development experience
- Automation and Planning
- Automation Project Management and Automation Architecture
- Lockless Programming Considerations for Xbox 360 and Microsoft Windows
- Performance considerations for keySet() and entrySet() of Map
- Lockless Programming Considerations for Xbox 360 and Microsoft Windows
- Roy Docker Image Build
- UI Automation: Tricks and Traps
- good example for web automation and exe automation
- 如何单独 build recovery image
- docker 通过Dockerfile build image
- Jackson2JsonRedisSerializer报错Could not read JSON: Unrecognized field...
- [LOG]AC自动机
- 无题之一
- Xcode代码块转移备份同步(CodeSnippets)代码块路径
- Handler、Thread和HandlerThread的差别
- DockerInAction-Build automation and advanced image considerations
- tableViewCell中添加webView,cell自适应webView高度,解决死循环的简单办法
- X86 dismatch X64 visual studio
- 蓝桥 大臣的旅费
- 使用PHPMailer发送邮件
- 获取jqGrid中选择的行的数据(附实例)
- OSI七层与TCP/IP五层网络架构详解
- 深度学习对抗样本的八个误解与事实
- springmvc框架原理