Docker Healthcheck without curl or wget

I use official Docker image of Ghost to deploy my Ghost websites. I use docker swarm for orchestration and I need to have a healtcheck to have zero-downtime upgrades. Common way of doing this using curl to make a request to a convenient URL to check if Ghost is running, like below:

healthcheck:
  test: "curl -H 'X-Forwarded-Proto: https' -If http://localhost:2368/ghost/api/admin/site/ || exit 1"
  interval: 10s
  timeout: 10s
  retries: 10
💡
I use X-Forwarded-Proto header to mimic a reverse proxy to bypass Ghost's SSL redirection.

The problem is, official Ghost Docker image doesn't include curl, or wget command. But it has NodeJS for sure (because Ghost runs on NodeJS). So instead of creating my own Docker image just to have curl command for health check, I decided to write a command in node to have same result.

healthcheck:
  test: "node -e 'require(\"http\").get({host: \"localhost\", port: 2368, path: \"/ghost/api/admin/site/\", headers: {\"X-Forwarded-Proto\": \"https\"}}, res => process.exit(res.statusCode === 200 ? 0 : 1)).on(\"error\", () => process.exit(1));'"
  interval: 10s
  timeout: 10s
  retries: 10

It's a little longer but it makes the job. Basically, this command runs the JavaScript code below as a single line command.

require("http").get({
    host: "localhost",
    port: 2368,
    path: "/ghost/api/admin/site/",
    headers: {
        "X-Forwarded-Proto": "https"
    }
}, res => process.exit(
    res.statusCode === 200 ? 0 : 1
)
).on("error", () => 
    process.exit(1)
);

This approach can be also used in Docker images other than JavaScript. As far as you can make an HTTP call from command line with the programming language that your docker image includes, it'll handle the task. For example, with Python:

healthcheck:
  test: "python3 -c 'import http.client; conn = http.client.HTTPConnection(\"localhost\", 2368); headers = {\"Custom-Header\": \"your-header-value\"}; conn.request(\"GET\", \"/\", headers=headers); res = conn.getresponse(); exit(0) if res.status == 200 else exit(1)'"

Hope this helps for some!

Me on Mastodon: https://synaps.space/@murat