Моей основной задаче было реализовать автоматическую сборка snap пакетов с помощью GitLab CI/CD. И так как в сети я нашел не очень много информации о том, как это сделать - я решился на написание этого поста.

Вроде бы задача кажется не такой уж и сложной со стороны, но в ней много подводных камней.

Начнем с написания snapcraft.yaml, который нужен для работы snapcraft.

name: yourSnapName
base: core22 
version: '1.0'
summary: C++ application
description: The fed launch assembly container
 

confinement: classic


lint:
  ignore:
    - classic 
    - library

parts:
  stub:
    source: .
    source-type: local
    plugin: dump
    build-packages:
      - cmake
      - make
      - g++
      - gcc
      - clang
      - build-essential
      - qtbase5-dev 
      - qt5-qmake
      - rapidjson-dev
      - libstdc++6
    override-build: |
      cd /project/path/to/your/project
      mkdir build
      cd build
      cmake .. -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_INSTALL_PREFIX=/usr
      cmake --build . -j12
      cp -r /project/path/to/BAS/your/build/bin $CRAFT_PART_INSTALL/bin
      chmod +rx /project/run.sh
      chmod +rx $CRAFT_PART_INSTALL/bin
      cp -r /project/run.sh $CRAFT_PART_INSTALL/bin


      


apps:
  stub:
    command: /bin/run.sh
    plugs: 
      - network
      - home
      - system-observe
      - hostname-control
      - removable-media

Оставлю данный файл без лишних комментариев, так как полную информацию вы можете найти в документации. Хочу отметить только одно, что здесь мне не хватило функциональности обычного плагина cmake для сборки проекта. Поэтому я переопределил этап build:

    override-build: |
      cd /project/path/to/your/project
      mkdir build
      cd build
      cmake .. -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_INSTALL_PREFIX=/usr
      cmake --build . -j12
      cp -r /project/path/to/BAS/your/build/bin $CRAFT_PART_INSTALL/bin
      chmod +rx /project/run.sh
      chmod +rx $CRAFT_PART_INSTALL/bin
      cp -r /project/run.sh $CRAFT_PART_INSTALL/bin

Файл run.sh:

#! /bin/sh

exec $SNAP/bin/$1 $2 $3

Далее мне пришлось собирать собственный docker образ для корректной работы snapcraft. Можно использовать уже готовые docker образы, но у меня на сервере были настроены proxy, что не давало возможности для скачивания и установки всех необходимых пакетов. Мой Dockerfile:

FROM ubuntu:jammy AS builder
ENV DEBIAN_FRONTEND=noninteractive
ARG ARCH

ENV http_proxy=http://<...>
ENV https_proxy=http://<...>

# Grab dependencies
RUN apt-get update
RUN apt-get dist-upgrade --yes
RUN apt-get install --yes \
      curl \
      jq \
      squashfs-tools

# download and extract core22 (required for snapcraft to run)
RUN curl -L $(curl -H 'X-Ubuntu-Series: 16' -H "X-Ubuntu-Architecture: $ARCH" \
    'https://api.snapcraft.io/api/v1/snaps/details/core22' | jq '.download_url' -r) --output core22.snap
RUN mkdir -p /snap/core22
RUN unsquashfs -d /snap/core22/current core22.snap

# download and extract snapcraft
RUN curl -L $(curl -H 'X-Ubuntu-Series: 16' -H "X-Ubuntu-Architecture: $ARCH" \
    'https://api.snapcraft.io/api/v1/snaps/details/snapcraft' | jq '.download_url' -r) --output snapcraft.snap
RUN mkdir -p /snap/snapcraft
RUN unsquashfs -d /snap/snapcraft/current snapcraft.snap

# Fix Python3 installation: Make sure we use the interpreter from
# the snapcraft snap:
RUN unlink /snap/snapcraft/current/usr/bin/python3
RUN ln -s /snap/snapcraft/current/usr/bin/python3.* /snap/snapcraft/current/usr/bin/python3
RUN echo /snap/snapcraft/current/lib/python3.*/site-packages >> /snap/snapcraft/current/usr/lib/python3/dist-packages/site-packages.pth

# Create a snapcraft runner
RUN mkdir -p /snap/bin
RUN echo "#!/bin/sh" > /snap/bin/snapcraft
RUN snap_version="$(awk '/^version:/{print $2}' /snap/snapcraft/current/meta/snap.yaml | tr -d \')" && echo "export SNAP_VERSION=\"$snap_version\"" >> /snap/bin/snapcraft
RUN echo 'exec "/snap/snapcraft/current/bin/python3" -m snapcraft "$@"' >> /snap/bin/snapcraft
RUN chmod +x /snap/bin/snapcraft

# download and extract core24
RUN curl -L $(curl -H 'X-Ubuntu-Series: 16' -H "X-Ubuntu-Architecture: $ARCH" \
    'https://api.snapcraft.io/api/v1/snaps/details/core24' | jq '.download_url' -r) --output core24.snap
RUN mkdir -p /snap/core24
RUN unsquashfs -d /snap/core24/current core24.snap

FROM ubuntu:noble
ENV DEBIAN_FRONTEND=noninteractive

COPY --from=builder /snap/core22 /snap/core22
COPY --from=builder /snap/core24 /snap/core24
COPY --from=builder /snap/snapcraft /snap/snapcraft
COPY --from=builder /snap/bin/snapcraft /snap/bin/snapcraft

ENV http_proxy=http://<...>
ENV https_proxy=http://<...>

# Generate locale and install dependencies.
RUN apt-get update && apt-get dist-upgrade --yes && apt-get install --yes snapd sudo locales git binutils && locale-gen en_US.UTF-8
RUN mkdir /snap/snapcraft/current/usr/share/snapcraft/keyrings \
    /snap/snapcraft/current/usr/share/snapcraft/extensions \
    /snap/snapcraft/current/usr/share/snapcraft/plugins \
    /snap/snapcraft/current/usr/share/snapcraft/schema -p

RUN apt install --yes build-essential
    
# Set the proper environment.
ENV LANG="en_US.UTF-8"
ENV LANGUAGE="en_US:en"
ENV LC_ALL="en_US.UTF-8"
ENV PATH="/snap/snapcraft/current/libexec/snapcraft/:/snap/bin:$PATH"
ENV SNAPCRAFT_BUILD_ENVIRONMENT=host

ENV http_proxy=http://<...>
ENV https_proxy=http://<...>

COPY . /project

WORKDIR /project

Ну и после этих действий можно уже приступить к самого главному - настройки GitLab CI.

У меня всего будет два этапа сборки:

stages:
    - build
    - deploy

Первым шагов нужно собрать docker образ, о котором упоминалось выше.

build-image:
  stage: build
  script:
    - docker login -u u -p p $CI_REGISTRY
    - docker build --no-cache -t $IMAGE_TO_BUILD .
    - echo Пушим образ $IMAGE_TO_BUILD
    - docker push $IMAGE_TO_BUILD

После успешной сборки образа, можно приступить к сборки snap-пакета.

build-snap: 
  stage: build
  needs: [build-image]
  script:
  - sh run-docker.sh
  - docker cp <YourName>:/project/<NameOfYourSnapPackage> .
  artifacts:
    paths:
      - /builds/your/path/<NameOfYourSnapPackage>
    expire_in: 1 week

Для запуска контейнера использовался файл run-docker.sh:

docker stop <YourName> && docker rm <YourName>
docker run -e HTTP_PROXY=http://<...> -e HTTPS_PROXY=http://<...> \
              -e NO_PROXY=localhost,127.0.0.1 --name=<YourName> <yourRegistry>/backend_snapcraft:latest snapcraft

После успешной сборки snap-пакета мне нужно было сохранять файл на сервере в определенную папку. Для этого нужно вмонтировать нужную директорию в gitLab-runner.

Открываем файл /etc/gitlab‑runner/config.toml под root. И в разделе [runners.docker] в поле volumes вставляем ["/home/your/directory:/mnt/snaps"] . После этого выполняем команду.

gitlab-runner restart

Теперь у вашего gitlab-runner есть доступ к пользовательским папкам.

И копируем все в нужную папку на вашем сервере.

deploy:
  stage: deploy
  needs: [build-snap]
  script:
    - cp /builds/your/path/<NameOfYourSnapPackage> /mnt/snaps/
  only:
    - main

Готово! Поставленная задача выполнена и наши snap-пакеты публикуются в нужную нам директорию.

Комментарии (1)


  1. kovserg
    13.12.2024 09:21

    Почему-то многие стараются snap-ы обходить стороной, предпочитая appimage.