---
# System prepended metadata

title: CI&CD Learning
tags: [gitlab, CI&CD]

---

# CI&CD Learning
###### tags: `CI&CD` `gitlab`
* Continuous Integration (CI)
* Continuous Delivery (CD)
* Continuous Deploymeny(CD)

Continuous Integration works by pushing small code chunks to your application's code base hosted in a Git repository and to every push, run a pipeline of scripts to build, test and validate the code chnages before merging them into the main branch
Continuous Delivery and deployment consist of a step further CI, deploying your application to production at every push to the default branch of the repository.

## GitLab CI/CD
It's configured by a file called `.gitlab-ci.yml` placed at the repositories root.The scripts set in this file are executed by the [GitLab Runner](https://docs.gitlab.com/runner/)

We will set on ubuntu 18.04 using the following steps:
- Create `deployer` user
- Install gitlab runner
- Register new gitlab runner
- Create `.gitlab-ci.yml` file

For the purpose of this demo we'll be deploying a laravel app. For server setup we're using LEMP Stack [How to setup Lemp Stack](https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-ubuntu-18-04)

#### 1. Create deployer

ssh to your remote server

    ssh root@public_ip_address
    
Create new user

    adduser deployer #Fill in user info and password
    usermod -g www-data deployer # Assign group www-data(primary)
    
Now ssh with user created to create ssh keys

    ssh deployer@public_ip_address
    

    
    

#### 2. Install gitlab runner
shh into remote server
Add GitLab's official repository

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

    apt-get install gitlab-runner
    

#### 3. Register new gitlab runner
This is the process that binds the runner with a GitLab instance. In order to register a runner, you need to obtain a token for your project, This can be found in the setting under CI/CD of you repository on gitlab

Run:
    
    gitlab-runner register
    
This command will ask you a series of questions:

    Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/): 
In our case we used `https://git.ralphowino.com/`


    Enter the token you obtained to register the Runner: 
Enter the token from your gitlab account


    Enter a description for the Runner, you can change this later in GitLab’s UI: 
Give your runner a descrition


    Please enter the gitlab-ci tags for this runner (comma separated):
    
Select executor to use
    
    Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell:
In our case we take `ssh` though it's not recommended. 
    
#### 4. Create `.gitlab-ci.yml` file
The following shows the sample of gitlab-ci.yml file we'll use:

```
stages:
  - building
  - testing
  - deploy

composer:
  stage: building
  image: composer:latest
  script:
    - composer install --prefer-dist --no-ansi --no-interaction --no-progress --no-scripts
    - cp .env.example .env
    - php artisan key:generate
  artifacts:
    paths:
      - vendor/
      - .env
    expire_in: 1 days
    when: always
  cache:
    paths:
      - vendor/

phpunit:
  stage: testing
  image: php:7.3-cli
  dependencies:
    - composer
  script:
    - ./vendor/bin/phpunit

deploying:
  image: ubuntu:latest
  dependencies:
    - phpunit
  stage: deploy
  before_script:
    - 'which ssh-agent || ( apt-get update -y && apt-get install sshpass -y && apt-get install openssh-client -y )'
    - mkdir -p ~/.ssh
    - eval $(ssh-agent -s)
    - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
    - ssh-add <(echo "$SSH_PRIVATE_KEY")
  script:
    - ssh deployer@"$QA_SERVER" "cd /var/www/html/cicd && git pull origin master"

```

I'll explain the deploying stage:
- Generate a public/private key pair will be used to ssh to our server.
- In your project settings/cicd, add the following variable
    - `SSH_PRIVATE_KEY` its value to be private key generated in the first step
    - `QA_SERVER` its value to be the public ip or domain of the server you want to deploy

###### image: ubuntu:latest
Deploying job depends will run on a ubuntu OS hence the `image: ubuntu:latest` entry. 

###### dependencies
It depends on `phpunit` job so if phpunit fails deploying won't run.

###### stage: deploy
The job should be run in the deploy stage of the pipeline

###### before_script
It run before any scripts in the deploying job are executed.
1. `which ssh-agent || ( apt-get update -y && apt-get install sshpass -y && apt-get install openssh-client -y )`  used to check if ssh client is install if none (`||`) install openssh client and sshpass. In our case we don't need sshpass(used to ssh using a password not recommended) so `which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )` would work.
2. `mkdir -p ~/.ssh` make .ssh directory in our home directory. `-p` flag means make any parent directory.
3. `eval $(ssh-agent -s)` start ssh client
4. `'[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'` automatically add new host keys to the user known hosts files.
5. `ssh-add <(echo "$SSH_PRIVATE_KEY")` add private key to our client.

###### script
`ssh deployer@"$QA_SERVER" "cd /var/www/html/cicd && git pull origin master"`. shh to our server navigate to our projects root and run a gill pull to get the latest changes. This step will work for public repositories. 

When using git-lab private repos you'll need to add the public key of our `deployer` user to git project as a deployment key for authentication. Under project `settings/repository` add a deployment key.

Branching - to deploy changes pushed to specific branches add in the deployment job
```
only:
    - master
    - ...
      
```
     