diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..bec10c10c972ff01fba8e75eb4c3321f53e648f2
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,3 @@
+./.dapper
+./.cache
+./dist
diff --git a/.drone.yml b/.drone.yml
new file mode 100644
index 0000000000000000000000000000000000000000..c03ca8ae2575858b1764d3051264937031897ddd
--- /dev/null
+++ b/.drone.yml
@@ -0,0 +1,221 @@
+---
+kind: pipeline
+name: amd64
+
+platform:
+  os: linux
+  arch: amd64
+
+steps:
+- name: build
+  image: rancher/dapper:v0.4.1
+  commands:
+  - dapper ci
+  volumes:
+  - name: docker
+    path: /var/run/docker.sock
+
+- name: github_binary_release
+  image: plugins/github-release
+  settings:
+    api_key:
+      from_secret: github_token
+    prerelease: true
+    checksum:
+    - sha256
+    checksum_file: CHECKSUMsum-amd64.txt
+    checksum_flatten: true
+    files:
+    - "dist/artifacts/*"
+  when:
+    instance:
+    - drone-publish.rancher.io
+    ref:
+    - refs/head/master
+    - refs/tags/*
+    event:
+    - tag
+
+- name: docker-publish
+  image: plugins/docker
+  settings:
+    dockerfile: package/Dockerfile
+    password:
+      from_secret: docker_password
+    repo: "rancher/local-path-provisioner"
+    tag: "${DRONE_TAG}-amd64"
+    username:
+      from_secret: docker_username
+  when:
+    instance:
+    - drone-publish.rancher.io
+    ref:
+    - refs/head/master
+    - refs/tags/*
+    event:
+    - tag
+
+volumes:
+- name: docker
+  host:
+    path: /var/run/docker.sock
+
+---
+kind: pipeline
+name: arm64
+
+platform:
+  os: linux
+  arch: arm64
+
+steps:
+- name: build
+  image: rancher/dapper:v0.4.1
+  commands:
+  - dapper ci
+  volumes:
+  - name: docker
+    path: /var/run/docker.sock
+
+- name: github_binary_release
+  image: plugins/github-release
+  settings:
+    api_key:
+      from_secret: github_token
+    prerelease: true
+    checksum:
+    - sha256
+    checksum_file: CHECKSUMsum-arm64.txt
+    checksum_flatten: true
+    files:
+    - "dist/artifacts/*"
+  when:
+    instance:
+    - drone-publish.rancher.io
+    ref:
+    - refs/head/master
+    - refs/tags/*
+    event:
+    - tag
+
+- name: docker-publish
+  image: plugins/docker
+  settings:
+    dockerfile: package/Dockerfile
+    password:
+      from_secret: docker_password
+    repo: "rancher/local-path-provisioner"
+    tag: "${DRONE_TAG}-arm64"
+    username:
+      from_secret: docker_username
+  when:
+    instance:
+    - drone-publish.rancher.io
+    ref:
+    - refs/head/master
+    - refs/tags/*
+    event:
+    - tag
+
+volumes:
+- name: docker
+  host:
+    path: /var/run/docker.sock
+
+---
+kind: pipeline
+name: arm
+
+platform:
+  os: linux
+  arch: arm
+
+steps:
+- name: build
+  image: rancher/dapper:v0.4.1
+  commands:
+  - dapper ci
+  volumes:
+  - name: docker
+    path: /var/run/docker.sock
+
+- name: github_binary_release
+  image: plugins/github-release
+  settings:
+    api_key:
+      from_secret: github_token
+    prerelease: true
+    checksum:
+    - sha256
+    checksum_file: CHECKSUMsum-arm.txt
+    checksum_flatten: true
+    files:
+    - "dist/artifacts/*"
+  when:
+    instance:
+    - drone-publish.rancher.io
+    ref:
+    - refs/head/master
+    - refs/tags/*
+    event:
+    - tag
+
+- name: docker-publish
+  image: plugins/docker
+  settings:
+    dockerfile: package/Dockerfile
+    password:
+      from_secret: docker_password
+    repo: "rancher/local-path-provisioner"
+    tag: "${DRONE_TAG}-arm"
+    username:
+      from_secret: docker_username
+  when:
+    instance:
+    - drone-publish.rancher.io
+    ref:
+    - refs/head/master
+    - refs/tags/*
+    event:
+    - tag
+
+volumes:
+- name: docker
+  host:
+    path: /var/run/docker.sock
+
+---
+kind: pipeline
+name: manifest
+
+platform:
+  os: linux
+  arch: amd64
+
+steps:
+- name: manifest
+  image: plugins/manifest:1.0.2
+  settings:
+    username:
+      from_secret: docker_username
+    password:
+      from_secret: docker_password
+    platforms:
+      - linux/amd64
+      - linux/arm64
+      - linux/arm
+    target: "rancher/local-path-provisioner:${DRONE_TAG}"
+    template: "rancher/local-path-provisioner:${DRONE_TAG}-ARCH"
+  when:
+    instance:
+    - drone-publish.rancher.io
+    ref:
+    - refs/head/master
+    - refs/tags/*
+    event:
+    - tag
+
+depends_on:
+- amd64
+- arm64
+- arm
diff --git a/.gitignore b/.gitignore
index cb26edc8987e9c4416ffad744b62eafe9b41ada8..4d32884980d2ff08c49349a283b77dd2f435cd7a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,16 +1,6 @@
-# Binaries for programs and plugins
-*.exe
-*.exe~
-*.dll
-*.so
-*.dylib
-
-# Test binary, build with `go test -c`
-*.test
-
-# Output of the go coverage tool, specifically when used with LiteIDE
-*.out
-
-*dapper*
-!Dockerfile.dapper
-bin/
\ No newline at end of file
+/.dapper
+/.cache
+/bin
+/dist
+*.swp
+.idea
diff --git a/.golangci.json b/.golangci.json
new file mode 100644
index 0000000000000000000000000000000000000000..f317e3171c4b19daf7206978bd3231915f7b2b1d
--- /dev/null
+++ b/.golangci.json
@@ -0,0 +1,19 @@
+{
+	"linters": {
+		"disable-all": true,
+		"enable": [
+			"govet",
+			"golint",
+			"goimports",
+			"misspell",
+			"ineffassign",
+			"gofmt"
+		]
+	},
+	"run": {
+		"skip-files": [
+			"/zz_generated_"
+		],
+		"deadline": "5m"
+	}
+}
diff --git a/Dockerfile.dapper b/Dockerfile.dapper
index ad11f816905f9fdf5630c497c792877715d310dd..930ada73b194bd11bb6ece437bf1a83396ff9ef8 100644
--- a/Dockerfile.dapper
+++ b/Dockerfile.dapper
@@ -1,33 +1,26 @@
-FROM ubuntu:16.04
-# FROM arm=armhf/ubuntu:16.04
-
-ARG DAPPER_HOST_ARCH=amd64
-ARG http_proxy
-ARG https_proxy
-ENV HOST_ARCH=${DAPPER_HOST_ARCH} ARCH=${DAPPER_HOST_ARCH}
-
-RUN apt-get update && \
-    apt-get install -y gcc ca-certificates git wget curl vim less file python-tox python-dev && \
-    rm -f /bin/sh && ln -s /bin/bash /bin/sh
-
-ENV DOCKER_URL_amd64=https://get.docker.com/builds/Linux/x86_64/docker-1.10.3 \
-    DOCKER_URL_arm=https://github.com/rancher/docker/releases/download/v1.10.3-ros1/docker-1.10.3_arm \
-    DOCKER_URL_arm64=https://github.com/rancher/docker/releases/download/v1.10.3-ros1/docker-1.10.3_arm64 \
-    DOCKER_URL=DOCKER_URL_${ARCH}
-
-RUN wget -O - ${!DOCKER_URL} > /usr/bin/docker && chmod +x /usr/bin/docker
-
-ENV GOLANG_ARCH_amd64=amd64 GOLANG_ARCH_arm=armv6l GOLANG_ARCH_arm64=arm64 GOLANG_ARCH=GOLANG_ARCH_${ARCH} \
-    GOPATH=/go PATH=/go/bin:/usr/local/go/bin:${PATH} SHELL=/bin/bash
-
-RUN wget -O - https://storage.googleapis.com/golang/go1.12.linux-${!GOLANG_ARCH}.tar.gz | tar -xzf - -C /usr/local
-RUN go get github.com/rancher/trash && go get golang.org/x/lint/golint
-
-ENV DAPPER_SOURCE /go/src/github.com/rancher/local-path-provisioner
-ENV DAPPER_OUTPUT ./bin
+FROM golang:1.12.1-alpine3.9
+
+ARG DAPPER_HOST_ARCH
+ENV ARCH $DAPPER_HOST_ARCH
+
+RUN apk -U add bash git gcc musl-dev docker vim less file curl wget ca-certificates
+RUN go get -d golang.org/x/lint/golint && \
+    git -C /go/src/golang.org/x/lint/golint checkout -b current 06c8688daad7faa9da5a0c2f163a3d14aac986ca && \
+    go install golang.org/x/lint/golint && \
+    rm -rf /go/src /go/pkg
+RUN mkdir -p /go/src/golang.org/x && \
+    cd /go/src/golang.org/x && git clone https://github.com/golang/tools && \
+    git -C /go/src/golang.org/x/tools checkout -b current aa82965741a9fecd12b026fbb3d3c6ed3231b8f8 && \
+    go install golang.org/x/tools/cmd/goimports
+RUN rm -rf /go/src /go/pkg
+RUN if [ "${ARCH}" == "amd64" ]; then \
+        curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.15.0; \
+    fi
+
+ENV DAPPER_ENV REPO TAG DRONE_TAG
+ENV DAPPER_SOURCE /go/src/github.com/rancher/local-path-provisioner/
+ENV DAPPER_OUTPUT ./bin ./dist
 ENV DAPPER_DOCKER_SOCKET true
-ENV DAPPER_ENV IMAGE REPO VERSION TAG
-ENV TRASH_CACHE ${DAPPER_SOURCE}/.trash-cache
 ENV HOME ${DAPPER_SOURCE}
 WORKDIR ${DAPPER_SOURCE}
 
diff --git a/LICENSE b/LICENSE
index 261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64..f433b1a53f5b830a205fd2df78e2b34974656c7b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,3 +1,4 @@
+
                                  Apache License
                            Version 2.0, January 2004
                         http://www.apache.org/licenses/
@@ -174,28 +175,3 @@
       of your accepting any such warranty or additional liability.
 
    END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/Makefile b/Makefile
index d7d72a16d549c844235ca9749a84b7da02dea048..a0649db7a3d53c4025c62f280390f974c5b58268 100644
--- a/Makefile
+++ b/Makefile
@@ -10,14 +10,6 @@ TARGETS := $(shell ls scripts)
 $(TARGETS): .dapper
 	./.dapper $@
 
-trash: .dapper
-	./.dapper -m bind trash
-
-trash-keep: .dapper
-	./.dapper -m bind trash -k
-
-deps: trash
-
-.DEFAULT_GOAL := ci
+.DEFAULT_GOAL := default
 
 .PHONY: $(TARGETS)
diff --git a/package/Dockerfile b/package/Dockerfile
index 042162e51c595bd75dc8e83c9938e208b4b7cf66..084dadec76952dbf162e2c5d7d7e9ba40264f872 100644
--- a/package/Dockerfile
+++ b/package/Dockerfile
@@ -1,5 +1,3 @@
-FROM alpine:latest
-
-COPY bin /bin
-
-ENTRYPOINT ["/bin/local-path-provisioner"]
+FROM alpine
+COPY bin/local-path-provisioner /usr/bin/
+CMD ["local-path-provisioner"]
diff --git a/scripts/build b/scripts/build
index 7ae6e279f42f92a566d24af8bfd9a377c6c2064a..7b7a588399d90a6dc6af1c2c404fc2b5d177a3f7 100755
--- a/scripts/build
+++ b/scripts/build
@@ -1,9 +1,18 @@
 #!/bin/bash
-set -e -x
+set -e
+
+source $(dirname $0)/version
 
 cd $(dirname $0)/..
-VERSION=${VERSION:-$(./scripts/version)}
 
 mkdir -p bin
-[ "$(uname)" != "Darwin" ] && LINKFLAGS="-extldflags -static -s -w"
-CGO_ENABLED=0 go build -ldflags "-X main.VERSION=$VERSION $LINKFLAGS" -o bin/local-path-provisioner
+if [ "$(uname)" = "Linux" ]; then
+    OTHER_LINKFLAGS="-extldflags -static -s"
+fi
+LINKFLAGS="-X github.com/rancher/local-path-provisioner.Version=$VERSION"
+LINKFLAGS="-X github.com/rancher/local-path-provisioner.GitCommit=$COMMIT $LINKFLAGS"
+CGO_ENABLED=0 go build -ldflags "$LINKFLAGS $OTHER_LINKFLAGS" -o bin/local-path-provisioner
+if [ "$CROSS" = "true" ] && [ "$ARCH" = "amd64" ]; then
+    GOOS=darwin go build -ldflags "$LINKFLAGS" -o bin/local-path-provisioner-darwin
+    GOOS=windows go build -ldflags "$LINKFLAGS" -o bin/local-path-provisioner-windows
+fi
diff --git a/scripts/ci b/scripts/ci
index c983f758d823a2a2a11c0ad4e6998e5548875d26..523341057a4b36bd5bb99b6257956836d1b336d7 100755
--- a/scripts/ci
+++ b/scripts/ci
@@ -4,11 +4,7 @@ set -e
 cd $(dirname $0)
 
 ./build
+./test
 ./validate
-./test -cover
+./validate-ci
 ./package
-
-image=`cat ../bin/latest_image`
-
-echo
-echo Longhorn Manager image: ${image}
diff --git a/scripts/default b/scripts/default
new file mode 100755
index 0000000000000000000000000000000000000000..af2ad2db15edac292af22805bc7f8cac6c439e30
--- /dev/null
+++ b/scripts/default
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -e
+
+cd $(dirname $0)
+
+./build
+./test
+./package
diff --git a/scripts/entry b/scripts/entry
index 2fbe29ba1f9d881b291c77d02b0ade72791152ac..78fb567905b77c72e0d333180e5e7304f5b7e686 100755
--- a/scripts/entry
+++ b/scripts/entry
@@ -3,7 +3,9 @@ set -e
 
 mkdir -p bin dist
 if [ -e ./scripts/$1 ]; then
-    exec ./scripts/"$@"
+    ./scripts/"$@"
 else
     exec "$@"
 fi
+
+chown -R $DAPPER_UID:$DAPPER_GID .
diff --git a/scripts/package b/scripts/package
index 495e2a1f1e41fd22cf093c54489601e0ca9a02e1..e16e016be29734105173d94605247b2711518d83 100755
--- a/scripts/package
+++ b/scripts/package
@@ -1,26 +1,18 @@
 #!/bin/bash
 set -e
 
-cd $(dirname $0)/..
-
-ARCH=${ARCH:-amd64}
-SUFFIX=""
-[ "${ARCH}" != "amd64" ] && SUFFIX="_${ARCH}"
+source $(dirname $0)/version
 
-export VERSION=${VERSION:-$(./scripts/version)}
+cd $(dirname $0)/..
 
-TAG=${TAG:-${VERSION}${SUFFIX}}
-REPO=${REPO:-rancher}
-IMAGE=${IMAGE:-${REPO}/local-path-provisioner:${TAG}}
+mkdir -p dist/artifacts
+cp bin/local-path-provisioner dist/artifacts/local-path-provisioner${SUFFIX}
 
-if [ ! -e ./bin/local-path-provisioner ]; then
-    ./scripts/build
+IMAGE=${REPO}/local-path-provisioner:${TAG}
+DOCKERFILE=package/Dockerfile
+if [ -e ${DOCKERFILE}.${ARCH} ]; then
+    DOCKERFILE=${DOCKERFILE}.${ARCH}
 fi
 
-cp -a ./bin ./package/
-trap 'rm -rf ./package/bin' exit
-docker build -t ${IMAGE} ./package
-
+docker build -f ${DOCKERFILE} -t ${IMAGE} .
 echo Built ${IMAGE}
-
-echo ${IMAGE} > ./bin/latest_image
diff --git a/scripts/test b/scripts/test
index e7e2c4f3c738863d918d49b2b250c65cf4916f93..08662432a909df0a42843680d8ef9175d7be90de 100755
--- a/scripts/test
+++ b/scripts/test
@@ -3,13 +3,5 @@ set -e
 
 cd $(dirname $0)/..
 
-args=$1
-
 echo Running tests
-
-PACKAGES="$(find . -name '*.go' | xargs -I{} dirname {} | sort -u | grep -Ev '(.git|.trash-cache|vendor|bin)')"
-
-echo Packages: ${PACKAGES}
-
-[ "${ARCH}" == "amd64" ] && RACE=-race
-go test ${RACE} ${args} ${PACKAGES}
+go test -cover -tags=test ./...
diff --git a/scripts/validate b/scripts/validate
index 534cab4c8037566670d8636badeeb75c8dfa6aa7..7f98128bdb486e454b0fe1b702279a8014b9540e 100755
--- a/scripts/validate
+++ b/scripts/validate
@@ -5,18 +5,17 @@ cd $(dirname $0)/..
 
 echo Running validation
 
-PACKAGES="$(find . -name '*.go' | grep -Ev '.pb.go' | xargs -I{} dirname {} | \
-	sort -u | grep -Ev '(.git|.trash-cache|vendor|bin|k8s/pkg|client)')"
+PACKAGES="$(go list ./...)"
+
+if ! command -v golangci-lint; then
+    echo Skipping validation: no golangci-lint available
+    exit
+fi
+
+echo Running validation
+
+echo Running: golangci-lint
+golangci-lint run
 
-echo Packages: ${PACKAGES}
-echo Running: go vet
-go vet ${PACKAGES}
-echo Running: golint
-for i in ${PACKAGES}; do
-    if [ -n "$(golint $i | grep -v 'should have comment.*or be unexported' | grep -v 'just return error instead.' | tee /dev/stderr)" ]; then
-        failed=true
-    fi
-done
-test -z "$failed"
 echo Running: go fmt
 test -z "$(go fmt ${PACKAGES} | tee /dev/stderr)"
diff --git a/scripts/validate-ci b/scripts/validate-ci
new file mode 100755
index 0000000000000000000000000000000000000000..5a6c52adbf59059f94c319aae15fbbcf70142ad9
--- /dev/null
+++ b/scripts/validate-ci
@@ -0,0 +1,13 @@
+#!/bin/bash
+set -e
+
+cd $(dirname $0)/..
+
+source ./scripts/version
+
+if [ -n "$DIRTY" ]; then
+    echo Git is dirty
+    git status
+    git diff
+    exit 1
+fi
diff --git a/scripts/version b/scripts/version
index eaf8c942bea5ece1604f37750ea71cea4356e365..1646092e5bcefe1283c38dce9154e209b272f98b 100755
--- a/scripts/version
+++ b/scripts/version
@@ -1,17 +1,27 @@
 #!/bin/bash
-set -e
 
 if [ -n "$(git status --porcelain --untracked-files=no)" ]; then
     DIRTY="-dirty"
 fi
 
 COMMIT=$(git rev-parse --short HEAD)
-GIT_TAG=$(git tag -l --contains HEAD | head -n 1)
+GIT_TAG=${DRONE_TAG:-$(git tag -l --contains HEAD | head -n 1)}
 
 if [[ -z "$DIRTY" && -n "$GIT_TAG" ]]; then
-    VER=$GIT_TAG
+    VERSION=$GIT_TAG
 else
-    VER="${COMMIT}${DIRTY}"
+    VERSION="${COMMIT}${DIRTY}"
 fi
 
-echo ${VER}
+if [ -z "$ARCH" ]; then
+    ARCH=$(go env GOHOSTARCH)
+fi
+
+SUFFIX="-${ARCH}"
+
+TAG=${TAG:-${VERSION}${SUFFIX}}
+REPO=${REPO:-rancher}
+
+if echo $TAG | grep -q dirty; then
+    TAG=dev
+fi