1

The documentation on GCP suggest that the right way to do is using App Engine/Node -- until you get the step that says

Follow the instructions on the Ghost website to install Ghost as an NPM Module.

Well, the instructions on the Ghost website say don't install Ghost as an NPM Module. It's not supported.

OK, how about CloudRun? I found this extremely promising sample on Git. Only downside is it uses an internal SqlLite database, and I need to connect to an existing MySQL database hosted on GCP.

Apparently, there is some sort of issue with hooking up to a MySQL database hosted on GCP over TCP. Dunno why, but there is a proxy you run locally instead. I can run Ghost from the command line, like this:

ghost config --ip 0.0.0.0 --port 8080 --no-prompt --url http://localhost:8080 --db mysql --dbhost localhost --dbuser ghost_service --dbpass <pass> --dbname darkstore_blog_db
ghost start

And it seems to work.

However, with the same arguments in the Dockerfile, I get

app_1  | [2020-02-01 02:15:39] ERROR Invalid database host.
app_1  |
app_1  | Invalid database host.
app_1  |
app_1  | "Please double check your database config."
app_1  |
app_1  | Error ID:
app_1  |     500

Now that's not absurd: the Docker container is a VM-like thing, with its own definition of "localhost". The documentation suggests using "host.docker.internal" instead. Nope, same result.

OK, fine, I don't need to run it on a local Docker container. The problem is, if it is running under CloudRun, it can't use the proxy, of course. I am supposed to set a configuration value called "socketPath" to the value /cloudsql/mycompany-1943107437902:us-west1:mycompany-blog-db, of course.

But there is no way to set socketPath! That's not an argument to ghost config and I don't see a way to supply a configuration file.

So I'm stymied. I'm a little annoyed at

  • the database people for thinking it's legitimate to require four or five separate arguments -- arguments that are not consistent across different DBMSs -- to open a connection
  • the Ghost people, for not supporting what looks to me like an obvious use case out of the box
  • the GCP people, just because they are getting on my nerves

But mostly, I'd like to get past this. Someone must have gotten this working.

Michael Lorton
  • 43,060
  • 26
  • 103
  • 144
  • `localhost` doesn't run `mysqld` (with this config, it will not attempt to connect anything outside of the container); ever tried the host-name & port of the CloudSQL instance? Connecting trough `localhost` would likely require `stunnel` to be setup. – Martin Zeitler Feb 01 '20 at 03:48
  • I did try the host-name and port: just as the documentation promised, it did not connect. I used `cloud_sql_proxy`, as Google recommended, and that worked. – Michael Lorton Feb 01 '20 at 05:08
  • Just updated my answer. So the question is, which one of them are you using? – Martin Zeitler Feb 03 '20 at 05:45

2 Answers2

4

I just spent the last hour trying to solve this and managed to come up with a working solution. This assumes you:

  1. Have a Cloud SQL instance running MySQL
  2. Want to deploy a Ghost docker image on Cloud Run

I first grabbed the unoffical docker image of Ghost

docker pull ghost:3.12.0

I then pushed up that image to my own GCR (required for Cloud Run).

docker tag ghost:3.12.0 gcr.io/<GCP_PROJECT_NAME>/ghost:3.12.0
docker push gcr.io/<GCP_PROJECT_NAME>/ghost:3.12.0

I then followed this tutorial to set up the Cloud SQL instance. Next, I created the Cloud Run instance (using that docker image we created above) and set a few parameters in the "Variables and Secrets" section (which are not documented at all), like so:

database__client=mysql
database__connection__user=root
database__connection__password=<DB PASSWORD>
database__connection__socketPath=/cloudsql/<INSTANCE_CONNECTION_NAME>
database__connection__database=ghost
url=<HOSTNAME>
parondeau
  • 123
  • 7
  • I wrote about this more extensively here: https://parondeau.com/blog/self-hosting-ghost-gcp – parondeau Apr 09 '20 at 13:56
  • That's a great tutorial! Thanks!! BTW, any chance to manage the Dockerfile deployment through github actions? – CSSer Jul 18 '21 at 04:57
  • @parondeau not sure why using latest image (4.32.3), it will be an error: Cloud Run error: Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable. Do you have any idea? – Louis Luk Jan 23 '22 at 13:59
0

The documentation explains the two different kinds of Cloud Run environments:

Cloud Run (fully managed):

  • No access to VPC / Compute Engine network.
  • Services are not part of the Istio service mesh.

Cloud Run for Anthos:

  • Access to VPC / Compute Engine network.
  • Services participate in the Istio service mesh.

At least Cloud Run for Anthos can connect to Cloud SQL via IP.


Probably socket would work in Ghost's config.production.json (Connecting to Cloud SQL):

"server": {
    // "socket": "/cloudsql/<PROJECT_ID:REGION:INSTANCE_ID>"
    "socket": "/cloudsql/mycompany-1943107437902:us-west1:mycompany-blog-db"
}

This socket might need mkdir /cloudsql && chmod 777 /cloudsql.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • Martin - This is not entirely correct and this is a documentation issue confusing proxy versus direct access. Cloud SQL Proxy for Cloud Run does not support IP addressing. Cloud Run can connect to any public service using IP addressing including Cloud SQL provided that the firewall is open and the credentials are correct. – John Hanley Feb 01 '20 at 16:21
  • Martin, I work with the Cloud Run engineering team as a GDE. – John Hanley Feb 01 '20 at 16:48
  • @JohnHanley just found the part of the documentation, which explains the difference. That's probably the reason why fully-managed wants to connect to local UNIX socket. There's no VPC, which one could apply firewall rules to. – Martin Zeitler Feb 03 '20 at 05:33
  • Martin, the firewall I am referring to is the Cloud SQL firewall. – John Hanley Feb 03 '20 at 14:51
  • 1
    `server.socket` is for configuring Ghost to listen to incoming connections on that unix socket. It is not for connecting to the database on that socket. If you want to connect to the database on a socket, you must do as I've explained in this answer: https://stackoverflow.com/a/60938880/1700889 – parondeau Mar 30 '20 at 20:22