Skip to content

Commit

Permalink
Merge pull request #200 from ktock/imagemounter-r
Browse files Browse the repository at this point in the history
Allow fetching unmodified container images to browser and running them
  • Loading branch information
ktock authored Jan 12, 2024
2 parents de10b1d + 0d38da0 commit 744e353
Show file tree
Hide file tree
Showing 42 changed files with 7,689 additions and 376 deletions.
12 changes: 9 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ ARG LINUX_LOGLEVEL=7
ARG INIT_DEBUG=true
ARG VM_MEMORY_SIZE_MB=128
ARG NO_VMTOUCH=
ARG EXTERNAL_BUNDLE=

ARG OUTPUT_NAME=out.wasm # for wasi
ARG JS_OUTPUT_NAME=out # for emscripten; must not include "."
Expand Down Expand Up @@ -43,6 +44,7 @@ ARG TARGETPLATFORM
ARG INIT_DEBUG
ARG OPTIMIZATION_MODE
ARG NO_VMTOUCH
ARG EXTERNAL_BUNDLE
COPY --link --from=assets / /work
WORKDIR /work
RUN --mount=type=cache,target=/root/.cache/go-build \
Expand All @@ -60,12 +62,16 @@ RUN mkdir -p /out/oci/rootfs /out/oci/bundle && \
NO_VMTOUCH_F=false && \
if test "${OPTIMIZATION_MODE}" = "native" ; then NO_VMTOUCH_F=true ; fi && \
if test "${NO_VMTOUCH}" != "" ; then NO_VMTOUCH_F="${NO_VMTOUCH}" ; fi && \
create-spec --debug=${INIT_DEBUG} --debug-init=${IS_WIZER} --no-vmtouch=${NO_VMTOUCH_F} \
EXTERNAL_BUNDLE_F=false && \
if test "${EXTERNAL_BUNDLE}" = "true" ; then EXTERNAL_BUNDLE_F=true ; fi && \
create-spec --debug=${INIT_DEBUG} --debug-init=${IS_WIZER} --no-vmtouch=${NO_VMTOUCH_F} --external-bundle=${EXTERNAL_BUNDLE_F} \
--image-config-path=/oci/image.json \
--runtime-config-path=/oci/spec.json \
--rootfs-path=/oci/rootfs \
/oci "${TARGETPLATFORM}" /out/oci/rootfs && \
mv image.json spec.json /out/oci/ && mv initconfig.json /out/oci/
/oci "${TARGETPLATFORM}" /out/oci/rootfs
RUN if test -f image.json; then mv image.json /out/oci/ ; fi && \
if test -f spec.json; then mv spec.json /out/oci/ ; fi
RUN mv initconfig.json /out/oci/

FROM ubuntu:22.04 AS gcc-riscv64-linux-gnu-base
RUN apt-get update && apt-get install -y gcc-riscv64-linux-gnu libc-dev-riscv64-cross git make
Expand Down
7 changes: 7 additions & 0 deletions Dockerfile.test
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ COPY ./tests/c2w-net-proxy-test /c2w-net-proxy-test
WORKDIR /c2w-net-proxy-test
RUN go build -o /out/c2w-net-proxy-test main.go

FROM golang:1.21 AS imagemounter-test-dev
COPY ./tests/imagemounter-test /imagemounter-test
WORKDIR /imagemounter-test
RUN go build -o /out/imagemounter-test main.go

FROM ubuntu:22.04
ARG BUILDX_VERSION
ARG DOCKER_VERSION
Expand Down Expand Up @@ -70,6 +75,7 @@ RUN wget https://github.com/WasmEdge/WasmEdge/releases/download/${WASMEDGE_VERSI
COPY --from=wazero-test-dev /out/wazero-test /usr/local/bin/
COPY --from=httphello-dev /out/httphello /usr/local/bin/
COPY --from=c2w-net-proxy-test-dev /out/c2w-net-proxy-test /usr/local/bin/
COPY --from=imagemounter-test-dev /out/imagemounter-test /usr/local/bin/

# install golang
RUN wget https://go.dev/dl/go${GOLANG_VERSION}.linux-amd64.tar.gz
Expand All @@ -83,6 +89,7 @@ WORKDIR /test/
RUN go build -o /usr/local/bin/ ./cmd/c2w
RUN go build -o /usr/local/bin/ ./cmd/c2w-net
RUN cd extras/c2w-net-proxy/ ; GOOS=wasip1 GOARCH=wasm go build -o /opt/c2w-net-proxy.wasm .
RUN cd extras/imagemounter/ ; GOOS=wasip1 GOARCH=wasm go build -o /opt/imagemounter.wasm .

