Skip to content
Snippets Groups Projects
Unverified Commit 1f897ac0 authored by Ariya Hidayat's avatar Ariya Hidayat Committed by GitHub
Browse files

Remove support for Heroku deployment (#25124)

parent 0573b4bc
Branches
Tags
No related merge requests found
web: HEROKU=true ./bin/start
{
"name": "Metabase",
"description": "Metabase report server",
"keywords": [
"business intelligence",
"analytics",
"dashboard",
"charting",
"metabase"
],
"website": "https://metabase.com/",
"repository": "https://github.com/metabase/metabase",
"logo": "https://avatars3.githubusercontent.com/u/10520629?v=3&s=200",
"success_url": "/setup",
"env": {
},
"addons": [
"heroku-postgresql"
],
"buildpacks": [
{ "url": "https://github.com/heroku/heroku-buildpack-nodejs" },
{ "url": "https://github.com/heroku/heroku-buildpack-clojure" }
]
}
#!/usr/bin/env bash
set -euo pipefail
if [ $# -gt 0 ] && [ "$1" == "-h" ]; then
cat <<EOM
Usage:
Deploy current branch to Heroku app "metabase-CURRENT_BRANCH_NAME"
./bin/heroku/deploy
Deploy current branch to Heroku app "HEROKU_APP_NAME"
./bin/heroku/deploy "HEROKU_APP_NAME"
Deploy "GIT_REF" (branch or tag) to Heroku app "HEROKU_APP_NAME"
./bin/heroku/deploy "HEROKU_APP_NAME" "GIT_REF"
EOM
exit 0
fi
if [ $# -gt 0 ]; then
heroku_app_name="$1"
else
if [ $(git rev-parse --abbrev-ref HEAD) == "HEAD" ]; then
echo "Detached HEAD. Specify a Heroku app name."
echo ""
echo "For more usage examples: $0 -h"
exit 1
fi
heroku_app_name="metabase-$(git rev-parse --abbrev-ref HEAD)"
fi
if [ $# -gt 1 ]; then
# "peel" annotated tags etc
git_local_ref="+$2^{}"
else
git_local_ref="HEAD"
fi
# use explicit "master" ref in case it doesn't exist yet
git_remote_ref="refs/heads/master"
if ! heroku ps -a "$heroku_app_name" > /dev/null; then
heroku apps:create -n --addons "heroku-postgresql:hobby-dev" "$heroku_app_name"
heroku buildpacks:clear -a "$heroku_app_name"
heroku buildpacks:add "https://github.com/heroku/heroku-buildpack-nodejs#yarn" -a "$heroku_app_name"
heroku buildpacks:add "https://github.com/heroku/heroku-buildpack-clojure" -a "$heroku_app_name"
fi
echo git push -f "https://git.heroku.com/$heroku_app_name.git" "$git_local_ref:$git_remote_ref"
time git push -f "https://git.heroku.com/$heroku_app_name.git" "$git_local_ref:$git_remote_ref"
heroku open -a "$heroku_app_name"
......@@ -10,7 +10,6 @@
[draft-release :as draft-release]
[elastic-beanstalk :as eb]
[git-tags :as git-tags]
[heroku :as heroku]
[set-build-options :as set-build-options]
[uberjar :as uberjar]
[version-info :as version-info]]
......@@ -26,7 +25,6 @@
:upload-uberjar uberjar/upload-uberjar!
:push-docker-image docker/push-docker-image!
:publish-draft-release draft-release/create-draft-release!
:update-heroku-buildpack heroku/update-heroku-buildpack!
:publish-elastic-beanstalk-artifacts eb/publish-elastic-beanstalk-artifacts!
:update-version-info version-info/update-version-info!))
......
......@@ -109,11 +109,6 @@
:oss "metabase/metabase.github.io"
nil))
(defn heroku-buildpack-repo []
(case (edition)
:oss "metabase/metabase-buildpack"
nil))
(defn metabase-repo
"Metabase GitHub repo"
[]
......
(ns release.heroku
"Code related to updating the Heroku build pack."
(:require [metabuild-common.core :as u]
[release.common :as c]
[release.common.git :as git]))
(def ^:private heroku-repo "metabase/metabase-buildpack")
(def ^:private dir "/tmp/metabase-heroku-buildpack")
(def ^:private version-file (str dir "/bin/version"))
(defn- validate-heroku-buildpack []
(u/step "Validate Heroku buildpack"
(let [[version] (u/sh {:dir dir} "git" "show" "origin/master:bin/version")]
(u/announce "Heroku buildpack version on origin/master is %s" version)
(assert (= version (c/version))
(format "Version does not equal %s" (c/version))))))
(defn update-heroku-buildpack! []
(u/step "Update Metabase Heroku buildpack"
(cond
(c/pre-release-version?)
(u/announce "Pre-release version -- not updating Heroku buildpack ")
(= (c/edition) :ee)
(u/announce "EE build -- not updating Herkou buildpack")
(not (c/latest-version?))
(u/announce "Not the latest version -- not updating Heroku buildpack")
:else
(do
(u/step (format "Clone Herkou Buildpack repo %s to %s" heroku-repo dir)
(u/delete-file! dir)
(u/sh "git" "clone" (format "git@github.com:%s.git" heroku-repo) dir))
(u/step (format "Update %s" (pr-str version-file))
(u/assert-file-exists version-file)
(spit version-file (str (c/version) "\n"))
(when-not (zero? (:exit (u/sh* {:dir dir} "git" "commit" "-am" (format "v%s" (c/version)))))
(u/announce "Nothing to update")))
(git/delete-local-tag! dir (c/version))
(git/delete-remote-tag! dir (c/version))
(u/step "Push updated tag"
(u/sh {:dir dir} "git" "tag" (c/version))
(u/sh {:dir dir} "git" "push")
(u/sh {:dir dir} "git" "push" "--tags" "origin" "master"))
(validate-heroku-buildpack)))))
#!/usr/bin/env bash
set -e
# NOTE: The canonical source for this file is in the metabase/metabase repository.
# Please update it there then copy to the metabase/metabase-deploy repository.
# Translate various Heroku environment variables to Metabase equivalents
if [ "$PORT" ]; then
export MB_JETTY_PORT="$PORT"
fi
# Heroku Postgres
if [ "$DATABASE_URL" ]; then
if [[ $string == *"?"* ]]; then
# if DATABASE_URL already has a query string don't mess with it
export MB_DB_CONNECTION_URI="$DATABASE_URL"
else
# otherwise add the SSL parameters to ensure upgraded databases work on Heroku
export MB_DB_CONNECTION_URI="$DATABASE_URL?ssl=true&sslmode=require&sslfactory=org.postgresql.ssl.NonValidatingFactory"
fi
fi
# Mailgun (Heroku)
if [ "$MAILGUN_SMTP_LOGIN" ]; then
export MB_EMAIL_SMTP_HOST="$MAILGUN_SMTP_SERVER"
export MB_EMAIL_SMTP_PORT="$MAILGUN_SMTP_PORT"
export MB_EMAIL_SMTP_USERNAME="$MAILGUN_SMTP_LOGIN"
export MB_EMAIL_SMTP_PASSWORD="$MAILGUN_SMTP_PASSWORD"
fi
# SendGrid (Heroku)
if [ "$SENDGRID_USERNAME" ]; then
export MB_EMAIL_SMTP_HOST="smtp.sendgrid.net"
export MB_EMAIL_SMTP_PORT="587"
export MB_EMAIL_SMTP_USERNAME="$SENDGRID_USERNAME"
export MB_EMAIL_SMTP_PASSWORD="$SENDGRID_PASSWORD"
export MB_EMAIL_SMTP_SECURITY="tls"
fi
# Mandrill (Heroku)
if [ "$MANDRILL_USERNAME" ]; then
export MB_EMAIL_SMTP_HOST="smtp.mandrillapp.com"
export MB_EMAIL_SMTP_PORT="587"
export MB_EMAIL_SMTP_USERNAME="$MANDRILL_USERNAME"
export MB_EMAIL_SMTP_PASSWORD="$MANDRILL_APIKEY"
fi
# Postmark (Heroku)
# NOTE: requires configuring sender signature for "from" address
if [ "$POSTMARK_API_TOKEN" ]; then
export MB_EMAIL_SMTP_HOST="$POSTMARK_SMTP_SERVER"
export MB_EMAIL_SMTP_PORT="25"
export MB_EMAIL_SMTP_USERNAME="$POSTMARK_API_TOKEN"
export MB_EMAIL_SMTP_PASSWORD="$POSTMARK_API_TOKEN"
export MB_EMAIL_SMTP_SECURITY="tls"
fi
# SparkPost (Heroku)
# NOTE: requires additional configuration
if [ "$SPARKPOST_SMTP_USERNAME" ]; then
export MB_EMAIL_SMTP_HOST="$SPARKPOST_SMTP_HOST"
export MB_EMAIL_SMTP_PORT="$SPARKPOST_SMTP_PORT"
export MB_EMAIL_SMTP_USERNAME="$SPARKPOST_SMTP_USERNAME"
export MB_EMAIL_SMTP_PASSWORD="$SPARKPOST_SMTP_PASSWORD"
fi
# Determine whether we're on Heroku on a free, hobby, 1x dyno or 2x dyno
#
# We set $HEROKU in the Procfile, so we know we're on Heroku when started from the
# Procfile.
#
# We need to override the $JAVA_OPTS and give it a slightly lower memory limit
# because Heroku tends to think we can use more memory than we actually can.
if [ -n "$HEROKU" ]; then
echo " -> Heroku detected"
if [ `ulimit -u` = 256 ]; then
# free, hobby or 1x dyno, it defaults to giving us 300m but that still ends
# up going over the 512MB limit for the dyno.
echo " => 1x dyno"
JAVA_OPTS="$JAVA_OPTS -Xmx248m" # This seems to be the right amount that prevents the dyno from going over the quota
fi
if [ `ulimit -u` = 512 ]; then
# 2x dyno, it defaults to giving us 800m but that still ends
# up going over the 1024MB limit for the dyno.
echo " => 2x dyno"
JAVA_OPTS="$JAVA_OPTS -Xmx496m" # This seems to be the right amount that prevents the dyno from going over the quota
fi
# Set a few other additional options to minimize memory usage as well.
JAVA_OPTS="$JAVA_OPTS -XX:-UseGCOverheadLimit" # Disable limit to amount of time spent in GC. Better slow than not working at all
JAVA_OPTS="$JAVA_OPTS -XX:+UseConcMarkSweepGC" # ConcMarkSweepGC seems to cause less OOM issues in my testing on low-mem Heroku envs
JAVA_OPTS="$JAVA_OPTS -XX:+CMSClassUnloadingEnabled" # Not 100% sure this does anything in Java 8 but if it does, we want to enable it
JAVA_OPTS="$JAVA_OPTS -XX:+UseCompressedOops" # Use 32-bit pointers. Reduces memory usage and GC events
JAVA_OPTS="$JAVA_OPTS -XX:+UseCompressedClassPointers" # Same as above. See also http://blog.leneghan.com/2012/03/reducing-java-memory-usage-and-garbage.html
fi
# Other Java options
JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions" # Don't barf if we see an option we don't understand (e.g. Java 9 option on Java 7/8)
JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true" # don't try to start AWT. Not sure this does anything but better safe than wasting memory
JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8" # Use UTF-8
echo "Using these JAVA_OPTS: ${JAVA_OPTS}"
exec java $JAVA_OPTS -jar ./target/uberjar/metabase.jar
......@@ -30,7 +30,6 @@ To run a development branch of Metabase, check out our [developer's guide](../de
- [Running on AWS Elastic Beanstalk](running-metabase-on-elastic-beanstalk.md)
- [Running on Azure Web Apps](running-metabase-on-azure.md)
- [Running on Heroku](running-metabase-on-heroku.md)
- [Running on Debian as a service](running-metabase-on-debian.md)
## Upgrading Metabase
......
---
title: Running Metabase on Heroku
redirect_from:
- /docs/latest/operations-guide/running-metabase-on-heroku
---
# Running Metabase on Heroku
Currently in beta. We've run Metabase on Heroku and it works just fine, but it's not hardened for production use just yet. If you're up for it then give it a shot and let us know how we can make it better!
### Launching Metabase
Before doing anything you should make sure you have a [Heroku](http://www.heroku.com) account that you can access.
If you've got a Heroku account then all there is to do is follow this one-click deployment button
[![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://downloads.metabase.com/launch-heroku.html)
This will launch a Heroku deployment using a GitHub repository that Metabase maintains.
It should only take a few minutes for Metabase to start. You can check on the progress by viewing the logs at [https://dashboard.heroku.com/apps/YOUR_APPLICATION_NAME/logs](https://dashboard.heroku.com/apps/YOUR_APPLICATION_NAME/logs) or using the Heroku command line tool with the `heroku logs -t -a YOUR_APPLICATION_NAME` command.
### Upgrading beyond the `Free` tier
Heroku is very kind and offers a free tier to be used for very small/non-critical workloads which is great if you just want to evaluate Metabase and see what it looks like. If you like what you see and decide to use Metabase as an ongoing part of your analytics workflow we recommend these upgrades which are quite affordable and will allow you to fully utilize all of Metabase's capabilities without running into annoying limitations.
1. Upgrade your dyno to the `Hobby` tier or one of the professional `Standard` 1x/2x dynos. The most important reason for this is that your dyno will never sleep and that allows Metabase to run all of its background work such as sending Pulses, syncing metadata, etc, in a reliable fashion.
2. Upgrade your Postgres database to the `Basic` package or for more peace of mind go for the `Standard 0` package. The primary reason for this upgrade is to get more than the minimum number of database rows offered in the free tier (10k), which we've had some users exhaust within a week. You'll also get better overall performance along with backups, which we think is worth it.
### Known Limitations
* Heroku’s 30 second timeouts on all web requests can cause a few issues if you happen to have longer running database queries. Most people don’t run into this but be aware that it’s possible.
* When using the `free` tier, if you don’t access the application for a while Heroku will sleep your Metabase environment. This prevents things like Pulses and Metabase background tasks from running when scheduled and at times makes the app appear to be slow when really it's just Heroku reloading your app. You can resolve this by upgrading to the `hobby` tier or higher.
* Sometimes Metabase may run out of memory and you will see messages like `Error R14 (Memory quota exceeded)` in the Heroku logs. If this happens regularly we recommend upgrading to the `standard-2x` tier dyno.
Now that you’ve installed Metabase, it’s time to [set it up and connect it to your database](../configuring-metabase/setting-up-metabase.md).
### Troubleshooting
* If your Metabase instance is getting stuck part way through the initialization process and only every shows roughly 30% completion on the loading progress.
* The most likely culprit here is a stale database migrations lock that was not cleared. This can happen if for some reason Heroku kills your Metabase dyno at the wrong time during startup. __To fix it:__ you can either clear the lock using the built-in [release-locks](../troubleshooting-guide/loading-from-h2.md) command line function, or if needed you can login to your Metabase application database directly and delete the row in the `DATABASECHANGELOGLOCK` table. Then just restart Metabase.
## Deploying New Versions of Metabase
We currently use a Heroku buildpack for deploying Metabase. The [metabase-deploy](https://github.com/metabase/metabase-deploy) repository is an app that relies on the buildpack and configures various properties for running Metabase on Heroku.
In order to upgrade to the latest version of Metabase on Heroku, you need to trigger a rebuild of your app. Typically this is done by pushing to the Heroku app's Git repository, but because we create the app using a Heroku Button, you'll need to link your app to our repo and push an empty commit.
Here's each step:
* Clone the metabase-deploy repo to your local machine:
```bash
git clone https://github.com/metabase/metabase-deploy.git
cd metabase-deploy
```
* Add a git remote with your Metabase setup:
```bash
git remote add heroku https://git.heroku.com/<YOUR-APP-NAME>.git
```
* If you are upgrading from a version that is lower than 0.25, add the Metabase buildpack to your Heroku app:
```bash
heroku buildpacks:add https://github.com/metabase/metabase-buildpack
```
* If there have been no new changes to the `metabase-deploy` repository since the last time you deployed Metabase, you will need to add an empty commit. This triggers Heroku to re-deploy the code, fetching the newest version of Metabase in the process.
```bash
git commit --allow-empty -m "empty commit"
git push heroku master
```
* Wait for the deploy to finish
## Testing New Versions using Heroku Pipelines
[Heroku pipelines](https://devcenter.heroku.com/articles/pipelines) are a feature that allow you to share the same codebase across multiple Heroku apps and maintain a continuous delivery pipeline. You can use this feature to test new versions of Metabase before deploying them to production.
In order to do this, you would create two different Metabase apps on Heroku and then create a pipeline with one app in staging and the other in production.
![Heroku Pipeline image](images/HerokuPipeline.png)
In order to trigger automatic deploys to your staging app, you will need to fork the [metabase-deploy](https://github.com/metabase/metabase-deploy) repository into your own GitHub user or organization and then enable [GitHub Sync](https://devcenter.heroku.com/articles/pipelines#github-sync) on that repository. To do this, connect the pipeline to your forked repository in the pipeline settings, then enable automatic deploys in the app you added to the staging environment.
Now, when you push to master on your forked `metabase-deploy` repository, the changes will automatically be deployed to your staging app! Once you're happy that everything is OK, you can promote the staging app to production using the Heroku UI or CLI.
Similar to the instructions above, to deploy a new version you just need to push an empty commit and the build will pick up the new version.
```bash
git commit --allow-empty -m "Upgrade Metabase"
git push master
```
### Database Syncs
You may want to ensure that your staging database is synced with production before you deploy a new version. Luckily with Heroku you can restore a backup from one app to another.
For example, assuming your production app is named `awesome-metabase-prod`, this command will create a backup:
```bash
heroku pg:backups:capture --app awesome-metabase-prod
```
Note the backup ID referenced in the above command and use that to restore the database to your staging app, `awesome-metabase-staging`.
```bash
heroku pg:backups:restore awesome-metabase-prod::b101 DATABASE_URL --app awesome-metabase-staging
```
This will restore backup ID `b101` from your prod app to your staging app.
Once this is done, restart your staging app and begin testing.
### Pinning Metabase versions
For whatever reason, should you want to pin Metabase to a specific version, you can append the version number to the buildpack URL (as long as that tag exists in the [`metabase-buildpack`](https://github.com/metabase/metabase-buildpack) repository).
If you haven't cloned the `metabase-deploy` repository, this can be done with the Heroku CLI:
```bash
heroku buildpacks:set --index 2 https://github.com/metabase/metabase-buildpack#0.34.1 \
--app <YOUR-APP-NAME>
```
If you are using pipelines as shown above, you can modify the `app.json` file in your forked `metabase-deploy` repository to use a tagged buildpack URL for the Metabase buildpack. You can then commit and push that change and promote your app when ready.
```json
"buildpacks": [
{
"url": "heroku/jvm"
},
{
"url": "https://github.com/metabase/metabase-buildpack#0.34.1"
}
]
```
......@@ -25,7 +25,6 @@ Our official hosted version, [Metabase Cloud](https://www.metabase.com/pricing).
### Other installation options
- [Running on Azure Web Apps](running-metabase-on-azure.md)
- [Running on Heroku](running-metabase-on-heroku.md)
- [Running on Debian as a service](running-metabase-on-debian.md)
- [Running on AWS Elastic Beanstalk](running-metabase-on-elastic-beanstalk.md)
- [Advanced topics for running on AWS Elastic Beanstalk](./advanced-topics-for-running-Metabase-in-AWS-ElasticBeanstalk.md)
......
......@@ -116,7 +116,5 @@ If you're on a [Metabase Cloud](https://www.metabase.com/pricing) plan, your Met
## Upgrading Metabase on other platforms
- [AWS Elastic Beanstalk deployments](./running-metabase-on-elastic-beanstalk.md#deploying-new-versions-of-metabase-on-elastic-beanstalk)
- [Azure Web Apps deployments](./running-metabase-on-azure.md#additional-configurations)
- [Heroku deployments](./running-metabase-on-heroku.md#deploying-new-versions-of-metabase)
- [Upgrading AWS Elastic Beanstalk deployments](running-metabase-on-elastic-beanstalk.md#deploying-new-versions-of-metabase-on-elastic-beanstalk)
- [Upgrading Azure Web Apps deployments](running-metabase-on-azure.md#additional-configurations)
......@@ -19,7 +19,6 @@ Fixes for timeout problems will depend on your specific setup. These resources m
- [Configuring Jetty connectors][configuring-jetty]
- [EC2 Troubleshooting][ec2-troubleshooting]
- [Elastic Load Balancing Connection Timeout Management][elb-timeout]
- [Heroku timeouts][heroku-timeout]
- [App Engine: Dealing with DeadlineExceededErrors][app-engine-timeout]
## Are you still stuck?
......@@ -34,5 +33,4 @@ If you can’t solve your problem using the troubleshooting guides:
[discourse]: https://discourse.metabase.com/
[ec2-troubleshooting]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/TroubleshootingInstancesConnecting.html
[elb-timeout]: https://aws.amazon.com/blogs/aws/elb-idle-timeout-control/
[heroku-timeout]: https://devcenter.heroku.com/articles/request-timeout
[known-issues]: ./known-issues.md
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment