Cloud Run Button: Deploy Docker Images from Public Repositories to Google Cloud Run with a Single Click

If you have a public repository with a Dockerfile you can have users automatically deploy the container to Google Cloud Run by adding a Cloud Run Button. It’s no more than an image that links to https://deploy.cloud.run, like so:

[![Run on Google Cloud](https://deploy.cloud.run/button.svg)](https://deploy.cloud.run)

Add that code to your README.md and when a visitor follows that link, Cloud Shell will open and it will Clone, Build, and Deploy the project onto Cloud Run for them. No need to manually create things in the Google Cloud Console nor use the gcloud binary 🙂

You basically only need the button, but you can tweak the source repository parameters through the querystring:

  • When no parameters are passed, the referer is used to detect the git repo and branch
  • To specify a git repo, add a git_repo=URL query parameter
  • To specify a git branch, add a revision=BRANCH_NAME query parameter.
  • To run the build in a subdirectory of the repo, add a dir=SUBDIR query parameter.

There’s also an app.json that you can optionally add to the root of your repo to tweak the deployment parameters.

{
    "name": "foo-app",
    "env": {
        "BACKGROUND_COLOR": {
            "description": "specify a css color",
            "value": "#fefefe",
            "required": false
        },
        "TITLE": {
            "description": "title for your site"
        },
        "APP_SECRET": {
            "generator": "secret"
        }
    },
    "options": {
        "allow-unauthenticated": false
    },
    "hooks": {
        "precreate": {
            "commands": [
                "echo 'test'"
            ]
        },
        "postcreate": {
            "commands": [
                "./setup.sh"
            ]
        }
    }
}

The values defined in the env key will be translated to prompts for Cloud Shell to ask. The props of each prompt is pretty straightforward but the special case of "generator": "secret" will ask/generate a secret.

By default it will deploy with allow-unauthenticated set to true but through the options you can override that.

The hooks part finally allows you to run commands in separate bash shells with the environment variables configured for the application and environment variables for GOOGLE_CLOUD_PROJECT, GOOGLE_CLOUD_REGION, and K_SERVICE.

~

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Deploying multi-source sites to Netlify

Deploying one site (from a single source repo) to Netlify ain’t that hard – see my instructions here – but what if your sources are spread out across multiple repos? How do you combine the data without duplicating it into a monorepo?

That’s exactly the problem Spatie was having for their docs.spatie.be: the website holds the documentation for all of their (bigger) open source packages, but the documentation itself is not part of said repo but is stored within each project’s repository.

To solve this they first created an inventory file repositories.json. The file keeps track of each part of the documentation and its location. Using a script named fetch-content.js they aggregate all those documentation parts:

const util = require("util");
const exec = util.promisify(require("child_process").exec);
console.log('Fetching repositories...');
console.time('Fetched repositories');

const repositories = require("./repositories.json");

function transformBranchToFolderName(branch) {
    return branch.startsWith('v') ? branch.substring(1) : branch;
}

(async function () {
    let promises = [];

    for (const repository of repositories) {
        for (const [branch, alias] of Object.entries(repository.branches)) {
            const folder = `content/${repository.name}/${alias}`;
            const url = `https://codeload.github.com/${repository.repository}/tar.gz/${branch}`;

            promises.push(exec(`mkdir -p ${folder} && curl ${url} \
             | tar -xz -C ${folder} --strip=2 ${repository.repository.split('/')[1]}-${transformBranchToFolderName(branch)}/docs \
             && echo "---\ntitle: ${repository.name}\ncategory: ${repository.category}\n---" > content/${repository.name}/_index.md`));
      
        }
    }

    await Promise.all(promises);
    console.timeEnd('Fetched repositories');
})();

To build the site they first launch fetch-content.js and successively run hugo.

[build]
  command = "node fetch-content.js && hugo -b https://docs.spatie.be"
  publish = "public"

By adding webhooks which point to the same endpoint on all of the listed repos, the docs website is built whenever a commit to any of those repos is pushed.

Going serverless with Hugo and Netlify →
docs.spatie.be Source (GitHub) →

Fastlane Screencast: Integrate fastlane into your Ionic Framework build process

fastlane are an awesome bunch of tools. Josh Holtz has recently started Fastlane Screencast, a website with videos/tutorials for explaining and implementing built-in fastlane tools, fastlane actions, third-party fastlane plugins, continuous integration, and anything else that fastlane can possibly do.

The first video covers integrating fastlane into your Ionic Framework build process:

A second tutorial – covering dotenv and environment variables – is already up too 🙂

Fastlane Screencast →
Fastlane Screencast: Integrate fastlane into your Ionic Framework build process →

Δ now: realtime global deployments

Δnow allows you to take your JavaScript (Node.js) or Docker powered websites, applications and services to the cloud with ease, speed and reliability. Every time you deploy a project, Δnow gives you a unique URL to it (even before build processes are complete!).
When it’s time to take your deployment to production, you simply pick an appropriate alias.

You can think of Δnow as a CDN for dynamic code (microservices and backends).

After having checked the video above, check out Now & Next.

Δnow →

Deployment at Github

deploying-at-github

All deployments happen in chat via Hubot commands, which ensures that everyone in the company (from development to operations to support) has visibility into changes that are being pushed into production.

Deploying branches to GitHub.com →

Reminds me of how deployments at Etsy happen. They’ve got Deployinator integrated into IRC and deploy using deployment trains. See Scaling Deployment at Etsy for more info.

Deployment with Envoy

// Contents of Envoy.blade.php
@servers(['web' => 'deploy-ex'])

<?php
$repo = '[email protected]:Servers-for-Hackers/deploy-ex.git';
$release_dir = '/var/www/releases';
$app_dir = '/var/www/app';
$release = 'release_' . date('YmdHis');
?>

@macro('deploy', ['on' => 'web'])
    fetch_repo
    run_composer
    update_permissions
    update_symlinks
@endmacro

@task('fetch_repo')
    [ -d {{ $release_dir }} ] || mkdir {{ $release_dir }};
    cd {{ $release_dir }};
    git clone {{ $repo }} {{ $release }};
@endtask

@task('run_composer')
    cd {{ $release_dir }}/{{ $release }};
    composer install --prefer-dist;
@endtask

@task('update_permissions')
    cd {{ $release_dir }};
    chgrp -R www-data {{ $release }};
    chmod -R ug+rwx {{ $release }};
@endtask

@task('update_symlinks')
    ln -nfs {{ $release_dir }}/{{ $release }} {{ $app_dir }};
    chgrp -h www-data {{ $app_dir }};
@endtask

We’ll use Laravel’s Envoy to deploy a PHP application to a production server. This will make a new release directory, clone the repository into it, run any needed build steps, and then finally swap the new code out with the older code, so that Nginx and PHP-FPM serve the new code.

Now that config is very readable. Video available at the original post.

Servers for Hackers: Deployment with Envoy →

PHPloy – Git FTP Deployment

; This is a sample deploy.ini file.
; You can specify as many servers as you need
; and use whichever configuration way you like.

[staging]
user = example
pass = password
host = staging-example.com
path = /path/to/installation
port = 21
passive = true

[production]
user = example
pass = password
host = production-example.com
path = /path/to/installation
port = 21
passive = true

; If that seemed too long for you, you can use quickmode instead:
[quickmode]
    staging = ftp://example:[email protected]:21/path/to/installation
    production = ftp://example:[email protected]:21/path/to/installation

PHPloy is a little PHP script that allows you to deploy files through FTP to a server. It makes use of Git to know which files it should upload and which one it should delete. PHPloy supports deployments of submodules and sub-submodules.

Comparable to the aforementioned git-ftp.py, yet written in PHP. PHPloy also supports rollbacks and multiple servers.

PHPloy →

Automatic Website Publishing with git-ftp.py on Mac OS X

On a recent project I collaborated on, deployment happened via git-ftp.py, a Python script which automatically publishes your git repository to an FTP server.

The script itself works with with an git-rev.txt file on the FTP server which keeps track of the last published commit. When deploying via git-ftp.py, the script only uploads the changes made since the last published commit.

~

Installing git-ftp

git-ftp.py relies on GitPython which itself can easily be installed using easy_install if you don’t want to worry about dependencies and the like.

  1. Install easy_install
    • Check your python version at the Terminal by running python (quit the python prompt by running exit() or hitting CTRL+D)
    • Download the correct .egg from http://pypi.python.org/pypi/setuptools/ (in my case: the one with 2.7 in its filename as my python version is 2.7.1)
    • Install it at the Terminal with sudo sh setuptools-0.6c11-py2.7.egg
  2. Install GitPython using easy_install
    • Just run sudo easy_install GitPython in Terminal and it’ll install GitPython along with all its dependencies for you
  3. Install git-ftp.py

~

Deploying with git-ftp.py

Before being able to deploy with git-ftp.py, you’ll have to provide it some FTP credentials. To do so, create a file ftpdata inside the (hidden) .git folder of your project (so the file is /path/to/project/.git/ftpdata). Set the contents of it to something like this:

[master]
username=projectname
password=projectpass
hostname=ftp.myproject.be
remotepath=/public_html
ssl=no

Note: you can add per-branch credentials if you want. Just duplicate the block and change [master] to the name of the branch you’re targetting.

Once configured, you can start deploying using this command:

python ~/Library/git-ftp.py

The script will output a list of all files that were uploaded.

Note: If you run git-ftp.py for the very first time on an FTP server containing an already published version of the project you should first place a git-rev.txt file on the server. Set the contents of the file to the SHA1 of the last commit which is already present on the server. Otherwise git-ftp.py will upload the whole repository which is not necessary.

~

Pro tip #1: set up an alias and save some time

In order to not having to type the entire publishing command all the time, set up an alias in .bash_profile. Run these commands at the Terminal:

echo "alias git-ftp='python ~/Library/git-ftp.py'" >> ~/.bash_profile
source ~/.bash_profile

That way you can deploying using this command:

git-ftp

~

Pro tip #2: Use a bare repository as a proxy

With git-ftp.py, it’s also possible to have a repository automatically publish when it’s being pushed upon. The git-ftp.py project has full instructions on how to set this up (haven’t used it myself).

~

Happy Deploying!

Did this help you out? Like what you see?
Consider donating.

I don’t run ads on my blog nor do I do this for profit. A donation however would always put a smile on my face though. Thanks!

☕️ Buy me a Coffee ($3)

Note: Whilst researching this I’ve stumbled upon git-ftp (not the same as git-ftp.py!), a shell script which – if I understand correctly – does about the same.

Alternatively – if you have Transmit – you could use Dock Send along with git-transmit.

If you’re more fond of the GitHub way of publishing (using a gh-pages branch), you’ll want to check out my own guide on Automatic website publishing with Git, GitHub-Style.

Finally, if you’re running all-Linux machines with SSH enabled, you’ll be better of with Capistrano.