# 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
- ...
```