diff --git a/docker/grafana/Dockerfile b/docker/grafana/Dockerfile
new file mode 100644
index 0000000000..14e303f9fd
--- /dev/null
+++ b/docker/grafana/Dockerfile
@@ -0,0 +1,26 @@
+# Copyright (c) 2020 Red Hat, Inc.
+#
+# 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.
+
+FROM docker.io/grafana/grafana:7.0.3-ubuntu
+
+LABEL maintainer="infra-root@openstack.org"
+
+USER root
+RUN apt-get update && apt-get install -y python3-pip \
+  && rm -rf /var/lib/apt/lists/*
+RUN pip3 install grafyaml
+
+COPY update-grafana /usr/local/bin
+RUN chmod a+x /usr/local/bin/update-grafana
diff --git a/docker/grafana/update-grafana b/docker/grafana/update-grafana
new file mode 100644
index 0000000000..1d18cabd31
--- /dev/null
+++ b/docker/grafana/update-grafana
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+#
+# Refresh grafana dashboards from project-config
+#
+
+GF_USER="$(cat /etc/grafana/secrets/admin_user)"
+GF_PASSWORD="$(cat /etc/grafana/secrets/admin_password)"
+GF_URL="http://${GF_USER}:${GF_PASSWORD}@localhost:3000/"
+
+grafana-dashboard --debug --grafana-url="${GF_URL}" update /opt/project-config/grafana
diff --git a/zuul.d/docker-images/grafana.yaml b/zuul.d/docker-images/grafana.yaml
new file mode 100644
index 0000000000..d756ac3425
--- /dev/null
+++ b/zuul.d/docker-images/grafana.yaml
@@ -0,0 +1,27 @@
+# Grafana jobs
+- job:
+    name: system-config-build-image-grafana
+    description: Build a grafana/grafyaml image.
+    provides: grafana-container-image
+    parent: system-config-build-image
+    vars: &grafana_vars
+      docker_images:
+        - context: docker/grafana
+          repository: opendevorg/grafana
+    files: &grafana_files
+      - docker/grafana
+
+- job:
+    name: system-config-upload-image-grafana
+    description: Build and upload a grafana image.
+    provides: grafana-container-image
+    parent: system-config-upload-image
+    vars: *grafana_vars
+    files: *grafana_files
+
+- job:
+    name: system-config-promote-image-grafana
+    description: Promote a previously published grafana image to latest.
+    parent: system-config-promote-image
+    vars: *grafana_vars
+    files: *grafana_files
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 045404aa53..0b966f31c9 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -64,6 +64,7 @@
                 soft: true
         - system-config-build-image-etherpad
         - system-config-build-image-gitea
+        - system-config-build-image-grafana
         - system-config-build-image-jitsi-meet
         - system-config-build-image-haproxy-statsd:
             dependencies:
@@ -142,6 +143,7 @@
                 soft: true
         - system-config-upload-image-etherpad
         - system-config-upload-image-gitea
+        - system-config-upload-image-grafana
         - system-config-upload-image-jitsi-meet
         - system-config-upload-image-haproxy-statsd:
             dependencies: