Software development infrastructure. Part 0x02. Setting things up. Gitlab

in #utopian-io7 years ago (edited)

Time to set up some containers. This is also where we make use of docker-compose.
wm_no_bg.png

What Will I Learn?

This is the next part of series of tutorials aimed at setting up a development infrastructure. Today we cover:

  • setting up of Gitlab in Docker
  • using Docker
  • using Docker Compose
  • automating the setup with bash scripts and a Makefile

Requirements

  • You need a running instance of Docker available
  • You need an installed Docker Compose
    Both of the above have been done in Part 0x01, be sure to check that out (no one submitted a homework, so the reward is still available, just saying).

Difficulty

It's all trivial.

Jokes aside, I'd say Intermediate. Some things will be super simple, some rather challenging. You are not expected to understand everything as I am not a perfect teacher. If you don't understand, don't feed your imposter syndrome, just ask. I will do my best to explain.

Tutorial Contents

Running docker compose

Just remember, there may be some differences in naming (for instance if you install docker through snap, it will be docker.compose, not docker-compose).

To start a set of containers with docker-compose, you will need to run

docker-compose up

This way you will see the logs and Ctrl+C will stop it (second Ctrl+C will kill it).

To clean up after that, run

docker-compose down

It will cleanup the network and stuff, but will leave volume folders intact. I need to sort this out.

If you start docker with

docker-compose up -d

it will be in detached state and you will be able to use the same terminal or close the window. You will not see the logs, however. If you want to see them now, you need to run

docker-compose logs

or add -f to keep them flowing.

All of the above commands assume that your docker-compose.yml file is in the current directory. If not, you need to add -f parameter followed by the location of you docker-compose.yml. For following the logs it makes the command line look silly:

docker-compose -f /path/t/docker-compose.yml logs -f

...but it works. Docker Compose takes the parameters located between the name and command, the command takes parameters located after it.

Apart from up and down, there are also start and stop. The first two set up and tear down the container composition, the second two just start and stop the containers. They are useful when you’re not rebuilding the containers composition over and over again.

At all times, a very useful command it docker-compose help which lists the commands, or details of a single command if you type it after help.

Ssh keys

I’m assuming below that you have your ssh key pair generated. It will be used for authenticating in git commands. If you don’t have it, execute

ssh-keygen -t rsa -b 4096

and follow the instructions.

Your key pair can be used to authenticate without a password when using ssh. I do recommend having such a setup. You will have two keys generated, a public and a private one. The public one will be added to the Gitlab to authenticate when using repositories.

Gitlab

Some of you may know Gitlab as employers to world class database removal specialists ( and they give support to others in such difficult situation ). We were really impressed by how they dealt with their problems then.

We host a community edition of Gitlab at work, so I would like to have fun with it. They provide some documentation for their docker images.

I started with a simple docker-compose.yml that was a spot on in terms of not working:

version: '2'
services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'gitlab'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://gitlab'
        # Add any other gitlab.rb configuration here, each on its own line
    ports:
      - '80'
    volumes:
      - './volumes/gitlab/config:/etc/gitlab'
      - './volumes/gitlab/logs:/var/log/gitlab'
      - './volumes/gitlab/data:/var/opt/gitlab'
    networks:
      le_net:
        ipv4_address: 10.5.0.10
networks:
  le_net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.5.0.0/16
          gateway: 10.5.0.1

To get the volumes to work, I created a following tree structure:

$ tree -d -L 2 volumes/
volumes/
└── gitlab
    ├── config
    ├── data
    └── logs

We will need to automate this somehow below. Note that this part of config is not needed and I could have left volumes as not accessible from my file system, but I prefer it this way. I can get to the files and browse them without getting into the container

You can see I have set up a network 10.5.0.0/16. Having a static network is quite handy, I went to /etc/hosts and added:

10.5.0.10 gitlab

Frankly speaking I wasn’t expecting it all to work on first try, and so it didn't. I removed the GITLAB_OMNIBUS_CONFIG that came from the sample, opened the rest of ports and there we are, http://gitlab shows:

This is the docker-compose.yml that worked:

version: '2'
services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'gitlab'
    ports:
      - '80'
      - '443'
      - '22'
    volumes:
      - './volumes/gitlab/config:/etc/gitlab'
      - './volumes/gitlab/logs:/var/log/gitlab'
      - './volumes/gitlab/data:/var/opt/gitlab'
    networks:
      le_net:
        ipv4_address: 10.5.0.10
networks:
  le_net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.5.0.0/16
          gateway: 10.5.0.1

Just note that it takes a long time to boot up at first, as it needs to create all the data and stuff. Also, you can note that files created are owned by root. If you want to access them, you’ll need to sudo.

I chose some password (the IEEE Standard Secure Password is 12345678, if you want).

I added some group and a project project in it. I used nice big shiny buttons on the front page.

I have also created a user user. I went to settings and just clicked it in. I could not set up a password, so after creating the user, I went into edit and then set up a password.

I could have an LDAP config to simplify this stuff, but don’t know how to do it yet. I could see some docker images for openldap. I guess I’ll sort this out some other time.

I think that there should be a way to preconfigure all of the above. I would like you to be able to clone my repo and run some command to get to a state I landed in. We’ll think about it later.

Anyway, I added user to group some in group settings, I logged in as user(had to change password, but it accepted the same one), added my ssh key and ran the following on my computer:

$ git clone git@gitlab:some/project.git
Cloning into 'project'...
The authenticity of host 'gitlab (10.5.0.10)' can't be established.
ECDSA key fingerprint is SHA256:Ralo1gYTTGl8xzEnmYC0AO2IWS5+7ROb04lg6H+rYYY.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'gitlab,10.5.0.10' (ECDSA) to the list of known hosts.
warning: You appear to have cloned an empty repository.

And there we are.

Automating the steps

The first idea that comes to my mind is to use a Makefile that would set things up.

What I need (would like to) automate so far:

  • create folders before start
  • set up /etc/hosts (I prefer to just provide the values, you can add them by yourself)
  • set up admin account
  • set up group
  • set up project
  • set up user account
  • add some cleanup after finishing

I started with the admin. It turns out there is a GITLAB_ROOT_PASSWORD env var that can automate the setup. Let’s try.

version: '2'
services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'gitlab'
    ports:
      - '80'
      - '443'
      - '22'
    volumes:
      - './volumes/gitlab/config:/etc/gitlab'
      - './volumes/gitlab/logs:/var/log/gitlab'
      - './volumes/gitlab/data:/var/opt/gitlab'
    environment:
      - GITLAB_ROOT_PASSWORD=12345678
    networks:
      le_net:
        ipv4_address: 10.5.0.10
networks:
  le_net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.5.0.0/16
          gateway: 10.5.0.1

Ran this and landed on the login page. Username root and password 12345678 works. Brilliant. Now the rest of the setup. Let’s use the api:
curl -XPOST --data "grant_type=password&username=root&password=12345678" http://gitlab/oauth/token
...returns:
{"access_token":"96925c73c77536a5370eda14d9a098e1566c3556e3702f33434434d88a721d3a","token_type":"bearer","refresh_token":"dac13077506ac16864ceae2329dfeea3ffa0ac9e60f3b45c745d179607f9d00d","scope":"api","created_at":1515684086}

Let’s do something to extract the value.

TOKEN=$(curl -XPOST --data "grant_type=password&username=root&password=12345678" http://gitlab/oauth/token | python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])")

I’ve already assigned the value to TOKEN to use it in future requests, like this one for example:

$ curl --header "Authorization: Bearer $TOKEN" http://gitlab/api/v4/user
{"id":1,"name":"Administrator","username":"root","state":"active","avatar_url":"http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon","web_url":"http://gitlab/root","created_at":"2018-01-11T14:12:10.267Z","bio":null,"location":null,"skype":"","linkedin":"","twitter":"","website_url":"","organization":null,"last_sign_in_at":null,"confirmed_at":"2018-01-11T14:12:10.185Z","last_activity_on":null,"email":"[email protected]","theme_id":1,"color_scheme_id":1,"projects_limit":100000,"current_sign_in_at":null,"identities":[],"can_create_group":true,"can_create_project":true,"two_factor_enabled":false,"external":false,"is_admin":true}

I won’t get into the whole API here as it’s quite big, but a couple things we need to run would look like this (available in the repo in scripts/gitlab/after-start):

echo fetch token
TOKEN=$(curl -XPOST --data "grant_type=password&username=root&password=12345678" http://gitlab/oauth/token | python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])")

echo create some group
curl -X POST --header "Authorization: Bearer $TOKEN" --data "name=some&path=some&visibility=internal" http://gitlab/api/v4/groups

echo create user
curl -X POST --header "Authorization: Bearer $TOKEN" --data "username=user&name=user&password=12345678&email=user@email&skip_confirmation=true" http://gitlab/api/v4/users

echo add user to some group
# shortcut:, user is a second user, so user_id is 2. I could have extracted like in token.
curl -X POST --header "Authorization: Bearer $TOKEN" --data "user_id=2&access_level=40" http://gitlab/api/v4/groups/some/members

echo add ssh key to user
# shortcut: user is a second user, so user_id is 2. I could have extracted like in token.
# shortcut: I’m assuming you have a key pair in ~/.ssh, only one pair, and public key file ends with .pub
# note that I’m passing the data differently; the key needs to be urlencoded so that pluses aren’t read as space characters
curl \
  -X POST \
  --header "Authorization: Bearer $TOKEN" \
  --data-urlencode "title=key" \
  --data-urlencode "key=$(cat ~/.ssh/*.pub)" \
  http://gitlab/api/v4/users/2/keys

echo create project
# shortcut: group_id is 2, I don’t know what namespace_id 1 is and I don’t really care
curl -X POST --header "Authorization: Bearer $TOKEN" --data "name=project&merge_requests_enabled=yes&namespace_id=2" http://gitlab/api/v4/projects

Now this script works. Let’s add some simplifications for regularly used commands. I’ve added a Makefile:

clean: stop
    ./scripts/gitlab/reset
    ./scripts/clean

before-start:
    ./scripts/gitlab/before-start

after-start:
    ./scripts/gitlab/after-start

start: before-start
    docker-compose up -d

stop:
    docker-compose down
  • clean removes volumes and cleans up the self-generated certificates from known_hosts, after making sure the container is down
  • before-start creates volumes
  • after-start creates groups and repos in Gitlab (provided above); it will succeed once Gitlab is up
  • start starts the containers (if you’re using snaps, change command to docker.compose)
  • stop stops the containers (if you’re using snaps, change command to docker.compose)

To start and initialize everything, simply run:

make start
# now wait for it to be up, check http://gitlab/
make after-start

Of course, you can simply follow the whole tutorial.

Summary

Gitlab is up and running, next we’ll set up Jenkins.

This part was a real pain in the lower back. I got everything working on first try, then I could not make my certificate work when automating. After a lot of tries I ended up regenerating my key and then it started working. After a retry, it stopped working again. It turned out whatever cleanup I was making, I wasn’t making folders clean enough (probably hidden folders remained), so I changed approach, removed reset and only left an updated clean script which worked as expected.

This is how it rolls in software engineering – a dumb mistake escalates and you keep looking in all the wrong places for far too long. If you’re lucky enough, it’s at least not your error.

Remember: THE DUMBEST QUESTIONS ARE THOSE NEVER ASKED

The final code version for this part is under tag 0x02.

Homework

Improve make’s goal after-start not to fail after start. Make it wait for Gitlab to be up. Again, after a week, I will select one submitter and reward him with 1SBD. If no one comes, I will wait for the first one to submit a working homework. Let's say I'll wait for a month.

Curriculum

Posts so far:

I have set up a git repository to host whatever files I may need in this tutorial. The readme also contains links to articles.



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Thank you for the contribution. It has been approved.

You can contact us on Discord.
[utopian-moderator]

Hey @jestemkioskiem, I just gave you a tip for your hard work on moderation. Upvote this comment to support the utopian moderators and increase your future rewards!

Your contribution cannot be approved because it does not follow the Utopian Rules.

  • wrong Repository and I don't seem to het the hang of what you are doing exactly
    You can contact us on Discord.
    [utopian-moderator]

Hey @creon, I just gave you a tip for your hard work on moderation. Upvote this comment to support the utopian moderators and increase your future rewards!

Hi @creon,
Thank you for your time to review this post. Im not sure what you mean by "wrong repository" - breadcentric/dev-infrastructure contains the code for this tutorial precisely.
With regards to the clarity, I will add am introduction to clearly state the goal of the whole series, as described in two previous parts of it. I will do it in an hour or so.
Do I need to ping you precisely when I'm done or can it be any moderator?

Thanks for sharing the knowledge :) tip! 0.3

Hi @breadcentric! You have received 0.3 SBD tip + 0.03 SBD @tipU from @cardboard :)

@cardboard wrote lately about: Just Testing. Feel free to follow @cardboard if you like it :)

@breadcentric, Contribution to open source project, I like you and upvote.

Hey @breadcentric I am @utopian-io. I have just upvoted you!

Achievements

  • You have less than 500 followers. Just gave you a gift to help you succeed!
  • Seems like you contribute quite often. AMAZING!

Suggestions

  • Contribute more often to get higher and higher rewards. I wish to see you often!
  • Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!

Get Noticed!

  • Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

Cool!

Didn't realise you were into dockers as well. I will have to post something that might be helpful for people in that regard as well.

Just a bit, we're not using it in production. I treat it as a handy tool to start something in a clean way and then tidy up.

Coin Marketplace

STEEM 0.18
TRX 0.16
JST 0.029
BTC 60883.28
ETH 2401.75
USDT 1.00
SBD 2.63