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

Autogenerate k8s manifests in skaffold init #3703

Merged
merged 5 commits into from
Mar 2, 2020

Conversation

nkubala
Copy link
Contributor

@nkubala nkubala commented Feb 19, 2020

NOTE: this feature is hidden behind a feature flag, --XXenableManifestGeneration, to allow for further iteration and improvement before exposing publicly.

this change adds support for autogenerating k8s manifests in skaffold init for projects that do not have any. skaffold will generate a k8s yaml for each found image that is not referenced by an existing k8s yaml in the project directory, and each generated yaml file will contain a deployment for the image, and a service exposing the deployment.

in the event that skaffold init finds a builder configuration in a project directory, but no k8s yaml referencing this image, we don't actually have any name for the image, so skaffold will generate a name. this name will either be:

the name of the encompassing directory, in the event that the builder is found in a nested directory; or,
the name of the builder file itself, in the event that only one builder configuration is found
for each image, a yaml file will be generated containing kubernetes resource definitions for a service and a deployment. this file will either be:

<directory_name>/deployment.yaml, for each builder that is found in a nested directory; or,
<image_name>-deployment.yaml, if we only have one builder configuration found

so for the microservices example, we would generate

.
├── leeroy-app
│   ├── app.go
│   ├── deployment.yaml <-- generated
│   └── Dockerfile
├── leeroy-web
│   ├── deployment.yaml <-- generated
│   ├── Dockerfile
│   └── web.go
├── README.md
└── skaffold.yaml <-- (also generated)

whereas for the getting-started example, we would generate

.
├── deployment.yaml <-- generated
├── Dockerfile
├── main.go
├── README.md
└── skaffold.yaml <-- generated

Future Work

  • figure out how to handle ports in the generated yaml - this is currently unsupported, so port forwarding will not work
  • figure out the right behavior for resolved and unresolved builder configurations - if we have a preexisting image1 being referenced in k8s.yaml, but also another builder configuration, should we always generate?
  • remove feature flag

@codecov
Copy link

codecov bot commented Feb 19, 2020

Codecov Report

Merging #3703 into master will decrease coverage by 0.43%.
The diff coverage is 53.9%.

Impacted Files Coverage Δ
pkg/skaffold/initializer/build/init.go 51.72% <0%> (-29.23%) ⬇️
pkg/skaffold/initializer/build/builders.go 57.69% <0%> (ø) ⬆️
pkg/skaffold/initializer/prompt/prompt.go 0% <0%> (ø) ⬆️
pkg/skaffold/initializer/build/cli.go 75% <0%> (ø) ⬆️
cmd/skaffold/app/cmd/init.go 100% <100%> (ø) ⬆️
pkg/skaffold/initializer/build/util.go 100% <100%> (ø) ⬆️
pkg/skaffold/initializer/init.go 38.63% <27.27%> (-11.37%) ⬇️
pkg/skaffold/initializer/deploy/init.go 68.96% <50%> (-21.04%) ⬇️
pkg/skaffold/initializer/deploy/kubectl.go 85.18% <55.55%> (-14.82%) ⬇️
pkg/skaffold/kubernetes/generator/generate.go 60% <60%> (ø)
... and 18 more

@dgageot dgageot self-assigned this Feb 20, 2020
pkg/skaffold/initializer/build/builders.go Outdated Show resolved Hide resolved
pkg/skaffold/initializer/init.go Show resolved Hide resolved
pkg/skaffold/initializer/prompt/prompt.go Outdated Show resolved Hide resolved
pkg/skaffold/initializer/init.go Outdated Show resolved Hide resolved
pkg/skaffold/initializer/init.go Outdated Show resolved Hide resolved
Copy link
Contributor

@balopat balopat left a comment

Choose a reason for hiding this comment

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

it seems to me that when generating manifests, the "unable to automatically resolve builder/image pairs; run 'skaffold init' without '--force' to manually resolve ambiguities" error path shouldn't even be exercised...there is nothing to match up!!! It is not the force that's broken -- I think this PR should contain the logic that when there is manifest generation, we know the pairing... especially the microservices case, when all the docker images are known and matched with exactly one manifest. but maybe I'm missing something.

@nkubala
Copy link
Contributor Author

nkubala commented Feb 24, 2020

@balopat the reason I left the commented out test in there is because we currently conflate two concepts in one flag:

  1. "--force-resolve" - the idea that we should force a resolution of builders to images, even if there are ambiguities found by skaffold
  2. "--force-write" - the idea that skaffold should write out the skaffold.yaml it generates without user confirmation

