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

refactor container packages and support mounts #313

Merged
merged 10 commits into from
Feb 19, 2019

Conversation

BenTheElder
Copy link
Member

@BenTheElder BenTheElder commented Feb 17, 2019

  • move pkg/docker to pkg/container/docker, long term we can better break up docker specific vs general container functionality and support other container runtimes.
  • create a CRI package, with types (Mount related only for now) copied from upstream
    • this allows us to avoid stability concerns, if necessary we can provide our own conversion
    • I added better JSON / yaml encoding for Mount's propagation field
      • I've tested that in the future we could instead use type Mount upstreamcri.Mount and still support this
  • add support for CRI Mounts in docker.Run, refactor docker.Run to take functional options
  • support mounts in the node config, update control-plane and worker node creation to support this

This is an alternative to #302 where we vendor CRI

cc @neolit123

@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: BenTheElder

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Feb 17, 2019
@BenTheElder
Copy link
Member Author

usage:

kind: Config
apiVersion: kind.sigs.k8s.io/v1alpha2
nodes:
- role: control-plane
  mounts:
  - container_path: /kind-source
    host_path: /Users/bentheelder/go/src/sigs.k8s.io/kind
    readonly: true

Things to consider for the future (but I think I'd rather not do in the first PR to keep the diff down):

  • swap out the snakeCase json fields for camelCase fields to match the rest of our config?
  • resolve environment variables in host_path or at least resolve relative paths with respect to the kind working directory. Docker requires absolute paths for bind mounts but that's not super great UX for our case I think ...

Copy link
Member

@neolit123 neolit123 left a comment

Choose a reason for hiding this comment

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

this seems good @BenTheElder
i just need to do some quick testing for Mounts *[]cri.Mount

@@ -54,6 +56,9 @@ type Node struct {
// KubeadmConfigPatchesJSON6902 are applied to the generated kubeadm config
// as patchesJson6902 to `kustomize build`
KubeadmConfigPatchesJSON6902 []kustomize.PatchJSON6902
// Mounts describes additional mount points for the node container
// These may be used to EG bind a hostpath
Mounts []cri.Mount `json:"mounts,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

there is a weird side effect when marshaling slices with omitempty, that is already a problem in k/k, kubeadm, cluster-api. i think the safe route was to use Mounts *[]cri.Mount json:"mounts,omitempty"` but i need to check this.

Copy link
Member

Choose a reason for hiding this comment

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

package main

import (
	"fmt"
	"log"
	"sigs.k8s.io/yaml"
)

type A struct {
	Mounts []string `json:"mounts,omitempty"`
}

func main() {
	a := A{Mounts: []string{}} // <--------- [*]
	fmt.Println(a.Mounts, a.Mounts == nil)
	b, err := yaml.Marshal(a)	
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(b))
	c := A{}
	err = yaml.Unmarshal(b, &c)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(c.Mounts, c.Mounts == nil)
}
[] false
{}
[] true

[*]
so this problem is relevant only if we assign a meaning to the "empty" value of Mounts and what is the "empty" value (is it a empty slice or nil) and if the user is marhaling the kind Config.

if there is no default value this problem is not relevant, but just referencing this here so that we don't have this problem for the future kind config:
kubernetes/kubeadm#1358

Copy link
Member Author

@BenTheElder BenTheElder Feb 17, 2019

Choose a reason for hiding this comment

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

What was it? https://play.golang.org/p/EOfDnWThpdj
Your comment hadn't loaded

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we can treat empty and nil the same, the node already has mounts (tmps and one docker volume) we're just adding additional mounts here (we should clarify that in the docs)

Copy link
Member

@neolit123 neolit123 Feb 17, 2019

Choose a reason for hiding this comment

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

hm, yes. i know the existing mounts are essential for the setup to work.

so in a way we already have default mounts and these mounts are extra mounts 🤔
would it be clearer naming this ExtraMounts and including some more notes in the field comment?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah I think that might make sense.

Copy link
Member Author

Choose a reason for hiding this comment

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

renamed it 👍

}{
Alias: (*Alias)(m),
}
if err := json.Unmarshal(data, &aux); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

ideally everything "unmarshall" should be using DisallowUnknownFields
but i leave this to you.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, trying to figure out if we should just do that inline or if there's a way to plumb through the option 🙄

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm going to tackle this in a follow up, but before the next release, I'm not sure how this will interact with the rest of the decoding logic.

i'm still hopeful for getting support for that upstream in API machinery.

// If set, the mount needs SELinux relabeling.
SelinuxRelabel bool `protobuf:"varint,4,opt,name=selinux_relabel,json=selinuxRelabel,proto3" json:"selinux_relabel,omitempty"`
// Requested propagation mode.
Propagation MountPropagation `protobuf:"varint,5,opt,name=propagation,proto3,enum=runtime.v1alpha2.MountPropagation" json:"propagation,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

looks like these variable names need "adjustments" upstream.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah I'm not sure if that's actually an option. I think it would probably be fine for us to match the types closely but use a different on-disk format.

Copy link
Member

@neolit123 neolit123 Feb 17, 2019

Choose a reason for hiding this comment

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

we still have the option to shim with getters and setters. this means some extra boiler plate.
this fixes both the field names and hides the upstream config.

create a CRI package, with types (Mount related only for now) copied from upstream

  • this allows us to avoid stability concerns, if necessary we can provide our own conversion

i need to know the roadmap for CRI in terms of do they have plans to remove or rename fields, because if there are upstream API changes our local type can end up invalid and we will have to break kind users because these fields are public in the kind config.

i will leave this to you at this point if you want us to proceed, but comments from others would be appreciated too.

Copy link
Member Author

@BenTheElder BenTheElder Feb 17, 2019

Choose a reason for hiding this comment

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

CRI is pretty stable at this point, this type hasn't actually changed in years.

But our local type can be a shim just closely matching their type, if they diverge we will translate. As long as we are not using the client this isn't an issue.

Also for the types we expose here for on disk purposes, what they are capable of is unlikely to change. They cannot remove support for these fields without breaking Kubernetes majorly.

Copy link
Member

Choose a reason for hiding this comment

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

ok

Copy link
Member Author

Choose a reason for hiding this comment

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

It is nice for now that they are literally the same definition, but if it diverges slightly (EG they add a field or break the type up) we can keep our changes compatible and translate.

The things we will need to expose in config like Mounts, DNS, ... those seem unlikely to change significantly.

More complex types like entire containers, those seem stable too but we don't need to expose those on disk anyhow.

Copy link
Member Author

Choose a reason for hiding this comment

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

I adjusted our names, strangely the proto json tags were already camelCase but not the actual json tags 🤷‍♂️

Where possible these match user facing API fields in Kubernetes APIs

MountPropagation_PROPAGATION_HOST_TO_CONTAINER MountPropagation = 1
// Mounts get propagated from the host to the container and from the
// container to the host ("rshared" in Linux).
MountPropagation_PROPAGATION_BIDIRECTIONAL MountPropagation = 2
Copy link
Member

Choose a reason for hiding this comment

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

i've missed if we are adding a linter exception for this file/package.

Copy link
Member Author

Choose a reason for hiding this comment

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

We did, it's a separate commit.

Copy link
Member

Choose a reason for hiding this comment

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

ah, saw it.

@neolit123
Copy link
Member

/assign @munnerz
hi, do you have comments on the new CRI mount support?

@BenTheElder
Copy link
Member Author

per discussion in the meeting I renamed to camel case and switched to the core/v1 VolumeMount strings for the mount enum. I think we can remove the lint exception now as well.

@BenTheElder
Copy link
Member Author

Re-enabled golint and fixed remaining lints.

Copy link
Member

@neolit123 neolit123 left a comment

Choose a reason for hiding this comment

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

as per the discussions today during the kind meeting LGTM.
/lgtm
/hold

@k8s-ci-robot k8s-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Feb 19, 2019
@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 19, 2019
// If set, the mount is read-only.
Readonly bool `protobuf:"varint,3,opt,name=readonly,proto3,json=readOnly,proto3" json:"readOnly,omitempty"`
// If set, the mount needs SELinux relabeling.
SelinuxRelabel bool `protobuf:"varint,4,opt,name=selinux_relabel,json=selinuxRelabel,proto3" json:"selinuxRelabel,omitempty"`
Copy link
Member Author

Choose a reason for hiding this comment

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

this one is not actually exposed directly in kubernetes volumes AFAICT, but from previous test-infra containerization work I remember control over this being necessary on some systems.

we should consider if we want to expose this or not, imho we can just document it well and expect the user to do the right thing, support for this shouldn't go anywhere in CRI

@BenTheElder
Copy link
Member Author

/hold cancel

Will follow up with considerations on EG relative paths / other UX improvements.

In the meantime this config is now possible:

kind: Config
apiVersion: kind.sigs.k8s.io/v1alpha2
nodes:
- role: control-plane
  extraMounts:
  - containerPath: /kind-source
    hostPath: /Users/bentheelder/go/src/sigs.k8s.io/kind
    readOnly: true

@k8s-ci-robot k8s-ci-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Feb 19, 2019
@k8s-ci-robot k8s-ci-robot merged commit 37389ea into kubernetes-sigs:master Feb 19, 2019
@BenTheElder BenTheElder deleted the mountalias branch February 19, 2019 05:45
stg-0 pushed a commit to stg-0/kind that referenced this pull request Oct 2, 2023
* Print build version

* Fix version

* Bump golang image

* Fix version

* Fix version
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants