├── .editorconfig
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug.md
│ ├── config.yml
│ └── enhancement.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── main.yml
│ └── stale.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Changelog.md
├── LICENSE.txt
├── Makefile
├── README.md
├── README_ZH_cn_.md
├── README_zh_tw.md
├── Vagrantfile
├── build-multiarch.sh
├── build.sh
├── image
├── Dockerfile
├── bin
│ ├── install_clean
│ ├── my_init
│ └── setuser
├── buildconfig
├── cleanup.sh
├── prepare.sh
├── services
│ ├── cron
│ │ ├── cron.runit
│ │ └── cron.sh
│ ├── sshd
│ │ ├── 00_regen_ssh_host_keys.sh
│ │ ├── enable_insecure_key
│ │ ├── keys
│ │ │ ├── insecure_key
│ │ │ ├── insecure_key.ppk
│ │ │ └── insecure_key.pub
│ │ ├── sshd.runit
│ │ ├── sshd.sh
│ │ └── sshd_config
│ └── syslog-ng
│ │ ├── logrotate.conf
│ │ ├── logrotate_syslogng
│ │ ├── smart-multi-line.fsm
│ │ ├── syslog-ng.conf
│ │ ├── syslog-ng.init
│ │ ├── syslog-ng.sh
│ │ ├── syslog-ng.shutdown
│ │ └── syslog_ng_default
├── system_services.sh
└── utilities.sh
├── install-tools.sh
├── test
├── runner.sh
└── test.sh
├── tools
├── README.md
├── baseimage-docker-nsenter
├── docker-bash
└── docker-ssh
└── vagrant-libs
└── bootstrap.sh
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 | indent_size = 4
11 | indent_style = tab
12 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: samip5
2 | custom: https://www.buymeacoffee.com/skykrypt
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels:kind: possible bug
6 | assignees: ''
7 | ---
8 |
9 | # Details
10 |
11 | **Image version:**
12 |
13 |
14 |
15 | **What steps did you take and what happened:**
16 |
17 |
18 |
19 | **What did you expect to happen:**
20 |
21 |
22 |
23 | **Anything else you would like to add:**
24 |
25 |
26 |
27 | **Additional Information:**
28 |
29 |
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | ---
2 | blank_issues_enabled: false
3 | contact_links:
4 | - name: Discuss on Discord
5 | url: https://discord.gg/PRT86Cdgnr
6 | about: Join our Discord community
7 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/enhancement.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: kind:enhancement
6 | assignees: ''
7 | ---
8 |
9 | # Details
10 |
11 | **Describe the solution you'd like:**
12 |
13 |
14 |
15 | **Anything else you would like to add:**
16 |
17 |
18 |
19 | **Additional Information:**
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
12 |
13 | **Description of the change**
14 |
15 |
16 |
17 | **Benefits**
18 |
19 |
20 |
21 | **Possible drawbacks**
22 |
23 |
24 |
25 | **Applicable issues**
26 |
27 |
28 | - fixes #
29 |
30 | **Additional information**
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | workflow_dispatch:
5 | release:
6 | types: [published]
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | if: "!contains(github.event.head_commit.message, '[ci-skip]')"
11 | steps:
12 | - name: Checkout
13 | uses: actions/checkout@v4
14 |
15 | - name: Prepare
16 | id: prep
17 | run: |
18 | DOCKER_IMAGE=phusion/baseimage
19 | GIT_BRANCH=${GITHUB_REF##*/}
20 | # Set the platforms to build for here and thus reduce duplicating it.
21 | PLATFORMS=amd64,arm,arm64
22 | TAGS="${DOCKER_IMAGE}:${GIT_BRANCH}, ghcr.io/${{ github.repository_owner }}/baseimage:${GIT_BRANCH}"
23 |
24 | # Set output parameters.
25 |
26 | if [ "${{github.event_name}}" == "pull_request" ]; then
27 | echo "push=false" >> $GITHUB_OUTPUT
28 | else
29 | echo "push=true" >> $GITHUB_OUTPUT
30 | echo "tags=${TAGS}" >> $GITHUB_OUTPUT
31 | echo "branch=${GIT_BRANCH}" >> $GITHUB_OUTPUT
32 | echo "docker_image=${DOCKER_IMAGE}" >> $GITHUB_OUTPUT
33 | fi
34 | echo "platforms=${PLATFORMS}" >> $GITHUB_OUTPUT
35 |
36 |
37 | - name: Set up QEMU
38 | uses: docker/setup-qemu-action@v3
39 | with:
40 | platforms: ${{ steps.prep.outputs.platforms }}
41 |
42 | - name: Login to GHCR (Github Container Registry)
43 | uses: docker/login-action@v3
44 | if: github.event_name != 'pull_request'
45 | with:
46 | registry: ghcr.io
47 | username: ${{ github.actor }}
48 | password: ${{ secrets.GITHUB_TOKEN }}
49 |
50 | - name: Set up Docker Buildx
51 | id: buildx
52 | uses: docker/setup-buildx-action@v3
53 | with:
54 | install: true
55 | version: latest
56 | driver-opts: image=moby/buildkit:latest
57 |
58 |
59 | - name: Login to Docker Hub
60 | if: github.event_name != 'pull_request'
61 | uses: docker/login-action@v3
62 | with:
63 | username: ${{ secrets.DOCKER_USERNAME }}
64 | password: ${{ secrets.DOCKER_PASSWORD }}
65 |
66 | - name: Build and Push
67 | uses: docker/build-push-action@v5
68 | with:
69 | builder: ${{ steps.buildx.outputs.name }}
70 | context: image
71 | platforms: ${{ steps.prep.outputs.platforms }}
72 | push: ${{ steps.prep.outputs.push }}
73 | tags: ${{ steps.prep.outputs.tags }}
74 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: 'Close stale issues and PRs'
2 | on:
3 | schedule:
4 | - cron: '0 1 * * *'
5 |
6 | jobs:
7 | stale:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/stale@v9
11 | with:
12 | repo-token: ${{ secrets.GITHUB_TOKEN }}
13 | stale-issue-message: 'This Issue has been automatically marked as "stale" because it has not had recent activity (for 15 days). It will be closed if no further activity occurs. Thanks for the feedback.'
14 | stale-pr-message: 'This Pull Request has been automatically marked as "stale" because it has not had recent activity (for 15 days). It will be closed if no further activity occurs. Thank you for your contribution.'
15 | close-issue-message: 'Due to the lack of activity in the last 5 days since it was marked as "stale", we proceed to close this Issue. Do not hesitate to reopen it later if necessary.'
16 | close-pr-message: 'Due to the lack of activity in the last 5 days since it was marked as "stale", we proceed to close this Pull Request. Do not hesitate to reopen it later if necessary.'
17 | days-before-stale: 15
18 | days-before-close: 5
19 | exempt-issue-labels: 'on-hold'
20 | exempt-pr-labels: 'on-hold'
21 | operations-per-run: 50
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .vagrant
3 | *.swp
4 | *.tar.gz
5 | *.log
6 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at Phusion Passenger:
38 |
39 | [FloorD](https://github.com/floord) (she/her), floor@phusion.nl, English / Dutch / German
40 |
41 | [Scarhand](https://github.com/scarhand) (he/his), niels@phusion.nl, English / Dutch
42 |
43 | The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
44 |
45 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
46 |
47 | ## Attribution
48 |
49 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
50 |
51 | [homepage]: http://contributor-covenant.org
52 | [version]: http://contributor-covenant.org/version/1/4/
53 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Hey, thanks for wanting to contribute to baseimage-docker. :)
2 |
3 | If you have a question, please use the [discussion forum](https://groups.google.com/d/forum/passenger-docker). The Github issue tracker is only for **bug reports and feature requests**.
4 |
5 | If you want to develop baseimage-docker, use the Vagrantfile in the repository. It will setup an Ubuntu VM with Docker installed in it. Use the Makefile to build the Docker image.
6 |
7 | All development happens on the `next` branch. The `master` branch is supposed to point to the latest stable release, because users read documentation from the `master` branch.
8 |
--------------------------------------------------------------------------------
/Changelog.md:
--------------------------------------------------------------------------------
1 | For the Changelog, please see [Releases](https://github.com/phusion/baseimage-docker/releases) on GitHub
2 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2025 Phusion Holding B.V.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | VERSION ?= noble-1.0.2
2 | ifdef BASE_IMAGE
3 | BUILD_ARG = --build-arg BASE_IMAGE=$(BASE_IMAGE)
4 | ifndef NAME
5 | NAME = phusion/baseimage-$(subst :,-,${BASE_IMAGE})
6 | endif
7 | else
8 | NAME ?= phusion/baseimage
9 | endif
10 | ifdef TAG_ARCH
11 | # VERSION_ARG = $(VERSION)-$(subst /,-,$(subst :,-,${BASE_IMAGE}))-$(TAG_ARCH)
12 | VERSION_ARG = $(VERSION)-$(TAG_ARCH)
13 | LATEST_VERSION = latest-$(TAG_ARCH)
14 | else
15 | # VERSION_ARG = $(VERSION)-$(subst /,-,$(subst :,-,${BASE_IMAGE}))
16 | VERSION_ARG = $(VERSION)
17 | LATEST_VERSION = latest
18 | endif
19 | VERSION_ARG ?= $(VERSION)
20 |
21 | .PHONY: all build test tag_latest release ssh
22 |
23 | all: build
24 |
25 | build:
26 | docker build --no-cache -t $(NAME):$(VERSION_ARG) $(BUILD_ARG) --build-arg QEMU_ARCH=$(QEMU_ARCH) --platform $(PLATFORM) --rm image
27 |
28 | build_multiarch:
29 | env NAME=$(NAME) VERSION=$(VERSION_ARG) ./build-multiarch.sh
30 |
31 | test:
32 | env NAME=$(NAME) VERSION=$(VERSION_ARG) ./test/runner.sh
33 |
34 | tag_latest:
35 | docker tag $(NAME):$(VERSION_ARG) $(NAME):$(LATEST_VERSION)
36 |
37 | tag_multiarch_latest:
38 | env NAME=$(NAME) VERSION=$(VERSION) TAG_LATEST=true ./build-multiarch.sh
39 |
40 | release: test
41 | @if ! docker images $(NAME) | awk '{ print $$2 }' | grep -q -F $(VERSION_ARG); then echo "$(NAME) version $(VERSION_ARG) is not yet built. Please run 'make build'"; false; fi
42 | docker push $(NAME)
43 | @echo "*** Don't forget to create a tag by creating an official GitHub release."
44 |
45 | ssh: SSH_COMMAND?=
46 | ssh:
47 | ID=$$(docker ps | grep -F "$(NAME):$(VERSION_ARG)" | awk '{ print $$1 }') && \
48 | if test "$$ID" = ""; then echo "Container is not running."; exit 1; fi && \
49 | tools/docker-ssh $$ID ${SSH_COMMAND}
50 |
51 | test_release:
52 | echo test_release
53 | env
54 |
55 | test_master:
56 | echo test_master
57 | env
58 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # A minimal Ubuntu base image modified for Docker-friendliness
2 |
3 | [](https://github.com/phusion/baseimage-docker/actions/workflows/main.yml)
4 |
5 | _Baseimage-docker only consumes 8.3 MB RAM and is much more powerful than Busybox or Alpine. See why below._
6 |
7 | Baseimage-docker is a special [Docker](https://www.docker.com) image that is configured for correct use within Docker containers. It is Ubuntu, plus:
8 |
9 | * Modifications for Docker-friendliness.
10 | * Administration tools that are especially useful in the context of Docker.
11 | * Mechanisms for easily running multiple processes, [without violating the Docker philosophy](#docker_single_process).
12 |
13 | You can use it as a base for your own Docker images.
14 |
15 | Baseimage-docker is available for pulling from [the Docker registry](https://hub.docker.com/r/phusion/baseimage) and [GHCR (GitHub Container Registry)](https://github.com/phusion/baseimage-docker/pkgs/container/baseimage)!
16 |
17 | ### What are the problems with the stock Ubuntu base image?
18 |
19 | Ubuntu is not designed to be run inside Docker. Its init system, Upstart, assumes that it's running on either real hardware or virtualized hardware, but not inside a Docker container. But inside a container you don't want a full system; you want a minimal system. Configuring that minimal system for use within a container has many strange corner cases that are hard to get right if you are not intimately familiar with the Unix system model. This can cause a lot of strange problems.
20 |
21 | Baseimage-docker gets everything right. The "Contents" section describes all the things that it modifies.
22 |
23 |
24 | ### Why use baseimage-docker?
25 |
26 | You can configure the stock `ubuntu` image yourself from your Dockerfile, so why bother using baseimage-docker?
27 |
28 | * Configuring the base system for Docker-friendliness is no easy task. As stated before, there are many corner cases. By the time that you've gotten all that right, you've reinvented baseimage-docker. Using baseimage-docker will save you from this effort.
29 | * It reduces the time needed to write a correct Dockerfile. You won't have to worry about the base system and you can focus on the stack and the app.
30 | * It reduces the time needed to run `docker build`, allowing you to iterate your Dockerfile more quickly.
31 | * It reduces download time during redeploys. Docker only needs to download the base image once: during the first deploy. On every subsequent deploys, only the changes you make on top of the base image are downloaded.
32 |
33 | -----------------------------------------
34 |
35 | **Related resources**:
36 | [Website](http://phusion.github.io/baseimage-docker/) |
37 | [Github](https://github.com/phusion/baseimage-docker) |
38 | [Docker registry](https://registry.hub.docker.com/r/phusion/baseimage/) |
39 | [Discussion forum](https://groups.google.com/d/forum/passenger-docker) |
40 | [Twitter](https://twitter.com/phusion_nl) |
41 | [Blog](http://blog.phusion.nl/)
42 |
43 | **Table of contents**
44 |
45 | * [What's inside the image?](#whats_inside)
46 | * [Overview](#whats_inside_overview)
47 | * [Wait, I thought Docker is about running a single process in a container?](#docker_single_process)
48 | * [Does Baseimage-docker advocate "fat containers" or "treating containers as VMs"?](#fat_containers)
49 | * [Inspecting baseimage-docker](#inspecting)
50 | * [Using baseimage-docker as base image](#using)
51 | * [Getting started](#getting_started)
52 | * [Adding additional daemons](#adding_additional_daemons)
53 | * [Running scripts during container startup](#running_startup_scripts)
54 | * [Environment variables](#environment_variables)
55 | * [Centrally defining your own environment variables](#envvar_central_definition)
56 | * [Environment variable dumps](#envvar_dumps)
57 | * [Modifying environment variables](#modifying_envvars)
58 | * [Security](#envvar_security)
59 | * [System logging](#logging)
60 | * [Upgrading the operating system inside the container](#upgrading_os)
61 | * [Container administration](#container_administration)
62 | * [Running a one-shot command in a new container](#oneshot)
63 | * [Running a command in an existing, running container](#run_inside_existing_container)
64 | * [Login to the container via `docker exec`](#login_docker_exec)
65 | * [Usage](#docker_exec)
66 | * [Login to the container via SSH](#login_ssh)
67 | * [Enabling SSH](#enabling_ssh)
68 | * [About SSH keys](#ssh_keys)
69 | * [Using the insecure key for one container only](#using_the_insecure_key_for_one_container_only)
70 | * [Enabling the insecure key permanently](#enabling_the_insecure_key_permanently)
71 | * [Using your own key](#using_your_own_key)
72 | * [The `docker-ssh` tool](#docker_ssh)
73 | * [Building the image yourself](#building)
74 | * [Removing optional services](#removing_optional_services)
75 | * [Conclusion](#conclusion)
76 |
77 | -----------------------------------------
78 |
79 |
80 | ## What's inside the image?
81 |
82 |
83 | ### Overview
84 |
85 | *Looking for a more complete base image, one that is ideal for Ruby, Python, Node.js and Meteor web apps? Take a look at [passenger-docker](https://github.com/phusion/passenger-docker).*
86 |
87 | | Component | Why is it included? / Remarks |
88 | | ---------------- | ------------------- |
89 | | Ubuntu 24.04 LTS | The base system. |
90 | | A **correct** init process | _Main article: [Docker and the PID 1 zombie reaping problem](http://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/)._
According to the Unix process model, [the init process](https://en.wikipedia.org/wiki/Init) -- PID 1 -- inherits all [orphaned child processes](https://en.wikipedia.org/wiki/Orphan_process) and must [reap them](https://en.wikipedia.org/wiki/Wait_(system_call)). Most Docker containers do not have an init process that does this correctly. As a result, their containers become filled with [zombie processes](https://en.wikipedia.org/wiki/Zombie_process) over time.
Furthermore, `docker stop` sends SIGTERM to the init process, which stops all services. Unfortunately most init systems don't do this correctly within Docker since they're built for hardware shutdowns instead. This causes processes to be hard killed with SIGKILL, which doesn't give them a chance to correctly deinitialize things. This can cause file corruption.
Baseimage-docker comes with an init process `/sbin/my_init` that performs both of these tasks correctly. |
91 | | Fixes APT incompatibilities with Docker | See https://github.com/dotcloud/docker/issues/1024. |
92 | | syslog-ng | A syslog daemon is necessary so that many services - including the kernel itself - can correctly log to /var/log/syslog. If no syslog daemon is running, a lot of important messages are silently swallowed.
Only listens locally. All syslog messages are forwarded to "docker logs".
Why syslog-ng?
I've had bad experience with rsyslog. I regularly run into bugs with rsyslog, and once in a while it takes my log host down by entering a 100% CPU loop in which it can't do anything. Syslog-ng seems to be much more stable. |
93 | | logrotate | Rotates and compresses logs on a regular basis. |
94 | | SSH server | Allows you to easily login to your container to [inspect or administer](#login_ssh) things.
_SSH is **disabled by default** and is only one of the methods provided by baseimage-docker for this purpose. The other method is through [docker exec](#login_docker_exec). SSH is also provided as an alternative because `docker exec` comes with several caveats._
Password and challenge-response authentication are disabled by default. Only key authentication is allowed. |
95 | | cron | The cron daemon must be running for cron jobs to work. |
96 | | [runit](http://smarden.org/runit/) | Replaces Ubuntu's Upstart. Used for service supervision and management. Much easier to use than SysV init and supports restarting daemons when they crash. Much easier to use and more lightweight than Upstart. |
97 | | `setuser` | A tool for running a command as another user. Easier to use than `su`, has a smaller attack vector than `sudo`, and unlike `chpst` this tool sets `$HOME` correctly. Available as `/sbin/setuser`. |
98 | | `install_clean` | A tool for installing `apt` packages that automatically cleans up after itself. All arguments are passed to `apt-get -y install --no-install-recommends` and after installation the apt caches are cleared. To include recommended packages, add `--install-recommends`. |
99 |
100 | Baseimage-docker is very lightweight: it only consumes 8.3 MB of memory.
101 |
102 |
103 | ### Wait, I thought Docker is about running a single process in a container?
104 |
105 | The Docker developers advocate the philosophy of running a single *logical service* per container. A logical service can consist of multiple OS processes.
106 |
107 | Baseimage-docker only advocates running multiple OS processes inside a single container. We believe this makes sense because at the very least it would solve [the PID 1 problem](http://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/) and the "syslog blackhole" problem. By running multiple processes, we solve very real Unix OS-level problems, with minimal overhead and without turning the container into multiple logical services.
108 |
109 | Splitting your logical service into multiple OS processes also makes sense from a security standpoint. By running processes as different users, you can limit the impact of vulnerabilities. Baseimage-docker provides tools to encourage running processes as different users, e.g. the `setuser` tool.
110 |
111 | Do we advocate running multiple *logical services* in a single container? Not necessarily, but we do not prohibit it either. While the Docker developers are very opinionated and have very rigid philosophies about how containers *should* be built, Baseimage-docker is completely unopinionated. We believe in freedom: sometimes it makes sense to run multiple services in a single container, and sometimes it doesn't. It is up to you to decide what makes sense, not the Docker developers.
112 |
113 |
114 | ### Does Baseimage-docker advocate "fat containers" or "treating containers as VMs"?
115 |
116 | There are people who think that Baseimage-docker advocates treating containers as VMs because Baseimage-docker advocates the use of multiple processes. Therefore, they also think that Baseimage-docker does not follow the Docker philosophy. Neither of these impressions are true.
117 |
118 | The Docker developers advocate running a single *logical service* inside a single container. But we are not disputing that. Baseimage-docker advocates running multiple *OS processes* inside a single container, and a single logical service can consist of multiple OS processes.
119 |
120 | It follows that Baseimage-docker also does not deny the Docker philosophy. In fact, many of the modifications we introduce are explicitly in line with the Docker philosophy. For example, using environment variables to pass parameters to containers is very much the "Docker way", and providing [a mechanism to easily work with environment variables](#environment_variables) in the presence of multiple processes that may run as different users.
121 |
122 |
123 | ## Inspecting baseimage-docker
124 |
125 | To look around in the image, run:
126 |
127 | docker run --rm -t -i phusion/baseimage: /sbin/my_init -- bash -l
128 |
129 | where `` is [one of the baseimage-docker version numbers](https://github.com/phusion/baseimage-docker/blob/master/Changelog.md).
130 |
131 | You don't have to download anything manually. The above command will automatically pull the baseimage-docker image from the Docker registry.
132 |
133 |
134 | ## Using baseimage-docker as base image
135 |
136 |
137 | ### Getting started
138 |
139 | The image is called `phusion/baseimage`, and is available on the Docker registry.
140 |
141 | # Use phusion/baseimage as base image. To make your builds reproducible, make
142 | # sure you lock down to a specific version, not to `latest`!
143 | # See https://github.com/phusion/baseimage-docker/blob/master/Changelog.md for
144 | # a list of version numbers.
145 | FROM phusion/baseimage:
146 |
147 | # Use baseimage-docker's init system.
148 | CMD ["/sbin/my_init"]
149 |
150 | # ...put your own build instructions here...
151 |
152 | # Clean up APT when done.
153 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
154 |
155 |
156 | ### Adding additional daemons
157 |
158 | A daemon is a program which runs in the background of its system, such
159 | as a web server.
160 |
161 | You can add additional daemons (for example, your own app) to the image
162 | by creating runit service directories. You only have to write a small
163 | shell script which runs your daemon;
164 | [`runsv`](http://smarden.org/runit/runsv.8.html) will start your script,
165 | and - by default - restart it upon its exit, after waiting one second.
166 |
167 | The shell script must be called `run`, must be executable, and is to be
168 | placed in the directory `/etc/service/`. `runsv` will switch to
169 | the directory and invoke `./run` after your container starts.
170 |
171 | **Be certain that you do not start your container using interactive mode
172 | (`-it`) with another command, as `runit` must be the first process to run. If you do this, your runit service directories won't be started. For instance, `docker run -it bash` will bring you to bash in your container, but you'll lose all your daemons.**
173 |
174 | Here's an example showing you how a `runit` service directory can be
175 | made for a `memcached` server.
176 |
177 | In `memcached.sh`, or whatever you choose to name your file (make sure
178 | this file is chmod +x):
179 | ```bash
180 | #!/bin/sh
181 | # `/sbin/setuser memcache` runs the given command as the user `memcache`.
182 | # If you omit that part, the command will be run as root.
183 | exec /sbin/setuser memcache /usr/bin/memcached >>/var/log/memcached.log 2>&1
184 | ```
185 | In an accompanying `Dockerfile`:
186 |
187 | ```Dockerfile
188 | RUN mkdir /etc/service/memcached
189 | COPY memcached.sh /etc/service/memcached/run
190 | RUN chmod +x /etc/service/memcached/run
191 | ```
192 | A given shell script must run **without daemonizing or forking itself**;
193 | this is because `runit` will start and restart your script on its own.
194 | Usually, daemons provide a command line flag or a config file option for
195 | preventing such behavior - essentially, you just want your script to run
196 | in the foreground, not the background.
197 |
198 |
199 | ### Running scripts during container startup
200 |
201 | The baseimage-docker init system, `/sbin/my_init`, runs the following scripts during startup, in the following order:
202 |
203 | * All executable scripts in `/etc/my_init.d`, if this directory exists. The scripts are run in lexicographic order.
204 | * The script `/etc/rc.local`, if this file exists.
205 |
206 | All scripts must exit correctly, e.g. with exit code 0. If any script exits with a non-zero exit code, the booting will fail.
207 |
208 | **Important note:** If you are executing the container in interactive mode (i.e. when you run a container with `-it`), rather than daemon mode, you are sending stdout directly to the terminal (`-i` interactive `-t` terminal). If you are not calling `/sbin/my_init` in your run declaration, `/sbin/my_init` will not be executed, therefore your scripts will not be called during container startup.
209 |
210 | The following example shows how you can add a startup script. This script simply logs the time of boot to the file /tmp/boottime.txt.
211 |
212 | In `logtime.sh`:
213 |
214 | #!/bin/sh
215 | date > /tmp/boottime.txt
216 |
217 | In `Dockerfile`:
218 |
219 | RUN mkdir -p /etc/my_init.d
220 | COPY logtime.sh /etc/my_init.d/logtime.sh
221 | RUN chmod +x /etc/my_init.d/logtime.sh
222 |
223 |
224 |
225 | #### Shutting down your process
226 |
227 | `/sbin/my_init` handles termination of children processes at shutdown. When it receives a SIGTERM
228 | it will pass the signal onto the child processes for correct shutdown. If your process is started with
229 | a shell script, make sure you `exec` the actual process, otherwise the shell will receive the signal
230 | and not your process.
231 |
232 | `/sbin/my_init` will terminate processes after a 5 second timeout. This can be adjusted by setting
233 | environment variables:
234 |
235 | # Give children processes 5 minutes to timeout
236 | ENV KILL_PROCESS_TIMEOUT=300
237 | # Give all other processes (such as those which have been forked) 5 minutes to timeout
238 | ENV KILL_ALL_PROCESSES_TIMEOUT=300
239 |
240 | Note: Prior to 0.11.1, the default values for `KILL_PROCESS_TIMEOUT` and `KILL_ALL_PROCESSES_TIMEOUT`
241 | were 5 seconds. In version 0.11.1+ the default process timeout has been adjusted to 30 seconds to
242 | allow more time for containers to terminate gracefully. The default timeout of your container runtime
243 | may supersede this setting, for example Docker currently applies a [10s timeout](https://docs.docker.com/engine/reference/commandline/stop/#options)
244 | by default before sending SIGKILL, upon `docker stop` or receiving SIGTERM.
245 |
246 | ### Environment variables
247 |
248 | If you use `/sbin/my_init` as the main container command, then any environment variables set with `docker run --env` or with the `ENV` command in the Dockerfile, will be picked up by `my_init`. These variables will also be passed to all child processes, including `/etc/my_init.d` startup scripts, Runit and Runit-managed services. There are however a few caveats you should be aware of:
249 |
250 | * Environment variables on Unix are inherited on a per-process basis. This means that it is generally not possible for a child process to change the environment variables of other processes.
251 | * Because of the aforementioned point, there is no good central place for defining environment variables for all applications and services. Debian has the `/etc/environment` file but it only works in some situations.
252 | * Some services change environment variables for child processes. Nginx is one such example: it removes all environment variables unless you explicitly instruct it to retain them through the `env` configuration option. If you host any applications on Nginx (e.g. using the [passenger-docker](https://github.com/phusion/passenger-docker) image, or using Phusion Passenger in your own image) then they will not see the environment variables that were originally passed by Docker.
253 | * We ignore HOME, SHELL, USER and a bunch of other environment variables on purpose, because _not_ ignoring them will break multi-user containers. See https://github.com/phusion/baseimage-docker/pull/86 -- A workaround for setting the `HOME` environment variable looks like this: `RUN echo /root > /etc/container_environment/HOME`. See https://github.com/phusion/baseimage-docker/issues/119
254 |
255 | `my_init` provides a solution for all these caveats.
256 |
257 |
258 | #### Centrally defining your own environment variables
259 |
260 | During startup, before running any [startup scripts](#running_startup_scripts), `my_init` imports environment variables from the directory `/etc/container_environment`. This directory contains files named after the environment variable names. The file contents contain the environment variable values. This directory is therefore a good place to centrally define your own environment variables, which will be inherited by all startup scripts and Runit services.
261 |
262 | For example, here's how you can define an environment variable from your Dockerfile:
263 |
264 | RUN echo Apachai Hopachai > /etc/container_environment/MY_NAME
265 |
266 | You can verify that it works, as follows:
267 |
268 | $ docker run -t -i /sbin/my_init -- bash -l
269 | ...
270 | *** Running bash -l...
271 | # echo $MY_NAME
272 | Apachai Hopachai
273 |
274 | **Handling newlines**
275 |
276 | If you've looked carefully, you'll notice that the 'echo' command actually prints a newline. Why does $MY_NAME not contain a newline then? It's because `my_init` strips the trailing newline. If you intended on the value having a newline, you should add *another* newline, like this:
277 |
278 | RUN echo -e "Apachai Hopachai\n" > /etc/container_environment/MY_NAME
279 |
280 |
281 | #### Environment variable dumps
282 |
283 | While the previously mentioned mechanism is good for centrally defining environment variables, itself does not prevent services (e.g. Nginx) from changing and resetting environment variables from child processes. However, the `my_init` mechanism does make it easy for you to query what the original environment variables are.
284 |
285 | During startup, right after importing environment variables from `/etc/container_environment`, `my_init` will dump all its environment variables (that is, all variables imported from `container_environment`, as well as all variables it picked up from `docker run --env`) to the following locations, in the following formats:
286 |
287 | * `/etc/container_environment`
288 | * `/etc/container_environment.sh` - a dump of the environment variables in Bash format. You can source the file directly from a Bash shell script.
289 | * `/etc/container_environment.json` - a dump of the environment variables in JSON format.
290 |
291 | The multiple formats make it easy for you to query the original environment variables no matter which language your scripts/apps are written in.
292 |
293 | Here is an example shell session showing you how the dumps look like:
294 |
295 | $ docker run -t -i \
296 | --env FOO=bar --env HELLO='my beautiful world' \
297 | phusion/baseimage: /sbin/my_init -- \
298 | bash -l
299 | ...
300 | *** Running bash -l...
301 | # ls /etc/container_environment
302 | FOO HELLO HOME HOSTNAME PATH TERM container
303 | # cat /etc/container_environment/HELLO; echo
304 | my beautiful world
305 | # cat /etc/container_environment.json; echo
306 | {"TERM": "xterm", "container": "lxc", "HOSTNAME": "f45449f06950", "HOME": "/root", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "FOO": "bar", "HELLO": "my beautiful world"}
307 | # source /etc/container_environment.sh
308 | # echo $HELLO
309 | my beautiful world
310 |
311 |
312 | #### Modifying environment variables
313 |
314 | It is even possible to modify the environment variables in `my_init` (and therefore the environment variables in all child processes that are spawned after that point in time), by altering the files in `/etc/container_environment`. After each time `my_init` runs a [startup script](#running_startup_scripts), it resets its own environment variables to the state in `/etc/container_environment`, and re-dumps the new environment variables to `container_environment.sh` and `container_environment.json`.
315 |
316 | But note that:
317 |
318 | * modifying `container_environment.sh` and `container_environment.json` has no effect.
319 | * Runit services cannot modify the environment like that. `my_init` only activates changes in `/etc/container_environment` when running startup scripts.
320 |
321 |
322 | #### Security
323 |
324 | Because environment variables can potentially contain sensitive information, `/etc/container_environment` and its Bash and JSON dumps are by default owned by root, and accessible only to the `docker_env` group (so that any user added this group will have these variables automatically loaded).
325 |
326 | If you are sure that your environment variables don't contain sensitive data, then you can also relax the permissions on that directory and those files by making them world-readable:
327 |
328 | RUN chmod 755 /etc/container_environment
329 | RUN chmod 644 /etc/container_environment.sh /etc/container_environment.json
330 |
331 |
332 | ### System logging
333 |
334 | Baseimage-docker uses syslog-ng to provide a syslog facility to the container. Syslog-ng is not managed as an runit service (see below). Syslog messages are forwarded to the console.
335 |
336 | #### Log startup/shutdown sequence
337 | In order to ensure that all application log messages are captured by syslog-ng, syslog-ng is started separately before the runit supervisor process, and shutdown after runit exits. This uses the [startup script facility](#running_startup_scripts) provided by this image. This avoids a race condition which would exist if syslog-ng were managed as an runit service, where runit kills syslog-ng in parallel with the container's other services, causing log messages to be dropped during a graceful shutdown if syslog-ng exits while logs are still being produced by other services.
338 |
339 |
340 | ### Upgrading the operating system inside the container
341 |
342 | Baseimage-docker images contain an Ubuntu operating system (see OS version at [Overview](#overview)). You may want to update this OS from time to time, for example to pull in the latest security updates. OpenSSL is a notorious example. Vulnerabilities are discovered in OpenSSL on a regular basis, so you should keep OpenSSL up-to-date as much as you can.
343 |
344 | While we release Baseimage-docker images with the latest OS updates from time to time, you do not have to rely on us. You can update the OS inside Baseimage-docker images yourself, and it is recommended that you do this instead of waiting for us.
345 |
346 | To upgrade the OS in the image, run this in your Dockerfile:
347 |
348 | RUN apt-get update && apt-get upgrade -y -o Dpkg::Options::="--force-confold"
349 |
350 |
351 | ## Container administration
352 |
353 | One of the ideas behind Docker is that containers should be stateless, easily restartable, and behave like a black box. However, you may occasionally encounter situations where you want to login to a container, or to run a command inside a container, for development, inspection and debugging purposes. This section describes how you can administer the container for those purposes.
354 |
355 |
356 | ### Running a one-shot command in a new container
357 |
358 | _**Note:** This section describes how to run a command insider a -new- container. To run a command inside an existing running container, see [Running a command in an existing, running container](#run_inside_existing_container)._
359 |
360 | Normally, when you want to create a new container in order to run a single command inside it, and immediately exit after the command exits, you invoke Docker like this:
361 |
362 | docker run YOUR_IMAGE COMMAND ARGUMENTS...
363 |
364 | However the downside of this approach is that the init system is not started. That is, while invoking `COMMAND`, important daemons such as cron and syslog are not running. Also, orphaned child processes are not properly reaped, because `COMMAND` is PID 1.
365 |
366 | Baseimage-docker provides a facility to run a single one-shot command, while solving all of the aforementioned problems. Run a single command in the following manner:
367 |
368 | docker run YOUR_IMAGE /sbin/my_init -- COMMAND ARGUMENTS ...
369 |
370 | This will perform the following:
371 |
372 | * Runs all system startup files, such as /etc/my_init.d/* and /etc/rc.local.
373 | * Starts all runit services.
374 | * Runs the specified command.
375 | * When the specified command exits, stops all runit services.
376 |
377 | For example:
378 |
379 | $ docker run phusion/baseimage: /sbin/my_init -- ls
380 | *** Running /etc/rc.local...
381 | *** Booting runit daemon...
382 | *** Runit started as PID 80
383 | *** Running ls...
384 | bin boot dev etc home image lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var
385 | *** ls exited with exit code 0.
386 | *** Shutting down runit daemon (PID 80)...
387 | *** Killing all processes...
388 |
389 | You may find that the default invocation is too noisy. Or perhaps you don't want to run the startup files. You can customize all this by passing arguments to `my_init`. Invoke `docker run YOUR_IMAGE /sbin/my_init --help` for more information.
390 |
391 | The following example runs `ls` without running the startup files and with less messages, while running all runit services:
392 |
393 | $ docker run phusion/baseimage: /sbin/my_init --skip-startup-files --quiet -- ls
394 | bin boot dev etc home image lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var
395 |
396 |
397 | ### Running a command in an existing, running container
398 |
399 | There are two ways to run a command inside an existing, running container.
400 |
401 | * Through the `docker exec` tool. This is builtin Docker tool, available since Docker 1.4. Internally, it uses Linux kernel system calls in order to execute a command within the context of a container. Learn more in [Login to the container, or running a command inside it, via `docker exec`](#login_docker_exec).
402 | * Through SSH. This approach requires running an SSH daemon inside the container, and requires you to setup SSH keys. Learn more in [Login to the container, or running a command inside it, via SSH](#login_ssh).
403 |
404 | Both way have their own pros and cons, which you can learn in their respective subsections.
405 |
406 |
407 | ### Login to the container, or running a command inside it, via `docker exec`
408 |
409 | You can use the `docker exec` tool on the Docker host OS to login to any container that is based on baseimage-docker. You can also use it to run a command inside a running container. `docker exec` works by using Linux kernel system calls.
410 |
411 | Here's how it compares to [using SSH to login to the container or to run a command inside it](#login_ssh):
412 |
413 | * Pros
414 | * Does not require running an SSH daemon inside the container.
415 | * Does not require setting up SSH keys.
416 | * Works on any container, even containers not based on baseimage-docker.
417 | * Cons
418 | * If the `docker exec` process on the host is terminated by a signal (e.g. with the `kill` command or even with Ctrl-C), then the command that is executed by `docker exec` is *not* killed and cleaned up. You will either have to do that manually, or you have to run `docker exec` with `-t -i`.
419 | * Requires privileges on the Docker host to be able to access the Docker daemon. Note that anybody who can access the Docker daemon effectively has root access.
420 | * Not possible to allow users to login to the container without also letting them login to the Docker host.
421 |
422 |
423 | #### Usage
424 |
425 | Start a container:
426 |
427 | docker run YOUR_IMAGE
428 |
429 | Find out the ID of the container that you just ran:
430 |
431 | docker ps
432 |
433 | Now that you have the ID, you can use `docker exec` to run arbitrary commands in the container. For example, to run `echo hello world`:
434 |
435 | docker exec YOUR-CONTAINER-ID echo hello world
436 |
437 | To open a bash session inside the container, you must pass `-t -i` so that a terminal is available:
438 |
439 | docker exec -t -i YOUR-CONTAINER-ID bash -l
440 |
441 |
442 | ### Login to the container, or running a command inside it, via SSH
443 |
444 | You can use SSH to login to any container that is based on baseimage-docker. You can also use it to run a command inside a running container.
445 |
446 | Here's how it compares to [using `docker exec` to login to the container or to run a command inside it](#login_docker_exec):
447 |
448 | * Pros
449 | * Does not require root privileges on the Docker host.
450 | * Allows you to let users login to the container, without letting them login to the Docker host. However, this is not enabled by default because baseimage-docker does not expose the SSH server to the public Internet by default.
451 | * Cons
452 | * Requires setting up SSH keys. However, baseimage-docker makes this easy for many cases through a pregenerated, insecure key. Read on to learn more.
453 |
454 |
455 | #### Enabling SSH
456 |
457 | Baseimage-docker disables the SSH server by default. Add the following to your Dockerfile to enable it:
458 |
459 | RUN rm -f /etc/service/sshd/down
460 |
461 | # Regenerate SSH host keys. baseimage-docker does not contain any, so you
462 | # have to do that yourself. You may also comment out this instruction; the
463 | # init system will auto-generate one during boot.
464 | RUN /etc/my_init.d/00_regen_ssh_host_keys.sh
465 |
466 | Alternatively, to enable sshd only for a single instance of your container, create a folder with a [startup script](#running_startup_scripts). The contents of that should be
467 |
468 | ### In myfolder/enable_ssh.sh (make sure this file is chmod +x):
469 | #!/bin/sh
470 | rm -f /etc/service/sshd/down
471 | ssh-keygen -P "" -t dsa -f /etc/ssh/ssh_host_dsa_key
472 |
473 | Then, you can start your container with
474 |
475 | docker run -d -v `pwd`/myfolder:/etc/my_init.d my/dockerimage
476 |
477 | This will initialize sshd on container boot. You can then access it with the insecure key as below, or using the methods to add a secure key. Further, you can publish the port to your machine with -p 2222:22 allowing you to ssh to 127.0.0.1:2222 instead of looking up the ip address of the container.
478 |
479 |
480 | #### About SSH keys
481 |
482 | First, you must ensure that you have the right SSH keys installed inside the container. By default, no keys are installed, so nobody can login. For convenience reasons, we provide [a pregenerated, insecure key](https://github.com/phusion/baseimage-docker/blob/master/image/services/sshd/keys/insecure_key) [(PuTTY format)](https://github.com/phusion/baseimage-docker/blob/master/image/services/sshd/keys/insecure_key.ppk) that you can easily enable. However, please be aware that using this key is for convenience only. It does not provide any security because this key (both the public and the private side) is publicly available. **In production environments, you should use your own keys**.
483 |
484 |
485 | #### Using the insecure key for one container only
486 |
487 | You can temporarily enable the insecure key for one container only. This means that the insecure key is installed at container boot. If you `docker stop` and `docker start` the container, the insecure key will still be there, but if you use `docker run` to start a new container then that container will not contain the insecure key.
488 |
489 | Start a container with `--enable-insecure-key`:
490 |
491 | docker run YOUR_IMAGE /sbin/my_init --enable-insecure-key
492 |
493 | Find out the ID of the container that you just ran:
494 |
495 | docker ps
496 |
497 | Once you have the ID, look for its IP address with:
498 |
499 | docker inspect -f "{{ .NetworkSettings.IPAddress }}"
500 |
501 | Now that you have the IP address, you can use SSH to login to the container, or to execute a command inside it:
502 |
503 | # Download the insecure private key
504 | curl -o insecure_key -fSL https://github.com/phusion/baseimage-docker/raw/master/image/services/sshd/keys/insecure_key
505 | chmod 600 insecure_key
506 |
507 | # Login to the container
508 | ssh -i insecure_key root@
509 |
510 | # Running a command inside the container
511 | ssh -i insecure_key root@ echo hello world
512 |
513 |
514 | #### Enabling the insecure key permanently
515 |
516 | It is also possible to enable the insecure key in the image permanently. This is not generally recommended, but is suitable for e.g. temporary development or demo environments where security does not matter.
517 |
518 | Edit your Dockerfile to install the insecure key permanently:
519 |
520 | RUN /usr/sbin/enable_insecure_key
521 |
522 | Instructions for logging into the container is the same as in section [Using the insecure key for one container only](#using_the_insecure_key_for_one_container_only).
523 |
524 |
525 | #### Using your own key
526 |
527 | Edit your Dockerfile to install an SSH public key:
528 |
529 | ## Install an SSH of your choice.
530 | COPY your_key.pub /tmp/your_key.pub
531 | RUN cat /tmp/your_key.pub >> /root/.ssh/authorized_keys && rm -f /tmp/your_key.pub
532 |
533 | Then rebuild your image. Once you have that, start a container based on that image:
534 |
535 | docker run your-image-name
536 |
537 | Find out the ID of the container that you just ran:
538 |
539 | docker ps
540 |
541 | Once you have the ID, look for its IP address with:
542 |
543 | docker inspect -f "{{ .NetworkSettings.IPAddress }}"
544 |
545 | Now that you have the IP address, you can use SSH to login to the container, or to execute a command inside it:
546 |
547 | # Login to the container
548 | ssh -i /path-to/your_key root@
549 |
550 | # Running a command inside the container
551 | ssh -i /path-to/your_key root@ echo hello world
552 |
553 |
554 | #### The `docker-ssh` tool
555 |
556 | Looking up the IP of a container and running an SSH command quickly becomes tedious. Luckily, we provide the `docker-ssh` tool which automates this process. This tool is to be run on the *Docker host*, not inside a Docker container.
557 |
558 | First, install the tool on the Docker host:
559 |
560 | curl --fail -L -O https://github.com/phusion/baseimage-docker/archive/master.tar.gz && \
561 | tar xzf master.tar.gz && \
562 | sudo ./baseimage-docker-master/install-tools.sh
563 |
564 | Then run the tool as follows to login to a container using SSH:
565 |
566 | docker-ssh YOUR-CONTAINER-ID
567 |
568 | You can lookup `YOUR-CONTAINER-ID` by running `docker ps`.
569 |
570 | By default, `docker-ssh` will open a Bash session. You can also tell it to run a command, and then exit:
571 |
572 | docker-ssh YOUR-CONTAINER-ID echo hello world
573 |
574 |
575 |
576 | ## Building the image yourself
577 |
578 | If for whatever reason you want to build the image yourself instead of downloading it from the Docker registry, follow these instructions.
579 |
580 | Clone this repository:
581 |
582 | git clone https://github.com/phusion/baseimage-docker.git
583 | cd baseimage-docker
584 |
585 | Start a virtual machine with Docker in it. You can use the Vagrantfile that we've already provided.
586 |
587 | First, install `vagrant-disksize` plug-in:
588 |
589 | vagrant plugin install vagrant-disksize
590 |
591 | Then, start the virtual machine
592 |
593 | vagrant up
594 | vagrant ssh
595 | cd /vagrant
596 |
597 | Build the image:
598 |
599 | make build
600 |
601 | If you want to call the resulting image something else, pass the NAME variable, like this:
602 |
603 | make build NAME=joe/baseimage
604 |
605 | You can also change the `ubuntu` base-image to `debian` as these distributions are quite similar.
606 |
607 | make build BASE_IMAGE=debian:stretch
608 |
609 | The image will be: `phusion/baseimage-debian-stretch`. Use the `NAME` variable in combination with the `BASE_IMAGE` one to call it `joe/stretch`.
610 |
611 | make build BASE_IMAGE=debian:stretch NAME=joe/stretch
612 |
613 | To verify that the various services are started, when the image is run as a container, add `test` to the end of your make invocations, e.g.:
614 |
615 | make build BASE_IMAGE=debian:stretch NAME=joe/stretch test
616 |
617 |
618 |
619 | ### Removing optional services
620 |
621 | The default baseimage-docker installs `syslog-ng`, `cron` and `sshd` services during the build process.
622 |
623 | In case you don't need one or more of these services in your image, you can disable its installation through the `image/buildconfig` that is sourced within `image/system_services.sh`. Do this at build time by passing a variable in with `--build-arg` as in `docker build --build-arg DISABLE_SYSLOG=1 image/`, or you may set the variable in `image/Dockerfile` with an ENV setting above the RUN directive.
624 |
625 | These represent build-time configuration, so setting them in the shell env at build-time [will not have any effect](https://github.com/phusion/baseimage-docker/issues/459#issuecomment-439177442). Setting them in child images' Dockerfiles will also not have any effect.)
626 |
627 | You can also set them directly as shown in the following example, to prevent `sshd` from being installed into your image, set `1` to the `DISABLE_SSH` variable in the `./image/buildconfig` file.
628 |
629 | ### In ./image/buildconfig
630 | # ...
631 | # Default services
632 | # Set 1 to the service you want to disable
633 | export DISABLE_SYSLOG=0
634 | export DISABLE_SSH=1
635 | export DISABLE_CRON=0
636 |
637 | Then you can proceed with `make build` command.
638 |
639 |
640 | ## Conclusion
641 |
642 | * Using baseimage-docker? [Tweet about us](https://twitter.com/share) or [follow us on Twitter](https://twitter.com/phusion_nl).
643 | * Having problems? Want to participate in development? Please post a message at [the discussion forum](https://groups.google.com/d/forum/passenger-docker).
644 | * Looking for a more complete base image, one that is ideal for Ruby, Python, Node.js and Meteor web apps? Take a look at [passenger-docker](https://github.com/phusion/passenger-docker).
645 | * Need a helping hand? Phusion also offers [consulting](https://www.phusion.nl/consultancy) on a wide range of topics, including Web Development, UI/UX Research & Design, Technology Migration and Auditing.
646 |
647 | [
](https://www.phusion.nl/)
648 |
649 | Please enjoy baseimage-docker, a product by [Phusion](http://www.phusion.nl/). :-)
650 |
--------------------------------------------------------------------------------
/README_ZH_cn_.md:
--------------------------------------------------------------------------------
1 |
2 | # Docker友好的,最小的Ubuntu基础镜像
3 |
4 | Baseimage-docker是一个特殊的[Docker](http://www.docker.io)镜像,在Docker容器内做了配置,并且可以正确使用。它确实是一个Ubuntu系统, 除此之外进行了如下修订:
5 |
6 | * 为更加友好的支持Docker,做了修订。
7 | * 在Docker环境下,作为管理工具特别有用。
8 | * 在[不违反Docker哲学](#docker_single_process)的前提下,能够很容易的运行多进程的机制。
9 |
10 | 可以把它作为自己的基础Docker镜像。
11 |
12 | Baseimage-docker项目可以直接从Docker的[registry](https://index.docker.io/u/phusion/baseimage/)获取!
13 |
14 |
15 | ### 原生的Ubuntu基础镜像有什么问题呢?
16 |
17 | 原生Ubuntu不是为了在Docker内运行而设计的。它的初始化系统Upstart,假定运行的环境要么是真实的硬件,要么是虚拟的硬件,而不是在Docker容器内。但是在一个Docker的容器内,并不需要一个完整的系统,你需要的只是一个很小的系统。但是如果你不是非常熟悉Unix的系统模型,想要在Docker容器内裁减出最小的系统,会碰到很多难以正确解决的陌生的技术坑。这些坑会引起很多莫名其妙的问题。
18 |
19 | Baseimage-docker让这一切完美。在"内容"部分描述了所有这些修改。
20 |
21 |
22 | ### 为什么使用baseimage-docker?
23 |
24 | 你自己可以从Dockerfile配置一个原生`ubuntu`镜像,为什么还要多此一举的使用baseimage-docker呢?
25 |
26 | * 配置一个Docker友好的基础系统并不是一个简单的任务。如前所述,过程中会碰到很多坑。当你搞定这些坑之后,只不过是又重新发明了一个baseimage-docker而已。使用baseimage-docker可以免去你这方面需要做的努力。
27 | * 减少需要正确编写Dockerfile文件的时间。你不用再担心基础系统,可以专注于你自己的技术栈和你的项目。
28 | * 减少需要运行`docker build`的时间,让你更快的迭代Dockerfile。
29 | * 减少了重新部署的时的下载时间。Docker只需要在第一次部署的时候下载一次基础镜像。在随后的部署中,只需要改变你下载之后对基础镜像进行修改的部分。
30 |
31 | -----------------------------------------
32 |
33 | **相关资源**
34 |
35 | [网站](http://phusion.github.io/baseimage-docker/) |
36 | [Github](https://github.com/phusion/baseimage-docker) |
37 | [Docker registry](https://index.docker.io/u/phusion/baseimage/) |
38 | [论坛](https://groups.google.com/d/forum/passenger-docker) |
39 | [Twitter](https://twitter.com/phusion_nl) |
40 | [Blog](http://blog.phusion.nl/)
41 |
42 | **目录**
43 |
44 | * [镜像里面有什么?](#whats_inside)
45 | * [概述](#whats_inside_overview)
46 | * [等等,我认为Docker在一个容器中只能允许运行一个进程?](#docker_single_process)
47 | * [Baseimage-docker更侧重于“胖容器”还是“把容器当作虚拟机”?](#fat_containers)
48 | * [查看baseimage-docker](#inspecting)
49 | * [使用baseimage-docker作为基础镜像](#using)
50 | * [开始](#getting_started)
51 | * [增加额外的后台进程](#adding_additional_daemons)
52 | * [容器启动时运行脚本](#running_startup_scripts)
53 | * [环境变量](#environment_variables)
54 | * [集中定义自己的环境变量](#envvar_central_definition)
55 | * [保存环境变量](#envvar_dumps)
56 | * [修改环境变量](#modifying_envvars)
57 | * [安全性](#envvar_security)
58 | * [容器管理](#container_administration)
59 | * [在一个新容器中运行单条命令](#oneshot)
60 | * [在正在运行的的容器中运行一条命令](#run_inside_existing_container)
61 | * [通过`docer exec`登录容器](#login_docker_exec)
62 | * [用法](#nsenter_usage)
63 | * [使用SSH登录容器](#login_ssh)
64 | * [启用SSH](#enabling_ssh)
65 | * [关于SSH的key](#ssh_keys)
66 | * [只对一个容器使用不安全key](#using_insecure_key_for_one_container_only)
67 | * [永久开启不安全key](#enabling_the_insecure_key_permanently)
68 | * [使用你自己的key](#using_your_own_key)
69 | * [`docker-ssh`工具](#docker_ssh)
70 | * [构建自己的镜像](#building)
71 | * [总结](#conclusion)
72 |
73 | -----------------------------------------
74 |
75 |
76 | ## 镜像里面有什么?
77 |
78 |
79 | ### 概述
80 |
81 | *想看一个里面包含Ruby,Python,Node.js以及Meteor的完整基础镜像?可以看一下[passenger-docker](https://github.com/phusion/passenger-docker)。*
82 |
83 | | 模块 | 为什么包含这些?以及备注 |
84 | | ---------------- | ------------------- |
85 | | Ubuntu 24.04 LTS | 基础系统。 |
86 | | 一个**正确**的初始化进程 | *主要文章:[Docker和PID 1 僵尸进程回收问题](http://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/)*
根据Unix进程模型,[初始化进程](https://en.wikipedia.org/wiki/Init) -- PID 1 -- 继承了所有[孤立的子进程](https://en.wikipedia.org/wiki/Orphan_process),并且必须[进行回收](https://en.wikipedia.org/wiki/Wait_(system_call))。大多数Docker容器没有一个初始化进程可以正确的完成此操作,随着时间的推移会导致他们的容器出现了大量的[僵尸进程](https://en.wikipedia.org/wiki/Zombie_process)。
而且,`docker stop`发送SIGTERM信号给初始化进程,照理说此信号应该可以停止所有服务。不幸的是由于它们对硬件进行了关闭操作,导致Docker内的大多数初始化系统没有正确执行。这会导致进程强行被SIGKILL信号关闭,从而丧失了一个正确取消初始化设置的机会。这会导致文件损坏。
Baseimage-docker配有一个名为`/sbin/my_init`的初始化进程来同时正确的完成这些任务。 |
87 | | 修复了APT与Docker不兼容的问题 | 详情参见:https://github.com/dotcloud/docker/issues/1024 。 |
88 | | syslog-ng | 对于很多服务-包括kernel自身,都需要一个syslog后台进程,以便可以正确的将log输出到/var/log/syslog中。如果没有运行syslog后台进程,很多重要的信息就会默默的丢失了。
只对本地进行监听。所有syslog信息会被转发给“docker logs”。 |
89 | | logrotate | 定期转存和压缩日志。 |
90 | | SSH服务 | 允许你很容易的登录到容器中进行[查询或管理](#login_ssh)操作。
_SSH**默认是禁用**的,这也是baseimage-docker为此目的提供的唯一方法。其它方法需要通过[docker exec](#login_docker_exec)。由于`docker exec`同时带来了几个需要注意的问题,SSH同时也提供了一个可替换的方法。_
密码和challenge-response认证方式默认是禁用的。只有key认证通过之后才能够开启。 |
91 | | cron | 为了保证cron任务能够工作,必须运行cron后台进程。 |
92 | | [runit](http://smarden.org/runit/) | 替换Ubuntu的Upstart。用于服务监控和管理。比SysV init更容易使用,同时当这些服务崩溃之后,支持后台进程自动重启。比Upstart更易使用,更加的轻量级。 |
93 | | `setuser` | 使用其它账户运行命令的工具。比`su`更容易使用,比使用`sudo`有那么一点优势,跟`chpst`不同,这个工具需要正确的设置`$HOME`。像`/sbin/setuser`这样。 |
94 | Baseimage-docker非常的轻量级:仅仅占用6MB内存。
95 |
96 |
97 | ### 等等,我认为Docker在一个容器中就运行一个进程吗?
98 | 绝对不是这样的. 在一个docker容器中,运行多个进程也是很好的. 事实上,没有什么技术原因限制你只运行一个进程,运行很多的进程,只会把容器中系统的基本功能搞的更乱,比如syslog.
99 |
100 | Baseimage-docker *鼓励* 通过runit来运行多进程.
101 |
102 |
103 | ## 检测一下baseimage-docker
104 |
105 | 要检测镜像,执行下面的命令:
106 |
107 | docker run --rm -t -i phusion/baseimage: /sbin/my_init -- bash -l
108 |
109 | `` 是[baseimage-docker的版本号](https://github.com/phusion/baseimage-docker/blob/master/Changelog.md).
110 |
111 | 你不用手动去下载任何文件.上面的命令会自动从docker仓库下载baseimage-docker镜像.
112 |
113 |
114 | ## 使用baseimage-docker作为基础镜像
115 |
116 |
117 | ### 入门指南
118 |
119 | 镜像名字叫`phusion/baseimage`,在Docker仓库上也是可用的.
120 |
121 | 下面的这个是一个Dockerfile的模板.
122 |
123 | # 使用phusion/baseimage作为基础镜像,去构建你自己的镜像,需要下载一个明确的版本,千万不要使用`latest`.
124 | # 查看https://github.com/phusion/baseimage-docker/blob/master/Changelog.md,可用看到版本的列表.
125 | FROM phusion/baseimage:
126 |
127 | # 设置正确的环境变量.
128 | ENV HOME /root
129 |
130 | # 生成SSH keys,baseimage-docker不包含任何的key,所以需要你自己生成.你也可以注释掉这句命令,系统在启动过程中,会生成一个.
131 | RUN /etc/my_init.d/00_regen_ssh_host_keys.sh
132 |
133 | # 初始化baseimage-docker系统
134 | CMD ["/sbin/my_init"]
135 |
136 | # 这里可以放置你自己需要构建的命令
137 |
138 | # 当完成后,清除APT.
139 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
140 |
141 |
142 |
143 | ### 增加后台进程
144 |
145 | 你可以通过runit工具向你的镜像中添加后台进程(例如:你自己的某些应用).你需要编写一个运行你需要的后台进程的脚本就可以了,runit工具会保证它的正常运行,如果进程死掉,runit也会重启它的.
146 |
147 | 脚本的名称必须是`run`,必须是可以运行的,它需要放到`/etc/service/`.
148 |
149 | 这里有一个例子,向你展示如果运行memcached服务的.
150 |
151 | ### memcached.sh(确定文件的权限是chmod +x):
152 | #!/bin/sh
153 | # `/sbin/setuser memcache` 指定一个`memcache`用户来运行命令.如果你忽略了这部分,就会使用root用户执行.
154 | exec /sbin/setuser memcache /usr/bin/memcached >>/var/log/memcached.log 2>&1
155 |
156 | ### 在Dockerfile中:
157 | RUN mkdir /etc/service/memcached
158 | COPY memcached.sh /etc/service/memcached/run
159 |
160 | 注意脚本必须运行在后台的,**不能让他们进程进行daemonize/fork**.通常,后台进程会提供一个标志位或者配置文件.
161 |
162 |
163 | ### 在容器启动的时候,运行脚本.
164 |
165 | baseimage-docker的初始化脚本 `/sbin/my_init`,在启动的时候进程运行,按照下面的顺序:
166 |
167 | * 如果`/etc/my_init.d`存在,则按照字母顺序执行脚本.
168 | * 如果`/etc/rc.local`存在,则执行里面的脚本.
169 |
170 | 所有的脚本都是正确退出的,例如:退出的code是0.如果有任何脚本以非0的code退出,启动就会失败.
171 |
172 | 下面的例子向你展示了怎么添加一个启动脚本.这个脚本很简单的记录的一个系统启动时间,将启动时间记录到/tmp/boottime.txt.
173 |
174 | ### 在 logtime.sh (文件权限chmod +x):
175 | #!/bin/sh
176 | date > /tmp/boottime.txt
177 |
178 | ### 在 Dockerfile中:
179 | RUN mkdir -p /etc/my_init.d
180 | COPY logtime.sh /etc/my_init.d/logtime.sh
181 |
182 |
183 |
184 | ### 环境变量
185 |
186 | 如果你使用`/sbin/my_init`作为主容器命令,那么通过`docker run --env`或者在Dockerfile文件中设置的`ENV`环境变量,都会被`my_init`读取.
187 |
188 | * 在Unix系统中,环境变量都会被子进程给继承.这就意味着,子进程不可能修改环境变量或者修改其他进程的环境变量.
189 | * 由于上面提到的一点,这里没有一个可以为所有应用和服务集中定义环境的地方.Debian提供了一个`/etc/environment` 文件,解决一些问题.
190 | * 某些服务更改环境变量是为了给子进程使用.Nginx有这样的一个例子:它移除了所有的环境变量,除非你通过`env`进行了配置,明确了某些是保留的.如果你部署了任何应用在Nginx镜像(例如:使用[passenger-docker](https://github.com/phusion/passenger-docker)镜像或者使用Phusion Passenger作为你的镜像.),那么你通过Docker,你不会看到任何环境变量.
191 |
192 |
193 | `my_init`提供了一个办法来解决这些问题.
194 |
195 |
196 | #### 集中定义你的环境变量
197 |
198 | 在启动的时候,在执行[startup scripts](#running_startup_scripts),`my_init`会从`/etc/container_environment`导入环境变量.这个文件夹下面,包含的文件,文件被命名为环境变量的名字.文件内容就是环境变量的值.这个文件夹是因此是一个集中定义你的环境变量的好地方,它会继承到所有启动项目和Runit管理的服务中.
199 |
200 | 给个例子,在你的dockerfile如何定义一个环境变量:
201 |
202 | RUN echo Apachai Hopachai > /etc/container_environment/MY_NAME
203 |
204 | 你可以按照下面这样验证:
205 |
206 | $ docker run -t -i /sbin/my_init -- bash -l
207 | ...
208 | *** Running bash -l...
209 | # echo $MY_NAME
210 | Apachai Hopachai
211 |
212 | **换行处理**
213 |
214 | 如果你观察仔细一点,你会注意到'echo'命令,实际上在它是在新行打印出来的.为什么$MY_NAME没有包含在一行呢? 因为`my_init`在尾部有个换行字符.如果你打算让你的值包含一个新行,你需要增*另外*一个新字符,像这样:
215 |
216 | RUN echo -e "Apachai Hopachai\n" > /etc/container_environment/MY_NAME
217 |
218 |
219 | #### 环境变量存储
220 |
221 | 上面提到集中定义环境变量,它不会从子服务进程改变父服务进程或者重置环境变量.而且,`my_init`也会很容易的让你查询到原始的环境变量是什么.
222 |
223 | 在启动的时候,`/etc/container_environment`, `my_init`中的变量会存储起来,并且导入到环境变量中,例如一下的格式:
224 |
225 | * `/etc/container_environment`
226 | * `/etc/container_environment.sh`- 一个bash存储的环境变量格式.你可以从这个命令中得到base格式的文件.
227 | * `/etc/container_environment.json` - 一个json格式存储的环境变量格式.
228 |
229 | 多种格式可以让你不管采用什么语言/apps都可以很容易使用环境变量.
230 |
231 | 这里有个例子,展示怎么使用:
232 |
233 | $ docker run -t -i \
234 | --env FOO=bar --env HELLO='my beautiful world' \
235 | phusion/baseimage: /sbin/my_init -- \
236 | bash -l
237 | ...
238 | *** Running bash -l...
239 | # ls /etc/container_environment
240 | FOO HELLO HOME HOSTNAME PATH TERM container
241 | # cat /etc/container_environment/HELLO; echo
242 | my beautiful world
243 | # cat /etc/container_environment.json; echo
244 | {"TERM": "xterm", "container": "lxc", "HOSTNAME": "f45449f06950", "HOME": "/root", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "FOO": "bar", "HELLO": "my beautiful world"}
245 | # source /etc/container_environment.sh
246 | # echo $HELLO
247 | my beautiful world
248 |
249 |
250 | #### 修改环境变量
251 |
252 | 通过修改`/etc/container_environment`这个文件,很有可能修改了`my_init`中的环境变量.之后,每次`my_init`启动[启动脚本](#running_startup_scripts),就会重置掉我们自己`/etc/container_environment`中的环境变量,也就会导致`container_environment.sh`和`container_environment.json`重新存储.
253 |
254 | 但是记住这些:
255 |
256 | * 修改`container_environment.sh` 和 `container_environment.json`是没有效果的.
257 | * Runit 的服务是不能像这样修改环境变量的.`my_init`运行的时候,只对`/etc/container_environment`中的修改是生效的.
258 |
259 |
260 | #### 安全
261 |
262 | 因为环境变量可能包含敏感信息, `/etc/container_environment`和它的bash文件和JSON文件,默认都是root,都是可以被`docker_env`群组可以访问的(所以任何用户只要添加到群组中,都可以自动的获取这些信息).
263 |
264 | 如果你确定你的环境变量中没有什么敏感信息,那么你可以放松管理权限,将文件夹和文件分配下面的权限:
265 |
266 | RUN chmod 755 /etc/container_environment
267 | RUN chmod 644 /etc/container_environment.sh /etc/container_environment.json
268 |
269 |
270 | ### 解决Docker没有办法解决的/etc/hosts的问题
271 |
272 | 当前是没有办法在docker容器中修改`/etc/hosts`,这个是因为[Docker bug 2267](https://github.com/dotcloud/docker/issues/2267).Baseimage-docker包含了解决这个问题的办法,你必须明白是怎么修改的.
273 |
274 | 修改的办法包含在系统库中的` libnss_files.so.2`文件,这个文件使用`/etc/workaround-docker-2267/hosts`来代替系统使用`/etc/hosts`.如果需要修改`/etc/hosts`,你只要修改`/etc/workaround-docker-2267/hosts`就可以了.
275 |
276 | 增加这个修改到你的Dockerfile.下面的命令修改了文件`libnss_files.so.2`.
277 |
278 | RUN /usr/bin/workaround-docker-2267
279 |
280 | (其实你不用在Dockerfile文件中运行这个命令,你可以在容器中运行一个shell就可以了.)
281 |
282 | 验证一下它是否生效了,[在你的容器中打开一个shell](#inspecting),修改`/etc/workaround-docker-2267/hosts`,检查一下是否生效了:
283 |
284 | bash# echo 127.0.0.1 my-test-domain.com >> /etc/workaround-docker-2267/hosts
285 | bash# ping my-test-domain.com
286 | ...should ping 127.0.0.1...
287 |
288 | **注意apt-get升级:** 如果Ubuntu升级,就有可能将`libnss_files.so.2`覆盖掉,那么修改就会失效.你必须重新运行`/usr/bin/workaround-docker-2267`.为了安全一点,你应该在运行`apt-get upgrade`之后,运行一下这个命令.
289 |
290 |
291 | ### 禁用SSH
292 | Baseimage-docker默认是支持SSH的,所以可以[使用SSH](#login_ssh)来[管理你的容器](#container_administration).万一你不想支持SSH,你只要禁用它就可以:
293 |
294 | RUN rm -rf /etc/service/sshd /etc/my_init.d/00_regen_ssh_host_keys.sh
295 |
296 |
297 | ## 容器管理
298 |
299 | 一个优秀的docker想法,就是docker是一个无状态的,容易启动的容器,就想一个黑盒子.然而,你可能遇到某种情况,需要登录到容器,或者运行命令在容器中.或者为了开发,需要查看或者debug的目的.这章就给你讲解怎么管理容器.
300 |
301 |
302 |
303 | ### 在一个新容器中运行一个一闪而过的命令
304 |
305 | _**备注:** 这章讲解怎么在一个-新-容器中运行命令.要在一个存在的容器中运行命令,请查看[在一个存在的容器中,运行一个命令](#run_inside_existing_container)._
306 |
307 | 正常情况下,当你创建了一个新容器,为了在容器中运行一个单独的命令,而且在运行之后会立即退出的,你会这样调用docker命令:
308 |
309 | docker run YOUR_IMAGE COMMAND ARGUMENTS...
310 |
311 | 然而下面的方法初始化系统的进行是不会启动.它是这样的,当调用`COMMAND`的时候,重要的后台进程,例如定时任务和系统日志都是不运行的.同样,子进程也是不会出现的,因为`COMMAND`的pid是1.
312 |
313 | Baseimage-docker提供了一个灵活的方式运行只要一闪而过的命令,同时也解决了上述所说的问题.以一下的方式运行一条命令:
314 |
315 | docker run YOUR_IMAGE /sbin/my_init -- COMMAND ARGUMENTS ...
316 |
317 | 他们会按照下面的流程执行:
318 |
319 | * 运行所有的启动文件,例如 /etc/my_init.d/* and /etc/rc.local.
320 | * 运行所有的runit服务
321 | * 运行指定的命令
322 | * 运行指定的命令结束之后,结束所有runit服务.
323 |
324 | 例如:
325 |
326 | $ docker run phusion/baseimage: /sbin/my_init -- ls
327 | *** Running /etc/my_init.d/00_regen_ssh_host_keys.sh...
328 | No SSH host key available. Generating one...
329 | Creating SSH2 RSA key; this may take some time ...
330 | Creating SSH2 DSA key; this may take some time ...
331 | Creating SSH2 ECDSA key; this may take some time ...
332 | *** Running /etc/rc.local...
333 | *** Booting runit daemon...
334 | *** Runit started as PID 80
335 | *** Running ls...
336 | bin boot dev etc home image lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var
337 | *** ls exited with exit code 0.
338 | *** Shutting down runit daemon (PID 80)...
339 | *** Killing all processes...
340 |
341 | 你会发现默认的启动流程太复杂或者你不希望执行启动文件, 你可以自定义这些参数传递给 `my_init`. 调用`docker run YOUR_IMAGE /sbin/my_init --help`可以看到帮助信息.
342 |
343 | 例如上面运行`ls`命令,同时要求不运行启动脚本,减少信息打印,运行runit所有命令.
344 |
345 | $ docker run phusion/baseimage: /sbin/my_init --skip-startup-files --quiet -- ls
346 | bin boot dev etc home image lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var
347 |
348 |
349 | ### 在一个已经运行的容器中,运行一条命令
350 |
351 | 这里有两种办法, 在一个已经运行的容器内执行命令.
352 |
353 | * 通过`nseneter`工具. 这个工具用于Linux内核调用在内嵌容器中运行命令. 可以查看[通过`nsenter`,登录容器或者在容器内执行命令](#login_nsenter).
354 | * 通过SSH.这种办法需要在容器中运行ssh服务,而且需要你创建自己的sshkey. 可以查看[通过`ssh`,登录容器或者在容器内执行命令](#login_ssh).
355 |
356 | 两种方法都是他们各自的优点和确定, 你可以学习他们各自的章节来了解他们.
357 |
358 |
359 | ### 通过`nsenter`,登录容器或者在容器内执行命令
360 |
361 | 你可以使用在docker主机上面的`nsenter`工具,来登录任何基于baseimage-docker的docker容器.你可以使用它在你的容器中运行命令.
362 |
363 | 这里有个和[通过`ssh`,登录容器或者在容器内执行命令](#login_ssh)的优缺点的比较:
364 |
365 | * 优点
366 | * 不需要在容器中运行ssh服务.
367 | * 不需要ssh key.
368 | * 运行在任何容器上,甚至不是基于baseimage-docker的容器.
369 | * 缺点
370 | * 通过`nsenter`运行的进程会和正常运行稍微有不同.例如,他们不同结束掉在容器中正常运行的进程.这适用于所有的子进程.
371 | * 如果`nsenter`进程被其他命令(如`kill`命令)给终止,然后由nsenter所执行的命令,是*不会*被结束的.你将不得不手动清理.(备注:终端控制命令像Ctrl-C *会* 清理所有的子进程,因为终端信号被发送到所有流程的终端会话)
372 | * 需要学习新工具.
373 | * 需要在docker主机上面提供root权限.
374 | * 需要在docker主机上面是可用的.在写这篇文字的时候(2014年7月),大多数linux发行版没有加载它.然而,baseimage-docker提供了预编译的二进制文件,允许你通过[docker-bash](#docker_bash)工具,来很容易的使用它.
375 | * 不可能没有登录到docker主机,就登录到docker容器中.(也就是说,你必须登录到docker主机,通过docker主机登录到容器.)
376 |
377 |
378 | #### 用例
379 |
380 | 第一,确定`nsenter`已经安装了.在写这篇文字的时候(2014年7月),大多数linux发行版没有加载它.然而,baseimage-docker提供了预编译的二进制文件,允许你通过[docker-bash](#docker_bash)工具,让任何人都可以使用.
381 |
382 | 接着,启动一个容器.
383 |
384 | docker run YOUR_IMAGE
385 |
386 | 找出你刚才运行容器的`ID`.
387 |
388 | docker ps
389 |
390 | 一旦得到容器的id, 找到运行容器的主进程`PID`.
391 |
392 | docker inspect -f "{{ .State.Pid }}"
393 |
394 | 现在你已得到容器的主进程PID, 就可以使用`nsenter`来登录容器, 或者在容器中执行命令:
395 |
396 | # 登录容器
397 | nsenter --target --mount --uts --ipc --net --pid bash -l
398 |
399 | # 在容器中执行命令
400 | nsenter --target --mount --uts --ipc --net --pid -- echo hello world
401 |
402 |
403 | #### `docker-bash`工具
404 | 目前(2017-03-31), 英文文档没有发现这个命令
405 |
406 | 查找一个容器的主要进程的PID和输入这么长的nsenter命令很快会变得乏味无比.幸运的是,我们提供了一个`docker-bash` 工具,它可以自动完成只要的工具.这个工具是运行在*docker主机*上面,不是在docker容器中.
407 |
408 | 该工具还附带了一个预编译的二进制`nsenter`,这样你不需要自己安装`nsenter`了.`docker-bash`是很简单的使用的.
409 |
410 | 首先,在docker主机上安装这个工具:
411 |
412 | curl --fail -L -O https://github.com/phusion/baseimage-docker/archive/master.tar.gz && \
413 | tar xzf master.tar.gz && \
414 | sudo ./baseimage-docker-master/install-tools.sh
415 |
416 | 运行这个工具登录到容器中:
417 |
418 | docker-bash YOUR-CONTAINER-ID
419 |
420 | 你可以通过`docker ps`来查找你的容器ID.
421 |
422 | 默认,`docker-bash`会打开一个bash 回话.你可以告诉运行什么命令,之后就会自动退出:
423 |
424 | docker-bash YOUR-CONTAINER-ID echo hello world
425 |
426 |
427 | ### 通过`ssh`,登录容器或者在容器内执行命令
428 |
429 | 你可以使用ssh来登录任何基于baseimage-docker的容器.你可以使用它在容器中执行命令.
430 |
431 | 这里有个和[通过`nsenter`,登录容器或者在容器内执行命令](#login_nsenter)的优缺点的比较:
432 |
433 | * 优点
434 | * 不像`nsenter`一样,运行在docker主机上面.几乎每个人都会安装一个ssh客户端.
435 | * 不想使用`nsenter`,运行的进程和正在的进程会不一样.
436 | * 不需要docker主机提供root权限.
437 | * 运行你让用户登录到容器,而不需要登录到docker主机.然而,默认这是不启用的,因为baseimage-docker默认不是开放ssh服务的.
438 | * 缺点
439 | * 需要设置ssh key.然而,baseimage-docker会提供一种方法,会让key的生成变得很容易.阅读更多信息.
440 |
441 | 第一件事情,就是你需要确定你在容器中已经安装设置了ssh key. 默认是不安装任何key的,所以任何人都无法登录.为了方便的原因,我们提供了一个[已经生成的key](https://github.com/phusion/baseimage-docker/blob/master/image/services/sshd/keys/insecure_key) [(PuTTY format)](https://github.com/phusion/baseimage-docker/blob/master/image/services/sshd/keys/insecure_key.ppk),为了让你使用方便.然后,请注意这个key仅仅是为方便.他没有任何安全性,因为它的key是在网络上提供的.**在生产环境,你必须使用你自己的key.**
442 |
443 |
444 |
445 | #### 在容器中使用key
446 |
447 | 你可以临时的使用key仅仅作为容器使用.这就以为这key是安装在容器上的.如果你使用`docker stop`和`docker start`控制容器,那么key是在容器中,但是如果你使用`docker run`开启一个新容器,那么这个容器是不包含key的.
448 |
449 | 启动新容器包含key`--enable-insecure-key`:
450 |
451 | docker run YOUR_IMAGE /sbin/my_init --enable-insecure-key
452 |
453 | 找出你的刚才运行的容器的ID:
454 |
455 | docker ps
456 |
457 | 一旦你得到容器的ID,就能找到容器使用的IP地址:
458 |
459 | docker inspect -f "{{ .NetworkSettings.IPAddress }}"
460 |
461 | 译者注: 类似 `"{{ .NetworkSettings.IPAddress }}"` 是用到了 [Go的模板语法](https://gohugo.io/templates/go-templates/).
462 |
463 | 现在你得到了IP地址, 你就可以通过SSH来登录容器,或者在容器中执行命令了:
464 |
465 | # 下载key
466 | curl -o insecure_key -fSL https://github.com/phusion/baseimage-docker/raw/master/image/services/sshd/keys/insecure_key
467 | chmod 600 insecure_key
468 |
469 | # 登录容器
470 | ssh -i insecure_key root@
471 |
472 | # 在容器中执行命令
473 | ssh -i insecure_key root@ echo hello world
474 |
475 |
476 | #### 支持一个长久的key
477 |
478 | 在一个长久存在的镜像中支持一个key是很可能的.一般是不推荐这么做,但是对于临时开始或者做demo演示,对安全要求不高,还是很合适的.
479 |
480 | 编辑你的dockerfile,来安装永久的key:
481 |
482 | RUN /usr/sbin/enable_insecure_key
483 |
484 | 在容器中怎么使用,同[在容器中使用key](#using_the_insecure_key_for_one_container_only)的章节说的一样.
485 |
486 |
487 | #### 使用你自己的key
488 |
489 | 编辑你的dockerfile,来安装ssh public key:
490 |
491 | ## 安装你自己的public key.
492 | COPY your_key.pub /tmp/your_key.pub
493 | RUN cat /tmp/your_key.pub >> /root/.ssh/authorized_keys && rm -f /tmp/your_key.pub
494 |
495 | 重新创建你的镜像.一旦你创建成功,启动基于这个镜像的容器.
496 |
497 | docker run your-image-name
498 |
499 | 找出你的刚才运行的容器的ID:
500 |
501 | docker ps
502 |
503 | 一旦你拥有容器的ID,就能找到容器使用的IP地址:
504 |
505 | docker inspect -f "{{ .NetworkSettings.IPAddress }}"
506 |
507 | 现在你有得了IP地址,你就可以通过SSH来登录容器,或者在容器中执行命令了:
508 |
509 | # 登录容器
510 | ssh -i /path-to/your_key root@
511 |
512 | # 在容器中执行命令
513 | ssh -i /path-to/your_key root@ echo hello world
514 |
515 |
516 | #### `docker-ssh`工具
517 |
518 | 找到容器的IP,运行ssh命令,很快会变得乏味无聊.幸运的是,我们提供了一个`docker-ssh`,可以自动完成这些事情.这个工具是运行在*Docker 主机*上的,不是安装在docker容器中的.
519 |
520 | 首先,在docker主机上面安装这个工具.
521 |
522 | curl --fail -L -O https://github.com/phusion/baseimage-docker/archive/master.tar.gz && \
523 | tar xzf master.tar.gz && \
524 | sudo ./baseimage-docker-master/install-tools.sh
525 |
526 | 使用这个工具通过ssh登录容器:
527 |
528 | docker-ssh YOUR-CONTAINER-ID
529 |
530 | 你可以使用`docker ps`找到`YOUR-CONTAINER-ID`.
531 |
532 | 默认,`docker-bash`会打开一个bash 回话.你可以告诉运行什么命令,之后就会自动退出:
533 |
534 | docker-ssh YOUR-CONTAINER-ID echo hello world
535 |
536 |
537 | ## 创建你自己的镜像
538 |
539 | 如果某些原因,你需要创建你自己的镜像,来替代从docker仓库下载镜像,可以按照的说明.
540 |
541 | 克隆仓库:
542 |
543 | git clone https://github.com/phusion/baseimage-docker.git
544 | cd baseimage-docker
545 |
546 | 创建一个包含docker在内的虚拟机.你可以使用我们提供的Vagrantfile.
547 |
548 | vagrant up
549 | vagrant ssh
550 | cd /vagrant
551 |
552 | 编译镜像:
553 |
554 | make build
555 |
556 | 如果你想修改镜像的名称, 通过`NAME`变量可以设置:
557 |
558 | make build NAME=joe/baseimage
559 |
560 |
561 | ## 总结
562 |
563 | * Using baseimage-docker? [Tweet about us](https://twitter.com/share) or [follow us on Twitter](https://twitter.com/phusion_nl).
564 | * Having problems? Want to participate in development? Please post a message at [the discussion forum](https://groups.google.com/d/forum/passenger-docker).
565 | * Looking for a more complete base image, one that is ideal for Ruby, Python, Node.js and Meteor web apps? Take a look at [passenger-docker](https://github.com/phusion/passenger-docker).
566 |
567 | [
](http://www.phusion.nl/)
568 |
569 | Please enjoy baseimage-docker, a product by [Phusion](http://www.phusion.nl/). :-)
570 |
--------------------------------------------------------------------------------
/README_zh_tw.md:
--------------------------------------------------------------------------------
1 |
2 | # Docker友好的,最小的Ubuntu基礎鏡像
3 |
4 | Baseimage-docker是一個特殊的[Docker](http://www.docker.io)鏡像,在Docker容器內做了配置,並且可以正確使用。它確實是一個Ubuntu系統, 除此之外進行了如下修訂:
5 |
6 | * 爲更加友好的支持Docker,做了修訂。
7 | * 在Docker環境下,作爲管理工具特別有用。
8 | * 在[不違反Docker哲學](#docker_single_process)的前提下,能夠很容易的運行多行程的機制。
9 |
10 | 可以把它作爲自己的基礎Docker鏡像。
11 |
12 | Baseimage-docker項目可以直接從Docker的[registry](https://index.docker.io/u/phusion/baseimage/)獲取!
13 |
14 |
15 | ### 原生的Ubuntu基礎鏡像有什麼問題呢?
16 |
17 | 原生Ubuntu不是爲了在Docker內運行而設計的。它的初始化系統Upstart,假定運行的環境要麼是真實的硬體,要麼是虛擬的硬體,而不是在Docker容器內。但是在一個Docker的容器內,並不需要一個完整的系統,你需要的只是一個很小的系統。但是如果你不是非常熟悉Unix的系統模型,想要在Docker容器內裁減出最小的系統,會碰到很多難以正確解決的陌生的技術坑。這些坑會引起很多莫名其妙的問題。
18 |
19 | Baseimage-docker讓這一切完美。在"內容"部分描述了所有這些修改。
20 |
21 |
22 | ### 爲什麼使用baseimage-docker?
23 |
24 | 你自己可以從Dockerfile配置一個原生`ubuntu`鏡像,爲什麼還要多此一舉的使用baseimage-docker呢?
25 |
26 | * 配置一個Docker友好的基礎系統並不是一個簡單的任務。如前所述,過程中會碰到很多坑。當你搞定這些坑之後,只不過是又重新發明了一個baseimage-docker而已。使用baseimage-docker可以免去你這方面需要做的努力。
27 | * 減少需要正確編寫Dockerfile文件的時間。你不用再擔心基礎系統,可以專注於你自己的技術棧和你的項目。
28 | * 減少需要運行`docker build`的時間,讓你更快的迭代Dockerfile。
29 | * 減少了重新部署的時的下載時間。Docker只需要在第一次部署的時候下載一次基礎鏡像。在隨後的部署中,只需要改變你下載之後對基礎鏡像進行修改的部分。
30 |
31 | -----------------------------------------
32 |
33 | **相關資源**
34 |
35 | [網站](http://phusion.github.io/baseimage-docker/) |
36 | [Github](https://github.com/phusion/baseimage-docker) |
37 | [Docker registry](https://index.docker.io/u/phusion/baseimage/) |
38 | [論壇](https://groups.google.com/d/forum/passenger-docker) |
39 | [Twitter](https://twitter.com/phusion_nl) |
40 | [Blog](http://blog.phusion.nl/)
41 |
42 | **目錄**
43 |
44 | * [鏡像裏面有什麼?](#whats_inside)
45 | * [概述](#whats_inside_overview)
46 | * [等等,我認爲Docker在一個容器中只能允許運行一個行程?](#docker_single_process)
47 | * [Baseimage-docker更側重於“胖容器”還是“把容器當作虛擬機”?](#fat_containers)
48 | * [查看baseimage-docker](#inspecting)
49 | * [使用baseimage-docker作爲基礎鏡像](#using)
50 | * [開始](#getting_started)
51 | * [增加額外的後臺行程](#adding_additional_daemons)
52 | * [容器啓動時運行腳本](#running_startup_scripts)
53 | * [環境變數](#environment_variables)
54 | * [集中定義自己的環境變數](#envvar_central_definition)
55 | * [保存環境變數](#envvar_dumps)
56 | * [修改環境變數](#modifying_envvars)
57 | * [安全性](#envvar_security)
58 | * [容器管理](#container_administration)
59 | * [在一個新容器中運行單條命令](#oneshot)
60 | * [在正在運行的的容器中運行一條命令](#run_inside_existing_container)
61 | * [通過`docer exec`登錄容器](#login_docker_exec)
62 | * [用法](#nsenter_usage)
63 | * [使用SSH登錄容器](#login_ssh)
64 | * [啓用SSH](#enabling_ssh)
65 | * [關於SSH的key](#ssh_keys)
66 | * [只對一個容器使用不安全key](#using_insecure_key_for_one_container_only)
67 | * [永久開啓不安全key](#enabling_the_insecure_key_permanently)
68 | * [使用你自己的key](#using_your_own_key)
69 | * [`docker-ssh`工具](#docker_ssh)
70 | * [構建自己的鏡像](#building)
71 | * [總結](#conclusion)
72 |
73 | -----------------------------------------
74 |
75 |
76 | ## 鏡像裏面有什麼?
77 |
78 |
79 | ### 概述
80 |
81 | *想看一個裏面包含Ruby,Python,Node.js以及Meteor的完整基礎鏡像?可以看一下[passenger-docker](https://github.com/phusion/passenger-docker)。*
82 |
83 | | 模塊 | 爲什麼包含這些?以及備註 |
84 | | ---------------- | ------------------- |
85 | | Ubuntu 24.04 LTS | 基礎系統。 |
86 | | 一個**正確**的初始化行程 | *主要文章:[Docker和PID 1 殭屍行程回收問題](http://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/)*
根據Unix行程模型,[初始化行程](https://en.wikipedia.org/wiki/Init) -- PID 1 -- 繼承了所有[孤立的子行程](https://en.wikipedia.org/wiki/Orphan_process),並且必須[進行回收](https://en.wikipedia.org/wiki/Wait_(system_call))。大多數Docker容器沒有一個初始化行程可以正確的完成此操作,隨着時間的推移會導致他們的容器出現了大量的[殭屍行程](https://en.wikipedia.org/wiki/Zombie_process)。
而且,`docker stop`發送SIGTERM信號給初始化行程,照理說此信號應該可以停止所有服務。不幸的是由於它們對硬體進行了關閉操作,導致Docker內的大多數初始化系統沒有正確執行。這會導致行程強行被SIGKILL信號關閉,從而喪失了一個正確取消初始化設置的機會。這會導致文件損壞。
Baseimage-docker配有一個名爲`/sbin/my_init`的初始化行程來同時正確的完成這些任務。 |
87 | | 修復了APT與Docker不兼容的問題 | 詳情參見:https://github.com/dotcloud/docker/issues/1024 。 |
88 | | syslog-ng | 對於很多服務-包括kernel自身,都需要一個syslog後臺行程,以便可以正確的將log輸出到/var/log/syslog中。如果沒有運行syslog後臺行程,很多重要的信息就會默默的丟失了。
只對本地進行監聽。所有syslog信息會被轉發給“docker logs”。 |
89 | | logrotate | 定期轉存和壓縮日誌。 |
90 | | SSH服務 | 允許你很容易的登錄到容器中進行[查詢或管理](#login_ssh)操作。
_SSH**默認是禁用**的,這也是baseimage-docker爲此目的提供的唯一方法。其它方法需要通過[docker exec](#login_docker_exec)。由於`docker exec`同時帶來了幾個需要注意的問題,SSH同時也提供了一個可替換的方法。_
密碼和challenge-response認證方式默認是禁用的。只有key認證通過之後才能夠開啓。 |
91 | | cron | 爲了保證cron任務能夠工作,必須運行cron後臺行程。 |
92 | | [runit](http://smarden.org/runit/) | 替換Ubuntu的Upstart。用於服務監控和管理。比SysV init更容易使用,同時當這些服務崩潰之後,支持後臺行程自動重啓。比Upstart更易使用,更加的輕量級。 |
93 | | `setuser` | 使用其它賬戶運行命令的工具。比`su`更容易使用,比使用`sudo`有那麼一點優勢,跟`chpst`不同,這個工具需要正確的設置`$HOME`。像`/sbin/setuser`這樣。 |
94 | Baseimage-docker非常的輕量級:僅僅佔用6MB內存。
95 |
96 |
97 | ### 等等,我認爲Docker在一個容器中就運行一個行程嗎?
98 | 絕對不是這樣的. 在一個docker容器中,運行多個行程也是很好的. 事實上,沒有什麼技術原因限制你只運行一個行程,運行很多的行程,只會把容器中系統的基本功能搞的更亂,比如syslog.
99 |
100 | Baseimage-docker *鼓勵* 通過runit來運行多行程.
101 |
102 |
103 | ## 檢測一下baseimage-docker
104 |
105 | 要檢測鏡像,執行下面的命令:
106 |
107 | docker run --rm -t -i phusion/baseimage: /sbin/my_init -- bash -l
108 |
109 | `` 是[baseimage-docker的版本號](https://github.com/phusion/baseimage-docker/blob/master/Changelog.md).
110 |
111 | 你不用手動去下載任何文件.上面的命令會自動從docker倉庫下載baseimage-docker鏡像.
112 |
113 |
114 | ## 使用baseimage-docker作爲基礎鏡像
115 |
116 |
117 | ### 入門指南
118 |
119 | The image is called `phusion/baseimage`, and is available on the Docker registry.
120 | 鏡像名字叫`phusion/baseimage`,在Docker倉庫上也是可用的.
121 |
122 | 下面的這個是一個Dockerfile的模板.
123 |
124 | # 使用phusion/baseimage作爲基礎鏡像,去構建你自己的鏡像,需要下載一個明確的版本,千萬不要使用`latest`.
125 | # 查看https://github.com/phusion/baseimage-docker/blob/master/Changelog.md,可用看到版本的列表.
126 | FROM phusion/baseimage:
127 |
128 | # 設置正確的環境變數.
129 | ENV HOME /root
130 |
131 | # 生成SSH keys,baseimage-docker不包含任何的key,所以需要你自己生成.你也可以註釋掉這句命令,系統在啓動過程中,會生成一個.
132 | RUN /etc/my_init.d/00_regen_ssh_host_keys.sh
133 |
134 | # 初始化baseimage-docker系統
135 | CMD ["/sbin/my_init"]
136 |
137 | # 這裏可以放置你自己需要構建的命令
138 |
139 | # 當完成後,清除APT.
140 | RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
141 |
142 |
143 |
144 | ### 增加後臺行程
145 |
146 | 你可以通過runit工具向你的鏡像中添加後臺行程(例如:你自己的某些應用).你需要編寫一個運行你需要的後臺行程的腳本就可以了,runit工具會保證它的正常運行,如果行程死掉,runit也會重啓它的.
147 |
148 | 腳本的名稱必須是`run`,必須是可以運行的,它需要放到`/etc/service/`.
149 |
150 | 這裏有一個例子,向你展示如果運行memcached服務的.
151 |
152 | ### memcached.sh(確定文件的權限是chmod +x):
153 | #!/bin/sh
154 | # `/sbin/setuser memcache` 指定一個`memcache`用戶來運行命令.如果你忽略了這部分,就會使用root用戶執行.
155 | exec /sbin/setuser memcache /usr/bin/memcached >>/var/log/memcached.log 2>&1
156 |
157 | ### 在Dockerfile中:
158 | RUN mkdir /etc/service/memcached
159 | COPY memcached.sh /etc/service/memcached/run
160 |
161 | 注意腳本必須運行在後臺的,**不能讓他們行程進行daemonize/fork**.通常,後臺行程會提供一個標誌位或者配置文件.
162 |
163 |
164 | ### 在容器啓動的時候,運行腳本.
165 |
166 | baseimage-docker的初始化腳本 `/sbin/my_init`,在啓動的時候行程運行,按照下面的順序:
167 |
168 | * 如果`/etc/my_init.d`存在,則按照字母順序執行腳本.
169 | * 如果`/etc/rc.local`存在,則執行裏面的腳本.
170 |
171 | 所有的腳本都是正確退出的,例如:退出的code是0.如果有任何腳本以非0的code退出,啓動就會失敗.
172 |
173 | 下面的例子向你展示了怎麼添加一個啓動腳本.這個腳本很簡單的記錄的一個系統啓動時間,將啓動時間記錄到/tmp/boottime.txt.
174 |
175 | ### 在 logtime.sh (文件權限chmod +x):
176 | #!/bin/sh
177 | date > /tmp/boottime.txt
178 |
179 | ### 在 Dockerfile中:
180 | RUN mkdir -p /etc/my_init.d
181 | COPY logtime.sh /etc/my_init.d/logtime.sh
182 |
183 |
184 |
185 | ### 環境變數
186 |
187 | 如果你使用`/sbin/my_init`作爲主容器命令,那麼通過`docker run --env`或者在Dockerfile文件中設置的`ENV`環境變數,都會被`my_init`讀取.
188 |
189 | * 在Unix系統中,環境變數都會被子行程給繼承.這就意味着,子行程不可能修改環境變數或者修改其他行程的環境變數.
190 | * 由於上面提到的一點,這裏沒有一個可以爲所有應用和服務集中定義環境的地方.Debian提供了一個`/etc/environment` 文件,解決一些問題.
191 | * 某些服務更改環境變數是爲了給子行程使用.Nginx有這樣的一個例子:它移除了所有的環境變數,除非你通過`env`進行了配置,明確了某些是保留的.如果你部署了任何應用在Nginx鏡像(例如:使用[passenger-docker](https://github.com/phusion/passenger-docker)鏡像或者使用Phusion Passenger作爲你的鏡像.),那麼你通過Docker,你不會看到任何環境變數.
192 |
193 |
194 | `my_init`提供了一個辦法來解決這些問題.
195 |
196 |
197 | #### 集中定義你的環境變數
198 |
199 | 在啓動的時候,在執行[startup scripts](#running_startup_scripts),`my_init`會從`/etc/container_environment`導入環境變數.這個文件夾下面,包含的文件,文件被命名爲環境變數的名字.文件內容就是環境變數的值.這個文件夾是因此是一個集中定義你的環境變數的好地方,它會繼承到所有啓動項目和Runit管理的服務中.
200 |
201 | 給個例子,在你的dockerfile如何定義一個環境變數:
202 |
203 | RUN echo Apachai Hopachai > /etc/container_environment/MY_NAME
204 |
205 | 你可以按照下面這樣驗證:
206 |
207 | $ docker run -t -i /sbin/my_init -- bash -l
208 | ...
209 | *** Running bash -l...
210 | # echo $MY_NAME
211 | Apachai Hopachai
212 |
213 | **換行處理**
214 |
215 | 如果你觀察仔細一點,你會注意到'echo'命令,實際上在它是在新行打印出來的.爲什麼$MY_NAME沒有包含在一行呢? 因爲`my_init`在尾部有個換行字符.如果你打算讓你的值包含一個新行,你需要增*另外*一個新字符,像這樣:
216 |
217 | RUN echo -e "Apachai Hopachai\n" > /etc/container_environment/MY_NAME
218 |
219 |
220 | #### 環境變數存儲
221 |
222 | 上面提到集中定義環境變數,它不會從子服務行程改變父服務行程或者重置環境變數.而且,`my_init`也會很容易的讓你查詢到原始的環境變數是什麼.
223 |
224 | 在啓動的時候,`/etc/container_environment`, `my_init`中的變數會存儲起來,並且導入到環境變數中,例如一下的格式:
225 |
226 | * `/etc/container_environment`
227 | * `/etc/container_environment.sh`- 一個bash存儲的環境變數格式.你可以從這個命令中得到base格式的文件.
228 | * `/etc/container_environment.json` - 一個json格式存儲的環境變數格式.
229 |
230 | 多種格式可以讓你不管採用什麼語言/apps都可以很容易使用環境變數.
231 |
232 | 這裏有個例子,展示怎麼使用:
233 |
234 | $ docker run -t -i \
235 | --env FOO=bar --env HELLO='my beautiful world' \
236 | phusion/baseimage: /sbin/my_init -- \
237 | bash -l
238 | ...
239 | *** Running bash -l...
240 | # ls /etc/container_environment
241 | FOO HELLO HOME HOSTNAME PATH TERM container
242 | # cat /etc/container_environment/HELLO; echo
243 | my beautiful world
244 | # cat /etc/container_environment.json; echo
245 | {"TERM": "xterm", "container": "lxc", "HOSTNAME": "f45449f06950", "HOME": "/root", "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "FOO": "bar", "HELLO": "my beautiful world"}
246 | # source /etc/container_environment.sh
247 | # echo $HELLO
248 | my beautiful world
249 |
250 |
251 | #### 修改環境變數
252 |
253 | 通過修改`/etc/container_environment`這個文件,很有可能修改了`my_init`中的環境變數.之後,每次`my_init`啓動[啓動腳本](#running_startup_scripts),就會重置掉我們自己`/etc/container_environment`中的環境變數,也就會導致`container_environment.sh`和`container_environment.json`重新存儲.
254 |
255 | 但是記住這些:
256 |
257 | * 修改`container_environment.sh` 和 `container_environment.json`是沒有效果的.
258 | * Runit 的服務是不能像這樣修改環境變數的.`my_init`運行的時候,只對`/etc/container_environment`中的修改是生效的.
259 |
260 |
261 | #### 安全
262 |
263 | 因爲環境變數可能包含敏感信息, `/etc/container_environment`和它的bash文件和JSON文件,默認都是root,都是可以被`docker_env`羣組可以訪問的(所以任何用戶只要添加到羣組中,都可以自動的獲取這些信息).
264 |
265 | 如果你確定你的環境變數中沒有什麼敏感信息,那麼你可以放鬆管理權限,將文件夾和文件分配下面的權限:
266 |
267 | RUN chmod 755 /etc/container_environment
268 | RUN chmod 644 /etc/container_environment.sh /etc/container_environment.json
269 |
270 |
271 | ### 解決Docker沒有辦法解決的/etc/hosts的問題
272 |
273 | 當前是沒有辦法在docker容器中修改`/etc/hosts`,這個是因爲[Docker bug 2267](https://github.com/dotcloud/docker/issues/2267).Baseimage-docker包含了解決這個問題的辦法,你必須明白是怎麼修改的.
274 |
275 | 修改的辦法包含在系統庫中的` libnss_files.so.2`文件,這個文件使用`/etc/workaround-docker-2267/hosts`來代替系統使用`/etc/hosts`.如果需要修改`/etc/hosts`,你只要修改`/etc/workaround-docker-2267/hosts`就可以了.
276 |
277 | 增加這個修改到你的Dockerfile.下面的命令修改了文件`libnss_files.so.2`.
278 |
279 | RUN /usr/bin/workaround-docker-2267
280 |
281 | (其實你不用在Dockerfile文件中運行這個命令,你可以在容器中運行一個shell就可以了.)
282 |
283 | 驗證一下它是否生效了,[在你的容器中打開一個shell](#inspecting),修改`/etc/workaround-docker-2267/hosts`,檢查一下是否生效了:
284 |
285 | bash# echo 127.0.0.1 my-test-domain.com >> /etc/workaround-docker-2267/hosts
286 | bash# ping my-test-domain.com
287 | ...should ping 127.0.0.1...
288 |
289 | **注意apt-get升級:** 如果Ubuntu升級,就有可能將`libnss_files.so.2`覆蓋掉,那麼修改就會失效.你必須重新運行`/usr/bin/workaround-docker-2267`.爲了安全一點,你應該在運行`apt-get upgrade`之後,運行一下這個命令.
290 |
291 |
292 | ### 禁用SSH
293 | Baseimage-docker默認是支持SSH的,所以可以[使用SSH](#login_ssh)來[管理你的容器](#container_administration).萬一你不想支持SSH,你可以只要禁用它:
294 |
295 | RUN rm -rf /etc/service/sshd /etc/my_init.d/00_regen_ssh_host_keys.sh
296 |
297 |
298 | ## 容器管理
299 |
300 | 一個優秀的docker想法,就是docker是一個無狀態的,容易啓動的容器,就想一個黑盒子.然而,你可能遇到某種情況,需要登錄到容器,或者運行命令在容器中.或者爲了開發,需要查看或者debug的目的.這章就給你講解怎麼管理容器.
301 |
302 |
303 |
304 | ### 在一個新容器中運行一個一閃而過的命令
305 |
306 | _**備註:** 這章講解怎麼在一個-新-容器中運行命令.要在一個存在的容器中運行命令,請查看[在一個存在的容器中,運行一個命令](#run_inside_existing_container)._
307 |
308 | 正常情況下,當你創建了一個新容器,爲了在容器中運行一個單獨的命令,而且在運行之後會立即退出的,你會這樣調用docker命令:
309 |
310 | docker run YOUR_IMAGE COMMAND ARGUMENTS...
311 |
312 | 然而下面的方法初始化系統的進行是不會啓動.它是這樣的,當調用`COMMAND`的時候,重要的後臺行程,例如定時任務和系統日誌都是不運行的.同樣,子行程也是不會出現的,因爲`COMMAND`的pid是1.
313 |
314 | Baseimage-docker提供了一個靈活的方式運行只要一閃而過的命令,同時也解決了上述所說的問題.以一下的方式運行一條命令:
315 |
316 | docker run YOUR_IMAGE /sbin/my_init -- COMMAND ARGUMENTS ...
317 |
318 | 他們會按照下面的流程執行:
319 |
320 | * 運行所有的啓動文件,例如 /etc/my_init.d/* and /etc/rc.local.
321 | * 運行所有的runit服務
322 | * 運行指定的命令
323 | * 運行指定的命令結束之後,結束所有runit服務.
324 |
325 | 例如:
326 |
327 | $ docker run phusion/baseimage: /sbin/my_init -- ls
328 | *** Running /etc/my_init.d/00_regen_ssh_host_keys.sh...
329 | No SSH host key available. Generating one...
330 | Creating SSH2 RSA key; this may take some time ...
331 | Creating SSH2 DSA key; this may take some time ...
332 | Creating SSH2 ECDSA key; this may take some time ...
333 | *** Running /etc/rc.local...
334 | *** Booting runit daemon...
335 | *** Runit started as PID 80
336 | *** Running ls...
337 | bin boot dev etc home image lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var
338 | *** ls exited with exit code 0.
339 | *** Shutting down runit daemon (PID 80)...
340 | *** Killing all processes...
341 |
342 | 你會發現默認的啓動的流程太負責.或者你不希望執行啓動文件.你可以自定義所有通過給`my_init`增加參數.調用`docker run YOUR_IMAGE /sbin/my_init --help`可以看到幫助信息.
343 |
344 | 例如上面運行`ls`命令,同時要求不運行啓動腳本,減少信息打印,運行runit所有命令.
345 |
346 | $ docker run phusion/baseimage: /sbin/my_init --skip-startup-files --quiet -- ls
347 | bin boot dev etc home image lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var
348 |
349 |
350 | ### 在一個已經運行的容器中,運行一條命令
351 |
352 | 這裏有兩種辦法去在一個已經運行的容器中運行命令.
353 |
354 | * 通過`nseneter`工具.這個工具用於Linux內核調用在內嵌容器中運行命令.可以查看[通過`nsenter`,登錄容器或者在容器內執行命令](#login_nsenter).
355 | * 通過SSH.這種辦法需要在容器中運行ssh服務,而且需要你創建自己的sshkey.可以查看[通過`ssh`,登錄容器或者在容器內執行命令](#login_ssh).
356 |
357 | 兩種方法都是他們各自的優點和確定,你可以學習他們各自的章節來了他們.
358 |
359 |
360 | ### 通過`nsenter`,登錄容器或者在容器內執行命令
361 |
362 | 你可以使用在docker主機上面的`nsenter`工具,來登錄任何基於baseimage-docker的docker容器.你可以使用它在你的容器中運行命令.
363 |
364 | 這裏有個和[通過`ssh`,登錄容器或者在容器內執行命令](#login_ssh)的優缺點的比較:
365 |
366 | * 優點
367 | * 不需要在容器中運行ssh服務.
368 | * 不需要ssh key.
369 | * 運行在任何容器上,甚至不是基於baseimage-docker的容器.
370 | * 缺點
371 | * 通過`nsenter`運行的行程會和正常運行稍微有不同.例如,他們不同結束掉在容器中正常運行的行程.這適用於所有的子行程.
372 | * 如果`nsenter`行程被其他命令(如`kill`命令)給終止,然後由nsenter所執行的命令,是*不會*被結束的.你將不得不手動清理.(備註:終端控制命令像Ctrl-C *會* 清理所有的子行程,因爲終端信號被髮送到所有流程的終端會話)
373 | * 需要學習新工具.
374 | * 需要在docker主機上面提供root權限.
375 | * 需要在docker主機上面是可用的.在寫這篇文字的時候(2014年7月),大多數linux發行版沒有加載它.然而,baseimage-docker提供了預編譯的二進制文件,允許你通過[docker-bash](#docker_bash)工具,來很容易的使用它.
376 | * 不可能沒有登錄到docker主機,就登錄到docker容器中.(也就是說,你必須登錄到docker主機,通過docker主機登錄到容器.)
377 |
378 |
379 | #### 用例
380 |
381 | 第一,確定`nsenter`已經安裝了.在寫這篇文字的時候(2014年7月),大多數linux發行版沒有加載它.然而,baseimage-docker提供了預編譯的二進制文件,允許你通過[docker-bash](#docker_bash)工具,讓任何人都可以使用.
382 |
383 | 接着,啓動一個容器.
384 |
385 | docker run YOUR_IMAGE
386 |
387 | 找出你剛纔運行容器的`ID`.
388 |
389 | docker ps
390 |
391 | 一旦擁有容器的id,找到運行容器的主要行程額`PID`.
392 |
393 | docker inspect -f "{{ .State.Pid }}"
394 |
395 | 現在你有的容器的主行程的PID,就可以使用`nsenter`來登錄容器,或者在容器裏面執行命令:
396 |
397 | # 登錄容器
398 | nsenter --target --mount --uts --ipc --net --pid bash -l
399 |
400 | # 在容器中執行命令
401 | nsenter --target --mount --uts --ipc --net --pid -- echo hello world
402 |
403 |
404 | #### `docker-bash`工具
405 |
406 | 查找一個容器的主要行程的PID和輸入這麼長的nsenter命令很快會變得乏味無論.幸運的是,我們提供了一個`docker-bash` 工具,它可以自動完成只要的工具.這個工具是運行在*docker主機*上面,不是在docker容器中.
407 |
408 | 該工具還附帶了一個預編譯的二進制`nsenter`,這樣你不需要自己安裝`nsenter`了.`docker-bash`是很簡單的使用的.
409 |
410 | 首先,在docker主機上安裝這個工具:
411 |
412 | curl --fail -L -O https://github.com/phusion/baseimage-docker/archive/master.tar.gz && \
413 | tar xzf master.tar.gz && \
414 | sudo ./baseimage-docker-master/install-tools.sh
415 |
416 | 運行這個工具登錄到容器中:
417 |
418 | docker-bash YOUR-CONTAINER-ID
419 |
420 | 你可以通過`docker ps`來查找你的容器ID.
421 |
422 | 默認,`docker-bash`會打開一個bash 回話.你可以告訴運行什麼命令,之後就會自動退出:
423 |
424 | docker-bash YOUR-CONTAINER-ID echo hello world
425 |
426 |
427 | ### 通過`ssh`,登錄容器或者在容器內執行命令
428 |
429 | 你可以使用ssh來登錄任何基於baseimage-docker的容器.你可以使用它在容器中執行命令.
430 |
431 | 這裏有個和[通過`nsenter`,登錄容器或者在容器內執行命令](#login_nsenter)的優缺點的比較:
432 |
433 | * 優點
434 | * 不像`nsenter`一樣,運行在docker主機上面.幾乎每個人都會安裝一個ssh客戶端.
435 | * 不想使用`nsenter`,運行的行程和正在的行程會不一樣.
436 | * 不需要docker主機提供root權限.
437 | * 運行你讓用戶登錄到容器,而不需要登錄到docker主機.然而,默認這是不啓用的,因爲baseimage-docker默認不是開放ssh服務的.
438 | * 缺點
439 | * 需要設置ssh key.然而,baseimage-docker會提供一中辦法,會讓key的生成會很容易.閱讀更多信息.
440 |
441 | 第一件事情,就是你需要確定你在容器中已經安裝設置了ssh key. 默認是不安裝任何key的,所以任何人都無法登錄.爲了方便的原因,我們提供了一個[已經生成的key](https://github.com/phusion/baseimage-docker/blob/master/image/services/sshd/keys/insecure_key) [(PuTTY format)](https://github.com/phusion/baseimage-docker/blob/master/image/services/sshd/keys/insecure_key.ppk),爲了讓你使用方便.然後,請注意這個key僅僅是爲方便.他沒有任何安全性,因爲它的key是在網絡上提供的.**在生產環境,你必須使用你自己的key.**
442 |
443 |
444 |
445 | #### 在容器中使用key
446 |
447 | 你可以臨時的使用key僅僅作爲容器使用.這就以爲這key是安裝在容器上的.如果你使用`docker stop`和`docker start`控制容器,那麼key是在容器中,但是如果你使用`docker run`開啓一個新容器,那麼這個容器是不包含key的.
448 |
449 | 啓動新容器包含key`--enable-insecure-key`:
450 |
451 | docker run YOUR_IMAGE /sbin/my_init --enable-insecure-key
452 |
453 | 找出你的剛纔運行的容器的ID:
454 |
455 | docker ps
456 |
457 | 一旦你擁有容器的ID,就能找到容器使用的IP地址:
458 |
459 | docker inspect -f "{{ .NetworkSettings.IPAddress }}"
460 |
461 | 現在你有得了IP地址,你就看通過SSH來登錄容器,或者在容器中執行命令了:
462 |
463 | # 下載key
464 | curl -o insecure_key -fSL https://github.com/phusion/baseimage-docker/raw/master/image/services/sshd/keys/insecure_key
465 | chmod 600 insecure_key
466 |
467 | # 登錄容器
468 | ssh -i insecure_key root@
469 |
470 | # 在容器中執行命令
471 | ssh -i insecure_key root@ echo hello world
472 |
473 |
474 | #### 支持一個長久的key
475 |
476 | 在一個長久存在的鏡像中支持一個key是很可能的.一般是不推薦這麼做,但是對於臨時開始或者做demo演示,對安全要求不高,還是很合適的.
477 |
478 | 編輯你的dockerfile,來安裝永久的key:
479 |
480 | RUN /usr/sbin/enable_insecure_key
481 |
482 | 在容器中怎麼使用,同[在容器中使用key](#using_the_insecure_key_for_one_container_only)的章節說的一樣.
483 |
484 |
485 | #### 使用你自己的key
486 |
487 | 編輯你的dockerfile,來安裝ssh public key:
488 |
489 | ## 安裝你自己的public key.
490 | COPY your_key.pub /tmp/your_key.pub
491 | RUN cat /tmp/your_key.pub >> /root/.ssh/authorized_keys && rm -f /tmp/your_key.pub
492 |
493 | 重新創建你的鏡像.一旦你創建成功,啓動基於這個鏡像的容器.
494 |
495 | docker run your-image-name
496 |
497 | 找出你的剛纔運行的容器的ID:
498 |
499 | docker ps
500 |
501 | 一旦你擁有容器的ID,就能找到容器使用的IP地址:
502 |
503 | docker inspect -f "{{ .NetworkSettings.IPAddress }}"
504 |
505 | 現在你有得了IP地址,你就看通過SSH來登錄容器,或者在容器中執行命令了:
506 |
507 | # 登錄容器
508 | ssh -i /path-to/your_key root@
509 |
510 | # 在容器中執行命令
511 | ssh -i /path-to/your_key root@ echo hello world
512 |
513 |
514 | #### `docker-ssh`工具
515 |
516 | 找到容器的IP,運行ssh命令,很快會變得乏味無聊.幸運的是,我們提供了一個`docker-ssh`,可以自動完成這些事情.這個工具是運行在*Docker 主機*上的,不是安裝在docker容器中的.
517 |
518 | 首先,在docker主機上面安裝這個工具.
519 |
520 | curl --fail -L -O https://github.com/phusion/baseimage-docker/archive/master.tar.gz && \
521 | tar xzf master.tar.gz && \
522 | sudo ./baseimage-docker-master/install-tools.sh
523 |
524 | 使用這個工具通過ssh登錄容器:
525 |
526 | docker-ssh YOUR-CONTAINER-ID
527 |
528 | 你可以使用`docker ps`找到`YOUR-CONTAINER-ID`.
529 |
530 | 默認,`docker-bash`會打開一個bash 回話.你可以告訴運行什麼命令,之後就會自動退出:
531 |
532 | docker-ssh YOUR-CONTAINER-ID echo hello world
533 |
534 |
535 | ## 創建你自己的鏡像
536 |
537 | 如果某些原因,你需要創建你自己的鏡像,來替代從docker倉庫下載鏡像,可以按照的說明.
538 |
539 | 克隆倉庫:
540 |
541 | git clone https://github.com/phusion/baseimage-docker.git
542 | cd baseimage-docker
543 |
544 | 創建一個包含docker在的虛擬機.你可以使用我們提供的Vagrantfile.
545 |
546 | vagrant up
547 | vagrant ssh
548 | cd /vagrant
549 |
550 | 編譯鏡像:
551 |
552 | make build
553 |
554 | 如果你想把創建的鏡像名字,叫其他名字,通過`NAME`變數可以設置:
555 |
556 | make build NAME=joe/baseimage
557 |
558 |
559 | ## 總結
560 |
561 | * Using baseimage-docker? [Tweet about us](https://twitter.com/share) or [follow us on Twitter](https://twitter.com/phusion_nl).
562 | * Having problems? Want to participate in development? Please post a message at [the discussion forum](https://groups.google.com/d/forum/passenger-docker).
563 | * Looking for a more complete base image, one that is ideal for Ruby, Python, Node.js and Meteor web apps? Take a look at [passenger-docker](https://github.com/phusion/passenger-docker).
564 |
565 | [
](http://www.phusion.nl/)
566 |
567 | Please enjoy baseimage-docker, a product by [Phusion](http://www.phusion.nl/). :-)
568 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure
5 | # configures the configuration version (we support older styles for
6 | # backwards compatibility). Please don't change it unless you know what
7 | # you're doing.
8 | Vagrant.configure("2") do |config|
9 | # The most common configuration options are documented and commented below.
10 | # For a complete reference, please see the online documentation at
11 | # https://docs.vagrantup.com.
12 |
13 | # Every Vagrant development environment requires a box. You can search for
14 | # boxes at https://atlas.hashicorp.com/search.
15 | config.vm.box = "ubuntu/noble64"
16 | config.disksize.size = '50GB'
17 |
18 | # Disable automatic box update checking. If you disable this, then
19 | # boxes will only be checked for updates when the user runs
20 | # `vagrant box outdated`. This is not recommended.
21 | # config.vm.box_check_update = false
22 |
23 | # Create a forwarded port mapping which allows access to a specific port
24 | # within the machine from a port on the host machine. In the example below,
25 | # accessing "localhost:8080" will access port 80 on the guest machine.
26 | # config.vm.network "forwarded_port", guest: 80, host: 8080
27 |
28 | # Create a private network, which allows host-only access to the machine
29 | # using a specific IP.
30 | # config.vm.network "private_network", ip: "192.168.33.10"
31 |
32 | # Create a public network, which generally matched to bridged network.
33 | # Bridged networks make the machine appear as another physical device on
34 | # your network.
35 | # config.vm.network "public_network"
36 |
37 | # Share an additional folder to the guest VM. The first argument is
38 | # the path on the host to the actual folder. The second argument is
39 | # the path on the guest to mount the folder. And the optional third
40 | # argument is a set of non-required options.
41 | # config.vm.synced_folder "../data", "/vagrant_data"
42 |
43 | # Provider-specific configuration so you can fine-tune various
44 | # backing providers for Vagrant. These expose provider-specific options.
45 | # Example for VirtualBox:
46 | #
47 | # config.vm.provider "virtualbox" do |vb|
48 | # # Display the VirtualBox GUI when booting the machine
49 | # vb.gui = true
50 | #
51 | # # Customize the amount of memory on the VM:
52 | # vb.memory = "1024"
53 | # end
54 | #
55 | # View the documentation for the provider you are using for more
56 | # information on available options.
57 |
58 | # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies
59 | # such as FTP and Heroku are also available. See the documentation at
60 | # https://docs.vagrantup.com/v2/push/atlas.html for more information.
61 | # config.push.define "atlas" do |push|
62 | # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME"
63 | # end
64 |
65 | # Enable provisioning with a shell script. Additional provisioners such as
66 | # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
67 | # documentation for more information about their specific syntax and use.
68 | # config.vm.provision "shell", inline: <<-SHELL
69 | # apt-get update
70 | # apt-get install -y apache2
71 | # SHELL
72 | config.vm.provision :shell,
73 | path: "vagrant-libs/bootstrap.sh"
74 | end
75 |
--------------------------------------------------------------------------------
/build-multiarch.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | set -x
4 |
5 | for arch in $ARCHS; do
6 | docker pull $NAME:$VERSION-${arch}
7 |
8 | if [[ $TAG_LATEST != 'true' ]]; then
9 | docker manifest create --amend $NAME:$VERSION $NAME:$VERSION-${arch}
10 | docker manifest annotate $NAME:$VERSION $NAME:$VERSION-${arch} --arch ${arch}
11 | else
12 | docker manifest create --amend $NAME:latest $NAME:$VERSION-${arch}
13 | docker manifest annotate $NAME:latest $NAME:$VERSION-${arch} --arch ${arch}
14 | fi
15 | done
16 |
17 | echo "Push manifests"
18 | if [[ $TAG_LATEST != 'true' ]]; then
19 | docker manifest push $NAME:$VERSION
20 | else
21 | docker manifest push $NAME:latest
22 | fi
23 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | # # Prepare qemu
5 | # if [ '$QEMU_ARCH' != 'amd64' ]; then
6 | # # docker run --rm --privileged multiarch/qemu-user-static:register --reset
7 | # fi
8 |
9 | # Get qemu package
10 | echo "Getting qemu package for $QEMU_ARCH"
11 |
12 | # Fake qemu for amd64 builds to avoid breaking COPY in Dockerfile
13 | if [[ $QEMU_ARCH == "amd64" ]]; then
14 | touch x86_64_qemu-"$QEMU_ARCH"-static.tar.gz
15 | mv x86_64_qemu-${QEMU_ARCH}-static.tar.gz image
16 | else
17 | curl -L -o x86_64_qemu-"$QEMU_ARCH"-static.tar.gz https://github.com/multiarch/qemu-user-static/releases/download/"$QEMU_VERSION"/x86_64_qemu-"$QEMU_ARCH"-static.tar.gz
18 | mv x86_64_qemu-${QEMU_ARCH}-static.tar.gz image
19 | fi
20 |
--------------------------------------------------------------------------------
/image/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG BASE_IMAGE=ubuntu:24.04
2 | FROM $BASE_IMAGE
3 |
4 | ARG QEMU_ARCH
5 | #ADD x86_64_qemu-${QEMU_ARCH}-static.tar.gz /usr/bin
6 |
7 | COPY . /bd_build
8 |
9 | RUN /bd_build/prepare.sh && \
10 | /bd_build/system_services.sh && \
11 | /bd_build/utilities.sh && \
12 | /bd_build/cleanup.sh
13 |
14 | ENV DEBIAN_FRONTEND="teletype" \
15 | LANG="en_US.UTF-8" \
16 | LANGUAGE="en_US:en" \
17 | LC_ALL="en_US.UTF-8"
18 |
19 | CMD ["/sbin/my_init"]
20 |
--------------------------------------------------------------------------------
/image/bin/install_clean:
--------------------------------------------------------------------------------
1 | #!/bin/bash -e
2 | # Apt installer helper for Docker images
3 |
4 | ARGS="$*"
5 | NO_RECOMMENDS="--no-install-recommends"
6 | RECOMMENDS="--install-recommends"
7 | if [[ $ARGS =~ "$RECOMMENDS" ]]; then
8 | NO_RECOMMENDS=""
9 | ARGS=$(sed "s/$RECOMMENDS//g" <<<"$ARGS")
10 | fi
11 |
12 | echo "Installing $ARGS"
13 |
14 | apt-get -q update && apt-get -qy install $NO_RECOMMENDS $ARGS \
15 | && apt-get -qy autoremove \
16 | && apt-get clean \
17 | && rm -r /var/lib/apt/lists/*
18 |
--------------------------------------------------------------------------------
/image/bin/my_init:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3 -u
2 | # -*- coding: utf-8 -*-
3 |
4 | import argparse
5 | import errno
6 | import json
7 | import os
8 | import os.path
9 | import re
10 | import signal
11 | import stat
12 | import sys
13 | import time
14 |
15 | ENV_INIT_DIRECTORY = os.environ.get('ENV_INIT_DIRECTORY', '/etc/my_init.d')
16 |
17 | KILL_PROCESS_TIMEOUT = int(os.environ.get('KILL_PROCESS_TIMEOUT', 30))
18 | KILL_ALL_PROCESSES_TIMEOUT = int(os.environ.get('KILL_ALL_PROCESSES_TIMEOUT', 30))
19 |
20 | LOG_LEVEL_ERROR = 1
21 | LOG_LEVEL_WARN = 1
22 | LOG_LEVEL_INFO = 2
23 | LOG_LEVEL_DEBUG = 3
24 |
25 | SHENV_NAME_WHITELIST_REGEX = re.compile(r'\W')
26 |
27 | log_level = None
28 |
29 | terminated_child_processes = {}
30 |
31 | _find_unsafe = re.compile(r'[^\w@%+=:,./-]').search
32 |
33 |
34 | class AlarmException(Exception):
35 | pass
36 |
37 |
38 | def error(message):
39 | if log_level >= LOG_LEVEL_ERROR:
40 | sys.stderr.write("*** %s\n" % message)
41 |
42 |
43 | def warn(message):
44 | if log_level >= LOG_LEVEL_WARN:
45 | sys.stderr.write("*** %s\n" % message)
46 |
47 |
48 | def info(message):
49 | if log_level >= LOG_LEVEL_INFO:
50 | sys.stderr.write("*** %s\n" % message)
51 |
52 |
53 | def debug(message):
54 | if log_level >= LOG_LEVEL_DEBUG:
55 | sys.stderr.write("*** %s\n" % message)
56 |
57 |
58 | def ignore_signals_and_raise_keyboard_interrupt(signame):
59 | signal.signal(signal.SIGTERM, signal.SIG_IGN)
60 | signal.signal(signal.SIGINT, signal.SIG_IGN)
61 | raise KeyboardInterrupt(signame)
62 |
63 |
64 | def raise_alarm_exception():
65 | raise AlarmException('Alarm')
66 |
67 |
68 | def listdir(path):
69 | try:
70 | result = os.stat(path)
71 | except OSError:
72 | return []
73 | if stat.S_ISDIR(result.st_mode):
74 | return sorted(os.listdir(path))
75 | else:
76 | return []
77 |
78 |
79 | def is_exe(path):
80 | try:
81 | return os.path.isfile(path) and os.access(path, os.X_OK)
82 | except OSError:
83 | return False
84 |
85 |
86 | def import_envvars(clear_existing_environment=True, override_existing_environment=True):
87 | if not os.path.exists("/etc/container_environment"):
88 | return
89 | new_env = {}
90 | for envfile in listdir("/etc/container_environment"):
91 | name = os.path.basename(envfile)
92 | with open("/etc/container_environment/" + envfile, "r") as f:
93 | # Text files often end with a trailing newline, which we
94 | # don't want to include in the env variable value. See
95 | # https://github.com/phusion/baseimage-docker/pull/49
96 | value = re.sub('\n\\Z', '', f.read())
97 | new_env[name] = value
98 | if clear_existing_environment:
99 | os.environ.clear()
100 | for name, value in new_env.items():
101 | if override_existing_environment or name not in os.environ:
102 | os.environ[name] = value
103 |
104 |
105 | def export_envvars(to_dir=True):
106 | if not os.path.exists("/etc/container_environment"):
107 | return
108 | shell_dump = ""
109 | for name, value in os.environ.items():
110 | if name in ['HOME', 'USER', 'GROUP', 'UID', 'GID', 'SHELL']:
111 | continue
112 | if to_dir:
113 | with open("/etc/container_environment/" + name, "w") as f:
114 | f.write(value)
115 | shell_dump += "export " + sanitize_shenvname(name) + "=" + shquote(value) + "\n"
116 | with open("/etc/container_environment.sh", "w") as f:
117 | f.write(shell_dump)
118 | with open("/etc/container_environment.json", "w") as f:
119 | f.write(json.dumps(dict(os.environ)))
120 |
121 |
122 | def shquote(s):
123 | """Return a shell-escaped version of the string *s*."""
124 | if not s:
125 | return "''"
126 | if _find_unsafe(s) is None:
127 | return s
128 |
129 | # use single quotes, and put single quotes into double quotes
130 | # the string $'b is then quoted as '$'"'"'b'
131 | return "'" + s.replace("'", "'\"'\"'") + "'"
132 |
133 |
134 | def sanitize_shenvname(s):
135 | """Return string with [0-9a-zA-Z_] characters"""
136 | return re.sub(SHENV_NAME_WHITELIST_REGEX, "_", s)
137 |
138 |
139 | # Waits for the child process with the given PID, while at the same time
140 | # reaping any other child processes that have exited (e.g. adopted child
141 | # processes that have terminated).
142 |
143 | def waitpid_reap_other_children(pid):
144 | global terminated_child_processes
145 |
146 | status = terminated_child_processes.get(pid)
147 | if status:
148 | # A previous call to waitpid_reap_other_children(),
149 | # with an argument not equal to the current argument,
150 | # already waited for this process. Return the status
151 | # that was obtained back then.
152 | del terminated_child_processes[pid]
153 | return status
154 |
155 | done = False
156 | status = None
157 | while not done:
158 | try:
159 | # https://github.com/phusion/baseimage-docker/issues/151#issuecomment-92660569
160 | this_pid, status = os.waitpid(pid, os.WNOHANG)
161 | if this_pid == 0:
162 | this_pid, status = os.waitpid(-1, 0)
163 | if this_pid == pid:
164 | done = True
165 | else:
166 | # Save status for later.
167 | terminated_child_processes[this_pid] = status
168 | except OSError as e:
169 | if e.errno == errno.ECHILD or e.errno == errno.ESRCH:
170 | return None
171 | else:
172 | raise
173 | return status
174 |
175 |
176 | def stop_child_process(name, pid, signo=signal.SIGTERM, time_limit=KILL_PROCESS_TIMEOUT):
177 | info("Shutting down %s (PID %d)..." % (name, pid))
178 | try:
179 | os.kill(pid, signo)
180 | except OSError:
181 | pass
182 | signal.alarm(time_limit)
183 | try:
184 | try:
185 | waitpid_reap_other_children(pid)
186 | except OSError:
187 | pass
188 | except AlarmException:
189 | warn("%s (PID %d) did not shut down in time. Forcing it to exit." % (name, pid))
190 | try:
191 | os.kill(pid, signal.SIGKILL)
192 | except OSError:
193 | pass
194 | try:
195 | waitpid_reap_other_children(pid)
196 | except OSError:
197 | pass
198 | finally:
199 | signal.alarm(0)
200 |
201 |
202 | def run_command_killable(*argv):
203 | filename = argv[0]
204 | status = None
205 | pid = os.spawnvp(os.P_NOWAIT, filename, argv)
206 | try:
207 | status = waitpid_reap_other_children(pid)
208 | except BaseException:
209 | warn("An error occurred. Aborting.")
210 | stop_child_process(filename, pid)
211 | raise
212 | if status != 0:
213 | if status is None:
214 | error("%s exited with unknown status\n" % filename)
215 | else:
216 | error("%s failed with status %d\n" % (filename, os.WEXITSTATUS(status)))
217 | sys.exit(1)
218 |
219 |
220 | def run_command_killable_and_import_envvars(*argv):
221 | run_command_killable(*argv)
222 | import_envvars()
223 | export_envvars(False)
224 |
225 |
226 | def kill_all_processes(time_limit):
227 | info("Killing all processes...")
228 | try:
229 | os.kill(-1, signal.SIGTERM)
230 | except OSError:
231 | pass
232 | signal.alarm(time_limit)
233 | try:
234 | # Wait until no more child processes exist.
235 | done = False
236 | while not done:
237 | try:
238 | os.waitpid(-1, 0)
239 | except OSError as e:
240 | if e.errno == errno.ECHILD:
241 | done = True
242 | else:
243 | raise
244 | except AlarmException:
245 | warn("Not all processes have exited in time. Forcing them to exit.")
246 | try:
247 | os.kill(-1, signal.SIGKILL)
248 | except OSError:
249 | pass
250 | finally:
251 | signal.alarm(0)
252 |
253 |
254 | def run_startup_files():
255 | # Run ENV_INIT_DIRECTORY/*
256 | for name in listdir(ENV_INIT_DIRECTORY):
257 | filename = os.path.join(ENV_INIT_DIRECTORY, name)
258 | if is_exe(filename):
259 | info("Running %s..." % filename)
260 | run_command_killable_and_import_envvars(filename)
261 |
262 | # Run /etc/rc.local.
263 | if is_exe("/etc/rc.local"):
264 | info("Running /etc/rc.local...")
265 | run_command_killable_and_import_envvars("/etc/rc.local")
266 |
267 |
268 | def run_pre_shutdown_scripts():
269 | debug("Running pre-shutdown scripts...")
270 |
271 | # Run /etc/my_init.pre_shutdown.d/*
272 | for name in listdir("/etc/my_init.pre_shutdown.d"):
273 | filename = "/etc/my_init.pre_shutdown.d/" + name
274 | if is_exe(filename):
275 | info("Running %s..." % filename)
276 | run_command_killable(filename)
277 |
278 |
279 | def run_post_shutdown_scripts():
280 | debug("Running post-shutdown scripts...")
281 |
282 | # Run /etc/my_init.post_shutdown.d/*
283 | for name in listdir("/etc/my_init.post_shutdown.d"):
284 | filename = "/etc/my_init.post_shutdown.d/" + name
285 | if is_exe(filename):
286 | info("Running %s..." % filename)
287 | run_command_killable(filename)
288 |
289 |
290 | def start_runit():
291 | info("Booting runit daemon...")
292 | pid = os.spawnl(os.P_NOWAIT, "/usr/bin/runsvdir", "/usr/bin/runsvdir",
293 | "-P", "/etc/service")
294 | info("Runit started as PID %d" % pid)
295 | return pid
296 |
297 |
298 | def wait_for_runit_or_interrupt(pid):
299 | status = waitpid_reap_other_children(pid)
300 | return (True, status)
301 |
302 |
303 | def shutdown_runit_services(quiet=False):
304 | if not quiet:
305 | debug("Begin shutting down runit services...")
306 | os.system("/usr/bin/sv -w %d force-stop /etc/service/* > /dev/null" % KILL_PROCESS_TIMEOUT)
307 |
308 |
309 | def wait_for_runit_services():
310 | debug("Waiting for runit services to exit...")
311 | done = False
312 | while not done:
313 | done = os.system("/usr/bin/sv status /etc/service/* | grep -q '^run:'") != 0
314 | if not done:
315 | time.sleep(0.1)
316 | # According to https://github.com/phusion/baseimage-docker/issues/315
317 | # there is a bug or race condition in Runit, causing it
318 | # not to shutdown services that are already being started.
319 | # So during shutdown we repeatedly instruct Runit to shutdown
320 | # services.
321 | shutdown_runit_services(True)
322 |
323 |
324 | def install_insecure_key():
325 | info("Installing insecure SSH key for user root")
326 | run_command_killable("/usr/sbin/enable_insecure_key")
327 |
328 |
329 | def main(args):
330 | import_envvars(False, False)
331 | export_envvars()
332 |
333 | if args.enable_insecure_key:
334 | install_insecure_key()
335 |
336 | if not args.skip_startup_files:
337 | run_startup_files()
338 |
339 | runit_exited = False
340 | exit_code = None
341 |
342 | if not args.skip_runit:
343 | runit_pid = start_runit()
344 | try:
345 | exit_status = None
346 | if len(args.main_command) == 0:
347 | runit_exited, exit_code = wait_for_runit_or_interrupt(runit_pid)
348 | if runit_exited:
349 | if exit_code is None:
350 | info("Runit exited with unknown status")
351 | exit_status = 1
352 | else:
353 | exit_status = os.WEXITSTATUS(exit_code)
354 | info("Runit exited with status %d" % exit_status)
355 | else:
356 | info("Running %s..." % " ".join(args.main_command))
357 | pid = os.spawnvp(os.P_NOWAIT, args.main_command[0], args.main_command)
358 | try:
359 | exit_code = waitpid_reap_other_children(pid)
360 | if exit_code is None:
361 | info("%s exited with unknown status." % args.main_command[0])
362 | exit_status = 1
363 | else:
364 | exit_status = os.WEXITSTATUS(exit_code)
365 | info("%s exited with status %d." % (args.main_command[0], exit_status))
366 | except KeyboardInterrupt:
367 | stop_child_process(args.main_command[0], pid)
368 | raise
369 | except BaseException:
370 | warn("An error occurred. Aborting.")
371 | stop_child_process(args.main_command[0], pid)
372 | raise
373 | sys.exit(exit_status)
374 | finally:
375 | if not args.skip_runit:
376 | run_pre_shutdown_scripts()
377 | shutdown_runit_services()
378 | if not runit_exited:
379 | stop_child_process("runit daemon", runit_pid)
380 | wait_for_runit_services()
381 | run_post_shutdown_scripts()
382 |
383 | # Parse options.
384 | parser = argparse.ArgumentParser(description='Initialize the system.')
385 | parser.add_argument('main_command', metavar='MAIN_COMMAND', type=str, nargs='*',
386 | help='The main command to run. (default: runit)')
387 | parser.add_argument('--enable-insecure-key', dest='enable_insecure_key',
388 | action='store_const', const=True, default=False,
389 | help='Install the insecure SSH key')
390 | parser.add_argument('--skip-startup-files', dest='skip_startup_files',
391 | action='store_const', const=True, default=False,
392 | help='Skip running /etc/my_init.d/* and /etc/rc.local')
393 | parser.add_argument('--skip-runit', dest='skip_runit',
394 | action='store_const', const=True, default=False,
395 | help='Do not run runit services')
396 | parser.add_argument('--no-kill-all-on-exit', dest='kill_all_on_exit',
397 | action='store_const', const=False, default=True,
398 | help='Don\'t kill all processes on the system upon exiting')
399 | parser.add_argument('--quiet', dest='log_level',
400 | action='store_const', const=LOG_LEVEL_WARN, default=LOG_LEVEL_INFO,
401 | help='Only print warnings and errors')
402 | args = parser.parse_args()
403 | log_level = args.log_level
404 |
405 | if args.skip_runit and len(args.main_command) == 0:
406 | error("When --skip-runit is given, you must also pass a main command.")
407 | sys.exit(1)
408 |
409 | # Run main function.
410 | signal.signal(signal.SIGTERM, lambda signum, frame: ignore_signals_and_raise_keyboard_interrupt('SIGTERM'))
411 | signal.signal(signal.SIGINT, lambda signum, frame: ignore_signals_and_raise_keyboard_interrupt('SIGINT'))
412 | signal.signal(signal.SIGALRM, lambda signum, frame: raise_alarm_exception())
413 | try:
414 | main(args)
415 | except KeyboardInterrupt:
416 | warn("Init system aborted.")
417 | exit(2)
418 | finally:
419 | if args.kill_all_on_exit:
420 | kill_all_processes(KILL_ALL_PROCESSES_TIMEOUT)
421 |
--------------------------------------------------------------------------------
/image/bin/setuser:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | '''
4 | Copyright (c) 2013-2015 Phusion Holding B.V.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
23 | '''
24 |
25 | import sys
26 | import os
27 | import pwd
28 |
29 |
30 | def abort(message):
31 | sys.stderr.write("setuser: %s\n" % message)
32 | sys.exit(1)
33 |
34 |
35 | def main():
36 | '''
37 | A simple alternative to sudo that executes a command as a user by setting
38 | the user ID and user parameters to those described by the system and then
39 | using execvp(3) to execute the command without the necessity of a TTY
40 | '''
41 |
42 | username = sys.argv[1]
43 | try:
44 | user = pwd.getpwnam(username)
45 | except KeyError:
46 | abort("user %s not found" % username)
47 | os.initgroups(username, user.pw_gid)
48 | os.setgid(user.pw_gid)
49 | os.setuid(user.pw_uid)
50 | os.environ['USER'] = username
51 | os.environ['HOME'] = user.pw_dir
52 | os.environ['UID'] = str(user.pw_uid)
53 | try:
54 | os.execvp(sys.argv[2], sys.argv[2:])
55 | except OSError as e:
56 | abort("cannot execute %s: %s" % (sys.argv[2], str(e)))
57 |
58 | if __name__ == '__main__':
59 |
60 | if len(sys.argv) < 3:
61 | sys.stderr.write("Usage: /sbin/setuser USERNAME COMMAND [args..]\n")
62 | sys.exit(1)
63 |
64 | main()
65 |
66 |
--------------------------------------------------------------------------------
/image/buildconfig:
--------------------------------------------------------------------------------
1 | export LC_ALL=C
2 | export DEBIAN_FRONTEND=noninteractive
3 | minimal_apt_get_install='apt-get install -y --no-install-recommends'
4 |
5 | # Default services
6 | # Set 1 to the service you want to disable
7 | export DISABLE_SYSLOG=${DISABLE_SYSLOG:-0}
8 | export DISABLE_SSH=${DISABLE_SSH:-0}
9 | export DISABLE_CRON=${DISABLE_CRON:-0}
10 |
--------------------------------------------------------------------------------
/image/cleanup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | source /bd_build/buildconfig
4 | set -x
5 |
6 | apt-get clean
7 | find /bd_build/ -not \( -name 'bd_build' -or -name 'buildconfig' -or -name 'cleanup.sh' \) -delete
8 | rm -rf /tmp/* /var/tmp/*
9 | rm -rf /var/lib/apt/lists/*
10 |
11 | # clean up python bytecode
12 | find / -mount -name *.pyc -delete
13 | find / -mount -name *__pycache__* -delete
14 |
15 | rm -f /etc/ssh/ssh_host_*
16 |
--------------------------------------------------------------------------------
/image/prepare.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | source /bd_build/buildconfig
4 | set -x
5 |
6 | ## Prevent initramfs updates from trying to run grub and lilo.
7 | ## https://journal.paul.querna.org/articles/2013/10/15/docker-ubuntu-on-rackspace/
8 | ## http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=594189
9 | export INITRD=no
10 | mkdir -p /etc/container_environment
11 | echo -n no > /etc/container_environment/INITRD
12 |
13 | ## Enable Ubuntu Universe, Multiverse, and deb-src for main.
14 | if grep -E '^ID=' /etc/os-release | grep -q ubuntu; then
15 | sed -i 's/^#\s*\(deb.*main restricted\)$/\1/g' /etc/apt/sources.list
16 | sed -i 's/^#\s*\(deb.*universe\)$/\1/g' /etc/apt/sources.list
17 | sed -i 's/^#\s*\(deb.*multiverse\)$/\1/g' /etc/apt/sources.list
18 | fi
19 |
20 | apt-get update
21 |
22 | ## Fix some issues with APT packages.
23 | ## See https://github.com/dotcloud/docker/issues/1024
24 | dpkg-divert --local --rename --add /sbin/initctl
25 | ln -sf /bin/true /sbin/initctl
26 |
27 | ## Replace the 'ischroot' tool to make it always return true.
28 | ## Prevent initscripts updates from breaking /dev/shm.
29 | ## https://journal.paul.querna.org/articles/2013/10/15/docker-ubuntu-on-rackspace/
30 | ## https://bugs.launchpad.net/launchpad/+bug/974584
31 | dpkg-divert --local --rename --add /usr/bin/ischroot
32 | ln -sf /bin/true /usr/bin/ischroot
33 |
34 | # apt-utils fix for Ubuntu 16.04
35 | $minimal_apt_get_install apt-utils
36 |
37 | ## Install HTTPS support for APT.
38 | $minimal_apt_get_install apt-transport-https ca-certificates
39 |
40 | ## Install add-apt-repository
41 | $minimal_apt_get_install software-properties-common
42 |
43 | ## Upgrade all packages.
44 | apt-get dist-upgrade -y --no-install-recommends -o Dpkg::Options::="--force-confold"
45 |
46 | ## Fix locale.
47 | case $(lsb_release -is) in
48 | Ubuntu)
49 | $minimal_apt_get_install language-pack-en
50 | ;;
51 | Debian)
52 | $minimal_apt_get_install locales locales-all
53 | echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
54 | ;;
55 | *)
56 | ;;
57 | esac
58 | locale-gen en_US
59 | update-locale LANG=en_US.UTF-8 LC_CTYPE=en_US.UTF-8
60 | echo -n en_US.UTF-8 > /etc/container_environment/LANG
61 | echo -n en_US.UTF-8 > /etc/container_environment/LC_CTYPE
62 |
--------------------------------------------------------------------------------
/image/services/cron/cron.runit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Touch cron files to fix 'NUMBER OF HARD LINKS > 1' issue. See https://github.com/phusion/baseimage-docker/issues/198
4 | touch -c /var/spool/cron/crontabs/*
5 | touch -c /etc/crontab
6 | touch -c /etc/cron.d/* /etc/cron.daily/* /etc/cron.hourly/* /etc/cron.monthly/* /etc/cron.weekly/*
7 |
8 | exec /usr/sbin/cron -f
9 |
--------------------------------------------------------------------------------
/image/services/cron/cron.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | source /bd_build/buildconfig
4 | set -x
5 |
6 | $minimal_apt_get_install cron
7 | mkdir /etc/service/cron
8 | chmod 600 /etc/crontab
9 | cp /bd_build/services/cron/cron.runit /etc/service/cron/run
10 | # Fix cron issues in 0.9.19, see also #345: https://github.com/phusion/baseimage-docker/issues/345
11 | sed -i 's/^\s*session\s\+required\s\+pam_loginuid.so/# &/' /etc/pam.d/cron
12 |
13 | ## Remove useless cron entries.
14 | # Checks for lost+found and scans for mtab.
15 | rm -f /etc/cron.daily/standard
16 | rm -f /etc/cron.daily/upstart
17 | rm -f /etc/cron.daily/dpkg
18 | rm -f /etc/cron.daily/password
19 | rm -f /etc/cron.weekly/fstrim
20 | rm -f /etc/cron.d/e2scrub_all
21 |
--------------------------------------------------------------------------------
/image/services/sshd/00_regen_ssh_host_keys.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | if [[ ! -e /etc/service/sshd/down && ! -e /etc/ssh/ssh_host_rsa_key ]] || [[ "$1" == "-f" ]]; then
4 | echo "No SSH host key available. Generating one..."
5 | export LC_ALL=C
6 | export DEBIAN_FRONTEND=noninteractive
7 | dpkg-reconfigure openssh-server
8 | fi
9 |
--------------------------------------------------------------------------------
/image/services/sshd/enable_insecure_key:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | AUTHORIZED_KEYS=/root/.ssh/authorized_keys
5 |
6 | if [[ -e "$AUTHORIZED_KEYS" ]] && grep -q baseimage-docker-insecure-key "$AUTHORIZED_KEYS"; then
7 | echo "Insecure key has already been added to $AUTHORIZED_KEYS."
8 | else
9 | DIR=`dirname "$AUTHORIZED_KEYS"`
10 | echo "Creating directory $DIR..."
11 | mkdir -p "$DIR"
12 | chmod 700 "$DIR"
13 | chown root:root "$DIR"
14 | echo "Editing $AUTHORIZED_KEYS..."
15 | cat /etc/insecure_key.pub >> "$AUTHORIZED_KEYS"
16 | echo "Success: insecure key has been added to $AUTHORIZED_KEYS"
17 | cat <<-EOF
18 |
19 | +------------------------------------------------------------------------------+
20 | | Insecure SSH key installed |
21 | | |
22 | | DO NOT expose port 22 on the Internet unless you know what you are doing! |
23 | | |
24 | | Use the private key below to connect with user root |
25 | +------------------------------------------------------------------------------+
26 |
27 | EOF
28 | cat /etc/insecure_key
29 | echo -e "\n\n"
30 | fi
31 |
--------------------------------------------------------------------------------
/image/services/sshd/keys/insecure_key:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | MIIEpQIBAAKCAQEA1ZswRub+3DvSEnBiyM5YRpRzRYV88vO1X2j867u6pyCHUNXv
3 | RRCr7ahMLPIVYsZwlHb4sF+Zb3DJOBH+E265o93chdMxbWG44k0spf10JRevA0JX
4 | NrEwHR8vesCR74e5MuddbSic88lsEqnnn+Fo3lStvE6nBp6tbqdEu7GhTtHSYejn
5 | wwINnA5ocsHkd1YE9L2Scqw1e4bXveTAQnSvhqe33QshGXFpt0tQwRWngah887f2
6 | P54wFSm2C/UyFT7pvIjINKzIi4vUoXz/nU+V7neTmt3XDdjloYg3ycOaX4RSVneO
7 | HCf7hkcEKbzbPzzSrGAAYYC5UzFB+ImsIbtV2wIDAQABAoIBAQCjROxgtX2Gft7y
8 | Ix8Ol9IXmK6HLCI2XZt7ovb3hFWGGzHy0qMBql2P2Tzoed1o038Hq+woe9n+uTnE
9 | dtQ6rD6PByzgyW2VSsWTjCOdeJ5HH9Qw7ItXDZZWHBkhfYHOkXI4e2oI3qshGAtY
10 | NLALn7KVhioJriCyyaSM2KOLx5khcY+EJ1inQfwQJKqPGsdKc72liz07T8ifRj+m
11 | NLKtwrxlK3IXYfIdgLp/1pCKdrC80DhprMsD4xvNgq4pCR9jd4FoqM9t/Up5ppTm
12 | +p6A/bDwdIPh6cFFeyMP+G3+bTlW1Gg7RLoNCc6qh53WWVgEOQqdLHcQ8Ge4RLmb
13 | wLUmnRuRAoGBAPfXYfjpPZi8rPIQpux13Bs7xaS1/Fa9WqrEfrPptFdUVHeFCGY8
14 | qOUVewPviHdbs0nB71Ynk9/e96agFYijQdqTQzVnpYI4i8GiGk5gPMiB2UYeJ/HZ
15 | mIB3jtWyf6Z/GO0hJ1a6mX0XD3zJGNqFaiwqaYgdO1Fwh9gcH3O2lHyjAoGBANyj
16 | TGDBYHpxPu6uKcGreLd0SgO61PEj7aOSNfrBB2PK83A+zjZCFZRIWqjfrkxGG6+a
17 | 2WuHbEHuCGvu2V5juHYxbAD/38iV/lQl/2xyvN1eR/baE3US06qn6idxjnmeNZDy
18 | DelAx1RGuEvLX1TNAzDTxBwYyzH3W2RpKAUAD11pAoGAN38YJhd8Pn5JL68A4cQG
19 | dGau/BHwHjAqZEC5qmmzgzaT72tvlQ0SOLHVqOzzHt7+x45QnHciSqfvxnTkPYNp
20 | FJuTGhtKWV12FfbJczFjivZgg63u/d3eoy2iY0GkCdE98KNS3r3L7tHCGwwgr5Xe
21 | T2Nz3BHHnZXYJVEuzcddeocCgYEAnhDjPAHtw2p0Inxlb9kPb6aBC/ECcwtBSUkL
22 | IOy/BZA1HPnxs89eNFAtmwQ8k2o6lXDDSJTJSuZj5CdGVKfuU8aOUJz/Tm2eudxL
23 | A/+jLJhJyCBthhcJyx3m04E4CAr+5ytyKeP9qXPMvoghcNg66/UabuKYV+CU+feX
24 | 8xUa7NkCgYEAlX8HGvWMmiG+ZRFB//3Loy87bBxGlN0pUtCEScabZxdB2HkI9Vp7
25 | Yr67QIZ3y7T88Mhkwam54JCjiV+3TZbSyRMOjkqf7UhTCZC6hHNqdUnlpv4bJWeW
26 | i5Eun8ltYxBnemNc2QGxA4r+KCspi+pRvWNGzL3PFVBGXiLsmOMul78=
27 | -----END RSA PRIVATE KEY-----
28 |
--------------------------------------------------------------------------------
/image/services/sshd/keys/insecure_key.ppk:
--------------------------------------------------------------------------------
1 | PuTTY-User-Key-File-2: ssh-rsa
2 | Encryption: none
3 | Comment: imported-openssh-key
4 | Public-Lines: 6
5 | AAAAB3NzaC1yc2EAAAADAQABAAABAQDVmzBG5v7cO9IScGLIzlhGlHNFhXzy87Vf
6 | aPzru7qnIIdQ1e9FEKvtqEws8hVixnCUdviwX5lvcMk4Ef4Tbrmj3dyF0zFtYbji
7 | TSyl/XQlF68DQlc2sTAdHy96wJHvh7ky511tKJzzyWwSqeef4WjeVK28TqcGnq1u
8 | p0S7saFO0dJh6OfDAg2cDmhyweR3VgT0vZJyrDV7hte95MBCdK+Gp7fdCyEZcWm3
9 | S1DBFaeBqHzzt/Y/njAVKbYL9TIVPum8iMg0rMiLi9ShfP+dT5Xud5Oa3dcN2OWh
10 | iDfJw5pfhFJWd44cJ/uGRwQpvNs/PNKsYABhgLlTMUH4iawhu1Xb
11 | Private-Lines: 14
12 | AAABAQCjROxgtX2Gft7yIx8Ol9IXmK6HLCI2XZt7ovb3hFWGGzHy0qMBql2P2Tzo
13 | ed1o038Hq+woe9n+uTnEdtQ6rD6PByzgyW2VSsWTjCOdeJ5HH9Qw7ItXDZZWHBkh
14 | fYHOkXI4e2oI3qshGAtYNLALn7KVhioJriCyyaSM2KOLx5khcY+EJ1inQfwQJKqP
15 | GsdKc72liz07T8ifRj+mNLKtwrxlK3IXYfIdgLp/1pCKdrC80DhprMsD4xvNgq4p
16 | CR9jd4FoqM9t/Up5ppTm+p6A/bDwdIPh6cFFeyMP+G3+bTlW1Gg7RLoNCc6qh53W
17 | WVgEOQqdLHcQ8Ge4RLmbwLUmnRuRAAAAgQD312H46T2YvKzyEKbsddwbO8WktfxW
18 | vVqqxH6z6bRXVFR3hQhmPKjlFXsD74h3W7NJwe9WJ5Pf3vemoBWIo0Hak0M1Z6WC
19 | OIvBohpOYDzIgdlGHifx2ZiAd47Vsn+mfxjtISdWupl9Fw98yRjahWosKmmIHTtR
20 | cIfYHB9ztpR8owAAAIEA3KNMYMFgenE+7q4pwat4t3RKA7rU8SPto5I1+sEHY8rz
21 | cD7ONkIVlEhaqN+uTEYbr5rZa4dsQe4Ia+7ZXmO4djFsAP/fyJX+VCX/bHK83V5H
22 | 9toTdRLTqqfqJ3GOeZ41kPIN6UDHVEa4S8tfVM0DMNPEHBjLMfdbZGkoBQAPXWkA
23 | AACBAJV/Bxr1jJohvmURQf/9y6MvO2wcRpTdKVLQhEnGm2cXQdh5CPVae2K+u0CG
24 | d8u0/PDIZMGpueCQo4lft02W0skTDo5Kn+1IUwmQuoRzanVJ5ab+GyVnlouRLp/J
25 | bWMQZ3pjXNkBsQOK/igrKYvqUb1jRsy9zxVQRl4i7JjjLpe/
26 | Private-MAC: ef1e472b5254ae2c5319a522d39ad31d432dde75
27 |
--------------------------------------------------------------------------------
/image/services/sshd/keys/insecure_key.pub:
--------------------------------------------------------------------------------
1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVmzBG5v7cO9IScGLIzlhGlHNFhXzy87VfaPzru7qnIIdQ1e9FEKvtqEws8hVixnCUdviwX5lvcMk4Ef4Tbrmj3dyF0zFtYbjiTSyl/XQlF68DQlc2sTAdHy96wJHvh7ky511tKJzzyWwSqeef4WjeVK28TqcGnq1up0S7saFO0dJh6OfDAg2cDmhyweR3VgT0vZJyrDV7hte95MBCdK+Gp7fdCyEZcWm3S1DBFaeBqHzzt/Y/njAVKbYL9TIVPum8iMg0rMiLi9ShfP+dT5Xud5Oa3dcN2OWhiDfJw5pfhFJWd44cJ/uGRwQpvNs/PNKsYABhgLlTMUH4iawhu1Xb baseimage-docker-insecure-key
2 |
--------------------------------------------------------------------------------
/image/services/sshd/sshd.runit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | exec /usr/sbin/sshd -D
4 |
--------------------------------------------------------------------------------
/image/services/sshd/sshd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | source /bd_build/buildconfig
4 | set -x
5 |
6 | SSHD_BUILD_PATH=/bd_build/services/sshd
7 |
8 | ## Install the SSH server.
9 | $minimal_apt_get_install openssh-server
10 | mkdir /var/run/sshd
11 | mkdir /etc/service/sshd
12 | touch /etc/service/sshd/down
13 | cp $SSHD_BUILD_PATH/sshd.runit /etc/service/sshd/run
14 | cp $SSHD_BUILD_PATH/sshd_config /etc/ssh/sshd_config
15 | cp $SSHD_BUILD_PATH/00_regen_ssh_host_keys.sh /etc/my_init.d/
16 |
17 | ## Install default SSH key for root and app.
18 | mkdir -p /root/.ssh
19 | chmod 700 /root/.ssh
20 | chown root:root /root/.ssh
21 | cp $SSHD_BUILD_PATH/keys/insecure_key.pub /etc/insecure_key.pub
22 | cp $SSHD_BUILD_PATH/keys/insecure_key /etc/insecure_key
23 | chmod 644 /etc/insecure_key*
24 | chown root:root /etc/insecure_key*
25 | cp $SSHD_BUILD_PATH/enable_insecure_key /usr/sbin/
26 |
--------------------------------------------------------------------------------
/image/services/sshd/sshd_config:
--------------------------------------------------------------------------------
1 | # $OpenBSD: sshd_config,v 1.80 2008/07/02 02:24:18 djm Exp $
2 |
3 | # This is the sshd server system-wide configuration file. See
4 | # sshd_config(5) for more information.
5 |
6 | # This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
7 |
8 | # The strategy used for options in the default sshd_config shipped with
9 | # OpenSSH is to specify options with their default value where
10 | # possible, but leave them commented. Uncommented options change a
11 | # default value.
12 |
13 | UseDNS no
14 |
15 | #Port 22
16 | #AddressFamily any
17 | #ListenAddress 0.0.0.0
18 | #ListenAddress ::
19 |
20 | # Disable legacy (protocol version 1) support in the server for new
21 | # installations. In future the default will change to require explicit
22 | # activation of protocol 1
23 | Protocol 2
24 |
25 | # HostKey for protocol version 1
26 | #HostKey /etc/ssh_host_key
27 | # HostKeys for protocol version 2
28 | #HostKey /etc/ssh_host_rsa_key
29 | #HostKey /etc/ssh_host_dsa_key
30 |
31 | # Lifetime and size of ephemeral version 1 server key
32 | #KeyRegenerationInterval 1h
33 | #ServerKeyBits 1024
34 |
35 | # Logging
36 | # obsoletes QuietMode and FascistLogging
37 | SyslogFacility AUTHPRIV
38 | #LogLevel INFO
39 |
40 | # Authentication:
41 |
42 | #LoginGraceTime 2m
43 | #PermitRootLogin yes
44 | #StrictModes yes
45 | #MaxAuthTries 6
46 | #MaxSessions 10
47 |
48 | #RSAAuthentication yes
49 | #PubkeyAuthentication yes
50 | #AuthorizedKeysFile .ssh/authorized_keys
51 |
52 | # For this to work you will also need host keys in /etc/ssh_known_hosts
53 | #RhostsRSAAuthentication no
54 | # similar for protocol version 2
55 | #HostbasedAuthentication no
56 | # Change to yes if you don't trust ~/.ssh/known_hosts for
57 | # RhostsRSAAuthentication and HostbasedAuthentication
58 | #IgnoreUserKnownHosts no
59 | # Don't read the user's ~/.rhosts and ~/.shosts files
60 | #IgnoreRhosts yes
61 |
62 | # To disable tunneled clear text passwords, change to no here! Also,
63 | # remember to set the UsePAM setting to 'no'.
64 | #PasswordAuthentication no
65 | #PermitEmptyPasswords no
66 |
67 | # SACL options
68 | # The default for the SACLSupport option is now "no", as this option has been
69 | # depreciated in favor of SACL enforcement in the PAM configuration (/etc/pam.d/sshd).
70 | #SACLSupport no
71 |
72 | # Change to no to disable s/key passwords
73 | # Disabled for passenger-docker. We only allow key authentication.
74 | ChallengeResponseAuthentication no
75 |
76 | # Kerberos options
77 | #KerberosAuthentication no
78 | #KerberosOrLocalPasswd yes
79 | #KerberosTicketCleanup yes
80 |
81 | # GSSAPI options
82 | #GSSAPIAuthentication no
83 | #GSSAPICleanupCredentials yes
84 | #GSSAPIStrictAcceptorCheck yes
85 | #GSSAPIKeyExchange no
86 |
87 | # Set this to 'yes' to enable PAM authentication, account processing,
88 | # and session processing. If this is enabled, PAM authentication will
89 | # be allowed through the ChallengeResponseAuthentication and
90 | # PasswordAuthentication. Depending on your PAM configuration,
91 | # PAM authentication via ChallengeResponseAuthentication may bypass
92 | # the setting of "PermitRootLogin without-password".
93 | # If you just want the PAM account and session checks to run without
94 | # PAM authentication, then enable this but set PasswordAuthentication
95 | # and ChallengeResponseAuthentication to 'no'.
96 | # Also, PAM will deny null passwords by default. If you need to allow
97 | # null passwords, add the " nullok" option to the end of the
98 | # securityserver.so line in /etc/pam.d/sshd.
99 | #UsePAM yes
100 |
101 | #AllowAgentForwarding yes
102 | #AllowTcpForwarding yes
103 | #GatewayPorts no
104 | X11Forwarding yes
105 | #X11DisplayOffset 10
106 | #X11UseLocalhost yes
107 | #PrintMotd yes
108 | #PrintLastLog yes
109 | #TCPKeepAlive yes
110 | #UseLogin no
111 | #UsePrivilegeSeparation yes
112 | #PermitUserEnvironment no
113 | #Compression delayed
114 | #ClientAliveInterval 0
115 | #ClientAliveCountMax 3
116 | #UseDNS yes
117 | #PidFile /var/run/sshd.pid
118 | #MaxStartups 10
119 | #PermitTunnel no
120 | #ChrootDirectory none
121 |
122 | # no default banner path
123 | #Banner none
124 |
125 | # override default of no subsystems
126 | Subsystem sftp /usr/lib/openssh/sftp-server
127 |
128 | # Example of overriding settings on a per-user basis
129 | #Match User anoncvs
130 | # X11Forwarding no
131 | # AllowTcpForwarding no
132 | # ForceCommand cvs server
133 |
--------------------------------------------------------------------------------
/image/services/syslog-ng/logrotate.conf:
--------------------------------------------------------------------------------
1 | # see "man logrotate" for details
2 | # rotate log files weekly
3 | weekly
4 |
5 | # use the syslog group by default, since this is the owning group
6 | # of /var/log/syslog.
7 | # su root syslog
8 |
9 | # keep 4 weeks worth of backlogs
10 | rotate 4
11 |
12 | # create new (empty) log files after rotating old ones
13 | create
14 |
15 | # uncomment this if you want your log files compressed
16 | #compress
17 |
18 | # packages drop log rotation information into this directory
19 | include /etc/logrotate.d
20 |
21 | # system-specific logs may be configured here
22 |
--------------------------------------------------------------------------------
/image/services/syslog-ng/logrotate_syslogng:
--------------------------------------------------------------------------------
1 | /var/log/syslog {
2 | rotate 7
3 | daily
4 | missingok
5 | notifempty
6 | delaycompress
7 | compress
8 | postrotate
9 | if [ -f /var/run/syslog-ng.pid ]; then
10 | kill -HUP `cat /var/run/syslog-ng.pid`
11 | fi
12 | endscript
13 | }
14 |
15 | /var/log/mail.info
16 | /var/log/mail.warn
17 | /var/log/mail.err
18 | /var/log/mail.log
19 | /var/log/daemon.log
20 | /var/log/kern.log
21 | /var/log/auth.log
22 | /var/log/user.log
23 | /var/log/lpr.log
24 | /var/log/cron.log
25 | /var/log/debug
26 | /var/log/messages {
27 | rotate 4
28 | weekly
29 | missingok
30 | notifempty
31 | compress
32 | delaycompress
33 | sharedscripts
34 | postrotate
35 | if [ -f /var/run/syslog-ng.pid ]; then
36 | kill -HUP `cat /var/run/syslog-ng.pid`
37 | fi
38 | endscript
39 | }
40 |
--------------------------------------------------------------------------------
/image/services/syslog-ng/smart-multi-line.fsm:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2023 Balazs Scheidler
3 | # Copyright 2016 Google Inc. All rights reserved.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | #
17 | # The regular expressions were extracted from
18 | # https://github.com/GoogleCloudPlatform/fluent-plugin-detect-exceptions
19 | # and converted into a TSV format by Balazs Scheidler.
20 | #
21 | # List of tab separated fields
22 | #
23 | # comma-separated-states /regexp/ new_state
24 | #
25 |
26 | # java
27 | start_state,java_start_exception /(?:Exception|Error|Throwable|V8 errors stack trace)[:\r\n]/ java_after_exception
28 | java_after_exception /^[\t ]*nested exception is:[\t ]*/ java_start_exception
29 | java_after_exception /^[\r\n]*$/ java_after_exception
30 | java_after_exception,java /^[\t ]+(?:eval )?at / java
31 | java_after_exception,java /^[\t ]+--- End of inner exception stack trace ---$/ java
32 | java_after_exception,java /^--- End of stack trace from previous location where exception was thrown ---$/ java
33 | java_after_exception,java /^[\t ]*(?:Caused by|Suppressed):/ java_after_exception
34 | java_after_exception,java /^[\t ]*... \d+ (?:more|common frames omitted)/ java
35 |
36 | # python
37 | start_state /^Traceback \(most recent call last\):$/ python
38 | python /^[\t ]*File / python_code
39 | python_code /[^\t ]/ python
40 | python /^(?:[^\s.():]+\.)*[^\s.():]+:/ start_state
41 |
42 | # PHP
43 | start_state /(?:PHP\ (?:Notice|Parse\ error|Fatal\ error|Warning):)|(?:exception\ '[^']+'\ with\ message\ ')/ php_stack_begin
44 | php_stack_begin /^Stack trace:/ php_stack_frames
45 | php_stack_frames /^#\d/ php_stack_frames
46 | php_stack_frames /^\s+thrown in / start_state
47 |
48 | # Go
49 | start_state /\bpanic: / go_after_panic
50 | start_state /http: panic serving/ go_goroutine
51 | go_after_panic,go_after_signal,go_frame_1 /^$/ go_goroutine
52 | go_after_panic /^\[signal / go_after_signal
53 | go_goroutine /^goroutine \d+ \[[^\]]+\]:$/ go_frame_1
54 | go_frame_1 /^(?:[^\s.:]+\.)*[^\s.():]+\(|^created by / go_frame_2
55 | go_frame_2 /^\s/ go_frame_1
56 |
57 | # Ruby
58 | start_state /Error \(.*\):$/ ruby_before_rails_trace
59 | ruby_before_rails_trace /^ $/ ruby
60 | ruby_before_rails_trace /^[\t ]+.*?\.rb:\d+:in `/ ruby
61 | ruby /^[\t ]+.*?\.rb:\d+:in `/ ruby
62 |
63 | # Dart
64 | start_state /^Unhandled exception:$/ dart_exc
65 | dart_exc /^(Instance of)|(Exception)|(Bad state)|(IntegerDivisionByZeroException)|(Invalid argument)|(RangeError)|(Assertion failed)|(Cannot instantiate)|(Reading static variable)|(UnimplementedError)|(Unsupported operation)|(Concurrent modification)|(Out of Memory)|(Stack Overflow)/ dart_stack
66 | dart_exc /^'.+?':.+?$/ dart_type_err_1
67 | dart_type_err_1 /^#\d+\s+.+?\(.+?\)$/ dart_stack
68 | dart_type_err_1 /^.+?$/ dart_type_err_2
69 | dart_type_err_2 /^.*?\^.*?$/ dart_type_err_3
70 | dart_type_err_3 /^$/ dart_type_err_4
71 | dart_type_err_4 /^$/ dart_stack
72 | dart_exc /^FormatException/ dart_format_err_1
73 | dart_format_err_1 /^#\d+\s+.+?\(.+?\)$/ dart_stack
74 | dart_format_err_1 /^./ dart_format_err_2
75 | dart_format_err_2 /^.*?\^/ dart_format_err_3
76 | dart_format_err_3 /^$/ dart_stack
77 | dart_exc /^NoSuchMethodError:/ dart_method_err_1
78 | dart_method_err_1 /^Receiver:/ dart_method_err_2
79 | dart_method_err_2 /^Tried calling:/ dart_method_err_3
80 | dart_method_err_3 /^Found:/ dart_stack
81 | dart_method_err_3 /^#\d+\s+.+?\(.+?\)$/ dart_stack
82 | dart_stack /^#\d+\s+.+?\(.+?\)$/ dart_stack
83 | dart_stack /^$/ dart_stack
84 |
--------------------------------------------------------------------------------
/image/services/syslog-ng/syslog-ng.conf:
--------------------------------------------------------------------------------
1 | @version: 4.3
2 | @include "scl.conf"
3 |
4 | # Syslog-ng configuration file, compatible with default Debian syslogd
5 | # installation.
6 |
7 | # First, set some global options.
8 | options { chain_hostnames(off); flush_lines(0); use_dns(no); use_fqdn(no);
9 | dns_cache(no); owner("root"); group("adm"); perm(0640);
10 | stats(freq(0)); bad_hostname("^gconfd$");
11 | };
12 |
13 | ########################
14 | # Sources
15 | ########################
16 | # This is the default behavior of sysklogd package
17 | # Logs may come from unix stream, but not from another machine.
18 | #
19 | source s_src {
20 | unix-dgram("/dev/log");
21 | internal();
22 | };
23 |
24 | # If you wish to get logs from remote machine you should uncomment
25 | # this and comment the above source line.
26 | #
27 | #source s_net { tcp(ip(127.0.0.1) port(1000)); };
28 |
29 | ########################
30 | # Destinations
31 | ########################
32 | # First some standard logfile
33 | #
34 | destination d_auth { file("/var/log/auth.log"); };
35 | destination d_cron { file("/var/log/cron.log"); };
36 | destination d_daemon { file("/var/log/daemon.log"); };
37 | destination d_kern { file("/var/log/kern.log"); };
38 | destination d_lpr { file("/var/log/lpr.log"); };
39 | destination d_mail { file("/var/log/mail.log"); };
40 | destination d_syslog { file("/var/log/syslog"); };
41 | destination d_user { file("/var/log/user.log"); };
42 | destination d_uucp { file("/var/log/uucp.log"); };
43 |
44 | # This files are the log come from the mail subsystem.
45 | #
46 | destination d_mailinfo { file("/var/log/mail.info"); };
47 | destination d_mailwarn { file("/var/log/mail.warn"); };
48 | destination d_mailerr { file("/var/log/mail.err"); };
49 |
50 | # Logging for INN news system
51 | #
52 | destination d_newscrit { file("/var/log/news/news.crit"); };
53 | destination d_newserr { file("/var/log/news/news.err"); };
54 | destination d_newsnotice { file("/var/log/news/news.notice"); };
55 |
56 | # Some 'catch-all' logfiles.
57 | #
58 | destination d_debug { file("/var/log/debug"); };
59 | destination d_error { file("/var/log/error"); };
60 | destination d_messages { file("/var/log/messages"); };
61 |
62 | # The named pipe /dev/xconsole is for the nsole' utility. To use it,
63 | # you must invoke nsole' with the -file' option:
64 | #
65 | # $ xconsole -file /dev/xconsole [...]
66 | #
67 | destination d_xconsole { pipe("/dev/xconsole"); };
68 |
69 | # Send the messages to an other host
70 | #
71 | #destination d_net { tcp("127.0.0.1" port(1000) log_fifo_size(1000)); };
72 |
73 | # Debian only
74 | destination d_ppp { file("/var/log/ppp.log"); };
75 |
76 | # stdout for docker
77 | destination d_stdout { ##SYSLOG_OUTPUT_MODE_DEV_STDOUT##("/dev/stdout"); };
78 |
79 | ########################
80 | # Filters
81 | ########################
82 | # Here's come the filter options. With this rules, we can set which
83 | # message go where.
84 |
85 | filter f_dbg { level(debug); };
86 | filter f_info { level(info); };
87 | filter f_notice { level(notice); };
88 | filter f_warn { level(warn); };
89 | filter f_err { level(err); };
90 | filter f_crit { level(crit .. emerg); };
91 |
92 | filter f_debug { level(debug) and not facility(auth, authpriv, news, mail); };
93 | filter f_error { level(err .. emerg) ; };
94 | filter f_messages { level(info,notice,warn) and
95 | not facility(auth,authpriv,cron,daemon,mail,news); };
96 |
97 | filter f_auth { facility(auth, authpriv) and not filter(f_debug); };
98 | filter f_cron { facility(cron) and not filter(f_debug); };
99 | filter f_daemon { facility(daemon) and not filter(f_debug); };
100 | filter f_kern { facility(kern) and not filter(f_debug); };
101 | filter f_lpr { facility(lpr) and not filter(f_debug); };
102 | filter f_local { facility(local0, local1, local3, local4, local5,
103 | local6, local7) and not filter(f_debug); };
104 | filter f_mail { facility(mail) and not filter(f_debug); };
105 | filter f_news { facility(news) and not filter(f_debug); };
106 | filter f_syslog3 { not facility(auth, authpriv, mail) and not filter(f_debug); };
107 | filter f_user { facility(user) and not filter(f_debug); };
108 | filter f_uucp { facility(uucp) and not filter(f_debug); };
109 |
110 | filter f_cnews { level(notice, err, crit) and facility(news); };
111 | filter f_cother { level(debug, info, notice, warn) or facility(daemon, mail); };
112 |
113 | filter f_ppp { facility(local2) and not filter(f_debug); };
114 | filter f_console { level(warn .. emerg); };
115 |
116 | ########################
117 | # Log paths
118 | ########################
119 | log { source(s_src); filter(f_auth); destination(d_auth); };
120 | log { source(s_src); filter(f_cron); destination(d_cron); };
121 | log { source(s_src); filter(f_daemon); destination(d_daemon); };
122 | log { source(s_src); filter(f_kern); destination(d_kern); };
123 | log { source(s_src); filter(f_lpr); destination(d_lpr); };
124 | log { source(s_src); filter(f_syslog3); destination(d_syslog); destination(d_stdout); };
125 | log { source(s_src); filter(f_user); destination(d_user); };
126 | log { source(s_src); filter(f_uucp); destination(d_uucp); };
127 |
128 | log { source(s_src); filter(f_mail); destination(d_mail); };
129 | #log { source(s_src); filter(f_mail); filter(f_info); destination(d_mailinfo); };
130 | #log { source(s_src); filter(f_mail); filter(f_warn); destination(d_mailwarn); };
131 | #log { source(s_src); filter(f_mail); filter(f_err); destination(d_mailerr); };
132 |
133 | log { source(s_src); filter(f_news); filter(f_crit); destination(d_newscrit); };
134 | log { source(s_src); filter(f_news); filter(f_err); destination(d_newserr); };
135 | log { source(s_src); filter(f_news); filter(f_notice); destination(d_newsnotice); };
136 | #log { source(s_src); filter(f_cnews); destination(d_console_all); };
137 | #log { source(s_src); filter(f_cother); destination(d_console_all); };
138 |
139 | #log { source(s_src); filter(f_ppp); destination(d_ppp); };
140 |
141 | log { source(s_src); filter(f_debug); destination(d_debug); };
142 | log { source(s_src); filter(f_error); destination(d_error); };
143 | log { source(s_src); filter(f_messages); destination(d_messages); };
144 |
145 | # All messages send to a remote site
146 | #
147 | #log { source(s_src); destination(d_net); };
148 |
149 | ###
150 | # Include all config files in /etc/syslog-ng/conf.d/
151 | ###
152 | @include "/etc/syslog-ng/conf.d/*.conf"
153 |
--------------------------------------------------------------------------------
/image/services/syslog-ng/syslog-ng.init:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -em
3 |
4 | # If /dev/log is either a named pipe or it was placed there accidentally,
5 | # e.g. because of the issue documented at https://github.com/phusion/baseimage-docker/pull/25,
6 | # then we remove it.
7 | if [ ! -S /dev/log ]; then rm -f /dev/log; fi
8 | if [ ! -S /var/lib/syslog-ng/syslog-ng.ctl ]; then rm -f /var/lib/syslog-ng/syslog-ng.ctl; fi
9 |
10 | # determine output mode on /dev/stdout because of the issue documented at https://github.com/phusion/baseimage-docker/issues/468
11 | if [ -p /dev/stdout ]; then
12 | sed -i 's/##SYSLOG_OUTPUT_MODE_DEV_STDOUT##/pipe/' /etc/syslog-ng/syslog-ng.conf
13 | else
14 | sed -i 's/##SYSLOG_OUTPUT_MODE_DEV_STDOUT##/file/' /etc/syslog-ng/syslog-ng.conf
15 | fi
16 |
17 | # If /var/log is writable by another user logrotate will fail
18 | /bin/chown root:root /var/log
19 | /bin/chmod 0755 /var/log
20 |
21 | PIDFILE="/var/run/syslog-ng.pid"
22 | SYSLOGNG_OPTS=""
23 |
24 | [ -r /etc/default/syslog-ng ] && . /etc/default/syslog-ng
25 |
26 | syslogng_wait() {
27 | if [ "$2" -ne 0 ]; then
28 | return 1
29 | fi
30 |
31 | RET=1
32 | for i in $(seq 1 30); do
33 | status=0
34 | syslog-ng-ctl stats >/dev/null 2>&1 || status=$?
35 | if [ "$status" != "$1" ]; then
36 | RET=0
37 | break
38 | fi
39 | sleep 1s
40 | done
41 | return $RET
42 | }
43 |
44 | /usr/sbin/syslog-ng --pidfile "$PIDFILE" -F $SYSLOGNG_OPTS &
45 | syslogng_wait 1 $?
46 |
--------------------------------------------------------------------------------
/image/services/syslog-ng/syslog-ng.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | source /bd_build/buildconfig
4 | set -x
5 |
6 | SYSLOG_NG_BUILD_PATH=/bd_build/services/syslog-ng
7 |
8 | ## Install a syslog daemon.
9 | $minimal_apt_get_install syslog-ng-core
10 | cp $SYSLOG_NG_BUILD_PATH/syslog-ng.init /etc/my_init.d/10_syslog-ng.init
11 | cp $SYSLOG_NG_BUILD_PATH/syslog-ng.shutdown /etc/my_init.post_shutdown.d/10_syslog-ng.shutdown
12 | cp $SYSLOG_NG_BUILD_PATH/smart-multi-line.fsm /usr/share/syslog-ng/smart-multi-line.fsm
13 | mkdir -p /var/lib/syslog-ng
14 | cp $SYSLOG_NG_BUILD_PATH/syslog_ng_default /etc/default/syslog-ng
15 | touch /var/log/syslog
16 | chmod u=rw,g=r,o= /var/log/syslog
17 | cp $SYSLOG_NG_BUILD_PATH/syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
18 |
19 | ## Install logrotate.
20 | $minimal_apt_get_install logrotate
21 | cp $SYSLOG_NG_BUILD_PATH/logrotate.conf /etc/logrotate.conf
22 | cp $SYSLOG_NG_BUILD_PATH/logrotate_syslogng /etc/logrotate.d/syslog-ng
23 |
--------------------------------------------------------------------------------
/image/services/syslog-ng/syslog-ng.shutdown:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | PIDFILE="/var/run/syslog-ng.pid"
4 |
5 | syslogng_wait() {
6 | if [ "$2" -ne 0 ]; then
7 | return 1
8 | fi
9 |
10 | RET=1
11 | for i in $(seq 1 30); do
12 | status=0
13 | syslog-ng-ctl stats >/dev/null 2>&1 || status=$?
14 | if [ "$status" != "$1" ]; then
15 | RET=0
16 | break
17 | fi
18 | sleep 1s
19 | done
20 | return $RET
21 | }
22 |
23 | if [ -f "$PIDFILE" ]; then
24 | kill $(cat "$PIDFILE")
25 | fi
26 |
27 | syslogng_wait 0 $?
28 |
--------------------------------------------------------------------------------
/image/services/syslog-ng/syslog_ng_default:
--------------------------------------------------------------------------------
1 | # If a variable is not set here, then the corresponding
2 | # parameter will not be changed.
3 | # If a variables is set, then every invocation of
4 | # syslog-ng's init script will set them using dmesg.
5 |
6 | # log level of messages which should go to console
7 | # see syslog(3) for details
8 | #
9 | #CONSOLE_LOG_LEVEL=1
10 |
11 | # Command line options to syslog-ng
12 | SYSLOGNG_OPTS="--no-caps"
13 |
--------------------------------------------------------------------------------
/image/system_services.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | source /bd_build/buildconfig
4 | set -x
5 |
6 | ## Install init process.
7 | cp /bd_build/bin/my_init /sbin/
8 | mkdir -p /etc/my_init.d
9 | mkdir -p /etc/my_init.pre_shutdown.d
10 | mkdir -p /etc/my_init.post_shutdown.d
11 | mkdir -p /etc/container_environment
12 | touch /etc/container_environment.sh
13 | touch /etc/container_environment.json
14 | chmod 700 /etc/container_environment
15 |
16 | groupadd -g 8377 docker_env
17 | chown :docker_env /etc/container_environment.sh /etc/container_environment.json
18 | chmod 640 /etc/container_environment.sh /etc/container_environment.json
19 | ln -s /etc/container_environment.sh /etc/profile.d/
20 |
21 | ## Install runit.
22 | $minimal_apt_get_install runit
23 |
24 | ## Install a syslog daemon and logrotate.
25 | [ "$DISABLE_SYSLOG" -eq 0 ] && /bd_build/services/syslog-ng/syslog-ng.sh || true
26 |
27 | ## Install the SSH server.
28 | [ "$DISABLE_SSH" -eq 0 ] && /bd_build/services/sshd/sshd.sh || true
29 |
30 | ## Install cron daemon.
31 | [ "$DISABLE_CRON" -eq 0 ] && /bd_build/services/cron/cron.sh || true
32 |
--------------------------------------------------------------------------------
/image/utilities.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | source /bd_build/buildconfig
4 | set -x
5 |
6 | ## Often used tools.
7 | $minimal_apt_get_install curl less vim-tiny psmisc gpg-agent dirmngr
8 | ln -s /usr/bin/vim.tiny /usr/bin/vim
9 |
10 | ## This tool runs a command as another user and sets $HOME.
11 | cp /bd_build/bin/setuser /sbin/setuser
12 |
13 | ## This tool allows installation of apt packages with automatic cache cleanup.
14 | cp /bd_build/bin/install_clean /sbin/install_clean
15 |
--------------------------------------------------------------------------------
/install-tools.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | dir=`dirname "$0"`
4 | cd "$dir"
5 |
6 | set -x
7 | cp tools/docker-bash /usr/local/bin/
8 | cp tools/docker-ssh /usr/local/bin/
9 | cp tools/baseimage-docker-nsenter /usr/local/bin/
10 | mkdir -p /usr/local/share/baseimage-docker
11 | cp image/services/sshd/keys/insecure_key /usr/local/share/baseimage-docker/
12 | chmod 644 /usr/local/share/baseimage-docker/insecure_key
13 |
--------------------------------------------------------------------------------
/test/runner.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | function abort()
5 | {
6 | echo "$@"
7 | exit 1
8 | }
9 |
10 | function cleanup()
11 | {
12 | echo " --> Stopping container"
13 | docker stop $ID >/dev/null
14 | docker rm $ID >/dev/null
15 | }
16 |
17 | echo " --> Starting insecure container"
18 | ID=`docker run -d -p 22 $NAME:$VERSION /sbin/my_init --enable-insecure-key`
19 | sleep 1
20 |
21 | echo " --> Obtaining SSH port number"
22 | SSHPORT=`docker inspect --format='{{(index (index .NetworkSettings.Ports "22/tcp") 0).HostPort}}' "$ID"`
23 | if [[ "$SSHPORT" = "" ]]; then
24 | abort "Unable to obtain container SSH port number"
25 | fi
26 |
27 | trap cleanup EXIT
28 |
29 | echo " --> Enabling SSH in the container"
30 | docker exec $ID /etc/my_init.d/00_regen_ssh_host_keys.sh -f
31 | docker exec $ID rm /etc/service/sshd/down
32 | docker exec $ID sv start /etc/service/sshd
33 | sleep 1
34 |
35 | echo " --> Logging into container and running tests"
36 | sleep 1 # Give container some more time to start up.
37 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
38 | tools/docker-ssh $ID bash < test/test.sh
39 |
--------------------------------------------------------------------------------
/test/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -o pipefail
3 |
4 | function ok()
5 | {
6 | echo " OK"
7 | }
8 |
9 | function fail()
10 | {
11 | echo " FAIL"
12 | exit 1
13 | }
14 |
15 | echo "Checking whether all services are running..."
16 | services=`sv status /etc/service/*`
17 | status=$?
18 | if [[ "$status" != 0 || "$services" = "" || "$services" =~ down ]]; then
19 | fail
20 | else
21 | ok
22 | fi
23 |
--------------------------------------------------------------------------------
/tools/README.md:
--------------------------------------------------------------------------------
1 | baseimage-docker-nsenter is the nsenter tool taken from https://github.com/jpetazzo/nsenter, commit 10ce18a7a32. It has been stripped in order to make it smaller.
2 |
--------------------------------------------------------------------------------
/tools/baseimage-docker-nsenter:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phusion/baseimage-docker/2403c5825475dbc95d4a44ab91406e20f391c7c5/tools/baseimage-docker-nsenter
--------------------------------------------------------------------------------
/tools/docker-bash:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | SELFDIR=`dirname "$0"`
5 | SELFDIR=`cd "$SELFDIR" && pwd`
6 |
7 | usage()
8 | {
9 | echo "Usage: docker-bash [COMMAND...]"
10 | echo "Login to a Baseimage-based Docker container using nsenter." \
11 | "If COMMAND is not given, opens an interactive shell." \
12 | "Otherwise, runs COMMAND inside the container."
13 | }
14 |
15 | if test $# = 0; then
16 | usage
17 | exit
18 | fi
19 |
20 | CONTAINER_ID="$1"
21 | shift
22 |
23 | PID=`docker inspect -f "{{ .State.Pid }}" "$CONTAINER_ID"`
24 | if test $# = 0; then
25 | exec "$SELFDIR/baseimage-docker-nsenter" --target "$PID" --mount --uts --ipc --net --pid -- /bin/bash -l
26 | else
27 | exec "$SELFDIR/baseimage-docker-nsenter" --target "$PID" --mount --uts --ipc --net --pid -- "$@"
28 | fi
29 |
30 |
--------------------------------------------------------------------------------
/tools/docker-ssh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | KNOWN_HOSTS_FILE=
5 | IP=
6 |
7 | usage()
8 | {
9 | echo "Usage: docker-ssh [COMMAND...]"
10 | echo "Login to a Baseimage-based Docker container using SSH." \
11 | "If COMMAND is not given, opens an interactive shell." \
12 | "Otherwise, runs COMMAND inside the container."
13 | }
14 |
15 | cleanup()
16 | {
17 | local pids=`jobs -p`
18 | if test "$pids" != ""; then
19 | kill $pids
20 | fi
21 |
22 | if test "$KNOWN_HOSTS_FILE" != ""; then
23 | rm -f "$KNOWN_HOSTS_FILE"
24 | fi
25 | }
26 |
27 | if test $# = 0; then
28 | usage
29 | exit
30 | fi
31 |
32 | CONTAINER_ID="$1"
33 | shift
34 |
35 | trap cleanup EXIT
36 |
37 | if ! test -e ~/.baseimage_docker_insecure_key; then
38 | if test -e /usr/local/share/baseimage-docker/insecure_key; then
39 | cp /usr/local/share/baseimage-docker/insecure_key ~/.baseimage_docker_insecure_key
40 | else
41 | dir=`dirname "$0"`
42 | dir=`cd "$dir/.." && pwd`
43 | if test -e "$dir/image/services/sshd/keys/insecure_key"; then
44 | cp "$dir/image/services/sshd/keys/insecure_key" ~/.baseimage_docker_insecure_key
45 | else
46 | echo "*** ERROR ***: Baseimage-docker insecure key not found." >&2
47 | echo "You probably didn't install docker-ssh properly. Please reinstall it:" >&2
48 | echo "" >&2
49 | echo " curl --fail -L -O https://github.com/phusion/baseimage-docker/archive/master.tar.gz && \\" >&2
50 | echo " tar xzf master.tar.gz && \\" >&2
51 | echo " sudo ./baseimage-docker-master/install-tools.sh" >&2
52 | exit 1
53 | fi
54 | fi
55 | chown "`whoami`": ~/.baseimage_docker_insecure_key
56 | chmod 600 ~/.baseimage_docker_insecure_key
57 | fi
58 |
59 | KNOWN_HOSTS_FILE=`mktemp /tmp/docker-ssh.XXXXXXXXX`
60 | IP=`docker inspect -f "{{ .NetworkSettings.IPAddress }}" "$CONTAINER_ID"`
61 | PORT=`docker inspect -f '{{(index (index .NetworkSettings.Ports "22/tcp") 0).HostPort}}' "$CONTAINER_ID"`
62 | if test "`uname`" = "Darwin"; then
63 | IP="127.0.0.1"
64 | else
65 | PORT=22
66 | fi
67 | echo "SSHing into $IP:$PORT"
68 |
69 | # Prevent SSH from warning about adding a host to the known_hosts file.
70 | ssh-keyscan "$IP" >"$KNOWN_HOSTS_FILE" 2>&1
71 |
72 | if ! ssh -i ~/.baseimage_docker_insecure_key \
73 | -o UserKnownHostsFile="$KNOWN_HOSTS_FILE" \
74 | -o StrictHostKeyChecking=no \
75 | -o PasswordAuthentication=no \
76 | -o KbdInteractiveAuthentication=no \
77 | -o ChallengeResponseAuthentication=no \
78 | -p $PORT \
79 | "root@$IP" "$@"
80 | then
81 | STATUS=$?
82 | if test $# = 0; then
83 | echo "----------------"
84 | echo "It appears that login to the Docker container failed. This could be caused by the following reasons:"
85 | echo "- The Docker container you're trying to login to is not based on Baseimage-docker. The docker-ssh tool only works with Baseimage-docker-based containers."
86 | echo "- You did not enable the the insecure key inside the container. Please read https://github.com/phusion/baseimage-docker/blob/master/README.md#login to learn how to enable the insecure key."
87 | fi
88 | exit $STATUS
89 | fi
90 |
--------------------------------------------------------------------------------
/vagrant-libs/bootstrap.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eux
3 |
4 | # Update Packages
5 | sudo apt-get update
6 | # sudo apt-get -y upgrade
7 | # sudo apt-get -y dist-upgrade
8 |
9 | # Install Packages
10 | sudo apt-get install -y build-essential checkinstall libreadline-gplv2-dev \
11 | libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev \
12 | libbz2-dev libffi-dev python3-pip unzip lsb-release software-properties-common \
13 | curl wget git rsync # python-dev python3-venv
14 |
15 | # Install Docker
16 | sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
17 | sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
18 | sudo apt-get update
19 | sudo apt-cache policy docker-ce
20 | sudo apt-get install -y docker-ce docker-compose
21 | # Re-install docker-compose to side-step a bug
22 | # docker build -t terraform-azure-vm . >> "free(): invalid pointer"
23 | # https://github.com/docker/for-linux/issues/563
24 | sudo apt-get remove -y golang-docker-credential-helpers
25 | sudo curl -L "https://github.com/docker/compose/releases/download/1.25.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
26 | echo '{"experimental": true}' > /etc/docker/daemon.json
27 | service docker restart
28 |
29 | # Add vagrant user to docker group
30 | sudo usermod -aG docker vagrant
31 |
32 |
--------------------------------------------------------------------------------