diff --git a/.drone/drone.yml b/.drone/drone.yml
deleted file mode 100644
index 288e4be..0000000
--- a/.drone/drone.yml
+++ /dev/null
@@ -1,168 +0,0 @@
-kind: pipeline
-type: docker
-name: linux-amd64
-
-platform:
-  arch: amd64
-  os: linux
-
-steps:
-- name: test
-  image: docker.io/drycc/go-dev
-  pull: always
-  privileged: true
-  commands:
-  - make docker-build test
-  environment:
-    VERSION: ${DRONE_TAG:-latest}-linux-amd64
-    DEV_REGISTRY: ${DEV_REGISTRY:-docker.io}
-    DRYCC_REGISTRY: ${DRYCC_REGISTRY:-docker.io}
-  when:
-    event:
-    - push
-    - tag
-    - pull_request
-  volumes:
-  - name: image_registries
-    path: /etc/containers/registries.conf
-
-- name: publish
-  image: docker.io/drycc/go-dev
-  pull: always
-  privileged: true
-  commands:
-  - echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin
-  - make docker-build docker-immutable-push
-  environment:
-    VERSION: ${DRONE_TAG:-latest}-linux-amd64
-    DEV_REGISTRY:
-      from_secret: dev_registry
-    DRYCC_REGISTRY:
-      from_secret: drycc_registry
-    DOCKER_USERNAME:
-      from_secret: docker_username
-    DOCKER_PASSWORD:
-      from_secret: docker_password
-  when:
-    event:
-    - push
-    - tag
-  volumes:
-  - name: image_registries
-    path: /etc/containers/registries.conf
-
-trigger:
-  event:
-  - push
-  - tag
-  - pull_request
-
-volumes:
-- name: image_registries
-  host:
-    path: /etc/containers/registries.conf
-
----
-kind: pipeline
-type: docker
-name: linux-arm64
-
-platform:
-  arch: arm64
-  os: linux
-
-steps:
-- name: publish
-  image: docker.io/drycc/go-dev
-  pull: always
-  privileged: true
-  commands:
-  - echo $DOCKER_PASSWORD | docker login --username $DOCKER_USERNAME --password-stdin
-  - make docker-build docker-immutable-push
-  environment:
-    VERSION: ${DRONE_TAG:-latest}-linux-arm64
-    DEV_REGISTRY:
-      from_secret: dev_registry
-    DRYCC_REGISTRY:
-      from_secret: drycc_registry
-    DOCKER_USERNAME:
-      from_secret: docker_username
-    DOCKER_PASSWORD:
-      from_secret: docker_password
-  volumes:
-  - name: image_registries
-    path: /etc/containers/registries.conf
-
-trigger:
-  event:
-  - push
-  - tag
-
-volumes:
-- name: image_registries
-  host:
-    path: /etc/containers/registries.conf
-
----
-kind: pipeline
-type: docker
-name: manifest
-
-steps:
-- name: generate manifest
-  image: docker.io/library/alpine
-  pull: always
-  commands:
-  - sed -i "s/docker.io/$${DRYCC_REGISTRY}/g" .drone/manifest.tmpl
-  environment:
-    DRYCC_REGISTRY:
-      from_secret: drycc_registry
-
-- name: publish
-  image: plugins/manifest
-  settings:
-    spec: .drone/manifest.tmpl
-    username:
-      from_secret: docker_username
-    password:
-      from_secret: docker_password
-  environment:
-    DEV_REGISTRY:
-      from_secret: dev_registry
-    DRYCC_REGISTRY:
-      from_secret: drycc_registry
-
-trigger:
-  event:
-  - push
-  - tag
-
-depends_on:
-- linux-amd64
-- linux-arm64
-
----
-kind: pipeline
-type: docker
-name: chart
-
-steps:
-- name: generate chart
-  image: docker.io/drycc/python-dev
-  commands:
-  - IMAGE_TAG=$([ ! -z $DRONE_TAG ] && echo ${DRONE_TAG:1} || echo \"canary\")
-  - sed -i "s/image_tag:\ \"canary\"/image_tag:\ $IMAGE_TAG/g" charts/imagebuilder/values.yaml
-  - helm package charts/imagebuilder --version ${DRONE_TAG:-v1.0.0}
-  - curl -u $CHARTMUSEUM_USERNAME:$CHARTMUSEUM_PASSWORD -F chart=@imagebuilder-${DRONE_TAG:-v1.0.0}.tgz "$CHARTMUSEUM_API/api/$([ -z $DRONE_TAG ] && echo testing || echo stable)/charts"
-  environment:
-    CHARTMUSEUM_USERNAME:
-      from_secret: chartmuseum_username
-    CHARTMUSEUM_PASSWORD:
-      from_secret: chartmuseum_password
-    CHARTMUSEUM_API:
-      from_secret: chartmuseum_api
-
-trigger:
-  event:
-  - push
-  - tag
diff --git a/.drone/manifest.tmpl b/.drone/manifest.tmpl
deleted file mode 100644
index 0faf9ca..0000000
--- a/.drone/manifest.tmpl
+++ /dev/null
@@ -1,19 +0,0 @@
-
-image: docker.io/drycc/imagebuilder:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}canary{{/if}}
-{{#if build.tags}}
-tags:
-{{#each build.tags}}
-  - {{this}}
-{{/each}}
-{{/if}}
-manifests:
-  -
-    image: docker.io/drycc/imagebuilder:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-amd64
-    platform:
-      architecture: amd64
-      os: linux
-  -
-    image: docker.io/drycc/imagebuilder:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-arm64
-    platform:
-      architecture: arm64
-      os: linux
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dbe9c82
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.vscode/
\ No newline at end of file
diff --git a/.woodpecker/build-linux.yml b/.woodpecker/build-linux.yml
new file mode 100644
index 0000000..ef4ecfd
--- /dev/null
+++ b/.woodpecker/build-linux.yml
@@ -0,0 +1,35 @@
+matrix:
+  platform:
+    - linux/amd64
+    - linux/arm64
+
+labels:
+  type: exec
+  platform: ${platform}
+
+steps:
+- name: publish-linux
+  image: bash
+  commands:
+  - export VERSION=$([ -z $CI_COMMIT_TAG ] && echo latest || echo $CI_COMMIT_TAG)-$(sed 's#/#-#g' <<< $CI_SYSTEM_PLATFORM)
+  - echo $CONTAINER_PASSWORD | podman login $DRYCC_REGISTRY --username $CONTAINER_USERNAME --password-stdin > /dev/null 2>&1
+  - make podman-build podman-immutable-push
+  environment:
+    CODENAME:
+      from_secret: codename
+    DEV_REGISTRY:
+      from_secret: dev_registry
+    DRYCC_REGISTRY:
+      from_secret: drycc_registry
+    CONTAINER_USERNAME:
+      from_secret: container_username
+    CONTAINER_PASSWORD:
+      from_secret: container_password
+  when:
+    event:
+    - push
+    - tag
+    - cron
+
+depends_on:
+- test-linux
\ No newline at end of file
diff --git a/.woodpecker/chart.yaml b/.woodpecker/chart.yaml
new file mode 100644
index 0000000..cfcd3ec
--- /dev/null
+++ b/.woodpecker/chart.yaml
@@ -0,0 +1,33 @@
+labels:
+  type: exec
+  platform: linux/amd64
+
+steps:
+- name: generate-chart
+  image: bash
+  commands:
+  - export VERSION=$(sed 's#v##' <<< $CI_COMMIT_TAG)
+  - export IMAGE_TAG=$([ ! -z $CI_COMMIT_TAG ] && echo \"$VERSION\" || echo \"canary\")
+  - export APP_VERSION=$([ -z $CI_COMMIT_TAG ] && echo $CI_COMMIT_SHA || echo $VERSION)
+  - export CHART_VERSION=$([ -z $CI_COMMIT_TAG ] && echo 1.0.0 || echo $VERSION)
+  - sed -i "s/imageTag:\ \"canary\"/imageTag:\ $IMAGE_TAG/g" charts/$${CI_REPO_NAME}/values.yaml
+  - helm package -u charts/$${CI_REPO_NAME} --version $CHART_VERSION --app-version $APP_VERSION
+  - echo $CONTAINER_PASSWORD | helm registry login $DRYCC_REGISTRY -u $CONTAINER_USERNAME --password-stdin
+  - helm push $${CI_REPO_NAME}-$CHART_VERSION.tgz oci://$DRYCC_REGISTRY/$([ -z $CI_COMMIT_TAG ] && echo charts-testing || echo charts)
+  environment:
+    DEV_REGISTRY:
+      from_secret: dev_registry
+    DRYCC_REGISTRY:
+      from_secret: drycc_registry
+    CONTAINER_USERNAME:
+      from_secret: container_username
+    CONTAINER_PASSWORD:
+      from_secret: container_password
+  when:
+    event:
+    - push
+    - tag
+    - cron
+
+depends_on:
+- manifest
diff --git a/.woodpecker/manifest.tmpl b/.woodpecker/manifest.tmpl
new file mode 100644
index 0000000..8739535
--- /dev/null
+++ b/.woodpecker/manifest.tmpl
@@ -0,0 +1,18 @@
+image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{trimPrefix "v" build.tag}}{{else}}canary{{/if}}
+{{#if build.tags}}
+tags:
+{{#each build.tags}}
+  - {{this}}
+{{/each}}
+{{/if}}
+manifests:
+  -
+    image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-amd64
+    platform:
+      architecture: amd64
+      os: linux
+  -
+    image: registry.drycc.cc/drycc/{{project}}:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-arm64
+    platform:
+      architecture: arm64
+      os: linux
diff --git a/.woodpecker/manifest.yml b/.woodpecker/manifest.yml
new file mode 100644
index 0000000..19fc70c
--- /dev/null
+++ b/.woodpecker/manifest.yml
@@ -0,0 +1,43 @@
+labels:
+  type: exec
+  platform: linux/amd64
+
+steps:
+- name: generate-manifest
+  image: bash
+  commands:
+  - sed -i "s/{{project}}/$${CI_REPO_NAME}/g" .woodpecker/manifest.tmpl
+  - sed -i "s/registry.drycc.cc/$${DRYCC_REGISTRY}/g" .woodpecker/manifest.tmpl
+  environment:
+    DRYCC_REGISTRY:
+      from_secret: drycc_registry
+  when:
+    event:
+    - tag
+    - push
+    - cron
+
+- name: publish-manifest
+  image: bash
+  commands:
+  - podman run --rm
+    -e PLUGIN_SPEC=.woodpecker/manifest.tmpl
+    -e PLUGIN_USERNAME=$CONTAINER_USERNAME
+    -e PLUGIN_PASSWORD=$CONTAINER_PASSWORD
+    -e DRONE_TAG=$CI_COMMIT_TAG
+    -v $(pwd):$(pwd)
+    -w $(pwd)
+    docker.io/plugins/manifest
+  environment:
+    CONTAINER_USERNAME:
+      from_secret: container_username
+    CONTAINER_PASSWORD:
+      from_secret: container_password
+  when:
+    event:
+    - tag
+    - push
+    - cron
+
+depends_on:
+- build-linux
diff --git a/.woodpecker/test-linux.yml b/.woodpecker/test-linux.yml
new file mode 100644
index 0000000..194832f
--- /dev/null
+++ b/.woodpecker/test-linux.yml
@@ -0,0 +1,24 @@
+matrix:
+  platform:
+  - linux/amd64
+  - linux/arm64
+
+labels:
+  type: exec
+  platform: ${platform}
+
+steps:
+- name: test-linux
+  image: bash
+  commands:
+  - make test
+  environment:
+    CODENAME:
+      from_secret: codename
+    DEV_REGISTRY:
+      from_secret: dev_registry
+  when:
+    event:
+    - push
+    - tag
+    - cron
diff --git a/Makefile b/Makefile
index 4df1cd2..338c04b 100644
--- a/Makefile
+++ b/Makefile
@@ -4,11 +4,7 @@ PLATFORM ?= linux/amd64,linux/arm64
 
 export GO15VENDOREXPERIMENT=1
 
-# Note that Minio currently uses CGO.
-
-LDFLAGS := "-s -X main.version=${VERSION}"
 IMAGE_PREFIX ?= drycc
-BINDIR := ./rootfs/bin
 
 include versioning.mk
 
@@ -19,11 +15,11 @@ SHELL_SCRIPTS = $(wildcard _scripts/*.sh) \
 # The following variables describe the containerized development environment
 # and other build options
 DEV_ENV_IMAGE := ${DEV_REGISTRY}/drycc/go-dev
-DEV_ENV_WORK_DIR := /go/src/${REPO_PATH}
-DEV_ENV_CMD := docker run --rm -v ${CURDIR}:${DEV_ENV_WORK_DIR} -w ${DEV_ENV_WORK_DIR} ${DEV_ENV_IMAGE}
-DEV_ENV_CMD_INT := docker run -it --rm -v ${CURDIR}:${DEV_ENV_WORK_DIR} -w ${DEV_ENV_WORK_DIR} ${DEV_ENV_IMAGE}
+DEV_ENV_WORK_DIR := /opt/drycc/go/src/${REPO_PATH}
+DEV_ENV_CMD := podman run --rm -v ${CURDIR}:${DEV_ENV_WORK_DIR} -w ${DEV_ENV_WORK_DIR} ${DEV_ENV_IMAGE}
+DEV_ENV_CMD_INT := podman run -it --rm -v ${CURDIR}:${DEV_ENV_WORK_DIR} -w ${DEV_ENV_WORK_DIR} ${DEV_ENV_IMAGE}
 
-all: build docker-build docker-push
+all: build podman-build podman-push
 
 bootstrap:
 	@echo Nothing to do.
@@ -31,14 +27,11 @@ bootstrap:
 build:
 	@echo Nothing to do.
 
-docker-build:
-	docker build ${DOCKER_BUILD_FLAGS} -t ${IMAGE} -f rootfs/Dockerfile rootfs
-	docker tag ${IMAGE} ${MUTABLE_IMAGE}
-
-docker-buildx:
-	docker buildx build --platform ${PLATFORM} ${DOCKER_BUILD_FLAGS} -t ${IMAGE} -f rootfs/Dockerfile rootfs --push
+podman-build:
+	podman build ${CONTAINER_BUILD_FLAGS} --build-arg CODENAME=${CODENAME} -t ${IMAGE} -f rootfs/Dockerfile rootfs
+	podman tag ${IMAGE} ${MUTABLE_IMAGE}
 
-deploy: docker-build docker-push
+deploy: podman-build podman-push
 
 kube-pod: kube-service
 	kubectl create -f ${POD}
@@ -65,5 +58,5 @@ test-style:
 test-functional:
 	@echo "Implement functional tests in _tests directory"
 
-.PHONY: all bootstrap build docker-build docker-push deploy kube-pod kube-secrets \
+.PHONY: all bootstrap build podman-build podman-push deploy kube-pod kube-secrets \
 	secrets kube-service kube-clean test
diff --git a/README.md b/README.md
index 63a26c7..1702973 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
 # Drycc imagebuilder v3
-[![Build Status](https://drone.drycc.cc/api/badges/drycc/imagebuilder/status.svg)](https://drone.drycc.cc/drycc/imagebuilder)
+[![Build Status](https://woodpecker.drycc.cc/api/badges/drycc/imagebuilder/status.svg)](https://woodpecker.drycc.cc/drycc/imagebuilder)
 
 Drycc (pronounced DAY-iss) Workflow is an open source Platform as a Service (PaaS) that adds a developer-friendly layer to any [Kubernetes](http://kubernetes.io) cluster, making it easy to deploy and manage applications on your own servers.
 
@@ -7,13 +7,27 @@ For more information about the Drycc Workflow, please visit the main project pag
 
 We welcome your input! If you have feedback, please [submit an issue][issues]. If you'd like to participate in development, please read the "Development" section below and [submit a pull request][prs].
 
-# About
+# Build config
 
 The V3 version of imagebuilder unifies the building model, uses the latest CNCF [buildpack](https://github.com/buildpacks) building program, and also supports the dockerfile format.
 
 You can use `DRYCC_STACK` specifies the construction mode. Currently, you can choose two construction formats: `container` and `buildpack`.
 
-# Development
+## Build arg config
+
+In Container Build, build arguments (ARG) a means to pass information into the build process. You can use them to parameterize the build, allowing for more flexible and configurable builds.
+
+It can be configured through `.build-arg`, argument=value to supply to the builder, this configuration file is universal in both container and buildpack scenarios.
+
+## Container config
+
+Normally, in container mode, as long as there is a Dockerfile in the root directory, it is sufficient, but we can use [drycc config path](https://www.drycc.cc/docs/applications/using-dryccpath/) to configure the build process more finely.
+
+## Buildpack config
+
+Add an empty `.clean_cache` file, clear image's associated cache before building.
+
+## Development
 
 The Drycc project welcomes contributions from all developers. The high level process for development matches many other open source projects. See below for an outline.
 
diff --git a/charts/imagebuilder/Chart.yaml b/charts/imagebuilder/Chart.yaml
index 5270ef8..ea04b30 100644
--- a/charts/imagebuilder/Chart.yaml
+++ b/charts/imagebuilder/Chart.yaml
@@ -1,5 +1,7 @@
 name: imagebuilder
 home: https://github.com/drycc/imagebuilder
+apiVersion: v2
+appVersion: 1.0.0
 version: v1.0.0
 description: Imagebuilder application builder for Drycc Workflow.
 maintainers:
diff --git a/charts/imagebuilder/templates/imagebuilder-configmap.yaml b/charts/imagebuilder/templates/imagebuilder-configmap.yaml
index 6c63880..490b705 100644
--- a/charts/imagebuilder/templates/imagebuilder-configmap.yaml
+++ b/charts/imagebuilder/templates/imagebuilder-configmap.yaml
@@ -5,17 +5,26 @@ metadata:
   labels:
     heritage: drycc
 data:
+  buildpacks: "{{.Values.imageRegistry}}/{{.Values.imageOrg}}/buildpacks:{{.Values.codename}}"
+  auths.json: |
+    {
+        "auths": {
+            "registry.drycc.cc": {
+              "auth": "YW5vbnltb3VzOmFub255bW91cw=="
+            }
+        }
+    }
   images.json: |
     [
         {
             "name": "container",
-            "image": "{{.Values.image_registry}}/{{.Values.image_org}}/imagebuilder:{{.Values.image_tag}}"
+            "image": "{{.Values.imageRegistry}}/{{.Values.imageOrg}}/imagebuilder:{{.Values.imageTag}}"
         },
         {
             "name": "buildpack",
-            "image": "{{.Values.image_registry}}/{{.Values.image_org}}/imagebuilder:{{.Values.image_tag}}"
+            "image": "{{.Values.imageRegistry}}/{{.Values.imageOrg}}/imagebuilder:{{.Values.imageTag}}"
         }
     ]
   registries.conf: |
-    {{- .Values.container_registries | nindent 4 }}
-  image_pull_policy: {{ .Values.image_pull_policy }}
+    {{- .Values.containerRegistries | nindent 4 }}
+  imagePullPolicy: {{ .Values.imagePullPolicy }}
diff --git a/charts/imagebuilder/templates/imagebuilder-networkpolicy.yaml b/charts/imagebuilder/templates/imagebuilder-networkpolicy.yaml
new file mode 100644
index 0000000..767af80
--- /dev/null
+++ b/charts/imagebuilder/templates/imagebuilder-networkpolicy.yaml
@@ -0,0 +1,47 @@
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: drycc-imagebuilder
+spec:
+  podSelector:
+    matchLabels:
+      app: drycc-imagebuilder
+  policyTypes:
+  - Egress
+  egress:
+  - to:
+    ports:
+    - protocol: UDP
+      port: 53
+  - to:
+    - ipBlock:
+        cidr: ::/0
+        except:
+        - fc00::/7
+  - to:
+    - ipBlock:
+        cidr: 0.0.0.0/0
+        except:
+        - 10.0.0.0/8
+        - 172.16.0.0/12
+        - 192.168.0.0/16
+  - to:
+    - namespaceSelector:
+        matchLabels:
+          kubernetes.io/metadata.name: {{ .Release.Name }}
+    - podSelector:
+        matchLabels:
+          app: drycc-registry
+    ports:
+    - protocol: TCP
+      port: 5000
+  - to:
+    - namespaceSelector:
+        matchLabels:
+          kubernetes.io/metadata.name: {{ .Release.Name }}
+    - podSelector:
+        matchLabels:
+          app: drycc-storage
+    ports:
+    - protocol: TCP
+      port: 9000
diff --git a/charts/imagebuilder/values.yaml b/charts/imagebuilder/values.yaml
index 4d1ff78..60ec3bc 100644
--- a/charts/imagebuilder/values.yaml
+++ b/charts/imagebuilder/values.yaml
@@ -1,7 +1,8 @@
-image_org: "drycc"
-image_pull_policy: "Always"
-image_tag: "canary"
-image_registry: "docker.io"
-container_registries: |
-  unqualified-search-registries = ["docker.io"]
-  short-name-mode="permissive"
\ No newline at end of file
+imageOrg: "drycc"
+imagePullPolicy: "Always"
+imageTag: "canary"
+imageRegistry: "registry.drycc.cc"
+codename: trixie
+containerRegistries: |
+  unqualified-search-registries = ["registry.drycc.cc"]
+  short-name-mode="permissive"
diff --git a/rootfs/.dockerignore b/rootfs/.dockerignore
index 1d8b3c2..06bf924 100644
--- a/rootfs/.dockerignore
+++ b/rootfs/.dockerignore
@@ -1 +1 @@
-Dockerfile.*
+Dockerfile.*
\ No newline at end of file
diff --git a/rootfs/Dockerfile b/rootfs/Dockerfile
index a4844cc..e14ea5d 100644
--- a/rootfs/Dockerfile
+++ b/rootfs/Dockerfile
@@ -1,17 +1,47 @@
-FROM docker.io/minio/mc:latest as mc
-FROM docker.io/drycc/go-dev:latest as go-dev
+ARG CODENAME
+FROM registry.drycc.cc/drycc/base:${CODENAME}
 
-FROM quay.io/containers/podman:latest
+ARG DRYCC_UID=1001 \
+  DRYCC_GID=1001 \
+  DRYCC_HOME_DIR=/home/drycc \
+  JQ_VERSION="1.7.1" \
+  YQ_VERSION="4.48.1" \
+  PODMAN_VERSION="5.7.0" \
+  RCLONE_VERSION="1.71.2" \
+  CADDY_VERSION="2.10.2" \
+  PACK_VERSION="0.38.2" \
+  GOSU_VERSION="1.19"
+
+RUN groupadd drycc --gid ${DRYCC_GID} \
+  && useradd drycc -u ${DRYCC_UID} -g ${DRYCC_GID} -s /bin/bash -m -d ${DRYCC_HOME_DIR}
 
 ADD . /
-COPY --from=mc /usr/bin/mc /bin/mc
-COPY --from=go-dev /usr/local/bin/pack /bin/pack
 
-RUN /imagebuilder/install
+RUN install-packages procps psmisc \
+  && install-stack jq $JQ_VERSION \
+  && install-stack yq $YQ_VERSION \
+  && install-stack podman $PODMAN_VERSION \
+  && install-stack rclone $RCLONE_VERSION \
+  && install-stack caddy $CADDY_VERSION \
+  && install-stack pack $PACK_VERSION \
+  && install-stack gosu $GOSU_VERSION \
+  && usermod --add-subuids 200000-201000 --add-subgids 200000-201000 drycc \
+  && chown -R ${DRYCC_UID}:${DRYCC_GID} /opt/drycc \
+  && rm -rf \
+      /usr/share/doc \
+      /usr/share/man \
+      /usr/share/info \
+      /usr/share/locale \
+      /var/lib/apt/lists/* \
+      /var/log/* \
+      /var/cache/debconf/* \
+      /etc/systemd \
+      /lib/lsb \
+      /lib/udev \
+      /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/IBM* \
+      /usr/lib/`echo $(uname -m)`-linux-gnu/gconv/EBC* \
+  && mkdir -p /usr/share/man/man{1..8}
 
-WORKDIR /app
-ENV HOME /tmp
-ENV XDG_DATA_HOME /tmp
-ENV XDG_CONFIG_HOME /tmp/.config
+WORKDIR /workspace
 
-ENTRYPOINT ["/imagebuilder/build"]
\ No newline at end of file
+ENTRYPOINT ["init-stack", "/imagebuilder/prebuild", "/imagebuilder/build"]
diff --git a/rootfs/imagebuilder/build b/rootfs/imagebuilder/build
index 49d4d1a..a78d0ee 100755
--- a/rootfs/imagebuilder/build
+++ b/rootfs/imagebuilder/build
@@ -1,7 +1,14 @@
 #!/usr/bin/env bash
 set -eo pipefail
 shopt -s expand_aliases
-alias podman="podman --cgroup-manager=cgroupfs --events-backend=file"
+
+log_level="error"
+if [[ "${DRYCC_DEBUG}" ]]; then
+    log_level="debug"
+    unset DRYCC_DEBUG
+fi
+
+alias podman='podman --log-level ${log_level} --cgroup-manager=cgroupfs --events-backend=file'
 
 function clean_before_exit {
     # delay before exiting, so stdout/stderr flushes through the logging system
@@ -29,102 +36,170 @@ function waiting_process {
     done
 }
 
-# Start podman service
-export DOCKER_PORT=1234
-export DOCKER_HOST=tcp://127.0.0.1:${DOCKER_PORT}
+function podman_publish {
+    local image dockerfile
+    image=$1
+    dockerfile=$2
 
-log_level="error"
-if [[ "${DRYCC_DEBUG}" ]]; then
-    log_level="debug"
-    unset DRYCC_DEBUG
+    podman_build="podman build . -f ${dockerfile} --tag ${image} --network host"
+    podman_push="podman push ${image} --tls-verify=false"
+    # append build arg
+    for build_arg in $( < "${envfile}" )
+    do
+        podman_build="$podman_build --build-arg $build_arg"
+    done
+    # append ptype build arg
+    if [[ -n "$3" ]]; then
+        for build_arg in $( < "${3}" )
+        do
+            podman_build="$podman_build --build-arg $build_arg"
+        done
+    fi
+    # build and push
+    $podman_build
+    $podman_push
+}
+
+function write_build_env {
+    local envfile dryccfile config items i
+    envfile=$1
+    dryccfile=$2
+    if [[ -f "$dryccfile" ]]; then
+        config=$(cat < "$dryccfile" | yq ".build.arg" -o json)
+        if [[ $config != null ]]; then
+            mapfile -t items < <(echo "$config" | jq -c -r 'to_entries[] | (.key, .value)')
+            for ((i=0; i<"${#items[@]}"; i=i+2)); do
+                echo "${items[i]}=${items[i+1]}" >> "${envfile}"
+            done
+        fi
+    fi
+}
+
+CONTAINERS_CONFIG_DIR="${HOME}"/.config/containers
+mkdir -p "${CONTAINERS_CONFIG_DIR}"
+from_registries_file="/etc/imagebuilder/registries.conf"
+cp -rf /opt/drycc/podman/etc/containers/* "${CONTAINERS_CONFIG_DIR}"
+if [ -f "${from_registries_file}" ]; then
+    install -D  "${from_registries_file}" "${CONTAINERS_CONFIG_DIR}"/registries.conf
 fi
 
-registries="/etc/imagebuilder/registries.conf"
-if [ -f "${registries}" ]; then
-    cat "${registries}" > /etc/containers/registries.conf
+# The directory cannot be changed, the position is hard coded, pack cli needs to be used.
+# https://github.com/buildpacks/pack/blob/main/internal/docker/context.go
+REGISTRY_AUTH_FILE="${HOME}"/.docker/config.json
+readonly REGISTRY_AUTH_FILE
+from_auths_file="/etc/imagebuilder/auths.json"
+if [ -f "${from_auths_file}" ]; then
+    install -D "${from_auths_file}" "${REGISTRY_AUTH_FILE}"
 fi
+export REGISTRY_AUTH_FILE
 
-podman system service --time 0 tcp:0.0.0.0:${DOCKER_PORT} &
+# fix: failed to reexec: Permission denied
+podman version>/dev/null 2>&1 || podman version
+# podman service
+podman system service --time 0 &
 
 waiting_process podman
 if [[ -n "${TAR_PATH}" ]]; then
     get_object
-    tar -xzf /tmp/app.tgz -C /app/ && unset TAR_PATH
+    tar -xzf /tmp/app.tgz -C /workspace/ && unset TAR_PATH
 fi
 
-pack_builder="docker.io/drycc/buildpacks:20"
+pack_builder=$(< /etc/imagebuilder/buildpacks tr -d '[:space:]')
 if [[ -f .pack-builder ]]; then
     pack_builder=$(< .pack-builder tr -d '[:space:]')
 fi
 
 # Get registry and login
 if [[ "${DRYCC_REGISTRY_LOCATION}" == "off-cluster" ]] ; then
-    registry="${DRYCC_REGISTRY_HOSTNAME}/${DRYCC_REGISTRY_ORGANIZATION}"
     podman login \
         --username "${DRYCC_REGISTRY_USERNAME}" \
         --password "${DRYCC_REGISTRY_PASSWORD}" \
-        "${DRYCC_REGISTRY_HOSTNAME}" \
+        "${DRYCC_REGISTRY_HOST}" \
         --tls-verify=false > /dev/null
 else
     # Start registry proxy
-    registry="${DRYCC_REGISTRY_PROXY_HOST}:${DRYCC_REGISTRY_PROXY_PORT}"
-    if [[ ${log_level} == "debug" ]] ; then
-        output="/dev/stdout"
-    else
-        output="/dev/null"
+    DRYCC_REGISTRY_PROXY_HOST="${DRYCC_REGISTRY_PROXY_HOST:?DRYCC_REGISTRY_PROXY_HOST env required}"
+    DRYCC_REGISTRY_PROXY_PORT=$(echo "${DRYCC_REGISTRY_PROXY_HOST}" | awk -F ':' '{print $2}')
+    caddy_command="caddy reverse-proxy \
+        --from :${DRYCC_REGISTRY_PROXY_PORT} \
+        --to ${DRYCC_REGISTRY_HOST}"
+    if [[ ${log_level} != "debug" ]] ; then
+        caddy_command="${caddy_command} > /dev/null"
     fi
-    caddy reverse-proxy \
-        --from ":${DRYCC_REGISTRY_PROXY_PORT}" \
-        --to "${DRYCC_REGISTRY_SERVICE_HOST}:${DRYCC_REGISTRY_SERVICE_PORT}" \
-        > "${output}" 2>&1 &
+    $caddy_command 2>&1 &
     waiting_process caddy
     podman login \
-        --username drycc \
-        --password drycc \
-        --tls-verify=false "${registry}" \
-        > /dev/null
+        --username "${DRYCC_REGISTRY_USERNAME}" \
+        --password "${DRYCC_REGISTRY_PASSWORD}" \
+        "${DRYCC_REGISTRY_PROXY_HOST}" \
+        --tls-verify=false > /dev/null
 fi
 
-# Get image name and image tag
-image_name=$(echo "${IMG_NAME}" | awk -F ':' '{print $1}')
-image_tag=$(echo "${IMG_NAME}" | awk -F ':' '{print $2}')
-image_repo="${registry}/${image_name}:${image_tag}"
-image_cache_repo="${registry}/${image_name}:cache"
-image_latest_repo="${registry}/${image_name}:latest"
+# create global build-arg
+envfile="${HOME}"/.config/build-arg
+echo "" > "${envfile}"
+if [[ -f .build-arg ]] ; then
+    cat .build-arg >> "${envfile}"
+fi
 
 # Building
 if [[ "${DRYCC_STACK}" == "container" ]] ; then
-    echo "---> Building container"
-    if [[ $log_level == "debug" ]] ; then
-        podman build --tag"${image_repo}" --network host .
-        podman push "${image_repo}" --tls-verify=false
-    else
-        podman build --quiet --tag "${image_repo}" --network host .
-        podman push "${image_repo}" --quiet --tls-verify=false
+    if [[ -d ".drycc" ]]; then
+        for dryccfile in $(find .drycc | grep -E '.(yml|yaml)$'); do
+            ptype=$(cat < "$dryccfile" | yq .ptype -o auto)
+            build=$(cat < "$dryccfile" | yq .build -o json)
+            if [[ "$build" != "null" ]]; then
+                dockerfile=$(echo "$build" | jq -r '.docker // "Dockerfile"')
+                if [[ "${ptype}" == "web" ]]; then
+                    image="${IMAGE_NAME}"
+                else
+                    image="${IMAGE_NAME}"-"${ptype}"
+                fi
+                # create ptype build-arg
+                ptype_envfile="${HOME}/.config/build-arg-${ptype}"
+                echo "" > "$ptype_envfile"
+                write_build_env "$ptype_envfile" "$dryccfile"
+                podman_publish "${image}" "${dockerfile}" "${ptype_envfile}"
+            fi
+        done
+    fi
+    # build default image
+    if [[ -f "Dockerfile" ]] && [[ $(podman images -q "${IMAGE_NAME}") == "" ]]; then
+        podman_publish "${IMAGE_NAME}" "Dockerfile"
     fi
 else
     echo "---> Building pack"
     echo "---> Using builder ${pack_builder}"
-    if [[ $log_level == "debug" ]] ; then
-        pack build "${image_repo}" \
-            --builder "${pack_builder}" \
-            --docker-host "${DOCKER_HOST}" \
-            --previous-image "${image_latest_repo}" \
-            --trust-builder \
-            --publish \
-            --cache-image "${image_cache_repo}" \
-            --tag "${image_latest_repo}" \
-            --network host \
-            --verbose
-    else
-        pack build "${image_repo}" \
-            --builder "${pack_builder}" \
-            --docker-host "${DOCKER_HOST}" \
-            --previous-image "${image_latest_repo}" \
-            --trust-builder \
+    # podman connection
+    DOCKER_HOST="unix://$(podman info -f '{{.Host.RemoteSocket.Path}}')"
+    readonly DOCKER_HOST
+    export DOCKER_HOST
+    # Get image name and image tag
+    drycc_app=$(echo "${IMAGE_NAME}" | awk -F '/' '{print $NF}' | awk -F ':' '{print $1}')
+    image_tag=$(echo "${IMAGE_NAME}" | awk -F ':' '{print $NF}')
+    image_base_name=$(echo "${IMAGE_NAME}" | sed -s "s#:${image_tag}##g")
+    image_cache_name="${image_base_name}":cache
+    image_latest_name="${image_base_name}":latest
+    pack_build="pack build ${IMAGE_NAME} \
+            --builder ${pack_builder} \
+            --lifecycle-image ${pack_builder} \
+            --env DRYCC_APP=${drycc_app} \
+            --docker-host ${DOCKER_HOST} \
+            --previous-image ${image_latest_name} \
             --publish \
-            --cache-image "${image_cache_repo}" \
-            --tag "${image_latest_repo}" \
-            --network host
+            --cache-image ${image_cache_name} \
+            --tag ${image_latest_name} \
+            --default-process web \
+            --env-file ${envfile} \
+            --network host"
+    # fix(pack): PACK_VOLUME_KEY is unset
+    PACK_VOLUME_KEY=${drycc_app}
+    export PACK_VOLUME_KEY
+    if [[ $log_level == "debug" ]] ; then
+        pack_build="$pack_build --verbose"
+    fi
+    if [[ -f .clear-cache ]]; then
+        pack_build="$pack_build --clear-cache"
     fi
-fi
\ No newline at end of file
+    $pack_build
+fi
diff --git a/rootfs/imagebuilder/install b/rootfs/imagebuilder/install
deleted file mode 100755
index 0cb0542..0000000
--- a/rootfs/imagebuilder/install
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bash
-set -eo pipefail
-
-# initArch discovers the architecture for this system.
-init_arch() {
-  ARCH=$(uname -m)
-  case $ARCH in
-    armv5*) ARCH="armv5";;
-    armv6*) ARCH="armv6";;
-    armv7*) ARCH="arm";;
-    aarch64) ARCH="arm64";;
-    x86) ARCH="386";;
-    x86_64) ARCH="amd64";;
-    i686) ARCH="386";;
-    i386) ARCH="386";;
-  esac
-}
-init_arch
-
-CADDY_DOWNLOAD_URL="https://github.com/caddyserver/caddy/releases/download/v2.4.5/caddy_2.4.5_linux_${ARCH}.tar.gz"
-(curl -sSL "${CADDY_DOWNLOAD_URL}" | tar -C /usr/local/bin/ --no-same-owner -xzv caddy)
-
-dnf install -yq procps-ng psmisc
-
-dnf clean all
-rm -rf /root/*
-rm -rf /tmp/*
\ No newline at end of file
diff --git a/rootfs/imagebuilder/prebuild b/rootfs/imagebuilder/prebuild
new file mode 100755
index 0000000..5e43335
--- /dev/null
+++ b/rootfs/imagebuilder/prebuild
@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+set -e
+
+mount --make-rshared /
+chown "${DRYCC_UID}":"${DRYCC_GID}" -R /workspace
+exec gosu "${DRYCC_UID}" "$@"
\ No newline at end of file
diff --git a/rootfs/usr/local/bin/get_object b/rootfs/usr/local/bin/get_object
index e6e90ea..6f0a3ac 100755
--- a/rootfs/usr/local/bin/get_object
+++ b/rootfs/usr/local/bin/get_object
@@ -1,6 +1,18 @@
 #!/usr/bin/env bash
+
+mkdir -p ~/.config/rclone
+touch ~/.config/rclone/rclone.conf
+rclone config create storage s3 \
+  provider=Other \
+  access_key_id="${DRYCC_STORAGE_ACCESSKEY}" \
+  secret_access_key="${DRYCC_STORAGE_SECRETKEY}" \
+  endpoint="${DRYCC_STORAGE_ENDPOINT}" \
+  force_path_style="${DRYCC_STORAGE_PATH_STYLE:-true}" --no-output
+
 GET_PATH=/tmp/app.tgz
-# shellcheck disable=SC1091
-source /usr/local/bin/normalize_storage
 
-mc cp minio/"${MINIO_BUCKET}/${TAR_PATH}" "${GET_PATH}" &>/tmp/objstorage.log
+if ! rclone lsd storage: > /dev/null 2>&1; then
+  sleep 9s
+  echo "waiting for object storage to become ready..."
+fi
+rclone copyto storage:"${DRYCC_STORAGE_BUCKET}/${TAR_PATH}" "${GET_PATH}"
diff --git a/rootfs/usr/local/bin/normalize_storage b/rootfs/usr/local/bin/normalize_storage
deleted file mode 100755
index d7ccd8f..0000000
--- a/rootfs/usr/local/bin/normalize_storage
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env bash
-BUCKET_FILE="/var/run/secrets/drycc/objectstore/creds/builder-bucket"
-ACCESS_KEY_FILE="/var/run/secrets/drycc/objectstore/creds/accesskey"
-SECRET_KEY_FILE="/var/run/secrets/drycc/objectstore/creds/secretkey"
-
-if [ -f $BUCKET_FILE ]; then
-  MINIO_BUCKET=$(cat "$BUCKET_FILE")
-  export MINIO_BUCKET
-fi
-if [ -f $ACCESS_KEY_FILE ]; then
-  MINIO_ACCESS_KEY=$(cat "$ACCESS_KEY_FILE")
-  export MINIO_ACCESS_KEY
-fi
-if [ -f $SECRET_KEY_FILE ]; then
-  MINIO_SECRET_KEY=$(cat "$SECRET_KEY_FILE")
-  export MINIO_SECRET_KEY
-fi
-
-export MINIO_ENDPOINT=http://"${DRYCC_MINIO_SERVICE_HOST}:${DRYCC_MINIO_SERVICE_PORT}"
-
-mc config host add minio "${MINIO_ENDPOINT}" "${MINIO_ACCESS_KEY}" "${MINIO_SECRET_KEY}" &>/tmp/objstorage.log
diff --git a/versioning.mk b/versioning.mk
index a9523f7..072dd72 100644
--- a/versioning.mk
+++ b/versioning.mk
@@ -1,6 +1,6 @@
 MUTABLE_VERSION ?= canary
 VERSION ?= git-$(shell git rev-parse --short HEAD)
-DOCKER_BUILD_FLAGS ?= --pull
+CONTAINER_BUILD_FLAGS ?= --pull
 
 IMAGE := ${DRYCC_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${VERSION}
 MUTABLE_IMAGE := ${DRYCC_REGISTRY}/${IMAGE_PREFIX}/${SHORT_NAME}:${MUTABLE_VERSION}
@@ -11,13 +11,13 @@ info:
 	@echo "Immutable tag:   ${IMAGE}"
 	@echo "Mutable tag:     ${MUTABLE_IMAGE}"
 
-.PHONY: docker-push
-docker-push: docker-immutable-push docker-mutable-push
+.PHONY: podman-push
+podman-push: podman-immutable-push podman-mutable-push
 
-.PHONY: docker-immutable-push
-docker-immutable-push:
-	docker push ${IMAGE}
+.PHONY: podman-immutable-push
+podman-immutable-push:
+	podman push ${IMAGE}
 
-.PHONY: docker-mutable-push
-docker-mutable-push:
-	docker push ${MUTABLE_IMAGE}
+.PHONY: podman-mutable-push
+podman-mutable-push:
+	podman push ${MUTABLE_IMAGE}
