Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standard Debian base image #41915

Merged
merged 1 commit into from
Feb 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 19 additions & 0 deletions build/debian-base/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

FROM scratch

ADD rootfs.tar /

CMD ["/bin/sh"]
102 changes: 102 additions & 0 deletions build/debian-base/Dockerfile.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

FROM BASEIMAGE

# If we're building for another architecture than amd64, the CROSS_BUILD_ placeholder is removed so
# e.g. CROSS_BUILD_COPY turns into COPY
# If we're building normally, for amd64, CROSS_BUILD lines are removed
CROSS_BUILD_COPY qemu-ARCH-static /usr/bin/

ENV DEBIAN_FRONTEND=noninteractive

# Smaller package install size.
COPY excludes /etc/dpkg/dpkg.cfg.d/excludes

# Convenience script for building on this base image.
COPY clean-install /usr/local/bin/clean-install

# Update system packages.
RUN apt-get update \
&& apt-get dist-upgrade -y

# Hold required packages to avoid breaking the installation of packages
RUN apt-mark hold apt gnupg adduser passwd libsemanage1

# Remove unnecessary packages.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how was this list produced?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started with the list in the ubuntu-slim image. Then from the remaining packages (apt list --installed), I ran apt-cache rdepends --installed --no-recommends to find the "root" packages. I made a call for each of those as to whether it was needed. I was tempted to remove everything that wasn't required for apt-get to run, but decided to keep some standard tools (e.g. ping) for the first iteration. When we have more time we can reevaluate some of those optional packages.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about making a full list of all the remaining dependencies and adding a justification for each one, but I was worried it would fall out of date too easily...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe put your first reply into a comment?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

# This list was generated manually by listing the installed packages (`apt list --installed`),
# then running `apt-cache rdepends --installed --no-recommends` to find the "root" packages.
# The root packages were evaluated based on whether they were needed in the container image.
# Several utilities (e.g. ping) were kept for usefulness, but may be removed in later versions.
RUN echo "Yes, do as I say!" | apt-get purge \
bash \
debconf-i18n \
e2fslibs \
e2fsprogs \
gcc-4.8-base \
init \
initscripts \
libcap2-bin \
libkmod2 \
libmount1 \
libsmartcols1 \
libudev1 \
libblkid1 \
libncursesw5 \
libprocps3 \
libslang2 \
libss2 \
libtext-charwidth-perl libtext-iconv-perl libtext-wrapi18n-perl \
ncurses-base \
ncurses-bin \
systemd \
systemd-sysv \
sysv-rc \
tzdata

# No-op stubs replace some unnecessary binaries that may be depended on in the install process (in
# particular we don't run an init process).
WORKDIR /usr/local/bin
RUN touch noop && \
chmod 555 noop && \
ln -s noop runlevel && \
ln -s noop invoke-rc.d && \
ln -s noop update-rc.d
WORKDIR /

# Cleanup cached and unnecessary files.
RUN apt-get autoremove -y && \
apt-get clean -y && \
tar -czf /usr/share/copyrights.tar.gz /usr/share/common-licenses /usr/share/doc/*/copyright && \
rm -rf \
/usr/share/doc \
/usr/share/man \
/usr/share/info \
/usr/share/locale \
/var/lib/apt/lists/* \
/var/log/* \
/var/cache/debconf/* \
/usr/share/common-licenses* \
/usr/share/bash-completion \
~/.bashrc \
~/.profile \
/etc/systemd \
/lib/lsb \
/lib/udev \
/usr/lib/x86_64-linux-gnu/gconv/IBM* \
/usr/lib/x86_64-linux-gnu/gconv/EBC* && \
mkdir -p /usr/share/man/man1 /usr/share/man/man2 \
/usr/share/man/man3 /usr/share/man/man4 \
/usr/share/man/man5 /usr/share/man/man6 \
/usr/share/man/man7 /usr/share/man/man8
76 changes: 76 additions & 0 deletions build/debian-base/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

all: build

REGISTRY ?= gcr.io/google-containers
IMAGE ?= debian-base
BUILD_IMAGE ?= debian-build

TAG ?= 0.1.0

TAR_FILE ?= rootfs.tar
ARCH?=amd64
TEMP_DIR:=$(shell mktemp -d)
QEMUVERSION=v2.7.0

ifeq ($(ARCH),amd64)
BASEIMAGE?=debian:jessie
endif
ifeq ($(ARCH),arm)
BASEIMAGE?=armhf/debian:jessie
QEMUARCH=arm
endif
ifeq ($(ARCH),arm64)
BASEIMAGE?=aarch64/debian:jessie
QEMUARCH=aarch64
endif
ifeq ($(ARCH),ppc64le)
BASEIMAGE?=ppc64le/debian:jessie
QEMUARCH=ppc64le
endif
ifeq ($(ARCH),s390x)
BASEIMAGE?=s390x/debian:jessie
QEMUARCH=s390x
endif

build: clean
cp ./* $(TEMP_DIR)
cat Dockerfile.build \
| sed "s|BASEIMAGE|$(BASEIMAGE)|g" \
| sed "s|ARCH|$(QEMUARCH)|g" \
> $(TEMP_DIR)/Dockerfile.build

ifeq ($(ARCH),amd64)
# When building "normally" for amd64, remove the whole line, it has no part in the amd64 image
sed "/CROSS_BUILD_/d" $(TEMP_DIR)/Dockerfile.build > $(TEMP_DIR)/Dockerfile.build.tmp
else
# When cross-building, only the placeholder "CROSS_BUILD_" should be removed
# Register /usr/bin/qemu-ARCH-static as the handler for ARM binaries in the kernel
docker run --rm --privileged multiarch/qemu-user-static:register --reset
curl -sSL https://github.com/multiarch/qemu-user-static/releases/download/$(QEMUVERSION)/x86_64_qemu-$(QEMUARCH)-static.tar.gz | tar -xz -C $(TEMP_DIR)
sed "s/CROSS_BUILD_//g" $(TEMP_DIR)/Dockerfile.build > $(TEMP_DIR)/Dockerfile.build.tmp
endif
mv $(TEMP_DIR)/Dockerfile.build.tmp $(TEMP_DIR)/Dockerfile.build

docker build --pull -t $(BUILD_IMAGE) -f $(TEMP_DIR)/Dockerfile.build $(TEMP_DIR)
docker create --name $(BUILD_IMAGE) $(BUILD_IMAGE)
docker export $(BUILD_IMAGE) > $(TEMP_DIR)/$(TAR_FILE)
docker build -t $(REGISTRY)/$(IMAGE)-$(ARCH):$(TAG) $(TEMP_DIR)
rm -rf $(TEMP_DIR)

clean:
docker rmi -f $(REGISTRY)/$(IMAGE)-$(ARCH):$(TAG) || true
docker rmi -f $(BUILD_IMAGE) || true
docker rm -f $(BUILD_IMAGE) || true
12 changes: 12 additions & 0 deletions build/debian-base/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Kubernetes Debian Base

The Kubernetes debian-base image provides a common base for Kubernetes system images that require
external dependencies (such as `iptables`, `sh`, or anything that is more than a static go-binary).

This image differs from the standard debian image by removing a lot of packages and files that are
generally not necessary in containers. The end result is an image that is just over 40 MB, down from
123 MB.

The image also provides a convenience script `/usr/local/bin/clean-install` that encapsulates the
process of updating apt repositories, installing the packages, and then cleaning up unnecessary
caches & logs.
34 changes: 34 additions & 0 deletions build/debian-base/clean-install
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/sh

# Copyright 2017 The Kubernetes Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# A script encapsulating a common Dockerimage pattern for installing packages
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe give an example?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

# and then cleaning up the unnecessary install artifacts.
# e.g. clean-install iptables ebtables conntrack

set -o errexit

if [ $# = 0 ]; then
echo >&2 "No packages specified"
exit 1
fi

apt-get update
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some images, we're running apt-get upgrade here also to get upgrades on "child" image builds.
Makes sense?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a higher layer upgrades packages in a lower layer, the image ends up carrying 2 copies of the package (the outdated version in the lower layer, which is masked by the update). Since we will maintain the base image, we should also be responsible for updating the base as needed.

apt-get install -y --no-install-recommends $@
apt-get clean -y
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't know if it makes sense, but I've seen cases where we do apt-get autoremove here as well

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to leave that as a manual step. The only reason autoremove would do anything here is if a package had 2 alternative dependencies, and another was added.

rm -rf \
/var/cache/debconf/* \
/var/lib/apt/lists/* \
/var/log/*
10 changes: 10 additions & 0 deletions build/debian-base/excludes
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
path-exclude /usr/share/doc/*
path-include /usr/share/doc/*/copyright
path-exclude /usr/share/groff/*
path-exclude /usr/share/i18n/locales/*
path-include /usr/share/i18n/locales/en_US*
path-exclude /usr/share/info/*
path-exclude /usr/share/locale/*
path-include /usr/share/locale/en_US*
path-include /usr/share/locale/locale.alias
path-exclude /usr/share/man/*