ENTRYPOINT ["dockerd-entrypoint.sh"]
CMD []
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ c2w-net:
c2w-net-proxy.wasm:
cd extras/c2w-net-proxy/ ; GOOS=wasip1 GOARCH=wasm go build -o $(PREFIX)/c2w-net-proxy.wasm .

imagemounter.wasm:
cd extras/imagemounter ; GOOS=wasip1 GOARCH=wasm go build -o $(PREFIX)/imagemounter.wasm .

install:
install -D -m 755 $(PREFIX)/c2w $(CMD_DESTDIR)/bin
install -D -m 755 $(PREFIX)/c2w-net $(CMD_DESTDIR)/bin
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ Re-compilation (and possibe re-implementation) of the application is needed.

- [`./examples/`](./examples): Examples (python, php, on-browser, networking, etc.)
- `vscode-container-wasm`: VSCode extension for running containers on VSCode on browser (e.g. `github.dev`), leveraging container2wasm: https://github.com/ktock/vscode-container-wasm
- [`./extras/imagemounter`]: A helper tool for enabling to distributing and running container images on browser without pre-conversion of the images.

## Acknowledgement

Expand Down
96 changes: 58 additions & 38 deletions cmd/c2w/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ func main() {
Name: "legacy",
Usage: "Use \"docker build\" instead of buildx (no support for assets flag)",
},
cli.BoolFlag{
Name: "external-bundle",
Usage: "Do not embed container image to the Wasm image but mount it during runtime",
},
}, flags...)
app.Action = rootAction
if err := app.Run(os.Args); err != nil {
Expand All @@ -80,9 +84,22 @@ func rootAction(clicontext *cli.Context) error {
fmt.Printf("\n")
return nil
}
srcImgName := clicontext.Args().First()
if srcImgName == "" {
return fmt.Errorf("specify image name")
arg1 := clicontext.Args().First()
if arg1 == "" {
if clicontext.Bool("external-bundle") {
return fmt.Errorf("specify output image name")
} else {
return fmt.Errorf("specify image name")
}
}
var outputPath string
if clicontext.Bool("external-bundle") {
outputPath = arg1
if clicontext.Args().Get(1) != "" {
return fmt.Errorf("command receives only 1 arg (output image path) with external-bundle")
}
} else {
outputPath = clicontext.Args().Get(1)
}
builderPath, err := exec.LookPath(clicontext.String("builder"))
if err != nil {
Expand All @@ -100,8 +117,8 @@ func rootAction(clicontext *cli.Context) error {
if clicontext.Bool("to-js") {
destFile = ""
}
if o := clicontext.Args().Get(1); o != "" {
d, f := filepath.Split(o)
if outputPath != "" {
d, f := filepath.Split(outputPath)
destDir, err = filepath.Abs(d)
if err != nil {
return err
Expand All @@ -113,28 +130,34 @@ func rootAction(clicontext *cli.Context) error {
if clicontext.Bool("to-js") && destFile != "" {
return fmt.Errorf("output destination must be a slash-terminated directory path when using \"to-js\" option")
}
if legacy {
return buildWithLegacyBuilder(builderPath, srcImgName, destDir, destFile, clicontext)
if a := clicontext.String("assets"); a != "" && legacy {
return fmt.Errorf("\"assets\" unsupported on docker build as of now; install docker buildx instead")
}

return build(builderPath, srcImgName, destDir, destFile, clicontext)
}

func build(builderPath string, srcImgName string, destDir, destFile string, clicontext *cli.Context) error {
srcImgName := arg1
tmpdir, err := os.MkdirTemp("", "container2wasm")
if err != nil {
return err
}
defer os.RemoveAll(tmpdir)

srcImgPath := filepath.Join(tmpdir, "img")
if err := os.Mkdir(srcImgPath, 0755); err != nil {
return err
}
if err := prepareSourceImg(builderPath, srcImgName, srcImgPath, clicontext.String("target-arch")); err != nil {
return fmt.Errorf("failed to prepare image: %w", err)
if !clicontext.Bool("external-bundle") {
if err := prepareSourceImg(builderPath, srcImgName, srcImgPath, clicontext.String("target-arch")); err != nil {
return fmt.Errorf("failed to prepare image: %w", err)
}
}

if legacy {
return buildWithLegacyBuilder(builderPath, srcImgPath, destDir, destFile, clicontext)
}

return build(builderPath, srcImgPath, destDir, destFile, clicontext)
}

func build(builderPath string, srcImgPath string, destDir, destFile string, clicontext *cli.Context) error {
buildxArgs := []string{
"buildx", "build", "--progress=plain",
"--build-arg", fmt.Sprintf("TARGETARCH=%s", clicontext.String("target-arch")),
Expand All @@ -145,11 +168,15 @@ func build(builderPath string, srcImgName string, destDir, destFile string, clic
if o := clicontext.String("dockerfile"); o != "" {
dockerfilePath = o
} else {
df := filepath.Join(tmpdir, "Dockerfile")
if err := os.WriteFile(df, vendor.Dockerfile, 0600); err != nil {
f, err := os.CreateTemp("", "container2wasm")
if err != nil {
return err
}
defer os.Remove(f.Name())
if _, err := f.Write(vendor.Dockerfile); err != nil {
return err
}
dockerfilePath = df
dockerfilePath = f.Name()
}
buildxArgs = append(buildxArgs, "-f", dockerfilePath)
if o := clicontext.String("assets"); o != "" {
Expand All @@ -173,6 +200,9 @@ func build(builderPath string, srcImgName string, destDir, destFile string, clic
"--build-arg", fmt.Sprintf("LINUX_LOGLEVEL=%d", linuxLogLevel),
"--build-arg", fmt.Sprintf("INIT_DEBUG=%v", initDebug),
)
if clicontext.Bool("external-bundle") {
buildxArgs = append(buildxArgs, "--build-arg", "EXTERNAL_BUNDLE=true")
}
for _, a := range clicontext.StringSlice("build-arg") {
buildxArgs = append(buildxArgs, "--build-arg", a)
}
Expand All @@ -185,24 +215,7 @@ func build(builderPath string, srcImgName string, destDir, destFile string, clic
return cmd.Run()
}

func buildWithLegacyBuilder(builderPath string, srcImgName, destDir, destFile string, clicontext *cli.Context) error {
if o := clicontext.String("assets"); o != "" {
return fmt.Errorf("\"assets\" unsupported on docker build as of now; install docker buildx instead")
}
tmpdir, err := os.MkdirTemp("", "container2wasm")
if err != nil {
return err
}
defer os.RemoveAll(tmpdir)

srcImgPath := filepath.Join(tmpdir, "img")
if err := os.Mkdir(srcImgPath, 0755); err != nil {
return err
}
if err := prepareSourceImg(builderPath, srcImgName, srcImgPath, clicontext.String("target-arch")); err != nil {
return fmt.Errorf("failed to prepare image: %w", err)
}

func buildWithLegacyBuilder(builderPath string, srcImgPath, destDir, destFile string, clicontext *cli.Context) error {
buildArgs := []string{
"build", "--progress=plain",
"--platform=linux/amd64",
Expand All @@ -212,11 +225,15 @@ func buildWithLegacyBuilder(builderPath string, srcImgName, destDir, destFile st
if o := clicontext.String("dockerfile"); o != "" {
dockerfilePath = o
} else {
df := filepath.Join(tmpdir, "Dockerfile")
if err := os.WriteFile(df, vendor.Dockerfile, 0600); err != nil {
f, err := os.CreateTemp("", "container2wasm")
if err != nil {
return err
}
dockerfilePath = df
defer os.Remove(f.Name())
if _, err := f.Write(vendor.Dockerfile); err != nil {
return err
}
dockerfilePath = f.Name()
}
buildArgs = append(buildArgs, "-f", dockerfilePath)
if clicontext.Bool("to-js") {
Expand All @@ -237,6 +254,9 @@ func buildWithLegacyBuilder(builderPath string, srcImgName, destDir, destFile st
"--build-arg", fmt.Sprintf("LINUX_LOGLEVEL=%d", linuxLogLevel),
"--build-arg", fmt.Sprintf("INIT_DEBUG=%v", initDebug),
)
if clicontext.Bool("external-bundle") {
buildArgs = append(buildArgs, "--build-arg", "EXTERNAL_BUNDLE=true")
}
for _, a := range clicontext.StringSlice("build-arg") {
buildArgs = append(buildArgs, "--build-arg", a)
}
Expand Down
Loading

0 comments on commit 744e353

Please sign in to comment.