chrootchanges the file system root (
/) that a process can see. This allows a process to use any directory as if it were a file system root instead of the actual file system root.
namespacesgroup resources together (like network and process IDs) so that only processes within a namespace can see the resources of that namespace.
cgroupsset CPU and memory limits for processes.
Dockerfilein the current working directory and tell Docker build it:
docker buildcommand clearly show how Docker executes the build based on our Dockerfile.
dockerCLI is the client that you use to send commands and data to the Docker daemon. The Docker daemon stores and runs containers. First, the
docker build .command tells Docker to use the local current working directory (
.) as the Docker context. The Docker context is sent to the Docker daemon.
COPY . /publiccopies all the files in the Docker context into the
/publicdirectory on our container image. This includes all the files in our local current working directory that was sent over to the daemon as the Docker context.
WORKDIR /publicsets the working directory for the container image we are building, so that when the container image is run, the current working directory for the process is
ENTRYPOINT ...sets the command to run when the container is run, which, in this case, runs an HTTP server that serves all the files in
/public. So, for example, if we had HTML files in our local current working directory, those would be served by this container.
5550043a7340, which can be used in subsequent
localhost:8000. If you had, say, an
index.htmlin your local current working directory, going to
localhost:8000would serve the contents of
RUNs can usually be combined:
FROMinstruction) builds a single image starting with the
FROMimage as the base. These builds run in a purely linear format from start to finish and the results of all intermediate steps become part of the resulting image. However, since a container image should only contain what is necessary to run your application, much of the files from intermediate steps are junk that is not needed at run-time.
mavenimage as the base for an intermediate image called
mvn packagebuilds the fatjar for the project.
openjdkimage that just has the JRE.
TODO: Show some bash commands that can generate a layer
osfields define the platform this container is built to run on. The
configfield defines the runtime configuration for the container, including any environment variables (
Env), the entrypoint (
Entrypoint), arguments to append to the entrypoint (
Cmd), ports to expose (
ExposedPorts), arbitrary annotations (
Labels), the directory to use as the current working directory (
WorkingDir), and the user to run the container process as (
TODO: Might want to talk about reasonings for burning runtime config into an image vs. defining in a runtime spec
TODO: Show example container configuration and running with Docker/Kubernetes and effective runtime configuration
rootfsobject and the
historyarray. Both contain metadata about the layers that make up the container file system.
rootfscontains a list of diff IDs. A diff ID for a layer is the digest (usually SHA256 hash) of the uncompressed tarball archive containing the files for that layer. Note that this is different from a layer's descriptor digest, which is a hash of the compressed archive. The
rootfsdefines a list of these diff IDs in the order in which the layers belong in the container overlay file system, from first to last. Note that these layers must match those defined in the manifest.
docker loadcan load a container image stored as a tarball archive into the Docker local repository store. This tarball archive includes the compressed tarball archives for all the layers, the container configuration JSON file, and the manifest JSON file (must be named
manifest.json). Here’s an example of the manifest JSON file:
manifest.jsonand reads it. The manifest tells Docker to load the container configuration from the
config.jsonfile and load the layers from
layer3.tar.gz, in that order. Note that this order must match the order of the layers defined in the container configuration under
RepoTagshere tells Docker to "tag" the image with the name
docker savecan also save images in a legacy Docker tarball archive format that
docker loadalso supports. In this legacy format, each layer would be stored in its own directory named with its SHA256 hash (digest of compressed layer tarball archive). Each of these directories contains a
jsonfile with a legacy container configuration (we won’t go into the details of this), a
VERSIONfile, and a
layer.tarthat is the uncompressed tarball archive of the layer contents.
2in this case
config- descriptor of container configuration blob
layers- list of descriptors of layer blobs, in the same order as the
rootfsof the container configuration
application/vnd.docker.container.image.v1+jsonfor a container configuration or
application/vnd.docker.image.rootfs.diff.tar.gzipfor a layer
size- the size of the blob, in bytes
digest- the digest of the content
busyboximage is composed of a container configuration stored as a blob with digest
sha256:3a093384…and a single layer blob with digest
sha256:57c14dd6…. Note that manifests simply contain references. The actual blob content is stored elsewhere and would need to be fetched and provided to a container run-time when running the image as a container.
mediaType- must be set to
config.mediaType- must be set to
openjdk. Since the repository is only a single level and the registry is Docker Hub, the repository is actually resolved as
library/openjdk. The tag component is specified after a colon. In this example, the tag is
8-jre-alpine. Although this tag is arbitrarily-defined, the maintainers of this repository chose to convey some information about the image through this tag. Here, this tag says that the specific image contains OpenJDK 8 with just the JRE (Java Runtime Environment) and Alpine (a tiny Linux distribution). Some other tags in the repository refer to the same image but contain more specific information, like
8u191-jre-alpine3.9. Other tags may be less specific, like
jre, which, at the time of writing, refers to an OpenJDK 11 image with the JRE and Debian Stretch. This tag will most likely move to refer to newer OpenJDK versions as they become GA. The latest tag also refers to the latest stable, default image the maintainers believes users will find useful in most cases and will move the tag as new versions become stable. There are some general tips and best practices for managing tags for a repository.
TODO: Maybe explain some tips?
gcr.io, which is the server URL for Google Container Registry. The repository is
my-gcp-project/my-awesome-app/message-service, which in GCR, means that the repository is on the
my-gcp-projectGoogle Cloud Platform project and under a
my-awesome-app/message-serviceGoogle Cloud Storage subdirectory. The tag is
v1.2.3, which is used to identify the version of the
message-servicethis container image contains.
dockerCLI tool, "tag" also refers to a label given to an image on the Docker daemon. For example, you might build an image called
4e905a76595b. This image ID is a shortened SHA256 digest of the built container configuration. Docker then "tags" the
4e905a76595bwith a label
myimage, which can be used to refer to the same image with future
dockercommands rather than using
4e905a76595ball the time. However, when you want to build and push an image to a registry, you would "tag" the image with the full image reference:
gcr.io/my-gcp-project/myimage:v1to be used in later docker commands, but
gcr.io/my-gcp-project/myimage:v1is actually an image reference with its tag as
openjdk, the endpoint would be
Authorization(explained in the Token Authentication section) and
Accept. For example, if you want to only accept and parse manifests for Docker Image Format V2 Schema 2, you would want to set
202 Acceptedresponse should contain a
Locationheader with the URL to send the blob content to. There are a few ways to send the blob content, but the recommended way is to send the content in a single request. The content can also be sent in chunks if you wish to implement resumable uploads. Send the blob content to the
202 Accepted. Once a blob is uploaded, the blob can be committed with its digest:
201 Created. If the blob mount fails (blob doesn’t exist or cross-repository blob mount not supported), the response will be a normal blob upload initialization response with a
Locationto send the blob content to.
Content-Typeto the correct manifest media type. For Docker V2.2, the media type would be
application/vnd.docker.distribution.manifest.v2+jsonand for OCI, the media type would be
Authorizationheader to be authenticated. Otherwise, a
403 Forbiddenresponse would be received.
Authorizationheader containing the credentials for access to the repository:
Authorizationheader would be
Authorization: Basic Y29vbGxvZzpkb250aGFja21lMTIz, where
Y29vbGxvZzpkb250aGFja21lMTIzis the Base64 encoding of
access_token(OAuth2) that is the authenticated Bearer token. The JSON also may also contain an
issued_atfield for knowing when the token expires. These tokens should be cached and applied to any subsequent requests (until expired) to skip steps 1 and 2.
scopes can be included. For example, for a cross-repository blob mount with
otheruser/baseimageas the source repository, the request may be:
Authorizationfor both scopes though.
docker login). This configuration can be found at the
.docker/config.jsonfile located in the user’s home directory. This configuration can store both raw credentials and references to credential helpers. Credential helpers are CLI tools that can be used to fetch credential.
authsfield that is a map with registry URLs as keys. For example:
credHelpersfield that maps from registry URLs to credential helper names. For example:
credsStorefield. For example:
getcommand, passing in the server URL as the input. For example, to fetch credentials from the credential helper named
Secretfield which can be used as the username and password, respectively, for authenticating a token.
blobs/directory contains files for each blob named by their digest. The
selectors/directory contains selector files whose names are the selectors themselves and contents are the digests of the blobs they point to. Both blobs and selectors should be immutable and unique.
ff, with each file being placed into the bin that matches the first two characters in its file name.
busyboximage from Docker Hub using some
curlthe registry API root to get the
busyboxis a public image, we don't need to include any
tarup the entire image and load it into Docker:
busyboximage we just pulled:
bash. We'll build a simple image that has a shell script that prints
"Hello World"on top of the
"Hello World"shell script and archive it into its own layer tarball:
<username>/hello. First, we need to push our layers. The first layer comes from
busybox, so we can actually just mount that into our new image:
busyboxlayer into our
- Separate into fine layers
- Speed up iterative build cycle - separate out parts that change more often into another layer
- Minimize change
- stream everything through sinks/sources