diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 21adcb7992bee7d693e9dd1b575f71cb71d5afca..3bffe099bc4ffad425b13b1aa7cc20d0f85b3723 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -81,3 +81,29 @@ jobs:
       # Ensure proto generation doesn't depend on external packages.
       - name: Verify proto
         run: make verify-proto
+
+  docker:
+    name: Docker
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v2
+
+      - name: Determine tag
+        uses: haya14busa/action-cond@v1
+        id: imagetag
+        with:
+          cond: ${{ github.event_name == 'pull_request' }}
+          if_true: ${{ github.sha }}
+          if_false: "master"
+
+      - name: Build
+        uses: docker/build-push-action@v1
+        with:
+          username: ${{ secrets.DOCKER_USERNAME }}
+          password: ${{ secrets.DOCKER_PASSWORD }}
+          repository: dexidp/dex
+          tags: ${{ steps.imagetag.outputs.value }}
+          add_git_labels: true
+          push: ${{ github.event_name == 'push' }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fbc3a20a32788fc02c0c34640f1ae4cfeabba41e
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,24 @@
+name: Release
+
+on:
+  push:
+    tags:
+      - "v[0-9]+.[0-9]+.[0-9]+"
+
+jobs:
+  docker:
+    name: Docker
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v2
+
+      - name: Build and push image
+        uses: docker/build-push-action@v1
+        with:
+          username: ${{ secrets.DOCKER_USERNAME }}
+          password: ${{ secrets.DOCKER_PASSWORD }}
+          repository: dexidp/dex
+          tags: latest
+          tag_with_ref: true
+          add_git_labels: true