# 🇬🇧 Fn project and GitLab CI - Part II

Hi! In the previous part: "Discovering Fn project", I explained how to set up Fn Project, how to write your 1st function and how to use a private registry. Then, I asked my self 2 questions:

  • What is the best way to manage source code of a serverless project with GitLab (or any other SCM software)?
  • How can I do continuous integration and deployment with GitLab CI (or any other CI software)?

Right now, I'm not sure to have the best answers, but I investigated and experimented with 2 things and let me explain that (the first thing today, the second will come in another blog post).

👋 ⚠️ This document is going to be a very very long blog post because at this time I use several VMs. So take your time, make yourself a good coffee. I think you need a computer, with at least 16 GB Ram. However, you can adapt Vagrantfiles, use multiple computers, or use VMs on the cloud. (e.g.: I use 2 runners, but you can probably use only one)

# My Vagrant project structure

.
├── config.rb
├── docker-registry
│   └── Vagrantfile
├── fnproject
│   └── Vagrantfile
├── fnproject-dev
│   └── Vagrantfile
├── gitlab
│   └── Vagrantfile
├── sandbox-runner
│   └── Vagrantfile
└── sandbox-runner-dev
    └── Vagrantfile

the config.rb file keeps all the IP addresses of the VM:

REGISTRY_NAME = "private-registry"
REGISTRY_IP = "172.16.245.160"
REGISTRY_PUBLIC_IP = "192.168.1.160"
REGISTRY_DOMAIN = "registry.test"
REGISTRY = "registry.test:5000"

REGISTRY_DEV = "registry.test:5001"

FN_DEV_SERVER_NAME = "fnproject-dev"
FN_DEV_SERVER_DOMAIN = "fnproject_dev.test"
FN_DEV_IP = "172.16.245.199"
FN_DEV_PUBLIC_IP = "192.168.1.199"

FN_SERVER_NAME = "fnproject"
FN_SERVER_DOMAIN = "fnproject.test"
FN_IP = "172.16.245.200"
FN_PUBLIC_IP = "192.168.1.200"

# === GitLab instance ===
GITLAB_DOMAIN = "gitlab-faas.test"
GITLAB_IP = "172.16.245.122"
GITLAB_PUB_IP = "192.168.1.122"
GITLAB_NAME = "gitlab-faas"

# Information from the GitLab instance, used by the GitLab runners
CI_REGISTRATION_TOKEN="VBG7_cYuu3DGnW1a3xEm"
CI_REGISTRATION_URL="http://gitlab-faas.test/"

SANDBOX_RUNNER_NAME="sandboxrunner"
SANDBOX_RUNNER_IP="172.16.245.135"
SANDBOX_RUNNER_PUB_IP = "192.168.1.135"
SANDBOX_RUNNER_TAG = "sandbox"

SANDBOX_DEV_RUNNER_NAME="sandboxrunner-dev"
SANDBOX_DEV_RUNNER_IP="172.16.245.134"
SANDBOX_DEV_RUNNER_PUB_IP = "192.168.1.134"
SANDBOX_DEV_RUNNER_TAG = "sandbox_dev"

Remark: You can see that I provide 2 IP addresses for each VM. I provide a private and a public IP address (the one you will see on your computer and another you will see from any computer on the same network)

Now I present all my Vagrant files (sometimes you should need to adapt some parts, especially about LAN setup for example).

# Vagrant file for the Docker registries

I created two registries in the same VM, and we can reach them at:

  • registry.test:5000
  • registry.test:5001
load '../config.rb'

BOX_IMAGE = "bento/ubuntu-16.04"
VERSION = "1.0"

Vagrant.configure("2") do |config|
  config.vm.box = BOX_IMAGE
  ENV['LC_ALL']="en_US.UTF-8"

  config.vm.define "#{REGISTRY_NAME}" do |node|

    node.vm.hostname = "#{REGISTRY_NAME}"    
    node.vm.network "public_network", ip: "#{REGISTRY_PUBLIC_IP}", bridge: "en0: Wi-Fi (AirPort)"
    node.vm.network "private_network", ip: "#{REGISTRY_IP}"

    node.vm.provider "virtualbox" do |vb|
      vb.memory = 512
      vb.cpus = 2
      vb.name = "#{REGISTRY_NAME}"
    end

    node.vm.provision :shell, inline: <<-SHELL
      apt-get update

      curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
      apt-key fingerprint 0EBFCD88
      add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
      apt-get update
      apt-get install -y docker-ce

      echo "😀 run registries"
      docker run -d -p 5000:5000 --restart=always --name registry registry:2
      docker run -d -p 5001:5000 --restart=always --name registry-dev registry:2      
    SHELL

  end

