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 Windows Hostprocess flag #795

Merged
merged 1 commit into from
Jan 13, 2023

Conversation

jsturtevant
Copy link
Contributor

@jsturtevant jsturtevant commented Feb 8, 2022

Fixes: #518

Still needs:

  • docs
  • a bit more thought on how to specific user
  • test

cmd/nerdctl/run_windows.go Outdated Show resolved Hide resolved
cmd/nerdctl/run_windows.go Outdated Show resolved Hide resolved
@AkihiroSuda AkihiroSuda added enhancement New feature or request impact/major platform/Windows/Non-WSL2 Microsoft Windows (non-WSL2) labels Feb 9, 2022
@jsturtevant jsturtevant force-pushed the hostprocess-containers branch 4 times, most recently from bacdd4c to 98a1c37 Compare February 10, 2022 16:52
@jsturtevant jsturtevant marked this pull request as ready for review February 10, 2022 17:02
README.md Outdated
@@ -370,6 +370,7 @@ Security flags:
- :whale: `--cap-add=<CAP>`: Add Linux capabilities
- :whale: `--cap-drop=<CAP>`: Drop Linux capabilities
- :whale: `--privileged`: Give extended privileges to this container
- :blue_square: :nerd_face: `--host-process`: Allow running Host Process containers on Windows. Inherits permissions from containerd process unless `--user` is specified then will start with user specified. The user specified must be present on the host. Requires Containerd 1.6+.
Copy link
Member

Choose a reason for hiding this comment

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

What about calling this --isolation=host

Copy link
Member

Choose a reason for hiding this comment

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

I like that idea, follows with what folks would be used to for process/hyper-v

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this has grown on me overnight. I do have a concern on naming... Right now we call this hostprocess containers in kubernetes and job containers in hcsshim and we would be adding another slightly different way of referencing this concept. I think it is a minor difference but thought to bring it up. thoughts?

Copy link
Member

Choose a reason for hiding this comment

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

The 'job containers' name was supposed to be just for the devs on hcsshim as it was what we got accustomed to when referring to it internally, although it does kind of suck that the name leaks out in some error strings. That should maybe get addressed/cleaned up. If that was touched up would that alleviate some of the concern on the three way split @jsturtevant?

Copy link
Member

Choose a reason for hiding this comment

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

Feel like the UX is a bit improved if all the Windows folks need to remember is --isolation and its three options vs. --isolation and then an option off to the side that also dramatically reduces the amount of isolation you have. Also might simplify the case where both are specified (--isolation and --host-process) as ideally we should error out if they are as they're conflicting options.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's a minor concern. Just wanted to call it out. Anytime we refer to the same thing multiple ways it adds complexity to understanding.

That said thinking about hostprocess as an --isolation resonates with me. and keeps it simple from the cli UX perspective.

This brings up one more thought, As of right now hostprocess doesn't not support hyper-v containers. Is it possible in the future it could? Does that even make sense?

Copy link
Member

Choose a reason for hiding this comment

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

That's a good question.. I could imagine a world where we could get it to work, but I'm not sure what use it would bring off the top of my head. I don't know if its worth putting too much brain power into thinking of at the moment though

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just want to make sure we don't back our selves into a naming thing. If it was a thing, would naming for isolation be something like hyperv-host 🤔

Copy link
Member

Choose a reason for hiding this comment

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

If we're able to specify --isolation twice (e.g. --isolation host --isolation hyper-v) would that suffice? We'd just need to short circuit on if someone specified process and a second option as that doesn't make sense. Or your idea of a fourth hyperv-host option.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sounds like we have some options. I don't think we need to solve it right now.

cmd/nerdctl/run.go Outdated Show resolved Hide resolved
go.mod Outdated Show resolved Hide resolved
@jsturtevant
Copy link
Contributor Author

The test failed with

   Command:  C:\Windows\system32\config\systemprofile\go\bin\nerdctl.exe --namespace=nerdctl-test run --rm --host-process -u "NT AUTHORITY\Local Service" gcr.io/k8s-staging-e2e-test-images/busybox:1.29-2 whoami
        ExitCode: 1
        Error:    exit status 1
        Stdout:   
        Stderr:   time="2022-02-10T18:18:12Z" level=fatal msg="failed to create user process token: failed to logon user: The user name or password is incorrect.: unknown"
        Failures:

I am guessing the containerd process isn't running with high enough privileges in the CI environment as this passes locally with containerd installed with a similar script. @dcantah do you know if there is another built in user we could use here?

@jsturtevant jsturtevant force-pushed the hostprocess-containers branch 2 times, most recently from 1d5b38f to 2d1613d Compare February 11, 2022 17:00
README.md Outdated
Comment on lines 336 to 400
Isolation flags:
- :whale: :blue_square: :nerd_face: `--isolation=(default|host)`: Used on Windows to change process isolation level. Valid values are `default` and `host`. `default` runs process isolated containers. `host` runs Host Process containers. Host process containers inherit permissions from containerd process unless `--user` is specified then will start with user specified. The user specified must be present on the host. `host` requires Containerd 1.6+. Not implemented for Linux.

Copy link
Member

Choose a reason for hiding this comment

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

Wasn't the Docker option for process isolated "process"? I think for Docker Desktop it defaulted to hyper-v if you didn't supply anything, and on server it defaulted to process. Regardless of that we should probably stick to the same naming as docker (unless I missed the discussion for naming this default 😆)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, I should probably have process as an explicit support flag but since hyper-v isn't really support fully in containerd we can default that.

The default flag uses whatever was set on the docker daemon via --exec-opt isolation=hyperv option: https://docs.docker.com/engine/reference/commandline/run/#specify-isolation-technology-for-container---isolation

I don't think containerd has this setting but the equivalent would be default_runtime_name?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've updated the logic here. I am not sure if I got it right... There seems to be a couple way to get hyper-v, one by setting the oci spec field hyper-v to not nil. Another is to set an option on the shimoptions

@AkihiroSuda
Copy link
Member

needs rebase

@jsturtevant jsturtevant force-pushed the hostprocess-containers branch 2 times, most recently from ea27336 to 2437d14 Compare February 18, 2022 16:38
@jsturtevant
Copy link
Contributor Author

Added a logging statement for the who the hostprocess container to see what it thinks it is running as and it is coming back as

run_windows_test.go:35: whoami nt authority\system

@dcantah I would think that since it is system it should be able to start Local Service?

@dcantah
Copy link
Member

dcantah commented Feb 18, 2022

Added a logging statement for the who the hostprocess container to see what it thinks it is running as and it is coming back as

run_windows_test.go:35: whoami nt authority\system

@dcantah I would think that since it is system it should be able to start Local Service?

Yea this is really odd.. The only thing I can think of is there's something blocking logging in users in this environment. The cri-integration tests in Containerd have tests that login as different service accounts https://github.com/containerd/containerd/blob/5162238c7da04d6bdd771d0aa43f8e34c91ea2ca/integration/windows_hostprocess_test.go#L38

@AkihiroSuda
Copy link
Member

What's current status?

@jsturtevant
Copy link
Contributor Author

I refreshed the PR. It is still failing when running in CI though it works locally, I thought it might be a Cirrus vs github actions thing but doesn't look like it.

I will need to dig deeper, as it is working locally when I test it.

@jsturtevant
Copy link
Contributor Author

debugging a different problem and got some insight from @marosset, It might be because I am not passing the user name info through on the config. going to try that and see I can get this working. better late than never 🙈

@marosset
Copy link

marosset commented Jan 5, 2023

debugging a different problem and got some insight from @marosset, It might be because I am not passing the user name info through on the config. going to try that and see I can get this working. better late than never 🙈

I think that will fix the issue

@dcantah
Copy link
Member

dcantah commented Jan 5, 2023

Nice. We didn't allow a blank username for CRI either, right? That's probably the right way.. defaulting to SYSTEM is kinda scary

@dcantah
Copy link
Member

dcantah commented Jan 5, 2023

Hmm.. if the username string is empty we should error a bit earlier https://github.com/microsoft/hcsshim/blob/6547959343d65e0cf431dd9d589f45ee2b98172c/internal/jobcontainers/logon.go#L109. Maybe it's filling in container-user/container-admin from the image? 🤷‍♂️

@jsturtevant
Copy link
Contributor Author

The windows tests are passing. Ends up the NT AUTHORITY must be upper case and I had some extra quotes when they were not needed in the test framework. I will clean up the commits and we should be good for a review.

@jsturtevant
Copy link
Contributor Author

@AkihiroSuda this is finally ready for review. I did move the Windows CI from Cirrus to Github actions during my debugging, I can either drop that commit or move it to a separate PR but I think I prefer GitHub UI for debugging and it aligns better with rest of the tests.

@dcantah
Copy link
Member

dcantah commented Jan 9, 2023

If Cirrus supports nested virt it might be worth staying on it, otherwise we won't be able to test hyper-v isolation on GHA (unless they made progress on offering this..)

@AkihiroSuda AkihiroSuda added this to the v1.2.0 milestone Jan 9, 2023
cmd/nerdctl/run.go Outdated Show resolved Hide resolved
@@ -395,6 +395,10 @@ Init process flags:
Please make sure the binary exists in your `PATH`.
- Default: `tini`

Isolation flags:
- :whale: :blue_square: :nerd_face: `--isolation=(default|process|host)`: Used on Windows to change process isolation level. `default` will use the runtime options configured in `default_runtime` in the [containerd configuration](https://github.com/containerd/containerd/blob/master/docs/cri/config.md#cri-plugin-config-guide) which is `process` in containerd by default. `process` runs process isolated containers. `host` runs Host Process containers. Host process containers inherit permissions from containerd process unless `--user` is specified then will start with user specified and the user specified must be present on the host. `host` requires Containerd 1.6+. Not implemented for Linux.

Copy link
Member

Choose a reason for hiding this comment

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

No support for the Hyper-V mode?

Copy link
Member

Choose a reason for hiding this comment

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

I think this should be a separate change, reason being is the way Windows launches the VM in the containerd-shim is a bit different than how it was done for docker (in terms of the resources assigned to the VM). It'd be a bit more than just filling in the hyper-v field on the runtime spec I imagine

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was also thinking this would be a separate changeset as the hyper-v support in containerd was only recently added.

README.md Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
cmd/nerdctl/run.go Outdated Show resolved Hide resolved
cmd/nerdctl/run_windows.go Outdated Show resolved Hide resolved
@marosset
Copy link

marosset commented Jan 9, 2023

I had a couple of suggestions for the usage but overall LGTM
Thanks @jsturtevant

Comment on lines 88 to 109
switch isolation {
case "host":
hpAnnotations := map[string]string{}
hpAnnotations[hostProcessContainer] = "true"

// If user is set we will attempt to start container with that user (must be present on the host)
// Otherwise we will inherit permissions from the user that the containerd process is running as
user, err := cmd.Flags().GetString("user")
if err != nil {
return nil, err
}
if user == "" {
hpAnnotations[hostProcessInheritUser] = "true"
}

opts = append(opts, oci.WithAnnotations(hpAnnotations))
case "default":
// no op
// use containerd's default runtime options
case "process":
opts = append(opts, WithWindowsProcessIsolated())
default:
// no op
// use containerd's default
}
Copy link
Member

Choose a reason for hiding this comment

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

I think we should combine default and process cases and get rid of the WithWindowsProcessIsolated option as the spec is only going to have that filled in if we set it anyways which would seem like a bug.

Suggested change
switch isolation {
case "host":
hpAnnotations := map[string]string{}
hpAnnotations[hostProcessContainer] = "true"
// If user is set we will attempt to start container with that user (must be present on the host)
// Otherwise we will inherit permissions from the user that the containerd process is running as
user, err := cmd.Flags().GetString("user")
if err != nil {
return nil, err
}
if user == "" {
hpAnnotations[hostProcessInheritUser] = "true"
}
opts = append(opts, oci.WithAnnotations(hpAnnotations))
case "default":
// no op
// use containerd's default runtime options
case "process":
opts = append(opts, WithWindowsProcessIsolated())
default:
// no op
// use containerd's default
}
switch isolation {
case "host":
hpAnnotations := map[string]string{
hostProcessContainer: "true",
}
// If user is set we will attempt to start container with that user (must be present on the host)
// Otherwise we will inherit permissions from the user that the containerd process is running as
user, err := cmd.Flags().GetString("user")
if err != nil {
return nil, err
}
if user == "" {
hpAnnotations[hostProcessInheritUser] = "true"
}
opts = append(opts, oci.WithAnnotations(hpAnnotations))
case "default", "process":
// no op
// use containerd's default runtime options
default:
return nil, fmt.Errorf("unknown isolation value %q. valid values are 'host', 'process' or 'default'", isolation)
}

Copy link
Member

@dcantah dcantah Jan 10, 2023

Choose a reason for hiding this comment

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

Also, on docker this flag was defined globally I believe and would error on Linux for an invalid value, should we do some validations for linux as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I remember why I did it this way now.

If the default_runtime is set in the config.toml to be hyper-v don't we need to override the default runtime settings? aka, blank out hyper-v part of the spec?

Maybe I don't quite understand it properly...

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

Ahh, missed that 😬 But there's no point in clearing the spec I think, as if they have runhcs-hypervisor as the default runtime the shim will set the hyperv section back anyways. We're setting all of this up before the shims launched so it seems moot

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But there's no point in clearing the spec I think, as if they have runhcs-hypervisor as the default runtime the shim will set the hyperv section back anyway

So this means if the default runtime is hyperv then you can't run process isolated? I not sure we can handle this from here. doing nothing when process and hyperv is the default runtime would be bad experience as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've added this back... Let me know what you think

Copy link
Member

@dcantah dcantah Jan 10, 2023

Choose a reason for hiding this comment

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

Wait now that I'm thinking about it, isn't the default_runtime_name a CRI field? That shouldn't matter or get read here right? @AkihiroSuda

You can change the runtime as a whole via --runtime (although process, hyperv and LCOW are all wrapped up in the same shim on Windows so it doesn't matter really). The shim options would have to change for this to matter, and it seems like the only runtime whose options are configured is runc https://github.com/containerd/nerdctl/blob/main/cmd/nerdctl/run_runtime.go#L34-L63. But regardless, nil'ing out hyperv is still not needed, as we're the ones controlling the spec here. If the shim ends up setting it for some reason (like here) it's irrelevant what we do here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the shim ends up setting it for some reason (like here) it's irrelevant what we do here

So this means if the default runtime is hyperv and the user runs nerdctl --isolation process the user won't get a process isolated container? Or is it only if sim options are set?

@jsturtevant
Copy link
Contributor Author

If Cirrus supports nested virt it might be worth staying on it, otherwise we won't be able to test hyper-v isolation on GHA (unless they made progress on offering this..)

great point, It does look like the compute_engine_instance (https://cirrus-ci.org/guide/custom-vms/) does support nested_virtualization: nested_virtualization: true # optional. Whether to enable Intel VT-x. Defaults to false.

I will drop this commit.

Copy link
Member

@dcantah dcantah left a comment

Choose a reason for hiding this comment

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

LGTM after those test renames (and assuming CI is green)

@dcantah
Copy link
Member

dcantah commented Jan 11, 2023

It does look like the compute_engine_instance (https://cirrus-ci.org/guide/custom-vms/) does support nested_virtualization: nested_virtualization: true # optional. Whether to enable Intel VT-x. Defaults to false.

Sweet!

Copy link
Member

@AkihiroSuda AkihiroSuda left a comment

Choose a reason for hiding this comment

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

Thanks, could you consider squashing commits

curl.exe -L https://github.com/containerd/containerd/releases/download/v$version/containerd-$version-windows-amd64.tar.gz -o containerd-windows-amd64.tar.gz
tar xvf containerd-windows-amd64.tar.gz
tar.exe xvf containerd-windows-amd64.tar.gz
Copy link
Member

Choose a reason for hiding this comment

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

?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not strictly necessary but makes it explicit we are using the tar.exe shipped with Windows vs a powershell alias.

Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
Copy link
Member

@AkihiroSuda AkihiroSuda left a comment

Choose a reason for hiding this comment

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

Thanks

@AkihiroSuda AkihiroSuda merged commit 0d8e0bd into containerd:main Jan 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request impact/major platform/Windows/Non-WSL2 Microsoft Windows (non-WSL2)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Windows hostprocess support
4 participants