diff --git a/.drone/drone.yml b/.drone/drone.yml
new file mode 100644
index 000000000..67c5c698f
--- /dev/null
+++ b/.drone/drone.yml
@@ -0,0 +1,151 @@
+kind: pipeline
+type: docker
+name: linux-amd64
+
+platform:
+  arch: amd64
+  os: linux
+
+steps:
+- name: test
+  image: docker.io/drycc/go-dev
+  pull: if-not-exists
+  privileged: true
+  commands:
+  - make test docker-build-test upload-coverage
+  environment:
+    VERSION: ${DRONE_TAG:-latest}-linux-amd64
+    DEV_REGISTRY: ${DEV_REGISTRY:-docker.io}
+    DRYCC_REGISTRY: ${DRYCC_REGISTRY:-docker.io}
+    CODECOV_TOKEN:
+      from_secret: codecov_token
+  when:
+    event:
+    - push
+    - tag
+    - pull_request
+
+- name: publish
+  image: docker.io/drycc/go-dev
+  pull: if-not-exists
+  privileged: true
+  commands:
+  - echo $DOCKER_PASSWORD | docker login $DRYCC_REGISTRY --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
+
+trigger:
+  event:
+  - push
+  - tag
+  - pull_request
+
+---
+kind: pipeline
+type: docker
+name: linux-arm64
+
+platform:
+  arch: arm64
+  os: linux
+
+steps:
+- name: publish
+  image: docker.io/drycc/go-dev
+  pull: if-not-exists
+  privileged: true
+  commands:
+  - echo $DOCKER_PASSWORD | docker login $DRYCC_REGISTRY --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
+
+trigger:
+  event:
+  - push
+  - tag
+
+---
+kind: pipeline
+type: docker
+name: manifest
+
+steps:
+- name: generate manifest
+  image: docker.io/library/alpine
+  pull: if-not-exists
+  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/controller/values.yaml
+  - helm package charts/controller --version ${DRONE_TAG:-v1.0.0}
+  - curl -u $CHARTMUSEUM_USERNAME:$CHARTMUSEUM_PASSWORD -F chart=@controller-${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
new file mode 100644
index 000000000..f9a049c18
--- /dev/null
+++ b/.drone/manifest.tmpl
@@ -0,0 +1,18 @@
+image: docker.io/drycc/controller:{{#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/controller:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-amd64
+    platform:
+      architecture: amd64
+      os: linux
+  -
+    image: docker.io/drycc/controller:{{#if build.tag}}{{build.tag}}-{{else}}latest-{{/if}}linux-arm64
+    platform:
+      architecture: arm64
+      os: linux
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 040b8db6a..000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-sudo: required
-language: go
-services:
-  - docker
-script: 
-  - DEV_REGISTRY="docker.io" make test
-  - DEV_REGISTRY="docker.io" make docker-build-test upload-coverage
-notifications:
-  slack:
-    rooms:
-      - drycc:xKmLlmJR4hfRAgVIOwdpAoC9#drycc
diff --git a/README.md b/README.md
index 121880c67..71461deed 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 
 # Drycc Controller
 
-[![Build Status](https://travis-ci.org/drycc/controller.svg?branch=main)](https://travis-ci.org/drycc/controller)
+[![Build Status](https://drone.drycc.cc/api/badges/drycc/controller/status.svg)](https://drone.drycc.cc/drycc/controller)
 [![codecov.io](https://codecov.io/github/drycc/controller/coverage.svg?branch=main)](https://codecov.io/github/drycc/controller?branch=main)
 
 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.
