Skip to content

Commit 306ed6c

Browse files
committed
feat(staged-dockerfile): basic support of all dockerfile stages at conveyor level
Signed-off-by: Timofey Kirillov <timofey.kirillov@flant.com>
1 parent f5f200e commit 306ed6c

File tree

18 files changed

+559
-15
lines changed

18 files changed

+559
-15
lines changed

pkg/build/image/dockerfile.go

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -118,21 +118,55 @@ func mapDockerfileToImagesSets(ctx context.Context, cfg *dockerfile.Dockerfile,
118118
}
119119

120120
for ind, instr := range stg.Instructions {
121+
stageName := stage.StageName(fmt.Sprintf("%d-%s", ind, instr.GetInstructionData().Name()))
122+
isFirstStage := (len(img.stages) == 0)
123+
baseStageOptions := &stage.BaseStageOptions{
124+
ImageName: img.Name,
125+
ImageTmpDir: img.TmpDir,
126+
ContainerWerfDir: img.ContainerWerfDir,
127+
ProjectName: opts.ProjectName,
128+
}
129+
130+
var stg stage.Interface
121131
switch typedInstr := any(instr).(type) {
132+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Add]:
133+
stg = stage_instruction.NewAdd(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
134+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Cmd]:
135+
stg = stage_instruction.NewCmd(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
136+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Copy]:
137+
stg = stage_instruction.NewCopy(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
138+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Entrypoint]:
139+
stg = stage_instruction.NewEntrypoint(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
140+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Env]:
141+
stg = stage_instruction.NewEnv(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
142+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Expose]:
143+
stg = stage_instruction.NewExpose(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
144+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Healthcheck]:
145+
stg = stage_instruction.NewHealthcheck(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
146+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Label]:
147+
stg = stage_instruction.NewLabel(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
148+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Maintainer]:
149+
stg = stage_instruction.NewMaintainer(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
150+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.OnBuild]:
151+
stg = stage_instruction.NewOnBuild(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
122152
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Run]:
123-
isFirstStage := (len(img.stages) == 0)
124-
125-
img.stages = append(img.stages, stage_instruction.NewRun(stage.StageName(fmt.Sprintf("%d-%s", ind, typedInstr.Data.Name())), typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, &stage.BaseStageOptions{
126-
ImageName: img.Name,
127-
ImageTmpDir: img.TmpDir,
128-
ContainerWerfDir: img.ContainerWerfDir,
129-
ProjectName: opts.ProjectName,
130-
}))
131-
153+
stg = stage_instruction.NewRun(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
154+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Shell]:
155+
stg = stage_instruction.NewShell(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
156+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.StopSignal]:
157+
stg = stage_instruction.NewStopSignal(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
158+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.User]:
159+
stg = stage_instruction.NewUser(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
160+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Volume]:
161+
stg = stage_instruction.NewVolume(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
162+
case *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Workdir]:
163+
stg = stage_instruction.NewWorkdir(stageName, typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, baseStageOptions)
132164
default:
133165
panic(fmt.Sprintf("unsupported instruction type %#v", instr))
134166
}
135167

168+
img.stages = append(img.stages, stg)
169+
136170
for _, dep := range instr.GetDependenciesByStageRef() {
137171
appendQueue(dep, item.Level+1)
138172
}

pkg/build/stage/instruction/add.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package instruction
2+
3+
import (
4+
"context"
5+
6+
"github.com/werf/werf/pkg/build/stage"
7+
"github.com/werf/werf/pkg/config"
8+
"github.com/werf/werf/pkg/container_backend"
9+
backend_instruction "github.com/werf/werf/pkg/container_backend/instruction"
10+
"github.com/werf/werf/pkg/dockerfile"
11+
dockerfile_instruction "github.com/werf/werf/pkg/dockerfile/instruction"
12+
"github.com/werf/werf/pkg/util"
13+
)
14+
15+
type Add struct {
16+
*Base[*dockerfile_instruction.Add]
17+
}
18+
19+
func NewAdd(name stage.StageName, i *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Add], dependencies []*config.Dependency, hasPrevStage bool, opts *stage.BaseStageOptions) *Add {
20+
return &Add{Base: NewBase(name, i, dependencies, hasPrevStage, opts)}
21+
}
22+
23+
func (stage *Add) GetDependencies(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevImage, prevBuiltImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) (string, error) {
24+
var args []string
25+
args = append(args, stage.instruction.Data.Name())
26+
args = append(args, stage.instruction.Data.Src...)
27+
args = append(args, stage.instruction.Data.Dst)
28+
args = append(args, stage.instruction.Data.Chown)
29+
args = append(args, stage.instruction.Data.Chmod)
30+
return util.Sha256Hash(args...), nil
31+
}
32+
33+
func (stage *Add) PrepareImage(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevBuiltImage, stageImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) error {
34+
return stage.Base.prepareInstruction(ctx, stageImage, buildContextArchive, backend_instruction.NewAdd(*stage.instruction.Data))
35+
}

pkg/build/stage/instruction/base.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package instruction
22

33
import (
4+
"context"
5+
46
"github.com/werf/werf/pkg/build/stage"
57
"github.com/werf/werf/pkg/config"
8+
"github.com/werf/werf/pkg/container_backend"
69
"github.com/werf/werf/pkg/dockerfile"
710
)
811

@@ -23,10 +26,16 @@ func NewBase[T dockerfile.InstructionDataInterface](name stage.StageName, instru
2326
}
2427
}
2528

26-
func (stage *Base[T]) HasPrevStage() bool {
27-
return stage.hasPrevStage
29+
func (stg *Base[T]) HasPrevStage() bool {
30+
return stg.hasPrevStage
2831
}
2932

30-
func (s *Base[T]) IsStapelStage() bool {
33+
func (stg *Base[T]) IsStapelStage() bool {
3134
return false
3235
}
36+
37+
func (stg *Base[T]) prepareInstruction(ctx context.Context, stageImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver, backendInstruction container_backend.InstructionInterface) error {
38+
stageImage.Builder.DockerfileStageBuilder().SetBuildContextArchive(buildContextArchive) // FIXME(staged-dockerfile): set context at build-phase level
39+
stageImage.Builder.DockerfileStageBuilder().AppendInstruction(backendInstruction)
40+
return nil
41+
}

pkg/build/stage/instruction/cmd.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package instruction
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/werf/werf/pkg/build/stage"
8+
"github.com/werf/werf/pkg/config"
9+
"github.com/werf/werf/pkg/container_backend"
10+
backend_instruction "github.com/werf/werf/pkg/container_backend/instruction"
11+
"github.com/werf/werf/pkg/dockerfile"
12+
dockerfile_instruction "github.com/werf/werf/pkg/dockerfile/instruction"
13+
"github.com/werf/werf/pkg/util"
14+
)
15+
16+
type Cmd struct {
17+
*Base[*dockerfile_instruction.Cmd]
18+
}
19+
20+
func NewCmd(name stage.StageName, i *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Cmd], dependencies []*config.Dependency, hasPrevStage bool, opts *stage.BaseStageOptions) *Cmd {
21+
return &Cmd{Base: NewBase(name, i, dependencies, hasPrevStage, opts)}
22+
}
23+
24+
func (stage *Cmd) GetDependencies(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevImage, prevBuiltImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) (string, error) {
25+
var args []string
26+
args = append(args, stage.instruction.Data.Name())
27+
args = append(args, stage.instruction.Data.Cmd...)
28+
args = append(args, fmt.Sprintf("%v", stage.instruction.Data.PrependShell))
29+
return util.Sha256Hash(args...), nil
30+
}
31+
32+
func (stage *Cmd) PrepareImage(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevBuiltImage, stageImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) error {
33+
return stage.Base.prepareInstruction(ctx, stageImage, buildContextArchive, backend_instruction.NewCmd(*stage.instruction.Data))
34+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package instruction
2+
3+
import (
4+
"context"
5+
6+
"github.com/werf/werf/pkg/build/stage"
7+
"github.com/werf/werf/pkg/config"
8+
"github.com/werf/werf/pkg/container_backend"
9+
backend_instruction "github.com/werf/werf/pkg/container_backend/instruction"
10+
"github.com/werf/werf/pkg/dockerfile"
11+
dockerfile_instruction "github.com/werf/werf/pkg/dockerfile/instruction"
12+
"github.com/werf/werf/pkg/util"
13+
)
14+
15+
type Copy struct {
16+
*Base[*dockerfile_instruction.Copy]
17+
}
18+
19+
func NewCopy(name stage.StageName, i *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Copy], dependencies []*config.Dependency, hasPrevStage bool, opts *stage.BaseStageOptions) *Copy {
20+
return &Copy{Base: NewBase(name, i, dependencies, hasPrevStage, opts)}
21+
}
22+
23+
func (stage *Copy) GetDependencies(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevImage, prevBuiltImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) (string, error) {
24+
var args []string
25+
args = append(args, stage.instruction.Data.Name())
26+
args = append(args, stage.instruction.Data.From)
27+
args = append(args, stage.instruction.Data.Src...)
28+
args = append(args, stage.instruction.Data.Dst)
29+
args = append(args, stage.instruction.Data.Chown)
30+
args = append(args, stage.instruction.Data.Chmod)
31+
return util.Sha256Hash(args...), nil
32+
}
33+
34+
func (stage *Copy) PrepareImage(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevBuiltImage, stageImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) error {
35+
return stage.Base.prepareInstruction(ctx, stageImage, buildContextArchive, backend_instruction.NewCopy(*stage.instruction.Data))
36+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package instruction
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/werf/werf/pkg/build/stage"
8+
"github.com/werf/werf/pkg/config"
9+
"github.com/werf/werf/pkg/container_backend"
10+
backend_instruction "github.com/werf/werf/pkg/container_backend/instruction"
11+
"github.com/werf/werf/pkg/dockerfile"
12+
dockerfile_instruction "github.com/werf/werf/pkg/dockerfile/instruction"
13+
"github.com/werf/werf/pkg/util"
14+
)
15+
16+
type Entrypoint struct {
17+
*Base[*dockerfile_instruction.Entrypoint]
18+
}
19+
20+
func NewEntrypoint(name stage.StageName, i *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Entrypoint], dependencies []*config.Dependency, hasPrevStage bool, opts *stage.BaseStageOptions) *Entrypoint {
21+
return &Entrypoint{Base: NewBase(name, i, dependencies, hasPrevStage, opts)}
22+
}
23+
24+
func (stage *Entrypoint) GetDependencies(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevImage, prevBuiltImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) (string, error) {
25+
var args []string
26+
args = append(args, stage.instruction.Data.Name())
27+
args = append(args, stage.instruction.Data.Entrypoint...)
28+
args = append(args, fmt.Sprintf("%v", stage.instruction.Data.PrependShell))
29+
return util.Sha256Hash(args...), nil
30+
}
31+
32+
func (stage *Entrypoint) PrepareImage(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevBuiltImage, stageImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) error {
33+
return stage.Base.prepareInstruction(ctx, stageImage, buildContextArchive, backend_instruction.NewEntrypoint(*stage.instruction.Data))
34+
}

pkg/build/stage/instruction/env.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package instruction
2+
3+
import (
4+
"context"
5+
6+
"github.com/werf/werf/pkg/build/stage"
7+
"github.com/werf/werf/pkg/config"
8+
"github.com/werf/werf/pkg/container_backend"
9+
backend_instruction "github.com/werf/werf/pkg/container_backend/instruction"
10+
"github.com/werf/werf/pkg/dockerfile"
11+
dockerfile_instruction "github.com/werf/werf/pkg/dockerfile/instruction"
12+
"github.com/werf/werf/pkg/util"
13+
)
14+
15+
type Env struct {
16+
*Base[*dockerfile_instruction.Env]
17+
}
18+
19+
func NewEnv(name stage.StageName, i *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Env], dependencies []*config.Dependency, hasPrevStage bool, opts *stage.BaseStageOptions) *Env {
20+
return &Env{Base: NewBase(name, i, dependencies, hasPrevStage, opts)}
21+
}
22+
23+
func (stage *Env) GetDependencies(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevImage, prevBuiltImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) (string, error) {
24+
var args []string
25+
args = append(args, stage.instruction.Data.Name())
26+
// FIXME(staged-dockerfile): sort envs
27+
for k, v := range stage.instruction.Data.Envs {
28+
args = append(args, k, v)
29+
}
30+
return util.Sha256Hash(args...), nil
31+
}
32+
33+
func (stage *Env) PrepareImage(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevBuiltImage, stageImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) error {
34+
return stage.Base.prepareInstruction(ctx, stageImage, buildContextArchive, backend_instruction.NewEnv(*stage.instruction.Data))
35+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package instruction
2+
3+
import (
4+
"context"
5+
6+
"github.com/werf/werf/pkg/build/stage"
7+
"github.com/werf/werf/pkg/config"
8+
"github.com/werf/werf/pkg/container_backend"
9+
backend_instruction "github.com/werf/werf/pkg/container_backend/instruction"
10+
"github.com/werf/werf/pkg/dockerfile"
11+
dockerfile_instruction "github.com/werf/werf/pkg/dockerfile/instruction"
12+
"github.com/werf/werf/pkg/util"
13+
)
14+
15+
type Expose struct {
16+
*Base[*dockerfile_instruction.Expose]
17+
}
18+
19+
func NewExpose(name stage.StageName, i *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Expose], dependencies []*config.Dependency, hasPrevStage bool, opts *stage.BaseStageOptions) *Expose {
20+
return &Expose{Base: NewBase(name, i, dependencies, hasPrevStage, opts)}
21+
}
22+
23+
func (stage *Expose) GetDependencies(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevImage, prevBuiltImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) (string, error) {
24+
var args []string
25+
args = append(args, stage.instruction.Data.Name())
26+
args = append(args, stage.instruction.Data.Ports...)
27+
return util.Sha256Hash(args...), nil
28+
}
29+
30+
func (stage *Expose) PrepareImage(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevBuiltImage, stageImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) error {
31+
return stage.Base.prepareInstruction(ctx, stageImage, buildContextArchive, backend_instruction.NewExpose(*stage.instruction.Data))
32+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package instruction
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/werf/werf/pkg/build/stage"
8+
"github.com/werf/werf/pkg/config"
9+
"github.com/werf/werf/pkg/container_backend"
10+
"github.com/werf/werf/pkg/dockerfile"
11+
dockerfile_instruction "github.com/werf/werf/pkg/dockerfile/instruction"
12+
"github.com/werf/werf/pkg/util"
13+
)
14+
15+
type Healthcheck struct {
16+
*Base[*dockerfile_instruction.Healthcheck]
17+
}
18+
19+
func NewHealthcheck(name stage.StageName, i *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Healthcheck], dependencies []*config.Dependency, hasPrevStage bool, opts *stage.BaseStageOptions) *Healthcheck {
20+
return &Healthcheck{Base: NewBase(name, i, dependencies, hasPrevStage, opts)}
21+
}
22+
23+
func (stage *Healthcheck) GetDependencies(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevImage, prevBuiltImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) (string, error) {
24+
var args []string
25+
args = append(args, stage.instruction.Data.Name())
26+
args = append(args, string(stage.instruction.Data.Type))
27+
args = append(args, stage.instruction.Data.Config.Test...)
28+
args = append(args, stage.instruction.Data.Config.Interval.String())
29+
args = append(args, stage.instruction.Data.Config.Timeout.String())
30+
args = append(args, stage.instruction.Data.Config.StartPeriod.String())
31+
args = append(args, fmt.Sprintf("%d", stage.instruction.Data.Config.Retries))
32+
return util.Sha256Hash(args...), nil
33+
}
34+
35+
func (stage *Healthcheck) PrepareImage(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevBuiltImage, stageImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) error {
36+
// FIXME(staged-dockerfile): construct backend instruction
37+
return stage.Base.prepareInstruction(ctx, stageImage, buildContextArchive, nil)
38+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package instruction
2+
3+
import (
4+
"context"
5+
6+
"github.com/werf/werf/pkg/build/stage"
7+
"github.com/werf/werf/pkg/config"
8+
"github.com/werf/werf/pkg/container_backend"
9+
backend_instruction "github.com/werf/werf/pkg/container_backend/instruction"
10+
"github.com/werf/werf/pkg/dockerfile"
11+
dockerfile_instruction "github.com/werf/werf/pkg/dockerfile/instruction"
12+
"github.com/werf/werf/pkg/util"
13+
)
14+
15+
type Label struct {
16+
*Base[*dockerfile_instruction.Label]
17+
}
18+
19+
func NewLabel(name stage.StageName, i *dockerfile.DockerfileStageInstruction[*dockerfile_instruction.Label], dependencies []*config.Dependency, hasPrevStage bool, opts *stage.BaseStageOptions) *Label {
20+
return &Label{Base: NewBase(name, i, dependencies, hasPrevStage, opts)}
21+
}
22+
23+
func (stage *Label) GetDependencies(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevImage, prevBuiltImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) (string, error) {
24+
var args []string
25+
args = append(args, stage.instruction.Data.Name())
26+
// FIXME(staged-dockerfile): sort labels map
27+
for k, v := range stage.instruction.Data.Labels {
28+
args = append(args, k, v)
29+
}
30+
return util.Sha256Hash(args...), nil
31+
}
32+
33+
func (stage *Label) PrepareImage(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevBuiltImage, stageImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) error {
34+
return stage.Base.prepareInstruction(ctx, stageImage, buildContextArchive, backend_instruction.NewLabel(*stage.instruction.Data))
35+
}

0 commit comments

Comments
 (0)