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