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

Add create-runtime, create-container, start-container hooks #1008

Merged
merged 1 commit into from
Dec 30, 2019

Conversation

RenaudWasTaken
Copy link
Contributor

Hello!

Since we discussed this during the last OCI weekly meeting, I wanted to continue the conversation on a more concrete change.
Related:

I've used the same names as LXC for the hooks. I'm happy to change them if we feel there are more appropriate names.
My reasoning while drafting this was to answer some of these questions:

  • Definition: How can we define the mount hook in a way that would clearly define the ability to mount "stuff" inside the container
  • Ordering: Is there an ordering that is required?
    Here it would be helpful to define the ordering such that the pre-start hook detects that it doesn't need to be executed in a setting where we specify both pre-start hook and mount hook for backwards compat reasons.

Questions still open:

  • Should we define "outside" and "inside" (in relation to the VM debate)

What do you think about this first draft?

Signed-off-by: Renaud Gaubert rgaubert@nvidia.com

@RenaudWasTaken
Copy link
Contributor Author

RenaudWasTaken commented Apr 24, 2019

@vbatts
Copy link
Member

vbatts commented Apr 30, 2019

cc @cyphar

config.md Outdated Show resolved Hide resolved
config.md Outdated Show resolved Hide resolved
config.md Outdated
The mount hooks MUST be called as part of the create operation at a time that would allow the hook to execute operations both inside and outside the container.
For example, on linux this would happen before the `pivot_root` operation is executed but after the mount namespace was created and setup.

For runtimes that implement the deprecated pre-start hooks as mount hooks, mount hooks MUST be called after the prestart hooks.
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure we should specify the order. Since the definition of the prestart hook is not changed, this order makes it impossible to implement a container runtime with support for the two hooks following the spec. And for compatibility, hooks installed on both prestart and mount could both check if the mount task is already done, so the order should not matter.

Copy link
Contributor Author

@RenaudWasTaken RenaudWasTaken May 1, 2019

Choose a reason for hiding this comment

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

And for compatibility, hooks installed on both prestart and mount could both check if the mount task is already done, so the order should not matter.

The goal here was that you can rely on ordering instead of checking for state you might have persisted in the mount or prestart hook.

this order makes it impossible to implement a container runtime with support for the two hooks following the spec

Do you mind detailing a bit more what you mean here :) ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Do you mind detailing a bit more what you mean here :) ?

Sorry, I take it back.

So now, the spec mandates steps to happen in this order:

  1. the container namespaces are created
  2. Prestart hooks
  3. Mount hooks
  4. pivot_root
  5. Start hooks
  6. The user-specified process is executed
  7. Poststart hooks

I thought the spec was saying that the Prestart hooks must happen after the namespaces are fully configured (including the pivot_root), which would make things impossible. But the wording is more vague:

[The pre-start hooks] are called after the container namespaces are created

So I think it's ok :)

@RenaudWasTaken
Copy link
Contributor Author

Thanks for your review @alban, will get to them tomorrow!

config.md Outdated
### <a name="configHooksMount" />Mount Hooks

The mount hooks MUST be called as part of the create operation at a time that would allow the hook to execute operations both inside and outside the container.
For example, on linux this would happen before the `pivot_root` operation is executed but after the mount namespace was created and setup.
Copy link
Member

Choose a reason for hiding this comment

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

linux -> Linux.

@RenaudWasTaken
Copy link
Contributor Author

Comments addressed :)

@RenaudWasTaken
Copy link
Contributor Author

Ping @cyphar @vbatts @alban :)

@cyphar cyphar mentioned this pull request May 15, 2019
@h-vetinari
Copy link
Contributor

Any update on this?

@RenaudWasTaken
Copy link
Contributor Author

@cyphar can you look into this :) ?
We would be happy to have your signoff!

@RenaudWasTaken
Copy link
Contributor Author

Ping @cyphar

@RenaudWasTaken
Copy link
Contributor Author

Ping @cyphar @vbatts

@h-vetinari
Copy link
Contributor

Can anyone provide an update/review here? Pings based on recent merges
@tianon @crosbymichael @hqhq @vbatts @caniszczyk

@RenaudWasTaken
Copy link
Contributor Author

Ping @cyphar @vbatts

@RenaudWasTaken
Copy link
Contributor Author

@cyphar @vbatts can you guys take a stab at reviewing this :) ?

Thanks!

config.md Outdated
@@ -384,6 +384,10 @@ For POSIX platforms, the configuration structure supports `hooks` for configurin
* **`env`** (array of strings, OPTIONAL) with the same semantics as [IEEE Std 1003.1-2008's `environ`][ieee-1003.1-2008-xbd-c8.1].
* **`timeout`** (int, OPTIONAL) is the number of seconds before aborting the hook.
If set, `timeout` MUST be greater than zero.
* **`mount`** (array of objects, OPTIONAL) is an array of [mount hooks](#mount-hooks).
Copy link
Contributor

Choose a reason for hiding this comment

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

"mount" is a really bad naming selection. It is applicable to single vendor at the moment (NVidia) and from naming denotes other usages. Currently prestart hook is used by others not only to do mounts, but also to do various devices initialization. If we want to be explicit in defining execution timings of the hooks, let's define that, but please don't imply in the names single use case of the hook.

config.md Outdated
@@ -375,7 +375,7 @@ For Windows based systems the user structure has the following fields:
For POSIX platforms, the configuration structure supports `hooks` for configuring custom actions related to the [lifecycle](runtime.md#lifecycle) of the container.

* **`hooks`** (object, OPTIONAL) MAY contain any of the following properties:
* **`prestart`** (array of objects, OPTIONAL) is an array of [pre-start hooks](#prestart).
* **`prestart`** (array of objects, OPTIONAL, **DEPRECATED**) is an array of [pre-start hooks](#prestart).
Copy link

Choose a reason for hiding this comment

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

I'd propose to not deprecate prestart hooks. They may be used for other purposes than mount and start hooks. For example our FPGA device plugin verifies and programs FPGA devices in a prestart hook.

@RenaudWasTaken
Copy link
Contributor Author

I'd propose to not deprecate prestart hooks. They may be used for other purposes than mount and start hooks. For example our FPGA device plugin verifies and programs FPGA devices in a prestart hook.
"mount" is a really bad naming selection. It is applicable to single vendor at the moment (NVidia) and from naming denotes other usages. Currently prestart hook is used by others not only to do mounts, but also to do various devices initialization. If we want to be explicit in defining execution timings of the hooks, let's define that, but please don't imply in the names single use case of the hook.

Let's take a step back :)

Pre-start hooks are not getting deprecated. In the spec, pre-start hooks are defined as follows:

The pre-start hooks MUST be called after the start operation is called but before the user-specified program command is executed.

After discussing this in opencontainers/runc#1811 we realized that this meant that this meant that pre-start hooks needed to be called after the pivot_root operation.
However, runc implemented pre-start hooks such that they were called before the pivot_root operation.

After discussion, we decided to clarify the meaning of pre-start hooks and allow to have hooks both "before" and "after" pivot_root.

Hence, we came up with the two new hooks:

  • mount hooks, which would be called at the exact same time as the current pre-start hook as currently implemented in runc
  • start hooks which would be called at the exact same time as the one defined in the spec.

So pre-start hooks aren't being deprecated "per-se", they are being renamed. The names were chosen based on LXC's current hooks but if you feel strongly about another name, I'll happily change the PR.

@kad
Copy link
Contributor

kad commented Sep 9, 2019

@RenaudWasTaken the problem is that "mount" implies a lot of meaning and does more confusion than clarification in comparison with current prestart name.

I would rather do the names that will explicitly refer to environment where it is executed (before/after pivot_root, to be explicit). Something like: keep current prestart name as it is, with adding clarification to the spec that it is executed in the host namespace and something like containerprestart to explicitly indicate that it will be executed in the container namespace.
Or something like you mentioned inside / outside combined with operations pre/post start/stop. Names should be descriptive enough for sysadmin who will be configuring those to understand without going and reading deeply OCI spec.

@RenaudWasTaken
Copy link
Contributor Author

Something like: keep current prestart name as it is, with adding clarification to the spec that it is executed in the host namespace

That's unfortunately not an option, clarifying it either way is a breaking change.

containerprestart to explicitly indicate that it will be executed in the container namespace.

I have no strong feelings on the naming, containerprestart seems fine. The naming used here is the same as the one chosen by LXC with the intention to cause less confusion.

If we think there is more value in using a different name that is clearer than I'm happy to change this PR.

config.md Outdated
@@ -399,6 +403,20 @@ The [state](runtime.md#state) of the container MUST be passed to hooks over stdi
The pre-start hooks MUST be called after the [`start`](runtime.md#start) operation is called but [before the user-specified program command is executed](runtime.md#lifecycle).
On Linux, for example, they are called after the container namespaces are created, so they provide an opportunity to customize the container (e.g. the network namespace could be specified in this hook).

Note: Prestart hooks were deprecated in favor of mount and start hooks, which have a clearer definition.
Copy link
Member

Choose a reason for hiding this comment

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

I would explicitly mention that runc incorrectly implemented them, to ensure users don't depend on them.

Copy link

Choose a reason for hiding this comment

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

Are we going to use -host and -container or -inside and -outside suffixes to the hook names? It's still not clear to me if proposed hooks will be executed in the host or container namespace. "mount" looks quite vague to me in this regard. It requires some guesswork to understand its purpose. Would it be better to have prestart-host and prestart-container instead?

Copy link
Contributor

Choose a reason for hiding this comment

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

@cyphar @RenaudWasTaken Can you clarify the statement about "runc incorrectly implemented them" ? From what I see in https://github.com/opencontainers/runtime-spec/blob/master/config.md#posix-platform-hooks it says "Hooks MUST be executed in the runtime namespace.", and prestart is executed accordingly to this specification.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The pre-start hooks MUST be called after the start operation is called but before the user-specified program command is executed.

This points to having the hook after the pivot_root is called :)

https://github.com/opencontainers/runtime-spec/blob/master/config.md#prestart

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bart0sh, is the naming something that can be resolved by better detailling the hooks in the spec?

Today they are worded as follows:
mount hooks

The mount hooks MUST be called as part of the create operation at a time that would allow the hook to execute operations both inside and outside the container.
For example, on Linux this would happen before the pivot_root operation is executed but after the mount namespace was created and setup.

start hooks

The start hooks MUST be called before the user-specified process is executed as part of the start operation.
This hook can be used to execute some operations in the container, for example running the ldconfig binary on linux before the container process is spawned.

Do you think we could reword the definition in a different way that would reduce the confusion?

Copy link
Contributor

Choose a reason for hiding this comment

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

The pre-start hooks MUST be called after the start operation is called but before the user-specified program command is executed.

This points to having the hook after the pivot_root is called :)
https://github.com/opencontainers/runtime-spec/blob/master/config.md#prestart

Well, not really. It specifies the timing. But where hook itself is called is specified by line that I quoted from spec above: "Hooks MUST be executed in the runtime namespace", and runtime namespace defined as https://github.com/opencontainers/runtime-spec/blob/master/glossary.md#runtime-namespace

"After pivot_root" will be already not a runtime namespace.

Copy link

Choose a reason for hiding this comment

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

Prestart hooks were deprecated in favor of mount and start hooks

mount and start hooks are executed in container namespace. Prestart hooks executed in runtime namespace. They can't be deprecated in favor of something that runs in a different namespace.

@cyphar
Copy link
Member

cyphar commented Oct 2, 2019

@kad runc will continue to support prestart indefinitely as-is (internally mapping them to mount hooks). This is precisely the reason why we need to have new hook names, to stop breaking existing users. But prestart is wrong as-is and so we need to deprecate it (to stop users from using it given the mismatch between runc and runtime-spec).

@RenaudWasTaken I think copying the LXC hooks is the only reasonable choice. I don't want to get caught up in bike-shedding over what hook names we should use.

From my side, this LGTM -- as long as the NVIDIA folks are happy with it (sorry for the long time to review, I've been swamped with openat2 and related work).

@RenaudWasTaken
Copy link
Contributor Author

I've updated the PR :)

@cyphar
Copy link
Member

cyphar commented Oct 2, 2019

/cc @opencontainers/runtime-spec-maintainers

@h-vetinari
Copy link
Contributor

h-vetinari commented Oct 2, 2019

@bart0sh: Would it be better to have prestart-host and prestart-container instead?

I like this idea. It keeps the original name "prestart", and clarifies how it has been split up.

@RenaudWasTaken: I've updated the PR :)

Did you forget to push? ;-)

@cyphar: sorry for the long time to review, I've been swamped with openat2 and related work

Glad to see this moving forward again in any case! I'm guessing you're thinking about solving this issue already for runc-1.0.0rc9, which I'm also guessing should go out quickly due to the new CVE? But IMO that shouldn't rush the decision of the naming here, which the community will be stuck with for a long time.

If my surmise about the situation is correct, how about releasing rc9 first and then solving the hooks under less time pressure?

@RenaudWasTaken
Copy link
Contributor Author

Did you forget to push? ;-)

Thanks! Updated

@bart0sh: Would it be better to have prestart-host and prestart-container instead?
I like this idea. It keeps the original name "prestart", and clarifies how it has been split up.

The issue that I faced with using the host word, is that it becomes pretty confusing as to what it means for a vm based runtime (is host the hypervisor or the guest?).

It seemed to me that keeping existing terminology (i.e: used in LXC) was a lot less confusing since a hook author is likely to be writing hooks for both OCI compliant runtimes (runc, ...) and non OCI compliant runtimes (LXC).

@RenaudWasTaken
Copy link
Contributor Author

In the latest update, the following changes were made:

  • create-container has now the same structure as the other hooks (before it had a field called pathContainer rather than path)
  • I specified for each hook in what namespace the path value should be resolved
  • I specified for each hook in what namespace it should be executed

Copy link
Member

@giuseppe giuseppe left a comment

Choose a reason for hiding this comment

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

left some minor comments.

schema/defs.json Outdated
@@ -108,6 +108,12 @@
"$ref": "#/definitions/Hook"
}
},
"ArrayOfContainerHooks": {
Copy link
Member

Choose a reason for hiding this comment

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

should this chunk be dropped now?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed, thanks for noticing!

@@ -125,13 +125,26 @@ type Hook struct {
Timeout *int `json:"timeout,omitempty"`
}

// Hook specifies a command that is run in the container at a particular event in the lifecycle of a container
Copy link
Member

Choose a reason for hiding this comment

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

here it should start with // Hooks .... or leave an empty line after the comment.

Otherwise "make .golint" will complain about it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed, thanks for noticing!

runtime.md Outdated
3. The [`prestart` hooks](config.md#prestart) MUST be invoked by the runtime.
If any `prestart` hook fails, the runtime MUST [generate an error](#errors), stop the container, and continue the lifecycle at step 12.
4. The [`create-runtime` hooks](config.md#create-runtime-hooks) MUST be invoked by the runtime.
If any `create-runtime` hook fails, the runtime MUST [generate an error](#errors), stop the container, and continue the lifecycle at step 12.
Copy link
Member

Choose a reason for hiding this comment

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

should create-runtime and create-container be specified in camel case as well as in config.md? At least the schema and the Go code seems to use the camel case version.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed!

Signed-off-by: Renaud Gaubert <rgaubert@nvidia.com>
Copy link
Member

@giuseppe giuseppe left a comment

Choose a reason for hiding this comment

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

LGTM

@cyphar
Copy link
Member

cyphar commented Dec 27, 2019

LGTM from my side.

@crosbymichael
Copy link
Member

crosbymichael commented Dec 30, 2019

LGTM

Approved with PullApprove

@crosbymichael crosbymichael merged commit e09c7c4 into opencontainers:master Dec 30, 2019
@vbatts vbatts mentioned this pull request Jan 9, 2020
@RenaudWasTaken RenaudWasTaken changed the title Add create-host, create-container, start-container hooks Add create-runtime, create-container, start-container hooks Feb 18, 2020
@h-vetinari
Copy link
Contributor

h-vetinari commented Mar 31, 2020

I'm quite sure no-one wants to receive a ping from this thread ever again, but since some parts of the new hooks were left un(der)specified, I opened a follow-up issue to track things: #1039.

AkayaKuromoto added a commit to AkayaKuromoto/runtime-spec that referenced this pull request Aug 10, 2021
In PR opencontainers#1008 3 new steps in the lifecycle were added and the referencing of the states to the corresponding lifecycle step was not adjusted. Corrected based on Tag v1.0.0-rc6.
AkayaKuromoto added a commit to AkayaKuromoto/runtime-spec that referenced this pull request Aug 10, 2021
In PR opencontainers#1008 3 new steps in the lifecycle were added and the referencing of the states to the corresponding lifecycle step was not adjusted. Corrected based on Tag v1.0.0-rc6.

Signed-off-by: Pascal Theml <pascal@familie-theml.de>
kolyshkin added a commit to kolyshkin/runtime-spec that referenced this pull request Jul 17, 2024
Poststart hooks exist in runc since 2015 [1], and since that time until
today, if a hook returned an error, runc kills the container.

In 2020, commit c166268 (PR opencontainers#1008) added the following text
(which became part of runtime-spec release v1.0.2):

> 9. The `poststart` MUST be invoked by the runtime. If any
> `poststart` hook fails, the runtime MUST log a warning, but the
> remaining hooks and lifecycle continue as if the hook had succeeded.

Now, this text conflicted with the pre-existing runtime (runc) behavior,
and it still conflicts with the current runc behavior.

At this point, we can either fix runtimes or the spec.

To my mind, fixing the spec is a better approach, because:
 - initial implementation predates the spec wording by a few years;
 - the wording in the spec was never implemented (in runc);
 - returning an error (and stopping the container) seems like a more
   versatile approach, since a hook can usually choose whether to
   return an error or not.

[1]: opencontainers/runc#392

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.