-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Improve sync #1102
Improve sync #1102
Changes from 9 commits
b0091ea
faecc29
fea9ad1
7f42c63
d860c54
97b0ea1
34ddc96
1017663
8149523
c53bb86
3e8f198
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,11 +17,11 @@ limitations under the License. | |
package kubernetes | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os/exec" | ||
"strings" | ||
"sync/atomic" | ||
|
||
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/constants" | ||
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/sync" | ||
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/util" | ||
"github.com/sirupsen/logrus" | ||
|
@@ -34,60 +34,76 @@ import ( | |
|
||
type KubectlSyncer struct{} | ||
|
||
func (k *KubectlSyncer) Sync(s *sync.Item) error { | ||
if err := perform(s.Image, s.Copy, copyFileFn); err != nil { | ||
return errors.Wrap(err, "copying files") | ||
func (k *KubectlSyncer) Sync(ctx context.Context, s *sync.Item) error { | ||
if len(s.Copy) > 0 { | ||
logrus.Infoln("Copying files:", s.Copy, "to", s.Image) | ||
|
||
if err := perform(ctx, s.Image, s.Copy, copyFileFn); err != nil { | ||
return errors.Wrap(err, "copying files") | ||
} | ||
} | ||
if err := perform(s.Image, s.Delete, deleteFileFn); err != nil { | ||
return errors.Wrap(err, "deleting files") | ||
|
||
if len(s.Delete) > 0 { | ||
logrus.Infoln("Deleting files:", s.Delete, "from", s.Image) | ||
|
||
if err := perform(ctx, s.Image, s.Delete, deleteFileFn); err != nil { | ||
return errors.Wrap(err, "deleting files") | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func deleteFileFn(pod v1.Pod, container v1.Container, src, dst string) *exec.Cmd { | ||
return exec.Command("kubectl", "exec", pod.Name, "--namespace", pod.Namespace, "-c", container.Name, "--", "rm", "-rf", dst) | ||
return nil | ||
} | ||
|
||
func copyFileFn(pod v1.Pod, container v1.Container, src, dst string) *exec.Cmd { | ||
return exec.Command("kubectl", "cp", src, fmt.Sprintf("%s/%s:%s", pod.Namespace, pod.Name, dst), "-c", container.Name) | ||
func deleteFileFn(ctx context.Context, pod v1.Pod, container v1.Container, src, dst string) *exec.Cmd { | ||
return exec.CommandContext(ctx, "kubectl", "exec", pod.Name, "--namespace", pod.Namespace, "-c", container.Name, "--", "rm", "-rf", dst) | ||
} | ||
|
||
func labelSelector() string { | ||
var reqs []string | ||
for k, v := range constants.Labels.DefaultLabels { | ||
reqs = append(reqs, fmt.Sprintf("%s=%s", k, v)) | ||
} | ||
return strings.Join(reqs, ",") | ||
func copyFileFn(ctx context.Context, pod v1.Pod, container v1.Container, src, dst string) *exec.Cmd { | ||
return exec.CommandContext(ctx, "kubectl", "cp", src, fmt.Sprintf("%s/%s:%s", pod.Namespace, pod.Name, dst), "-c", container.Name) | ||
} | ||
|
||
func perform(image string, files map[string]string, cmdFn func(v1.Pod, v1.Container, string, string) *exec.Cmd) error { | ||
logrus.Info("Syncing files:", files) | ||
func perform(ctx context.Context, image string, files map[string]string, cmdFn func(context.Context, v1.Pod, v1.Container, string, string) *exec.Cmd) error { | ||
client, err := Client() | ||
if err != nil { | ||
return errors.Wrap(err, "getting k8s client") | ||
} | ||
pods, err := client.CoreV1().Pods("").List(meta_v1.ListOptions{ | ||
LabelSelector: labelSelector(), | ||
}) | ||
|
||
pods, err := client.CoreV1().Pods("").List(meta_v1.ListOptions{}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use the skaffold labelselector here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed it because it wasn't working. What I saw is that when I use a deployment, this deployment gets the labels but not the pods. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah good point 👍 |
||
if err != nil { | ||
return errors.Wrap(err, "getting pods") | ||
} | ||
|
||
var performed int32 | ||
var e errgroup.Group | ||
|
||
for _, p := range pods.Items { | ||
for _, c := range p.Spec.Containers { | ||
if c.Image == image { | ||
var e errgroup.Group | ||
for src, dst := range files { | ||
src, dst := src, dst | ||
e.Go(func() error { | ||
cmd := cmdFn(p, c, src, dst) | ||
return util.RunCmd(cmd) | ||
}) | ||
} | ||
if err := e.Wait(); err != nil { | ||
return errors.Wrap(err, "syncing files") | ||
} | ||
if c.Image != image { | ||
continue | ||
} | ||
|
||
for src, dst := range files { | ||
cmd := cmdFn(ctx, p, c, src, dst) | ||
|
||
e.Go(func() error { | ||
if err := util.RunCmd(cmd); err != nil { | ||
return err | ||
} | ||
|
||
atomic.AddInt32(&performed, 1) | ||
return nil | ||
}) | ||
} | ||
} | ||
} | ||
|
||
if err := e.Wait(); err != nil { | ||
return errors.Wrap(err, "syncing files") | ||
} | ||
|
||
if int(performed) != len(files) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think you need to count here. errgroup handles this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The check is to make sure that we try to perform the sync for n files. It has nothing to do with errors. For example, with the code that filters on skaffold labels, it always syncs zero files without giving an error. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, I guess this is a bit tricky. What if we have 2 replicas? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, I'll see how to fix it. Each file should be synced at least once, I guess. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I think thats the best we can do. But making sure we sync at least once is a good check. |
||
return errors.New("couldn't sync all the files") | ||
} | ||
|
||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,7 @@ import ( | |
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/kaniko" | ||
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/local" | ||
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/tag" | ||
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/color" | ||
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config" | ||
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/deploy" | ||
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker" | ||
|
@@ -259,8 +260,7 @@ func (r *SkaffoldRunner) Dev(ctx context.Context, out io.Writer, artifacts []*la | |
} | ||
if s != nil { | ||
changed.AddResync(s) | ||
} | ||
if s == nil { | ||
} else { | ||
changed.AddRebuild(a.artifact) | ||
} | ||
} | ||
|
@@ -271,12 +271,12 @@ func (r *SkaffoldRunner) Dev(ctx context.Context, out io.Writer, artifacts []*la | |
return ErrorConfigurationChanged | ||
case len(changed.needsResync) > 0: | ||
for _, s := range changed.needsResync { | ||
if err := r.Syncer.Sync(s); err != nil { | ||
color.Default.Fprintf(out, "Syncing %d files for %s\n", len(s.Copy)+len(s.Delete), s.Image) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. update to latest code There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean I'm rebased on old code? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah just maybe the last commit. I changed this message to the debug and info statement. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, the one I asked you to add? It didn't work well in reality :-) Didn't give enough feedback There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :) SGTM |
||
|
||
if err := r.Syncer.Sync(ctx, s); err != nil { | ||
logrus.Warnln("Skipping build and deploy due to sync error:", err) | ||
return nil | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I forgot to add this but if we get an error here, we should add that dirty artifact back to the rebuild list There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How would you do that? |
||
} | ||
logrus.Infof("Synced %d files for %s", len(s.Copy)+len(s.Delete), s.Image) | ||
logrus.Debugf("Synced files for %s...\nCopied: %s\nDeleted: %s\n", s.Image, s.Copy, s.Delete) | ||
} | ||
case len(changed.needsRebuild) > 0: | ||
bRes, err := r.Build(ctx, out, r.Tagger, changed.needsRebuild) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe move the len check into
perform
? a few lines of code savedThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can do that, yes.