Skip to content

Commit

Permalink
feat: dockerfile action support build context from user params (#52)
Browse files Browse the repository at this point in the history
* feat: dockerfile action support build context from user input

Signed-off-by: Ash <[email protected]>

* optimize refresh repo credential tips

Signed-off-by: Ash <[email protected]>

* remove as warning

Signed-off-by: Ash <[email protected]>

* remove defualt behaviour platform specified params

Signed-off-by: Ash <[email protected]>

* upgrade dockerfile action, support build context

Signed-off-by: Ash <[email protected]>

* Dockerfile action: README.md add build_context example

Signed-off-by: Ash <[email protected]>

---------

Signed-off-by: Ash <[email protected]>
  • Loading branch information
iutx authored Sep 13, 2024
1 parent 088ce0b commit f19b50b
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 109 deletions.
13 changes: 8 additions & 5 deletions actions/dockerfile/1.0/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
FROM registry.erda.cloud/erda-actions/custom-script:2.0 AS builder
FROM registry.erda.cloud/retag/buildkit:v0.11.3 AS buildkit
FROM registry.erda.cloud/erda-x/golang:1.22 AS builder

ENV CGO_ENABLED 0

COPY . /go/src/github.com/erda-project/erda-actions
WORKDIR /go/src/github.com/erda-project/erda-actions

ENV CGO_ENABLED=0

COPY . .

RUN go build -o /opt/action/run github.com/erda-project/erda-actions/actions/dockerfile/1.0/internal/cmd

FROM registry.erda.cloud/erda-actions/custom-script:2.0
FROM registry.erda.cloud/erda-x/debian-bookworm:12

COPY --from=builder /opt/action/run /opt/action/run
COPY --from=buildkit /usr/bin/buildctl /usr/bin/buildctl
RUN chmod +x /opt/action/run
31 changes: 29 additions & 2 deletions actions/dockerfile/1.0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#### 使用

dockerfile 位于应用根目录:
1. dockerfile 位于应用根目录:

```yml
- dockerfile:
Expand All @@ -16,11 +16,38 @@ dockerfile 位于应用根目录:
NODE_OPTIONS: --max_old_space_size=3040
```
dockerfile 位于应用子目录下:
2. dockerfile 位于应用子目录下:
```yml
- dockerfile:
params:
workdir: ${git-checkout}
path: subdir/Dockerfile
```
3. 构建上下文配置
```yml
- stage:
- git-checkout:
alias: git-checkout
version: "1.0"
...
- git-checkout:
alias: other-repo
version: "1.0"
...
- stage:
- dockerfile:
params:
build_context:
other-resource: ${other-repo}
workdir: ${git-checkout}
path: subdir/Dockerfile
```
`Dockerfile` 中,使用 `COPY` 指令从不同的构建上下文(如 other-resource)中复制资源:

```Dockerfile
COPY --from=other-resource <source_path> <target_path>
```
2 changes: 1 addition & 1 deletion actions/dockerfile/1.0/dice.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
### job 配置项
jobs:
dockerfile:
image: registry.erda.cloud/erda-actions/dockerfile-action:1.0-20230712152621-b9ad349
image: registry.erda.cloud/erda-actions/dockerfile-action:1.0-20240912171845-238b6eec
resources:
cpu: 1
mem: 2048
91 changes: 91 additions & 0 deletions actions/dockerfile/1.0/internal/pkg/build/buildkit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package build

import (
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"

"github.com/erda-project/erda-actions/actions/dockerfile/1.0/internal/pkg/conf"
pkgconf "github.com/erda-project/erda-actions/pkg/envconf"
"github.com/erda-project/erda-infra/pkg/strutil"
)

const (
defaultCaCertPath = "/.buildkit/ca.pem"
defaultCertPath = "/.buildkit/cert.pem"
defaultCertKeyPath = "/.buildkit/key.pem"
)

type buildkit struct {
config *conf.Conf
args []string
}

func NewBuildkit(c *conf.Conf) Builder {
args := []string{
"--addr", c.BuildkitdAddr,
fmt.Sprintf("--tlscacert=%s", defaultCaCertPath),
fmt.Sprintf("--tlscert=%s", defaultCertPath),
fmt.Sprintf("--tlskey=%s", defaultCertKeyPath),
"build",
"--frontend", "dockerfile.v0",
"--local", "context=" + c.Context,
"--local", "dockerfile=" + resolveDockerfileDir(c),
"--opt", fmt.Sprintf("platform=%s", pkgconf.GetTargetPlatforms()),
}

return &buildkit{
config: c,
args: args,
}
}

func (b *buildkit) Build(p *Params, o *OutPut) error {
// generate command from action params provided
b.appendBuildArgs(p.Args)
b.appendBuildContexts(p.BuildContext)

// set output
b.args = append(b.args,
"--output",
fmt.Sprintf("type=image,name=%s,push=%s", o.Image, strconv.FormatBool(o.Push)),
)

buildCmd := exec.Command("buildctl", b.args...)
fmt.Println(strutil.Join(buildCmd.Args, " ", false))

buildCmd.Dir = b.config.WorkDir
buildCmd.Stdout = os.Stdout
buildCmd.Stderr = os.Stderr

if err := buildCmd.Run(); err != nil {
return fmt.Errorf("failed to build image: %v", err)
}

fmt.Fprintf(os.Stdout, "Successfully built and pushed image: %s\n", o.Image)
return nil
}

func resolveDockerfileDir(c *conf.Conf) string {
if path.IsAbs(c.Path) {
return filepath.Dir(c.Path)
}
return filepath.Dir(path.Join(c.Context, c.Path))
}

func (b *buildkit) appendBuildArgs(args map[string]string) {
for k, v := range args {
b.args = append(b.args, "--opt", fmt.Sprintf("build-arg:%s=%s", k, v))
}
}

func (b *buildkit) appendBuildContexts(buildContexts map[string]string) {
for k, v := range buildContexts {
b.args = append(b.args,
"--local", fmt.Sprintf("%s=%s", k, v),
"--opt", fmt.Sprintf("context:%s=local:%s", k, k))
}
}
77 changes: 77 additions & 0 deletions actions/dockerfile/1.0/internal/pkg/build/docker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package build

import (
"fmt"
"os"
"os/exec"
"strconv"

"github.com/erda-project/erda-actions/actions/dockerfile/1.0/internal/pkg/conf"
"github.com/erda-project/erda-actions/pkg/docker"
"github.com/erda-project/erda/apistructs"
)

type dockerBuilder struct {
config *conf.Conf
args []string
}

func NewDocker(c *conf.Conf) Builder {
args := []string{
"build",
".", // set current dir is build context
"-f", c.Path,
}

return &dockerBuilder{
config: c,
args: args,
}
}

func (d *dockerBuilder) Build(p *Params, o *OutPut) error {
// generate command from action params provided
d.appendBuildArgs(p.Args)
d.appendBuildContexts(p.BuildContext)

// set resource limit
d.args = append(d.args,
"--cpu-quota", strconv.FormatFloat(d.config.CPU*100000, 'f', 0, 64),
"--memory", strconv.FormatInt(int64(d.config.Memory*apistructs.MB), 10),
)

// generate build command
buildCmd := exec.Command("docker", d.args...)
fmt.Fprintf(os.Stdout, "Docker build command: %v\n", buildCmd.Args)

buildCmd.Stdout = os.Stdout
buildCmd.Stderr = os.Stderr
buildCmd.Dir = d.config.WorkDir

if err := buildCmd.Run(); err != nil {
return fmt.Errorf("failed to build docker image: %v", err)
}

if o.Push {
if err := docker.PushByCmd(o.Image, ""); err != nil {
return fmt.Errorf("failed to push docker image: %v", err)
}
}

fmt.Fprintf(os.Stdout, "Successfully built and pushed image: %s\n", o.Image)
return nil
}

// appendBuildArgs
func (d *dockerBuilder) appendBuildArgs(args map[string]string) {
for k, v := range args {
d.args = append(d.args, "--build-arg", fmt.Sprintf("%s=%s", k, v))
}
}

// appendBuildContexts
func (d *dockerBuilder) appendBuildContexts(contexts map[string]string) {
for k, v := range contexts {
d.args = append(d.args, "--build-context", fmt.Sprintf("%s=%s", k, v))
}
}
Loading

0 comments on commit f19b50b

Please sign in to comment.