clearly we don't want to support the first concept here if we're generating manifests, but we need to support the second concept to run the tests that actually call skaffold init without having to pass confirmation to the test to write the file. this has been fine for the existing test because it doesn't have any ambiguities in the builder/image pairs - but adding a test where there is an ambiguity (i.e. we need to generate a manifest and an image name), is now impossible to pass because I can't tell skaffold to force write the config. the test will hang and timeout.

I agree we should fix these flags, but I don't think that should happen in this PR.

pkg/skaffold/initializer/build/builders.go Outdated Show resolved Hide resolved
return nil
}

func getGeneratedBuilderPair(b InitBuilder) GeneratedBuilderImagePair {
Copy link
Member

Choose a reason for hiding this comment

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

Can we add some tests for this method?
filepath.Dir() will return all but last component meaning it will contain \, . which are not valid image name chars

https://play.golang.org/p/huk3EmORFw5

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 is implicitly tested through TestResolveBuilderImages and TestAutoSelectBuilders. because of the way we detect builders in the analyze step of the initializer, the last 5 cases in your linked snippet will never happen.

Copy link
Member

Choose a reason for hiding this comment

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

I am not sure if this true.
I run checked out your branch and ran into this issue

Project tree:

examples/getting-started <say this is root of the repo>
|__app
      |__ deploy
              |---- Dockerfile
      |- main.go

Currently, the code assumes you are running skaffold init from inside examples/app. This logic is very sensitive to run context.


tejaldesai@@helm-deployment (init-k8sgen)$ ../../out/skaffold init --XXenableManifestGeneration
adding manifest path app/deploy/deployment.yaml for image app/deploy
apiVersion: skaffold/v2alpha4
kind: Config
metadata:
  name: helm-deployment
deploy:
  kubectl:
    manifests:
    - app/deploy/deployment.yaml

app/deploy/deployment.yaml - apiVersion: v1
kind: Service
metadata:
  name: app/deploy
  labels:
    app: app/deploy
spec:
  clusterIP: None
  selector:
    app: app/deploy
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app/deploy
  labels:
    app: app/deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app/deploy
  template:
    metadata:
      labels:
        app: app/deploy
    spec:
      containers:
      - name: app/deploy
        image: app/deploy

Do you want to write this configuration, along with the generated k8s manifests, to skaffold.yaml? [y/n]: y
Generated manifest app/deploy/deployment.yaml was written
Configuration skaffold.yaml was written
You can now run [skaffold build] to build the artifacts
or [skaffold run] to build and deploy
or [skaffold dev] to enter development mode, with auto-redeploy

Copy link
Contributor Author

Choose a reason for hiding this comment

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

so I dug into this one more, and skaffold init actually doesn't even work with this directory structure :/

i'm going to add sanitization to this PR, and open an issue to fix this separately.

@nkubala nkubala force-pushed the init-k8sgen branch 2 times, most recently from 6c5d54c to ec97f6c Compare February 26, 2020 00:17
@dgageot
Copy link
Contributor

dgageot commented Feb 28, 2020

@tejal29 @balopat did @nkubala address all your feedback?

@nkubala
Copy link
Contributor Author

nkubala commented Feb 28, 2020

@dgageot I'm going to add sanitization for the generated image name since it can contain illegal characters and then this should be good to go in

@balopat
Copy link
Contributor

balopat commented Mar 1, 2020

@balopat the reason I left the commented out test in there is because we currently conflate two concepts in one flag:

  1. "--force-resolve" - the idea that we should force a resolution of builders to images, even if there are ambiguities found by skaffold
  2. "--force-write" - the idea that skaffold should write out the skaffold.yaml it generates without user confirmation

clearly we don't want to support the first concept here if we're generating manifests, but we need to support the second concept to run the tests that actually call skaffold init without having to pass confirmation to the test to write the file. this has been fine for the existing test because it doesn't have any ambiguities in the builder/image pairs - but adding a test where there is an ambiguity (i.e. we need to generate a manifest and an image name), is now impossible to pass because I can't tell skaffold to force write the config. the test will hang and timeout.

I agree we should fix these flags, but I don't think that should happen in this PR.

Thanks for the explanation. I'm okay to go forward with this.

@nkubala nkubala dismissed tejal29’s stale review March 2, 2020 18:03

addressed feedback

@nkubala nkubala merged commit 0a024c4 into GoogleContainerTools:master Mar 2, 2020
@nkubala nkubala deleted the init-k8sgen branch March 2, 2020 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants