Skip to content

Commit 8135121

Browse files
fix(build, buildah, dockerfile, staged): ensure setting ENTRYPOINT correctly resets base image CMD
If CMD is defined from the base image, setting ENTRYPOINT will reset CMD to an empty value. In this scenario, CMD must be defined in the current image to have a value. Reference: https://docs.docker.com/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact Signed-off-by: Alexey Igrychev <alexey.igrychev@flant.com>
1 parent d3fc7f5 commit 8135121

File tree

5 files changed

+34
-12
lines changed

5 files changed

+34
-12
lines changed

pkg/build/image/dockerfile.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,18 @@ func mapDockerfileToImagesSets(ctx context.Context, cfg *dockerfile.Dockerfile,
176176
instrNum = 0
177177
}
178178

179+
var entrypointResetCMD bool
180+
loop:
181+
for _, instr := range stg.Instructions {
182+
switch any(instr).(type) {
183+
case *dockerfile.DockerfileStageInstruction[*instructions.CmdCommand]:
184+
entrypointResetCMD = false
185+
break loop
186+
case *dockerfile.DockerfileStageInstruction[*instructions.EntrypointCommand]:
187+
entrypointResetCMD = true
188+
}
189+
}
190+
179191
for _, instr := range stg.Instructions {
180192
stageLogName := fmt.Sprintf("%s%d", strings.ToUpper(instr.GetInstructionData().Name()), instrNum+1)
181193
isFirstStage := (len(img.stages) == 0)
@@ -193,7 +205,7 @@ func mapDockerfileToImagesSets(ctx context.Context, cfg *dockerfile.Dockerfile,
193205
case *dockerfile.DockerfileStageInstruction[*instructions.CopyCommand]:
194206
stg = stage_instruction.NewCopy(typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, &baseStageOptions)
195207
case *dockerfile.DockerfileStageInstruction[*instructions.EntrypointCommand]:
196-
stg = stage_instruction.NewEntrypoint(typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, &baseStageOptions)
208+
stg = stage_instruction.NewEntrypoint(typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, entrypointResetCMD, &baseStageOptions)
197209
case *dockerfile.DockerfileStageInstruction[*instructions.EnvCommand]:
198210
stg = stage_instruction.NewEnv(typedInstr, dockerfileImageConfig.Dependencies, !isFirstStage, &baseStageOptions)
199211
case *dockerfile.DockerfileStageInstruction[*instructions.ExposeCommand]:

pkg/build/stage/instruction/entrypoint.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ type Entrypoint struct {
1818
*Base[*instructions.EntrypointCommand, *backend_instruction.Entrypoint]
1919
}
2020

21-
func NewEntrypoint(i *dockerfile.DockerfileStageInstruction[*instructions.EntrypointCommand], dependencies []*config.Dependency, hasPrevStage bool, opts *stage.BaseStageOptions) *Entrypoint {
22-
return &Entrypoint{Base: NewBase(i, backend_instruction.NewEntrypoint(*i.Data), dependencies, hasPrevStage, opts)}
21+
func NewEntrypoint(i *dockerfile.DockerfileStageInstruction[*instructions.EntrypointCommand], dependencies []*config.Dependency, hasPrevStage, entrypointResetCMD bool, opts *stage.BaseStageOptions) *Entrypoint {
22+
return &Entrypoint{Base: NewBase(i, backend_instruction.NewEntrypoint(*i.Data, entrypointResetCMD), dependencies, hasPrevStage, opts)}
2323
}
2424

2525
func (stg *Entrypoint) GetDependencies(ctx context.Context, c stage.Conveyor, cb container_backend.ContainerBackend, prevImage, prevBuiltImage *stage.StageImage, buildContextArchive container_backend.BuildContextArchiver) (string, error) {

pkg/buildah/common.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,17 @@ type ConfigOpts struct {
106106
CmdPrependShell bool
107107
Entrypoint []string
108108
EntrypointPrependShell bool
109-
User string
110-
Workdir string
111-
Healthcheck *thirdparty.BuildahHealthConfig
112-
OnBuild string
113-
StopSignal string
114-
Shell []string
115-
Maintainer string
109+
110+
// If CMD is defined from the base image, setting ENTRYPOINT will reset CMD to an empty value.
111+
// https://docs.docker.com/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact
112+
EntrypointResetCMD bool
113+
User string
114+
Workdir string
115+
Healthcheck *thirdparty.BuildahHealthConfig
116+
OnBuild string
117+
StopSignal string
118+
Shell []string
119+
Maintainer string
116120
}
117121

118122
type CopyOpts struct {

pkg/buildah/native_linux.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,10 @@ func (b *NativeBuildah) Config(ctx context.Context, container string, opts Confi
641641
builder.SetShell(opts.Shell)
642642
}
643643

644+
if opts.EntrypointResetCMD {
645+
builder.SetCmd(nil)
646+
}
647+
644648
if len(opts.Cmd) > 0 {
645649
var cmd []string
646650
if opts.CmdPrependShell {

pkg/container_backend/instruction/entrypoint.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ import (
1212

1313
type Entrypoint struct {
1414
instructions.EntrypointCommand
15+
EntrypointResetCMD bool
1516
}
1617

17-
func NewEntrypoint(i instructions.EntrypointCommand) *Entrypoint {
18-
return &Entrypoint{EntrypointCommand: i}
18+
func NewEntrypoint(i instructions.EntrypointCommand, entrypointResetCMD bool) *Entrypoint {
19+
return &Entrypoint{EntrypointCommand: i, EntrypointResetCMD: entrypointResetCMD}
1920
}
2021

2122
func (i *Entrypoint) UsesBuildContext() bool {
@@ -27,6 +28,7 @@ func (i *Entrypoint) Apply(ctx context.Context, containerName string, drv builda
2728
CommonOpts: drvOpts,
2829
Entrypoint: i.CmdLine,
2930
EntrypointPrependShell: i.PrependShell,
31+
EntrypointResetCMD: i.EntrypointResetCMD,
3032
}); err != nil {
3133
return fmt.Errorf("error setting entrypoint %v for container %s: %w", i.CmdLine, containerName, err)
3234
}

0 commit comments

Comments
 (0)