Creating test VMs via GitLab CI
You can use Yandex Cloud to automate routine tasks, such as running a specific script after each commit in the master
branch in a Git repository. The example below creates and tests a VM following each commit.
To configure Continuous Integration (CI) for VM disk snapshots:
- Create a VM for the test application: Create a new VM whose disk snapshot will be used to create new VMs via CI.
- Set the VM up with a test application: Deploy a web server and components to support the test application to the VM. Write a test application that will reverse the words in a text sent to the server.
- Check how the application works: Send a test request to check the server settings and the results.
- Create a VM disk snapshot: create a VM disk snapshot for CI to use to create new VMs.
- Create a VM with GitLab: create a VM with GitLab
to store CI settings and a functionality test script in a repository. - Configure GitLab: create a file repository and get the parameters required for configuration.
- Configure Runner: a tool for performing tasks.
- Configure CI: set the CI configuration by specifying the necessary parameters for commands and testing.
- Check that the application runs on the VM created using CI: make sure that the VMs you are trying to create with CI and the VM snapshot have been created and the test application is functional.
If you no longer need the created VMs, delete them.
Prepare your cloud
Sign up for Yandex Cloud and create a billing account:
- Go to the management console
and log in to Yandex Cloud or create an account if you do not have one yet. - On the Yandex Cloud Billing
page, make sure you have a billing account linked and it has theACTIVE
orTRIAL_ACTIVE
status. If you do not have a billing account, create one.
If you have an active billing account, you can go to the cloud page
Learn more about clouds and folders.
Before creating a VM:
- Go to the management console
Yandex Cloud and select the folder to perform your steps in. - Make sure the selected folder has a network with a subnet you can connect the VM to. To do this, select Virtual Private Cloud on the folder page. If the list contains a network, click on its name to see the list of subnets. If there is neither network nor subnet, create them.
Required paid resources
The cost of this infrastructure includes:
- A fee for continuously running VMs (see Yandex Compute Cloud pricing).
- A fee for storing created images (see Compute Cloud pricing).
- A charge for using dynamic public IPs (see Yandex Virtual Private Cloud pricing).
Create a VM for the test application
Create a VM to deploy the test application to, a set of components required for it to run, and a web server:
- On the folder page in the management console
, click Create resource and select Virtual machine. - In the Name field, enter the VM name as
ci-tutorial-test-app
. - Select an availability zone to place the VM in.
- Under Image/boot disk selection, go to the Cloud Marketplace tab and select a public Ubuntu 18.04 image.
- In the Computing resources section, select the following configuration:
- Platform: Intel Ice Lake.
- Guaranteed vCPU share: 20%.
- vCPU: 2.
- RAM: 1 GB.
- In Network settings, select the subnet to connect the VM to once it is created.
- Enter the VM access information:
- Click Create VM.
It may take a few minutes to create the VM. When the VM status changes to RUNNING
, you can start configuring it.
Once created, the VM is assigned an IP address and a host name (FQDN). This data can be used for SSH access.
Prepare a VM with the test application
On the created VM, deploy a collection of components required for the test application to run and a web server to handle requests. The application will be written in Python 2.
-
Under Network on the VM page in the management console
find the VM's public IP address. -
Connect to the VM via SSH. You can use the
ssh
utility in Linux or macOS, or PuTTY in Windows.ssh <Login>@<VM_public_IP>
-
Run the
apt update
command to update the lists of packages available for installation. -
Install the necessary packages (jq JSON processor, git client, PIP package manager, virtualenv virtual environment management system, the set of header files for Python C API, and the nginx web server):
sudo apt-get --yes install jq git python-pip virtualenv python-dev nginx-full
-
Create a directory to host the application. In addition, change the ownership of the directory to the user under which you will be connecting to the VM:
sudo mkdir /srv/test-app sudo chown -R $USER /srv/test-app
-
Go to the folder and create a
virtualenv
virtual environment in it:cd /srv/test-app virtualenv test-venv
-
Activate the virtual environment:
. test-venv/bin/activate
-
Install the Flask framework and the uWSGI web server in the virtual environment:
pip install flask uwsgi
-
Deactivate the virtual environment:
deactivate
-
Create the
api.py
file in the/srv/test-app
folder:touch api.py
-
Open the
api.py
file using any text editor, and insert the Python code that:- Accepts a text string as input in the
text
parameter. - Writes each word from the passed string in the opposite order.
- Returns a response:
- In JSON format, if the client application can accept JSON.
- In plain text if the client application does not accept JSON.
# api.py import json from flask import Flask, request, make_response as response app = Flask(__name__) @app.route("/") def index(): text = request.args.get('text') json_type = 'application/json' json_accepted = json_type in request.headers.get('Accept', '') if text: words = text.split() reversed_words = [word[::-1] for word in words] if json_accepted: res = response(json.dumps({'text': reversed_words}), 200) else: res = response(' '.join(reversed_words), 200) else: res = response('text not found', 501) res.headers['Content-Type'] = json_type if json_accepted else 'text/plain' return res
- Accepts a text string as input in the
-
Create the
wsgi.py
file in the/srv/test-app
folder:touch wsgi.py
-
Open the
wsgi.py
file using any text editor and insert the code that runs the test application:# wsgi.py from api import app if __name__ == "__main__": app.run()
-
Create the
test-app.ini
file in the/srv/test-app
folder:touch test-app.ini
-
Open the
test-app.ini
file using any text editor and insert the configuration of the uWSGI server:#test-app.ini [uwsgi] module = wsgi:app master = true processes = 1 socket = test-app.sock chmod-socket = 660 vacuum = true die-on-term = true
-
Assign the
www-data
user as the owner of the/srv/test-app
folder and the files it contains:sudo chown -R www-data:www-data /srv/test-app
-
Prepare the service to start your uWSGI server. To do this, make the
/etc/systemd/system/test-app.service
file look like this:#/etc/systemd/system/test-app.service [Unit] Description=uWSGI instance to serve test API After=network.target [Service] User=www-data Group=www-data WorkingDirectory=/srv/test-app Environment="PATH=/srv/test-app/test-venv/bin" ExecStart=/srv/test-app/test-venv/bin/uwsgi --ini test-app.ini [Install] WantedBy=multi-user.target
-
Specify the settings of the new virtual server in the nginx configuration by making the
/etc/nginx/sites-available/test-app.conf
file look like this:#/etc/nginx/sites-available/test-app.conf server { #server_name test-app.yandex www.test-app.yandex; listen 80; location /test/ { include uwsgi_params; uwsgi_param SCRIPT_NAME /test; uwsgi_modifier1 30; uwsgi_pass unix:/srv/test-app/test-app.sock; } }
-
Create a symbolic link that points to the Nginx configuration file
test-app.conf
:sudo ln -s /etc/nginx/sites-available/test-app.conf /etc/nginx/sites-enabled/
-
Delete the symbolic link that points to the default Nginx configuration:
sudo unlink /etc/nginx/sites-enabled/default
-
Add the service to the system autorun list:
sudo systemctl enable test-app.service
Check that the test application is working
To make sure the test application is functional and the web server is properly configured, send a simple request.
-
In the browser bar, enter the URL for testing the web server and application:
http://<VM_public_IP>/test/?text=hello_world
-
If everything is working, the screen will display text with reversed words from the
text
parameter.
Take a snapshot of the VM disk
To easily transfer the app and the web server configuration you created to VMs spawned with CI, you will need to take a snapshot of the test VM's disk.
- In the management console
Yandex Cloud, select the folder you created your VM in. - Select Compute Cloud.
- Find and select the VM called
ci-tutorial-test-app
. - Click Stop.
- In the window that opens, click Stop.
- After stopping the VM, select the Disks tab.
- In the row with the desired disk, click
and select Create snapshot. - In the window that opens, enter a name for the snapshot:
test-app-snap
. - Click Create snapshot.
Create a VM with GitLab
One of the ways to set up CI in Yandex Cloud is to take advantage of a public image with GitLab pre-installed. GitLab includes a set of tools for managing Git repositories and configuring CI.
- On the folder page in the management console
, click Create resource and select Virtual machine. - In the Name field, enter the VM name as follows:
ci-tutorial-gitlab
. - Select an availability zone to place the VM in.
- Under Image/boot disk selection, click the Cloud Marketplace tab and select GitLab as your image.
- In the Computing resources section, select the following configuration:
- Guaranteed vCPU share: 100%.
- vCPU: 2.
- RAM: 2 GB.
- In Network settings, select the subnet to connect the VM to once it is created.
- Enter the VM access information:
- Click Create VM.
It may take a few minutes to create the VM. When the VM status changes to RUNNING
, you can start configuring it.
Once created, the VM is assigned an IP address and a host name (FQDN). This data can be used for SSH access.
Configure GitLab
To set GitLab up and configure the CI process, create a new project and enter the CI login credentials:
-
On the Compute Cloud page, select the created VM and copy its public IP.
-
Connect to the VM via SSH.
-
Get the GitLab administrator password using the VM command:
sudo cat /etc/gitlab/initial_root_password
-
Copy the password (without spaces) from the
Password
row to the clipboard or a separate file. -
In the browser, open a link in the format
http://<public VM IP address>
. The GitLab web interface will open. -
Log in using the administrator account:
- Username or email:
root
. - Password: The previously copied password.
If you are unable to log in, reset the administrator account password
. - Username or email:
-
Log in to the system again using the administrator account and the new password.
-
Select Create a project.
-
Set the project name:
gitlab-test
. -
Click Create project.
-
Obtain an OAuth token from the Yandex OAuth service. To do this, follow the link
and click Allow. -
In the browser, open a link that looks like
http://<VM-public-IP-address>/root
. -
Select the
gitlab-test
project. -
On the screen that opens, choose the Settings tab on the left. In the menu that opens, select CI/CD.
-
Under Variables, click Expand.
-
Create a new variable:
- For the variable name, specify
YC_OAUTH
. - Specify the OAuth token you received as the value of the variable.
- Click Save variables.
- For the variable name, specify
-
Under Runners, click Expand.
-
Under Set up a specific Runner automatically, you will see the server address to connect to and the token for registering the server in the project. Use these values when registering Runner.
Configure Runner
Runner is a tool for performing tasks that a user creates. You need to deploy Runner to the VM and register it in GitLab. For Runner to be able to perform tasks, set up additional components: install the Yandex Cloud CLI and create a test to check the created VM.
-
Connect to the VM with GitLab over SSH:
ssh <Login>@<public_IP_of_VM_with_GitLab>
-
Add the new repository to the package manager:
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
-
Install the Runner that will run your CI scripts:
sudo apt-get -y install gitlab-runner
-
Register the Runner:
- When you get to
Please enter the gitlab-ci coordinator URL
, specify the GitLab server address. - In the step
Please enter the gitlab-ci token for this runner
, specify the Runner token. - In the step
Please enter the gitlab-ci description for this runner
, enter the descriptiongitlab test runner
. - In the step
Please enter the gitlab-ci tags for this runner
, don't type anything. Press Enter. - In the step
Please enter the executor
, specifyshell
.
sudo gitlab-runner register Runtime platform arch=amd64 os=linux pid=8197 revision=3afdaba6 version=11.5.0 Running in system-mode. Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/): http://<IP-address-ci-gitlab>/ Please enter the gitlab-ci token for this runner: <token-Runner> Please enter the gitlab-ci description for this runner: [ci-tutorial-gitlab]: gitlab test runner Please enter the gitlab-ci tags for this runner (comma separated): Registering runner... succeeded runner=wZqzyy9s Please enter the executor: virtualbox, docker+machine, docker-ssh+machine, kubernetes, docker, docker-ssh, shell, ssh, parallels: shell Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
- When you get to
-
For the CI script to be able to create VMs, please install the Yandex Cloud CLI:
curl https://storage.yandexcloud.net/yandexcloud-yc/install.sh --output install.sh sudo bash install.sh -n -i /opt/yc
-
To perform functional testing, install the
pytest
package:sudo apt-get install python-pytest
-
Create the
test.py
file with the functional testing script:-
Open the home page of the
gitlab-test
repository. -
Click + and choose New file.
-
In the window that opens, give the file the name
test.py
. -
Copy the following code to the file body:
# test.py import pytest import json import socket as s @pytest.fixture def hostname(request): with open("instance-creation.out", "r") as fd: fqdn = json.loads(fd.read()).get("fqdn") return fqdn @pytest.fixture def socket(request): _socket = s.socket(s.AF_INET, s.SOCK_STREAM) def socket_teardown(): _socket.close() request.addfinalizer(socket_teardown) return _socket def test_server_connect(socket, hostname): socket.connect((hostname, 80)) assert socket
-
Write any commit message and click Commit changes.
-
Configure CI
You need to define the configuration for CI.
-
Open the home page of the
gitlab-test
repository.http://<public_IP_of_VM_with_GitLab>/root/gitlab-test
-
Click Set up CI/CD. You will see the screen for adding a new file.
-
GitLab will automatically name the file
.gitlab-ci.yml
. Do not rename it. Copy the following configuration to the file:#.gitlab-ci.yml stages: - build - test build: stage: build variables: snapshot_name: test-app-snap folder_id: <folder ID> subnet_name: <subnet name> script: - export instance_name="ci-tutorial-test-app-$(date +%s)" - export PATH="/opt/yc/bin:${PATH}" - yc config set token $YC_OAUTH - yc compute instance create --format json --name $instance_name --folder-id $folder_id --zone ru-central1-a --network-interface subnet-name=$subnet_name,nat-ip-version=ipv4 --create-boot-disk name=$instance_name-boot,type=network-ssd,size=15,snapshot-name=$snapshot_name,auto-delete=true --memory 1 --cores 1 --hostname $instance_name > instance-creation.out - sleep 30 artifacts: when: on_success paths: - instance-creation.out expire_in: 10 mins test_external: stage: test script: - py.test test.py > pytest-external.out artifacts: paths: - pytest-external.out expire_in: 1 hour
-
In the
snapshot_name
field, enter the name of the first VM snapshot.
In thefolder_id
field, specify the ID of the folder where VMs are created.
In thesubnet_name
field, specify the name of the subnet that the VMs will connect to. You can retrieve the name in the management console by opening the appropriate folder and going to the Virtual Private Cloud service page. -
Click Commit changes.
Check how the application works on the VM created using CI
After the commit, you need to make sure that CI worked correctly. The desired folder should display a new VM where the test application and the web server are deployed.
To test the created VM:
-
Open the Yandex Cloud management console.
-
In the folder where the VMs were created, select Compute Cloud.
-
If everything has been properly configured, the VM list should display a new VM named something like
ci-tutorial-test-app-1543910277
. -
Select the created VM and copy the created VM's public address.
-
In the browser, open a link in this format:
http://<public_IP_of_created_VM>/test/?text=hello_world
-
The application created in the previous steps should also function on the created VM and return the inverted words from the
text
parameter.
Delete the resources you created
If you no longer need the VMs and images: