> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# What are Services

> This guide covers GitLab CI/CD pipeline configurations using runners, Docker images, and service containers for efficient job execution.

<Frame>
  ![The image is a blue gradient background with the text "GitLab CI/CD – Image and Service" and a copyright notice for KodeKloud.](https://kodekloud.com/kk-media/image/upload/v1752877293/notes-assets/images/GitLab-CICD-Architecting-Deploying-and-Optimizing-Pipelines-What-are-Services/gitlab-ci-cd-image-service.jpg)
</Frame>

GitLab CI/CD pipelines run jobs on self-managed or GitLab-hosted runners. Each job executes in an environment defined by tags, Docker images, and optional service containers. This guide covers:

* Choosing runners with tags
* Default containers for SAST
* Installing custom runtimes
* Using dedicated Docker images
* Spinning up service containers

## 1. Choosing a Runner with Tags

Tags assign jobs to specific runners. For example, `ubuntu-latest` provides a full Ubuntu environment with pre-installed tools:

```yaml theme={null}
# .gitlab-ci.yml
unit-testing:
  tags:
    - ubuntu-latest
  script:
    - echo "Running unit tests on Ubuntu"
```

## 2. Default Containers for SAST Runners

GitLab’s SAST runners come pre-configured with a Ruby 3.1 image. This is ideal for Ruby projects but can lead to errors if used for other languages:

```yaml theme={null}
# .gitlab-ci.yml
workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

sast-unit-test:
  tags:
    - sast-linux-small-amd64
  script:
    - ruby --version
    - bundle install
    - bundle exec rspec
```

## 3. Installing Custom Runtimes

When you need a language runtime not in the default image—such as Node.js 20—you can install it during `before_script`. This adds pipeline time and may increase CI minutes usage.

<Callout icon="lightbulb" color="#1CB2FE">
  Installing additional packages in `before_script` can slow down your pipelines. Consider using a custom image (see next section) for faster, repeatable builds.
</Callout>

```yaml theme={null}
# .gitlab-ci.yml
workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

node-test:
  tags:
    - sast-linux-small-amd64
  before_script:
    - apt-get update && apt-get install -y curl gnupg
    - curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
    - apt-get install -y nodejs
  script:
    - npm install
    - npm test
```

## 4. Using Dedicated Docker Images

Specifying an image lets GitLab pull a pre-built container with your desired tools. This ensures consistency and speeds up jobs by eliminating runtime installation steps.

```yaml theme={null}
# .gitlab-ci.yml
workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

node-test:
  tags:
    - linux
  image: node:20-alpine3.17
  script:
    - npm install
    - npm test
```

Docker Container - node:20-alpine3.17

1. Checkout Code – 2s
2. Install Dependencies – 3m
3. Run Tests – 5m

### Comparison: Before vs. After Using an Image

| Configuration         | Installation Steps                 | Pipeline Duration | Maintenance Overhead |
| --------------------- | ---------------------------------- | ----------------- | -------------------- |
| Custom Runtime in Job | Update OS, add repos, install Node | High              | High                 |
| Docker Image          | Pull pre-built container           | Low               | Low                  |

## 5. Avoid Hitting Production Dependencies

<Callout icon="triangle-alert" color="#FF6B6B">
  Running tests against your production database can degrade performance and expose sensitive data. Always use a separate test database or service container for CI tasks.
</Callout>

## 6. Using Service Containers

Service containers run alongside your job’s main container in the same network. Use them for databases, caches, or any supporting service:

```yaml theme={null}
# .gitlab-ci.yml
workflow:
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

integration-test:
  tags:
    - linux
  image: node:20-alpine3.17
  services:
    - name: siddarth67/mongo-db:non-prod
      alias: mongo
  variables:
    MONGO_URI: "mongodb://mongo:27017/db"
  script:
    - npm install
    - npm test
```

When this job runs, GitLab launches two containers on a shared bridge network:

1. **mongo** (alias): MongoDB service with test data
2. **Job container**: Checks out code, installs dependencies, and runs tests against `mongodb://mongo:27017/db`

## Summary

By combining runner tags, Docker images, and service containers, you can build CI/CD pipelines that are:

* Isolated and reproducible
* Fast and cost-effective
* Configurable per-project requirements

## Links and References

* [GitLab CI/CD Documentation](https://docs.gitlab.com/ee/ci/)
* [Docker Hub: node](https://hub.docker.com/_/node)
* [NodeSource Node.js Binaries](https://github.com/nodesource/distributions)

<CardGroup>
  <Card title="Watch Video" icon="video" cta="Learn more" href="https://learn.kodekloud.com/user/courses/gitlab-ci-cd-architecting-deploying-and-optimizing-pipelines/module/3a1c2306-8091-4dfe-b40f-e2ca53918553/lesson/18021019-745f-4240-b254-428200696166" />
</CardGroup>
