Skip to content

Commit

Permalink
fix compose build integration (#2305)
Browse files Browse the repository at this point in the history
* fix: compose build integration

Signed-off-by: Javier López Barba <javier@okteto.com>

* fix: use image tag with sha

Signed-off-by: Javier López Barba <javier@okteto.com>

* refactor: convert stackVolume to SyncFolder

Signed-off-by: Javier López Barba <javier@okteto.com>

* fix: remove unused params

Signed-off-by: Javier López Barba <javier@okteto.com>
  • Loading branch information
jLopezbarb committed Mar 7, 2022
1 parent 79daee5 commit fea9900
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 63 deletions.
40 changes: 29 additions & 11 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func Build(ctx context.Context) *cobra.Command {
}

if isBuildV2 {
return buildV2(manifest.Build, options, args)
return buildV2(manifest, options, args)
}

return buildV1(options, args)
Expand Down Expand Up @@ -143,8 +143,8 @@ func isSelectedService(service string, selected []string) bool {
return false
}

func buildV2(buildManifest model.ManifestBuild, cmdOptions build.BuildOptions, args []string) error {

func buildV2(manifest *model.Manifest, cmdOptions build.BuildOptions, args []string) error {
buildManifest := manifest.Build
selectedArgs := []string{}
if len(args) != 0 {
selectedArgs = args
Expand All @@ -164,31 +164,35 @@ func buildV2(buildManifest model.ManifestBuild, cmdOptions build.BuildOptions, a
}
}

for service, manifestOpts := range buildManifest {
for service, buildInfo := range buildManifest {

if buildSelected && !isSelectedService(service, selectedArgs) {
continue
}

if isSingleService {
if cmdOptions.Target != "" {
manifestOpts.Target = cmdOptions.Target
buildInfo.Target = cmdOptions.Target
}
if len(cmdOptions.CacheFrom) != 0 {
manifestOpts.CacheFrom = cmdOptions.CacheFrom
buildInfo.CacheFrom = cmdOptions.CacheFrom
}
if cmdOptions.Tag != "" {
manifestOpts.Image = cmdOptions.Tag
buildInfo.Image = cmdOptions.Tag
}
}
if !okteto.Context().IsOkteto && manifestOpts.Image == "" {
if !okteto.Context().IsOkteto && buildInfo.Image == "" {
return fmt.Errorf("'build.%s.image' is required if your context is not managed by Okteto", service)
}
if cwd, err := os.Getwd(); err == nil && manifestOpts.Name == "" {
manifestOpts.Name = utils.InferName(cwd)
if cwd, err := os.Getwd(); err == nil && buildInfo.Name == "" {
buildInfo.Name = utils.InferName(cwd)
}

cmdOptsFromManifest := build.OptsFromManifest(service, manifestOpts, cmdOptions)
volumesToInclude := buildInfo.VolumesToInclude
if len(buildInfo.VolumesToInclude) > 0 {
buildInfo.VolumesToInclude = nil
}
cmdOptsFromManifest := build.OptsFromManifest(service, buildInfo, cmdOptions)

// check if image is at registry and skip
if build.ShouldOptimizeBuild(cmdOptsFromManifest.Tag) && !cmdOptions.BuildToGlobal {
Expand All @@ -214,6 +218,20 @@ func buildV2(buildManifest model.ManifestBuild, cmdOptions build.BuildOptions, a
if err := buildV1(cmdOptsFromManifest, []string{cmdOptsFromManifest.Path}); err != nil {
return err
}
if len(volumesToInclude) > 0 {
oktetoLog.Information("Including volume hosts for service '%s'", service)
svcBuild, err := registry.CreateDockerfileWithVolumeMounts(cmdOptsFromManifest.Tag, volumesToInclude)
if err != nil {
return err
}
svcBuild.VolumesToInclude = volumesToInclude
svcBuild.Name = buildInfo.Name
options := build.OptsFromManifest(service, svcBuild, build.BuildOptions{})
if err := buildV1(options, []string{options.Path}); err != nil {
return err
}

}
}
return nil
}
Expand Down
53 changes: 41 additions & 12 deletions cmd/deploy/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,14 +234,14 @@ func (dc *DeployCommand) RunDeploy(ctx context.Context, deployOptions *Options)
}

if deployOptions.Build {
for service, mBuildInfo := range deployOptions.Manifest.Build {
for service := range deployOptions.Manifest.Build {
oktetoLog.Debug("force build from manifest definition")
if err := runBuildAndSetEnvs(ctx, service, mBuildInfo); err != nil {
if err := runBuildAndSetEnvs(ctx, service, deployOptions.Manifest); err != nil {
return err
}
}

} else if err := checkBuildFromManifest(ctx, deployOptions.Manifest.Build); err != nil {
} else if err := checkBuildFromManifest(ctx, deployOptions.Manifest); err != nil {
return err
}

Expand Down Expand Up @@ -517,9 +517,13 @@ func checkImageAtGlobalAndSetEnvs(service string, options build.BuildOptions) (b

}

func runBuildAndSetEnvs(ctx context.Context, service string, buildInfo *model.BuildInfo) error {
func runBuildAndSetEnvs(ctx context.Context, service string, manifest *model.Manifest) error {
buildInfo := manifest.Build[service]
oktetoLog.Information("Building image for service '%s'", service)

volumesToInclude := buildInfo.VolumesToInclude
if len(buildInfo.VolumesToInclude) > 0 {
buildInfo.VolumesToInclude = nil
}
options := build.OptsFromManifest(service, buildInfo, build.BuildOptions{})
if err := build.Run(ctx, options); err != nil {
return err
Expand All @@ -529,8 +533,33 @@ func runBuildAndSetEnvs(ctx context.Context, service string, buildInfo *model.Bu
return fmt.Errorf("error accessing image at registry %s: %v", options.Tag, err)
}

if len(volumesToInclude) > 0 {
oktetoLog.Information("Including volume hosts for service '%s'", service)
svcBuild, err := registry.CreateDockerfileWithVolumeMounts(options.Tag, volumesToInclude)
if err != nil {
return err
}
svcBuild.VolumesToInclude = volumesToInclude
options = build.OptsFromManifest(service, svcBuild, build.BuildOptions{})
if err := build.Run(ctx, options); err != nil {
return err
}
imageWithDigest, err = registry.GetImageTagWithDigest(options.Tag)
if err != nil {
return fmt.Errorf("error accessing image at registry %s: %v", options.Tag, err)
}
}
oktetoLog.Success("Image for service '%s' pushed to registry: %s", service, options.Tag)
return setManifestEnvVars(service, imageWithDigest)
if err := setManifestEnvVars(service, imageWithDigest); err != nil {
return err
}
if manifest.Deploy != nil && manifest.Deploy.Compose != nil && manifest.Deploy.Compose.Stack != nil {
stack := manifest.Deploy.Compose.Stack
if stack.Services[service].Image == "" {
stack.Services[service].Image = fmt.Sprintf("$OKTETO_BUILD_%s_IMAGE", strings.ToUpper(service))
}
}
return nil
}

func setManifestEnvVars(service, reference string) error {
Expand Down Expand Up @@ -775,8 +804,8 @@ func shouldExecuteRemotely(options *Options) bool {
return options.Branch != "" || options.Repository != ""
}

func checkServicesToBuild(service string, mOptions *model.BuildInfo, ch chan string) error {
opts := build.OptsFromManifest(service, mOptions, build.BuildOptions{})
func checkServicesToBuild(service string, mOptions model.BuildInfo, ch chan string) error {
opts := build.OptsFromManifest(service, &mOptions, build.BuildOptions{})

if build.ShouldOptimizeBuild(opts.Tag) {
oktetoLog.Debug("found OKTETO_GIT_COMMIT, optimizing the build flow")
Expand All @@ -801,13 +830,14 @@ func checkServicesToBuild(service string, mOptions *model.BuildInfo, ch chan str
return setManifestEnvVars(service, imageWithDigest)
}

func checkBuildFromManifest(ctx context.Context, buildManifest model.ManifestBuild) error {
func checkBuildFromManifest(ctx context.Context, manifest *model.Manifest) error {
buildManifest := manifest.Build
// check if images are at registry (global or dev) and set envs or send to build
toBuild := make(chan string, len(buildManifest))
g, _ := errgroup.WithContext(ctx)

for service, mBuildInfo := range buildManifest {
service, mBuildInfo := service, mBuildInfo
service, mBuildInfo := service, *mBuildInfo
g.Go(func() error {
return checkServicesToBuild(service, mBuildInfo, toBuild)
})
Expand All @@ -825,8 +855,7 @@ func checkBuildFromManifest(ctx context.Context, buildManifest model.ManifestBui
for svc := range toBuild {
oktetoLog.Warning("Image for service '%s' doesn't exist and it needs to be built", svc)
oktetoLog.Information("To rebuild this image run 'okteto build %s' or 'okteto deploy --build'", svc)
mBuildInfo := buildManifest[svc]
if err := runBuildAndSetEnvs(ctx, svc, mBuildInfo); err != nil {
if err := runBuildAndSetEnvs(ctx, svc, manifest); err != nil {
return err
}
}
Expand Down
5 changes: 4 additions & 1 deletion pkg/cmd/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,11 @@ func OptsFromManifest(service string, b *model.BuildInfo, o BuildOptions) BuildO
if o.BuildToGlobal {
targetRegistry = okteto.GlobalRegistry
}

b.Image = fmt.Sprintf("%s/%s-%s:%s", targetRegistry, b.Name, service, tag)
if len(b.VolumesToInclude) > 0 {
b.Image = fmt.Sprintf("%s/%s-%s:%s", targetRegistry, b.Name, service, model.OktetoImageTagWithVolumes)
}

}

file := b.Dockerfile
Expand Down
20 changes: 12 additions & 8 deletions pkg/cmd/stack/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,16 @@ func buildServices(ctx context.Context, s *model.Stack, options *StackDeployOpti
if !okteto.IsOkteto() && svc.Image == "" {
return hasBuiltSomething, fmt.Errorf("'build' and 'image' fields of service '%s' cannot be empty", name)
}
image := svc.Image
if okteto.IsOkteto() && !registry.IsOktetoRegistry(svc.Image) {
svc.Image = fmt.Sprintf("okteto.dev/%s-%s:okteto", s.Name, name)
image = fmt.Sprintf("okteto.dev/%s-%s:%s", s.Name, name, model.OktetoDefaultImageTag)
}
if !options.ForceBuild {
if _, err := registry.GetImageTagWithDigest(svc.Image); err != oktetoErrors.ErrNotFound {
if _, err := registry.GetImageTagWithDigest(image); err != oktetoErrors.ErrNotFound {
s.Services[name] = svc
continue
}
oktetoLog.Infof("image '%s' not found, building it", svc.Image)
oktetoLog.Infof("image '%s' not found, building it", image)
}
if !hasBuiltSomething {
hasBuiltSomething = true
Expand All @@ -173,7 +174,7 @@ func buildServices(ctx context.Context, s *model.Stack, options *StackDeployOpti
buildOptions := build.BuildOptions{
Path: svc.Build.Context,
File: svc.Build.Dockerfile,
Tag: svc.Image,
Tag: image,
Target: svc.Build.Target,
NoCache: options.NoCache,
CacheFrom: svc.Build.CacheFrom,
Expand All @@ -184,6 +185,7 @@ func buildServices(ctx context.Context, s *model.Stack, options *StackDeployOpti
return hasBuiltSomething, err
}
svc.SetLastBuiltAnnotation()
svc.Image = image
s.Services[name] = svc
oktetoLog.Success("Image for service '%s' successfully pushed", name)
}
Expand All @@ -206,15 +208,16 @@ func addVolumeMountsToBuiltImage(ctx context.Context, s *model.Stack, options *S
return hasAddedAnyVolumeMounts, err
}
svc.Build = svcBuild
image := svc.Image
if okteto.IsOkteto() {
svc.Image = fmt.Sprintf("okteto.dev/%s-%s:okteto-with-volume-mounts", s.Name, name)
image = fmt.Sprintf("okteto.dev/%s-%s:%s", s.Name, name, model.OktetoImageTagWithVolumes)
}
if !options.ForceBuild {
if _, err := registry.GetImageTagWithDigest(svc.Image); err != oktetoErrors.ErrNotFound {
if _, err := registry.GetImageTagWithDigest(image); err != oktetoErrors.ErrNotFound {
s.Services[name] = svc
continue
}
oktetoLog.Infof("image '%s' not found, building it", svc.Image)
oktetoLog.Infof("image '%s' not found, building it", image)
}
if !hasBuiltSomething && !hasAddedAnyVolumeMounts {
hasAddedAnyVolumeMounts = true
Expand All @@ -226,7 +229,7 @@ func addVolumeMountsToBuiltImage(ctx context.Context, s *model.Stack, options *S
buildOptions := build.BuildOptions{
Path: svc.Build.Context,
File: svc.Build.Dockerfile,
Tag: svc.Image,
Tag: image,
Target: svc.Build.Target,
NoCache: options.NoCache,
CacheFrom: svc.Build.CacheFrom,
Expand All @@ -237,6 +240,7 @@ func addVolumeMountsToBuiltImage(ctx context.Context, s *model.Stack, options *S
return hasAddedAnyVolumeMounts, err
}
svc.SetLastBuiltAnnotation()
svc.Image = image
s.Services[name] = svc
oktetoLog.Success("Image for service '%s' successfully pushed", name)
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/model/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,4 +320,7 @@ const (

// OktetoDefaultImageTag default tag assigned to image to build
OktetoDefaultImageTag = "okteto"

// OktetoImageTagWithVolumes is the tag assigned to an image with volume mounts
OktetoImageTagWithVolumes = "okteto-with-volume-mounts"
)
15 changes: 8 additions & 7 deletions pkg/model/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,14 @@ type Args struct {

// BuildInfo represents the build info to generate an image
type BuildInfo struct {
Name string `yaml:"name,omitempty"`
Context string `yaml:"context,omitempty"`
Dockerfile string `yaml:"dockerfile,omitempty"`
CacheFrom []string `yaml:"cache_from,omitempty"`
Target string `yaml:"target,omitempty"`
Args Environment `yaml:"args,omitempty"`
Image string `yaml:"image,omitempty"`
Name string `yaml:"name,omitempty"`
Context string `yaml:"context,omitempty"`
Dockerfile string `yaml:"dockerfile,omitempty"`
CacheFrom []string `yaml:"cache_from,omitempty"`
Target string `yaml:"target,omitempty"`
Args Environment `yaml:"args,omitempty"`
Image string `yaml:"image,omitempty"`
VolumesToInclude []StackVolume `yaml:"-"`
}

// DevBuildInfo throws a warning if it's not single line
Expand Down

0 comments on commit fea9900

Please sign in to comment.