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

Kubernetes transport #205

Closed
wants to merge 4 commits into from
Closed

Conversation

coderanger
Copy link

Includes a test harness using the same tests as for Docker.

This uses kubectl exec internally. Windows pods are not supported at this time, mostly because I have no way to test them.

Signed-off-by: Noah Kantrowitz <noah@coderanger.net>
Signed-off-by: Noah Kantrowitz <noah@coderanger.net>
Signed-off-by: Noah Kantrowitz <noah@coderanger.net>
@coderanger coderanger requested a review from a team November 6, 2017 06:33
Signed-off-by: Noah Kantrowitz <noah@coderanger.net>
@adamleff
Copy link
Contributor

adamleff commented Nov 6, 2017

Thanks for the contribution, @coderanger! We're discussing this one internally in relation to some other kubernetes work we've been discussing. Hopefully we'll have more feedback for you next week.

Copy link
Contributor

@chris-rock chris-rock left a comment

Choose a reason for hiding this comment

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

@coderanger Thank you very much for this huge improvement. We always wanted to add k8s as native supported transport, therefore this is a great step into the right direction. I left some comments to better understand your design.

@@ -40,6 +40,16 @@ matrix:
- rvm: 2.4.1
script: bundle exec rake $SUITE
env: SUITE="test:docker config=test-travis-ubuntu.yml"
- rvm: 2.4.1
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice to have the integration tests included. That is great!

@@ -0,0 +1,152 @@
# encoding: utf-8
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we move that file to test/integration/k8s/test.rb?

Copy link
Author

Choose a reason for hiding this comment

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

Sure, this was used to match with the existing Docker tests.

@@ -0,0 +1,152 @@
# encoding: utf-8
#
# Copyright 2017, Noah Kantrowitz
Copy link
Contributor

Choose a reason for hiding this comment

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

Please change that to Author.

@@ -31,7 +31,7 @@ def root_group(os)
end

def selinux_label(backend, path = nil)
return nil if backend.class.to_s =~ /docker/i
return nil if backend.class.to_s =~ /docker|kubernetes/i
Copy link
Contributor

Choose a reason for hiding this comment

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

We are preparing inspec/inspec#1661 in Train and InSpec. kubernetes will become a platform in train. At this point, we are adding a k8s transport for the execution inside of containers only. We think k8s-exec is a better name for this specific implementation.

Copy link
Author

Choose a reason for hiding this comment

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

I don't understand, that PR says "platform" would be things like RedHat or Ubuntu, in which case Kubernetes will not be a platform. The OS image used in the underlying container would be the platform, just like with Docker.

end

def run_command(cmd)
kubectl_cmd = [options[:kubectl_path], 'exec']
Copy link
Contributor

Choose a reason for hiding this comment

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

This implementation relies on shelling out to kubectl rather than using the API directly. This limits the usage and decreases the usability of train/inspec. Is there any reason why you decided against using https://github.com/abonas/kubeclient directly?

Copy link
Author

Choose a reason for hiding this comment

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

A couple of reasons:

  1. Stability, the APIs change a lot and kubectl/client-go will always be the first class citizen in the ecosystem.
  2. Performance, Ruby network perf is not great and because we're using it as the file transport system too it would be annoying.
  3. Support, Kubeclient (and pretty much all other client libs) don't actually implement the exec API. Most libraries just do the REST API, which here wouldn't actually help with anything. The exec API is weirdly undocumented but it initiates over an HTTP POST and then upgrades to SPDY (which will be replaced with websockets soon). Implementing a client for this in Ruby would be very annoying.

@@ -0,0 +1,72 @@
# encoding: utf-8
#
# Copyright 2017, Noah Kantrowitz
Copy link
Contributor

Choose a reason for hiding this comment

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

Please change to author

Copy link
Author

Choose a reason for hiding this comment

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

Copyright is correct as I remain the owner of this code. Unless you're requesting I assign copyright to Chef Software, which would be unusual?

@@ -76,7 +72,11 @@

it 'has selinux label handling' do
res = Test.selinux_label(backend, file.path)
file.selinux_label.must_equal(res)
if res.nil?
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you expect that is a result from a method is nil, that this is okay?

Copy link
Author

Choose a reason for hiding this comment

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

As noted above, you already returned nil here during the Docker tests, and I extended that to also return nil on Kubernetes tests. You weren't actually handling that in most of the tests so I fixed that while making the Kubernetes tests pass.

chris-rock referenced this pull request Dec 22, 2017
* Add cache connection to train
* Update caching to be on BaseConnection
* Refactor tests and cleanup logic
* Move caching into base_connection and privatize connection calls
* Update mock transport to use base caching.
* Add author tag and caching comments.
* Added exception for invalid cache type and small logic refactor.

Signed-off-by: Jared Quick <jquick@chef.io>
@aaronlippold
Copy link
Collaborator

How would this connect to openShift as well? Would we want a individual openshift or oc:// transport or would it be a "type" of k8r transport do you think?

@frezbo
Copy link
Contributor

frezbo commented Aug 16, 2018

@aaronlippold as OC still uses the same k8s API server, it think it would be ok to use the same transport that k8s uses. Maybe in inspec we could alias k8s transport to oc.

@chris-rock
Copy link
Contributor

I agree with @frezbo here, we should keep it to plain k8s. I also do not recommend to use an alias since this may confuses the community. The confusion may come from the fact that this implementation uses kubectl. I would like to avoid that and instead talk to the k8s api directly. Then we are talking about API compatible solutions not binary compatible solutions

@frezbo
Copy link
Contributor

frezbo commented Aug 16, 2018

+1 on the usage of API. I hope we use this: https://github.com/kubernetes-client/ruby seems there are a lot of k8s ruby API's

@chris-rock
Copy link
Contributor

That is a great reference @frezbo I missed that we have near official clients for ruby now

@coderanger
Copy link
Author

No, it's not a great a reference, that's an abandoned project from 8 months ago. And it doesn't expose the pod execution API because almost no clients do. I explained why I used kubectl last year and all the same reasons apply.

@frezbo
Copy link
Contributor

frezbo commented Aug 16, 2018

That's sad. I really hope all other API's gets the same love as go-client.

@coderanger
Copy link
Author

Maybe in a long long time when the API stabilizes more fully. Until then, that seems highly unlikely.

@coderanger
Copy link
Author

As for the original question, the oc command is mostly just an extension to kubectl so to make that work we would just need to set kubectl_path: 'oc'.

@clintoncwolfe
Copy link
Contributor

So, I thought I'd chime in here.

This PR is about creating a Kubernetes transport to talk to a running container within a pod, which is absolutely a great idea, and very much wanted. The behavior is very well specified through integration tests.

It was submitted prior to our efforts to make Train plugins more practical; today we'd shuffle this into a plugin, in a separate repo with its own lifecycle and distributed as an independent gem.

Regarding implementation. From my perspective, we have two concerns:

  1. A desire to use the API vs driving kubectl. For my part, I don't much care, so long as the user never need know ( though a requirement for having kubectl available is reasonable). But I don't think we should change the target URI schema based on the implementation details; I'm against using something like kubectl://. If/when a solid API and Ruby library becomes available, the plugin could internally refactor to rely on it, and no targets need change.

  2. I do however have concerns about how to model auditing the internals of a container (ie, the exec use case, which is interested in files and commands, and would target one container at a time) and auditing the cluster as a whole. You'd want to be able to examine things like what services are available, networking, etc. Our train design today can't support talking to more than one target (ie, you're either talking to one container, or you're talking to one API endpoint). So, perhaps there are two Train plugins here - one for talking to the internals of containers, and one for auditing the cluster. Naming things is hard; we could use train-k8s for the cluster, and train-k8s-container for the use case exemplified here. We currently have a 1:1 coupling between plugin names and target URIs, so those would be used as -t k8s://... to target a cluster and -t k8s-containter://... to examine inside a container.

Thoughts?

@clintoncwolfe
Copy link
Contributor

We will one day get around to adding a kubernetes transport; it will likely be a separate plugin, however, and may be "chimeric" (internally using multiple means to answer questions - perhaps both kubectl and some ruby api (a cursory glance indicates that https://github.com/kubernetes-client/ruby appears to be active as of right now)).

This is excellent work, and when a kube plugin is started in earnest, we'll certainly refer to this (with attribution and copyright if we're outright copying).

For now though, this PR isn't likely to ever be merged into train (and train has 18 months of growth since this was last touched) so, I'm going to close this. It's linked from the issue, so it won't get misplaced.

@bgeesaman
Copy link

https://github.com/bgeesaman/inspec-k8s which relies on https://github.com/bgeesaman/train-kubernetes was recently released. train-k8s was already reserved on rubygems, so train-kubernetes attempts to permit assertions on Kubernetes API objects and their specs (the "k8s" transport mentioned by @clintoncwolfe above). It does not implement kubectl exec like functionality like this PR does (the "k8s-container" transport mentioned above). Feedback is welcomed.

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.

7 participants