end

To run the registries VM you have to type:

cd docker-registry
vagrant up

⚠️ You must update your hosts file (e.g.: sudo vi /etc/hosts) and add this entry:

172.16.245.160 registry.test

# Vagrant file for the GitLab instance + setup

It's very easy to install a GitLab instance (I used the Omnibus package installation: https://about.gitlab.com/installation/#ubuntu)

# === 🦊 GitLab ===
load '../config.rb'

BOX_IMAGE = "bento/ubuntu-16.04"
VERSION = "1.0"

Vagrant.configure("2") do |config|
  config.vm.box = BOX_IMAGE

  ENV['LC_ALL']="en_US.UTF-8"

  config.vm.define "#{GITLAB_NAME}" do |node| 

    node.vm.hostname = "#{GITLAB_NAME}"
  
    node.vm.network "public_network", ip:"#{GITLAB_PUB_IP}",  bridge: "en0: Wi-Fi (AirPort)"
    node.vm.network "private_network", ip: "#{GITLAB_IP}"

    node.vm.provider "virtualbox" do |vb|
      vb.memory = 4096
      vb.cpus = 2
      vb.name = "#{GITLAB_NAME}"
    end

    node.vm.provision :shell, inline: <<-SHELL
      echo "👋 setup"
      # download GitLab packages
      curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | sudo bash
      # install GitLab
      EXTERNAL_URL="http://#{GITLAB_DOMAIN}" apt-get install -y gitlab-ee

      echo "Bye! 👋👋👋 go to http://#{GITLAB_DOMAIN}"
      echo "- Change the password of the root user"
    SHELL
    
  end
  # end of GitLab setup

end

To run the GitLab VM you have to type:

cd gitlab
vagrant up

⚠️ You must update your hosts file and add this entry:

172.16.245.122 gitlab-faas.test

Now, you can reach your GitLab instance with this url: http://gitlab-faas.test (opens new window). The first time you connect you have to create a root user (and create your user with admin rights). Once connected (with admin rights) you have to get the CI token to give the rights to your runners to use GitLab CI:

# Information from the GitLab instance, used by the GitLab runners
CI_REGISTRATION_TOKEN="your token"
CI_REGISTRATION_URL="http://gitlab-faas.test/"

Don't forget to copy the GitLab instance url with the / at the end

# Vagrant file(s) for the Fn-Project server

I created 2 Vagrant files because I want a production server and a development server.

# Development server

load '../config.rb'

BOX_IMAGE = "bento/ubuntu-16.04"
VERSION = "1.0"

Vagrant.configure("2") do |config|
  config.vm.box = BOX_IMAGE
  ENV['LC_ALL']="en_US.UTF-8"

  config.vm.define "#{FN_DEV_SERVER_NAME}" do |node|

    node.vm.hostname = "#{FN_DEV_SERVER_NAME}"
    
    node.vm.network "public_network", ip: "#{FN_DEV_PUBLIC_IP}", bridge: "en0: Wi-Fi (AirPort)"
    node.vm.network "private_network", ip: "#{FN_DEV_IP}"

    node.vm.provider "virtualbox" do |vb|
      vb.memory = 1024
      vb.cpus = 2
      vb.name = "#{FN_DEV_SERVER_NAME}"
    end

    node.vm.provision :shell, inline: <<-SHELL

      apt-get update

      # ----- Docker Installation -----
      curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
      apt-key fingerprint 0EBFCD88
      add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
      apt-get update
      apt-get install -y docker-ce

      # ----- Fn Project Installation -----
      curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh

      # Add entries to hosts file:
      echo "" >> /etc/hosts
      echo '#{REGISTRY_IP} #{REGISTRY_DOMAIN}' >> /etc/hosts 
      echo "" >> /etc/hosts

      # Add unsecure registry
      echo "" >> /etc/docker/daemon.json
      echo '{' >> /etc/docker/daemon.json
      echo '  "insecure-registries" : ["#{REGISTRY_DEV}"]' >> /etc/docker/daemon.json
      echo '}' >> /etc/docker/daemon.json
      echo "" >> /etc/docker/daemon.json

      service docker restart

    SHELL

    node.vm.provision :shell, run: "always", inline: <<-SHELL
      nohup sudo fn start > /dev/null 2>&1 & 
    SHELL

  end

end

Remarks: my VM need to "see" on the network the docker registry, so I added an entry in the hosts file (echo '#{REGISTRY_IP} #{REGISTRY_DOMAIN}' >> /etc/hosts) and I declared the registry as an insecure registry in the daemon.json file (echo ' "insecure-registries" : ["#{REGISTRY_DEV}"]' >> /etc/docker/daemon.json)

# Production server

The Vagrant file is almost the same:

load '../config.rb'

BOX_IMAGE = "bento/ubuntu-16.04"
VERSION = "1.0"

Vagrant.configure("2") do |config|
  config.vm.box = BOX_IMAGE
  ENV['LC_ALL']="en_US.UTF-8"

  config.vm.define "#{FN_SERVER_NAME}" do |node|

    node.vm.hostname = "#{FN_SERVER_NAME}"
    
    node.vm.network "public_network", ip: "#{FN_PUBLIC_IP}", bridge: "en0: Wi-Fi (AirPort)"
    node.vm.network "private_network", ip: "#{FN_IP}"

    node.vm.provider "virtualbox" do |vb|
      vb.memory = 1024
      vb.cpus = 2
      vb.name = "#{FN_SERVER_NAME}"
    end

    node.vm.provision :shell, inline: <<-SHELL

      apt-get update

      # ----- Docker Installation -----
      curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
      apt-key fingerprint 0EBFCD88
      add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
      apt-get update
      apt-get install -y docker-ce

      # ----- Fn Project Installation -----
      curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh

      # Add entries to hosts file:
      echo "" >> /etc/hosts
      echo '#{REGISTRY_IP} #{REGISTRY_DOMAIN}' >> /etc/hosts 
      echo "" >> /etc/hosts

      # Add unsecure registry
      echo "" >> /etc/docker/daemon.json
      echo '{' >> /etc/docker/daemon.json
      echo '  "insecure-registries" : ["#{REGISTRY}"]' >> /etc/docker/daemon.json
      echo '}' >> /etc/docker/daemon.json
      echo "" >> /etc/docker/daemon.json

      service docker restart

    SHELL

    node.vm.provision :shell, run: "always", inline: <<-SHELL
      nohup sudo fn start > /dev/null 2>&1 & 
    SHELL

  end

end

To run the 2 Fn-Project VMs you have to type:

cd fnproject-dev
vagrant up
cd fnproject
vagrant up

⚠️ You must update your hosts file and add this entry:

172.16.245.200 fnproject.test # http://fnproject.test:8080 
172.16.245.199 fnproject_dev.test # http://fnproject_dev.test:8080

# And finally, the Vagrant file(s) for the GitLab runners

I'm using 2 runners, one to deploy on the development server and the other to deploy on the production server.

Each runner needs the following components:

  • Docker client
  • GitLab Runner
  • Fn project CLI

And I need to declare for the two runners that they can use an unsecured registry (I declared the registry as an insecure registry in the daemon.json file (echo ' "insecure-registries" : ["#{REGISTRY_DEV}"]' >> /etc/docker/daemon.json))

And I updated the hosts file of each runner, so now they can "see" on the network these VMS:

  • GitLab
  • The Docker Registries
  • The Fn Project servers

And finally, I registered the 2 runners with the CI token (CI_REGISTRATION_TOKEN), like that:

gitlab-runner register --non-interactive \
--url "#{CI_REGISTRATION_URL}" \
--name "#{SANDBOX_DEV_RUNNER_NAME}" \
--registration-token #{CI_REGISTRATION_TOKEN} \
--tag-list "#{SANDBOX_DEV_RUNNER_TAG}" \
--executor shell

# Development runner

# GitLab Runner [TESTS]
load '../config.rb'

BOX_IMAGE = "bento/ubuntu-16.04"
VERSION = "1.0"

Vagrant.configure("2") do |config|
  config.vm.box = BOX_IMAGE

  ENV['LC_ALL']="en_US.UTF-8"

  config.vm.define "#{SANDBOX_DEV_RUNNER_NAME}" do |node|

    node.vm.hostname = "#{SANDBOX_DEV_RUNNER_NAME}"
    
    node.vm.network "public_network", ip:"#{SANDBOX_DEV_RUNNER_PUB_IP}", bridge: "en0: Wi-Fi (AirPort)"
    node.vm.network "private_network", ip: "#{SANDBOX_DEV_RUNNER_IP}"

    node.vm.provider "virtualbox" do |vb|
      vb.memory = 512
      vb.cpus = 1
      vb.name = "#{SANDBOX_DEV_RUNNER_NAME}"
    end

    node.vm.provision :shell, inline: <<-SHELL
      echo "👋 setup"

      apt-get install -y sshpass

      # ----- Install Docker -----
      curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
      apt-key fingerprint 0EBFCD88
      add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
      apt-get update
      apt-get install -y docker-ce
      # -----------------------  

      # Install GitLab Runner
      curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
      apt-get install -y gitlab-runner

      # Install Fn project CLI
      curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh

      # Add entries to hosts file:
      echo "" >> /etc/hosts
      echo '#{GITLAB_IP} #{GITLAB_DOMAIN}' >> /etc/hosts 
      echo '#{REGISTRY_IP} #{REGISTRY_DOMAIN}' >> /etc/hosts 
      echo '#{FN_DEV_IP} #{FN_DEV_SERVER_DOMAIN}' >> /etc/hosts 
      echo "" >> /etc/hosts

      # Add unsecure registry
      echo "" >> /etc/docker/daemon.json
      echo '{' >> /etc/docker/daemon.json
      echo '  "insecure-registries" : ["#{REGISTRY_DEV}"]' >> /etc/docker/daemon.json
      echo '}' >> /etc/docker/daemon.json
      echo "" >> /etc/docker/daemon.json

      service docker restart

      # Registering GitLab Runner
      gitlab-runner register --non-interactive \
        --url "#{CI_REGISTRATION_URL}" \
        --name "#{SANDBOX_DEV_RUNNER_NAME}" \
        --registration-token #{CI_REGISTRATION_TOKEN} \
        --tag-list "#{SANDBOX_DEV_RUNNER_TAG}" \
        --executor shell

    SHELL

    node.vm.provision :shell, run: "always", inline: <<-SHELL
    # add $USER to docker group
    usermod -a -G docker $USER
    # allowing non-sudo use
    chmod 666 /var/run/docker.sock
  SHELL

  end

end

Remark: you can read this line --tag-list "#{SANDBOX_DEV_RUNNER_TAG}" for the runner registration, and if you read the config.rb file, you can see that the value of SANDBOX_DEV_RUNNER_TAG is sandbox_dev. This tag is convenient to choose which runner to use for a CitLab CI job.

# Production runner

# GitLab Runner [TESTS]
load '../config.rb'

BOX_IMAGE = "bento/ubuntu-16.04"
VERSION = "1.0"

Vagrant.configure("2") do |config|
  config.vm.box = BOX_IMAGE

  ENV['LC_ALL']="en_US.UTF-8"

  config.vm.define "#{SANDBOX_RUNNER_NAME}" do |node|

    node.vm.hostname = "#{SANDBOX_RUNNER_NAME}"
    
    node.vm.network "public_network", ip:"#{SANDBOX_RUNNER_PUB_IP}", bridge: "en0: Wi-Fi (AirPort)"
    node.vm.network "private_network", ip: "#{SANDBOX_RUNNER_IP}"

    node.vm.provider "virtualbox" do |vb|
      vb.memory = 512
      vb.cpus = 1
      vb.name = "#{SANDBOX_RUNNER_NAME}"
    end

    node.vm.provision :shell, inline: <<-SHELL
      echo "👋 setup"

      apt-get install -y sshpass

      # ----- Install Docker -----
      curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
      apt-key fingerprint 0EBFCD88
      add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
      apt-get update
      apt-get install -y docker-ce
      # -----------------------  

      # Install GitLab Runner
      curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
      apt-get install -y gitlab-runner

      # Install Fn project CLI
      curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh

      # Add entries to hosts file:
      echo "" >> /etc/hosts
      echo '#{GITLAB_IP} #{GITLAB_DOMAIN}' >> /etc/hosts 
      echo '#{REGISTRY_IP} #{REGISTRY_DOMAIN}' >> /etc/hosts 
      echo '#{FN_IP} #{FN_SERVER_DOMAIN}' >> /etc/hosts 
      echo "" >> /etc/hosts

      # Add unsecure registry
      echo "" >> /etc/docker/daemon.json
      echo '{' >> /etc/docker/daemon.json
      echo '  "insecure-registries" : ["#{REGISTRY}"]' >> /etc/docker/daemon.json
      echo '}' >> /etc/docker/daemon.json
      echo "" >> /etc/docker/daemon.json

      service docker restart

      # Registering GitLab Runner
      gitlab-runner register --non-interactive \
        --url "#{CI_REGISTRATION_URL}" \
        --name "#{SANDBOX_RUNNER_NAME}" \
        --registration-token #{CI_REGISTRATION_TOKEN} \
        --tag-list "#{SANDBOX_RUNNER_TAG}" \
        --executor shell

    SHELL

    node.vm.provision :shell, run: "always", inline: <<-SHELL
    # add $USER to docker group
    usermod -a -G docker $USER
    # allowing non-sudo use
    chmod 666 /var/run/docker.sock
  SHELL

  end

end

Remark: you can read this line --tag-list "#{SANDBOX_RUNNER_NAME}" for the runner registration, and if you read the config.rb file, you can see that the value of SANDBOX_RUNNER_NAME is sandbox. This tag is convenient to choose which runner to use for a CitLab CI job.

So, it's done with the setup part. Now we can create our first FaaS project 🎉

# First FaaS project

First, you need to install the Fn CLI on your computer (see the previous blog post: http://k33g.gitlab.io/articles/2018-08-13-FNPROJECT.html#create-your-first-function (opens new window))

# Create a hello-world project

fn init --runtime node hello-world

And of course you can test it with:

cd hello-world
fn run

# Create a repository on GitLab

First, go to your GitLab instance and create an empty project named "hello-world"

The, on your side (your laptop, your computer, ...)

cd hello-world
git init
git remote add origin git@gitlab-faas.test:k33g/hello-world.git
git add .
git commit -m ":tada: Initial commit"
git push -u origin master

Remarks: To be able to push your project, you need to set up you ssh key in your GitLab Profile (see https://docs.gitlab.com/ee/ssh/ (opens new window))

# Setup Continuous deployment for your Fn Function

Now the goal is to execute all the deployment procedures by the GitLab Runners.

So, on the GitLab side, in the settings section of your project, you have to create some environment variables that will be used by GitLab CI:

And add all these variables:

  • FN_API_URL with this value http://fnproject.test:8080
  • FN_REGISTRY with this value registry.test:5000
  • FN_DEV_API_URL with this value http://fnproject_dev.test:8080
  • FN_DEV_REGISTRY with this value registry.test:5001

We need to add your token user (or a token of a user with some rights), so you need to create a personal access token for your user (go to http://gitlab-faas.test/profile/personal_access_tokens (opens new window))

And again add these variables:

  • USER_CI with this value k33g (⚠️ k33g is my handle, please replace with your own)
  • USER_YOKEN with this value your_token (⚠️ please replace your_token with the appropriate value)

Don't forget to save the variables.

So, now in your project (on your computer), you have to create a file named .gitlab-ci.yml with this content:

stages:
  - deploy

variables:
  GIT_STRATEGY: clone

# Deploy the function in production
deploy_function_in_production:
  stage: deploy
  environment:
    name: production
    url:  $FN_API_URL/r/hello-world-app/hello-world
  tags:
    - sandbox # we are going to use the "production" runner
  only:
    - master # the job is triggered only when we push on the master branch

  script:
    - export FN_REGISTRY=$FN_REGISTRY
    - export FN_API_URL=$FN_API_URL
    - fn deploy --app hello-world-app

👋 ⚠️ Important: each time you use the command fn deploy --app hello-world-appis called, the fn project CLI will increment the version number of the function in this file: func.yaml. So we need to commit the update od the file in our project (otherwise, the function won't be deployed on the next change). So in the script section of the .gitlab-ci.yml add these lines:

    - git checkout -b "temp-master-branch"
    - git commit -m "auto increment version number at revision $CI_COMMIT_SHA [skip ci]" func.yaml || true
    - git push http://$USER_CI:$USER_TOKEN@gitlab-faas.test/k33g/hello-world.git HEAD:master

👋 ⚠️ Important: note the "key word" [skip ci] in the commit message, it's a workaround to "tell" GitLab CI "hey! don't run again the CI Job with this commit"

👋 ⚠️ Important bis repetitas: on your side, don't forget to do a git pull after a deployment to get the last version of the func.yaml file

Now, you can commit and push your new .gitlab-ci.yml file to GitLab:

git add .
git commit -m ":construction_worker: add CI file"
git push

And if you go to the CI/CD >> Pipelines section (http://gitlab-faas.test/k33g/hello-world/pipelines (opens new window)) of your project, you can see that there are 2 new jobs in the list:

  • one with the status passed, linked to the commit 👷 add CI file (when we created the file on the master branch)
  • another with the status skipped, linked to the commit auto increment version number at revision 3a2307ac [skip ci] (when the runner did the commit), btw if you read the history of the commit, you can check that the version number has changed.

If you browse the func.yaml file, you should get this content:

name: hello-world
version: 0.0.2
runtime: node
entrypoint: node func.js
format: json

And you can access to your deployed function with this link: http://fnproject.test:8080/r/hello-world-app/hello-world (opens new window), and you'll get something like that {"message":"Hello World"}.

Now, it's time to add more feature to our CI/CD workflow 😉

👋 don't forget to do a git pull

# Review App with Fn Project and GitLab CI

I really love the Review Apps feature of GitLab CI:

"Code, commit, and preview your branch in a live environment. Review Apps automatically spin up dynamic environments for your merge requests". You can find more information at https://about.gitlab.com/features/review-apps/ (opens new window).

So, we are going to update our .gitlab-ci.yml file, and in a moment, we'll be able to test our change in a preview environment before to deploy to the production environment (when we merge on the master branch). Add this new job at the end of the .gitlab-ci.yml file

# Deploy the function on the preview instance
deploy_function_for_preview:
  stage: deploy
  environment:
    name: preview
    url:  $FN_DEV_API_URL/r/hello-world-app/hello-world
  tags:
    - sandbox_dev # we are going to use the "dev" runner
  except: # the job is triggered only on feature branches
    - master
  script:
    - export FN_REGISTRY=$FN_DEV_REGISTRY
    - export FN_API_URL=$FN_DEV_API_URL
    - fn deploy --app hello-world-app
    - git checkout -b "temp_review_branch"
    - git commit -m "auto increment function version at revision $CI_COMMIT_SHA [skip ci]" func.yaml || true
    - git push http://$USER_CI:$USER_TOKEN@gitlab-faas.test/k33g/hello-world.git HEAD:$CI_COMMIT_REF_NAME

And commit your changes:

git add .
git commit -m ":construction_worker: update CI file [skip-ci]"
git push

Remark: I added [skip-ci] in the commit message to avoid to run the CI job

Now, each time, you'll create a merge request, at each commit, your feature branch will be deployed on the Development Fn Server (fnproject_dev.test), and you'll be able to test the function on this url: http://fnproject_dev.test:8080/r/hello-world-app/hello-world (opens new window). And each time you'll merge the feature branch (of your merge request) on the master branch, the updated function will be deployed on the production environment.

This is not perfect, and there are some bad/weird things in my project:

  • We don't master the version number of the function (there is an increment each time we commit something)

One working possibility would be to use the --no-bump flag when using the fn deploy command. But, in this case, we have to manage the version number by ourselves. E.g. we could determine the new number when merging.

  • In a normal way, when using the Review Apps, we get the url of the review app directly in the merge request page thanks the last result of the CI jobs. But in our case, the last CI job is skipped and we haven't this information.

Until we find a solution, you can got to the environment section of your project: http://gitlab-faas.test/k33g/hello-world/environments (opens new window) and you'll get the urls to acces to your functions.

In the next blog post (the part III) I will present an other way of managing a Fn project in GitLab with several functions in the same project, and so, I will come with some answers.

Last Articles