Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ DOC_FILES := \
layer.md \
config.md \
annotations.md \
conversion.md \
considerations.md \
implementations.md

Expand Down
119 changes: 119 additions & 0 deletions conversion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Conversion to OCI Runtime Configuration

When extracting an OCI Image into an [OCI Runtime bundle][oci-runtime-bundle], two orthogonal components of the extraction are relevant:

1. Extraction of the root filesystem from the set of [filesystem layers](layers.md).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How will we verify implementations that have either the bundle or config opaque to the end user?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In the same way that we would have to test runtime implementations that similarly make the bundle or config opaque to the user. This document only concerns tools that implement this conversion (that intend to actually also implement either a runtime or to produce a config.json to the user).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

link broken, layers.md should be layer.md

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This document only concerns tools that implement this conversion (that intend to actually also implement either a runtime or to produce a config.json to the user).

In practice, this conversion will be performed by systems that will make this opaque. The advice here applies, but may not be verifiable without an introspection mechanism (read: leaky abstraction). For example, we'd like to be able to pass this spec through several systems before writing out the resulting config.json.

2. Conversion of the [image configuration blob](config.md) to an [OCI Runtime configuration blob][oci-runtime-config].

This section defines how to convert an `application/vnd.oci.image.config.v1+json` blob to an [OCI runtime configuration blob][oci-runtime-config] (the latter component of extraction).
The former component of extraction is defined [elsewhere](layers.md) and is orthogonal to configuration of a runtime bundle.
Copy link
Copy Markdown
Member

@coolljt0725 coolljt0725 Mar 8, 2017

Choose a reason for hiding this comment

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

same here, layers.md -> layer.md

The values of runtime configuration properties not specified by this document are implementation-defined.

A converter MUST rely on the OCI image configuration to build the OCI runtime configuration as described by this document; this will create the "default generated runtime configuration".

The "default generated runtime configuration" MAY be overridden or combined with externally provided inputs from the caller.
In addition, a converter MAY have its own implementation-defined defaults and extensions which MAY be combined with the "default generated runtime configuration".
The restrictions in this document refer only to combining implementation-defined defaults with the "default generated runtime configuration".
Externally provided inputs are considered to be a modification of the `application/vnd.oci.image.config.v1+json` used as a source, and such modifications have no restrictions.

For example, externally provided inputs MAY cause an environment variable to be added, removed or changed.
However an implementation-defined default SHOULD NOT result in an environment variable being removed or changed.

[oci-runtime-bundle]: https://github.com/opencontainers/runtime-spec/blob/v1.0.0-rc5/bundle.md
[oci-runtime-config]: https://github.com/opencontainers/runtime-spec/blob/v1.0.0-rc5/config.md

## Verbatim Fields

Certain image configuration fields have an identical counterpart in the runtime configuration.
Some of these are purely annotation-based fields, and have been extracted into a [separate subsection](#annotation-fields).
A compliant configuration converter MUST extract the following fields verbatim to the corresponding field in the generated runtime configuration:

| Image Field | Runtime Field | Notes |
| ------------------- | --------------- | ----- |
| `architecture` | `platform.arch` | |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this some sort of field path syntax?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah, it's in platform/arch. I wasn't sure how to reference it, so I felt the . dereferencing style was clear enough.

| `os` | `platform.os` | |
| `Config.WorkingDir` | `process.cwd` | |
| `Config.Env` | `process.env` | 1 |
| `Config.Entrypoint` | `process.args` | 2 |
| `Config.Cmd` | `process.args` | 2 |

1. The converter MAY add additional entries to `process.env` but it SHOULD NOT add entries that have variable names present in `Config.Env`.
2. If both `Config.Entrypoint` and `Config.Cmd` are specified, the converter MUST append the value of `Config.Cmd` to the value of `Config.Entrypoint` and set `process.args` to that combined value.

### Annotation Fields

These fields all affect the `annotations` of the runtime configuration, and are thus subject to [precedence](#annotations).

| Image Field | Runtime Field | Notes |
| ------------------- | --------------- | ----- |
| `author` | `annotations` | 1,2 |
| `created` | `annotations` | 1,3 |
| `Config.Labels` | `annotations` | |
| `Config.StopSignal` | `annotations` | 1,4 |

1. If a user has explicitly specified this annotation with `Config.Labels`, then the value specified in this field takes lower [precedence](#annotations) and the converter MUST instead use the value from `Config.Labels`.
2. The value of this field MUST be set as the value of `org.opencontainers.image.author` in `annotations`.
3. The value of this field MUST be set as the value of `org.opencontainers.image.created` in `annotations`.
4. The value of this field MUST be set as the value of `org.opencontainers.image.stopSignal` in `annotations`.

## Parsed Fields

Certain image configuration fields have a counterpart that must first be translated.
A compliant configuration converter SHOULD parse all of these fields and set the corresponding fields in the generated runtime configuration:

| Image Field | Runtime Field |
| ------------------- | --------------- |
| `Config.User` | `process.user.*` |

The method of parsing the above image fields are described in the following sections.

### `Config.User`

If the values of [`user` or `group`](config.md#properties) in `Config.User` are numeric (`uid` or `gid`) then the values MUST be copied verbatim to `process.user.uid` and `process.user.gid` respectively.
If the values of [`user` or `group`](config.md#properties) in `Config.User` are not numeric (`user` or `group`) then a converter SHOULD resolve the user information using a method appropriate for the container's context.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is fairly complex to perform outside the container's context. Wouldn't it be easier to set the direct values in the runtime and have it perform the correct uid lookups before exec?

Copy link
Copy Markdown
Member Author

@cyphar cyphar Mar 7, 2017

Choose a reason for hiding this comment

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

The OCI runtime configuration only accepts fully resolved uids, gids and additionalGids for several reasons. As a result, the runtime simply can't do the resolution and it needs to be done during the conversion from Image config to config.json.

However, I'm not sure I agree that (for the simple case) it is hard to implement. I've intentionally left this section vague when the values of Config.User are non-numeric, because at a certain level a runtime could implement whatever the hell they want there.

Though it should be noted that libcontainer/user is an implementation of /etc/passwd and /etc/group parsing which implements this already. NSS is ugly, but nothing is stopping a converter from running a container (with a partially generated config.json) to figure out the UID/GID.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@cyphar I'm just worried about reproducing https://linux.die.net/man/3/getpwnam behavior outside the container, when the runtime might be best positioned to do this correctly.

@crosbymichael Any thoughts here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

but nothing is stopping a converter from running a container (with a partially generated config.json) to figure out the UID/GID.

This seems pretty ugly, forces the converter to mount the rootfs just to resolve. What is the more common value for Config.User, name:group or uid:gid?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@dmcgowan name:group is used very extensively in Docker images. You don't need to resolve NSS -- I expect that most converters would just parse /etc/passwd and /etc/group. Hell, the converter doesn't even have to support name:group.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You don't need to resolve NSS -- I expect that most converters would just parse /etc/passwd and /etc/group

This might be a no go for certain organizations, although I haven't seen this problem in container deployments. Why do you make the assertion that NSS isn't required?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@stevvooe Effectively what this section is saying (and maybe you can come up with better wording than me) is that:

  1. If the Config.User is numerical (uid:gid or similar) then uid and gid in the runtime configuration must be set to the numerical values.

  2. If the Config.User is not numerical, then the converter may set uid and gid to any value. However, the recommendation is that the converter attempt to resolve the string into a reasonable uid and gid in the container's context. I don't want to require this (for many reasons, mostly because it would tie config.json to the rootfs far too much).

For Unix-like systems, this MAY involve resolution through NSS or parsing `/etc/passwd` from the extracted container's root filesystem to determine the values of `process.user.uid` and `process.user.gid`.

In addition, a converter SHOULD set the value of `process.user.additionalGids` to a value corresponding to the user in the container's context described by `Config.User`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Again, this is very complex to do correctly outside the container's context.

For Unix-like systems, this MAY involve resolution through NSS or parsing `/etc/group` and determining the group memberships of the user specified in `process.user.uid`.
If the value of [`user`](config.md#properties) in `Config.User` is numeric, the converter SHOULD NOT modify `process.user.additionalGids`.

If `Config.User` is not defined, the converted `process.user` value is implementation-defined.
If `Config.User` does not correspond to a user in the container's context, the converter MUST return an error.

## Optional Fields

Certain image configuration fields are not applicable to all conversion use cases, and thus are optional for configuration converters to implement.
A compliant configuration converter SHOULD provide a way for users to extract these fields into the generated runtime configuration:

| Image Field | Runtime Field | Notes |
| --------------------- | ------------------ | ----- |
| `Config.ExposedPorts` | `annotations` | 1 |
| `Config.Volumes` | `mounts` | 2 |

1. The runtime configuration does not have a corresponding field for this image field.
However, converters SHOULD set the [`org.opencontainers.image.exposedPorts` annotation](#config.exposedports).
2. If a converter implements conversion for this field using mountpoints, it SHOULD set the `destination` of the mountpoint to the value specified in `Config.Volumes`.
The other `mounts` fields are platform and context dependent, and thus are implementation-defined.
Note that the implementation of `Config.Volumes` need not use mountpoints, as it is effectively a mask of the filesystem.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@cyphar could you help me fully understand point 2 for Config.Volumes; the first line reads:

If a converter implements conversion for this field using mountpoints, it SHOULD set the destination of the mountpoint to the value specified in Config.Volumes.

what does that mean? are there any other way to implement conversion for this field other than mountpoints? if yes, which ones?
How's the expected flow to implement the field with mountpoints for runtimes? create a host dir for that volume and bind mount it in the container?

Note that the implementation of Config.Volumes need not use mountpoints, as it is effectively a mask of the filesystem.

as a non-native speaker this seems in contrast with the first sentence. It now reads "don't use mountpoints!"

Copy link
Copy Markdown
Member Author

@cyphar cyphar May 22, 2017

Choose a reason for hiding this comment

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

are there any other way to implement conversion for this field other than mountpoints?

Yes, you could just copy the contents of the volume into the container. Hopefully (see #496) the purpose of volumes is to restrict how implementations should handle diff layers (allow external data that is not snapshotted).

In the case of umoci I could envisage this all being done through manifests and black-holing certain directories so umoci will simply ignore them.

How's the expected flow to implement the field with mountpoints for runtimes?

I only mention the destination. In particular what this is meant to mean is that the value of Config.Volumes should be a mountpoint (though there are reasons to not do that). The source of the mountpoint, the type of filesystem and so on can be whatever you want (it could be a tmpfs for example or NFS).

as a non-native speaker this seems in contrast with the first sentence. It now reads "don't use mountpoints!"

The first sentence says you SHOULD, but the second sentence says you don't have to. To be fair, maybe I shouldn't repeat that point but I felt worried people would make the same assumption you did.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, you could just copy the contents of the volume into the container.

alright, I guess what's still not clear to me is the definition of a volume which this doc is missing. What's a volume then? some directory/mountpoint on the host or somewhere else?
from that sentence, as you said, it can be anything.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this also stipulate that data from the image may be copied into the volume?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No, because that's forbidden by the definition of Config.Volume (https://github.com/opencontainers/image-spec/blame/master/config.md#L152):

If a file or folder exists within the image with the same path as a data volume, that file or folder will be replaced by the data volume and never be merged.

Copy link
Copy Markdown
Member Author

@cyphar cyphar May 23, 2017

Choose a reason for hiding this comment

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

Sorry, the entire directory is masked, not just the files that are in the data volume. Maybe I should make this sentence clearer but given the Config.Volume definition I can't imagine a reasonable reading of this text would conclude that merging is okay.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is behavior that docker allows today: effectively, the contents of a volume can be seeded with the contents of the image.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Okay, but that's not what the spec currently allows (I don't agree with that design either, but let's discuss that somewhere else). Would you mind if we handle that in a separate PR (it's got nothing to do with the config generation and more to do with extraction surely).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@cyphar I'll file an issue and not hold up this PR further on this matter.


### `Config.ExposedPorts`

The OCI runtime configuration does not provide a way of expressing the concept of "container exposed ports".
However, converters SHOULD set the **org.opencontainers.image.exposedPorts** annotation, unless doing so will [cause a conflict](#annotations).

**org.opencontainers.image.exposedPorts** is the list of values that correspond to the [keys defined for `Config.ExposedPorts`](config.md) (string, comma-separated values).

## Annotations

There are three ways of annotating an OCI image in this specification:

1. `Config.Labels` in the [configuration](config.md) of the image.
2. `annotations` in the [manifest](manifest.md) of the image.
3. `annotations` in the [image index](image-index.md) of the image.

In addition, there are also implicit annotations that are defined by this section which are determined from the values of the image configuration.
A converter SHOULD NOT attempt to extract annotations from [manifests](manifest.md) or [image indices](image-index.md).
If there is a conflict (same key but different value) between an implicit annotation (or annotation in [manifests](manifest.md) or [image indices](image-index.md)) and an explicitly specified annotation in `Config.Labels`, the value specified in `Config.Labels` MUST take precedence.

A converter MAY add annotations which have keys not specified in the image.
A converter MUST NOT modify the values of annotations specified in the image.
2 changes: 1 addition & 1 deletion manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ There are three main goals of the Image Manifest Specification.
The first goal is content-addressable images, by supporting an image model where the image's configuration can be hashed to generate a unique ID for the image and its components.
The second goal is to allow multi-architecture images, through a "fat manifest" which references image manifests for platform-specific versions of an image.
In OCI, this is codified in an [image index](image-index.md).
The third goal is to be translatable to the [OCI Runtime Specification](https://github.com/opencontainers/runtime-spec).
The third goal is to be [translatable](conversion.md) to the [OCI Runtime Specification](https://github.com/opencontainers/runtime-spec).

This section defines the `application/vnd.oci.image.manifest.v1+json` [media type](media-types.md).
For the media type(s) that this is compatible with see the [matrix](media-types.md#compatibility-matrix).
Expand Down