Now Reading
Establishing a packaging surroundings for Alpine Linux (introducing alpkg)

Establishing a packaging surroundings for Alpine Linux (introducing alpkg)

2023-03-27 05:31:10

Not too long ago I’ve been eager about Alpine Linux and thought it will be good to keep up some Rust packages of their repositories. On this put up, I’ll share my notes/adventures on establishing a packaging surroundings and a instrument referred to as “alpkg” for automating this course of.

mountain view

My first curiosity in Alpine Linux started once I first began to containerize my open supply initiatives utilizing light-weight Alpine containers. I particularly wish to comply with this method for Rust functions as a result of the sizes of conventional (glibc) distro containers like Debian/Ubuntu can go as much as 200-300MB on account of bloat whereas Alpine (musl) containers can keep so minimal similar to solely 3 MB!

Right here is an instance Dockerfile from rustypaste that ends in a 3MB image when constructed/compressed:

FROM rust:1.67.0-alpine3.17 as builder
WORKDIR /app
RUN apk replace
RUN apk add --no-cache musl-dev
COPY . .
RUN cargo construct --locked --release
RUN mkdir -p build-out/
RUN cp goal/launch/rustypaste build-out/

FROM scratch
WORKDIR /app
COPY --from=builder /app/build-out/rustypaste .
ENV SERVER__ADDRESS=0.0.0.0:8000
EXPOSE 8000
USER 1000:1000
CMD ["./rustypaste"]

One factor to notice right here, I particularly select scratch picture because the runner since it’s tremendous minimal. You will get related outcomes with pictures like distroless as nicely.

Though you have to take care of compiling with musl typically, it’s well worth the problem when the result’s that satisfying. Different issues which might be completely different in Alpine are the next:

glibc               ➔  musl
systemd             ➔  OpenRC
GNU Core Utilities  ➔  BusyBox

For extra details about Alpine, take a look at this post which works into element about why it is neat.

Now, let’s speak about how one can arrange a packaging surroundings for Alpine Linux.


Overview

In my particular case, I wish to preserve utilizing my Arch Linux system and likewise bundle for Alpine Linux. There are a few choices for doing that:

  • Run Alpine Linux on a virtual machine
  • Run Alpine Linux in a chroot
  • Use a Docker/Podman container with persistent storage

I instantly eradicated the primary possibility since I did not need to take care of VM software program and thought it will add additional complexity to my setup.

Then I spun up a Docker container that runs Alpine and tried to make the storage persistent. After coming throughout this StackOverflow post, it turned out to be one thing tougher than I anticipated and I began to really feel like I used to be re-inventing VMs on account of all these mount-binds and permissions. Unsurprisingly sufficient, I ditched that concept as nicely.

Afterward, I got here throughout this great article on Alpine Wiki about making a chroot:

Contained in the chroot surroundings, you possibly can construct, debug, and run Alpine packages or develop issues. It is probably the most recognized approach to take action with out changing your system or utilizing a Digital Machine.

That is precisely what I wanted!

After deciding on what to make use of, I had a plan in thoughts and got here up with this diagram:



Let’s break it down:

  • Every part is working inside Arch Linux.
  • There’s a chroot container that holds the bundle sources and Alpine SDK instruments wanted.
    • In Alpine, packages are APKBUILD scripts that include the construct directions for abuild instrument.
  • There’s a Git repository arrange outdoors the chroot for including/updating/deleting packages.
    • For interacting with the repositories, we will merely ship a patch (i.e. merge request) to aports repositories which reside in gitlab.alpinelinux.org/alpine/aports.
    • We solely must create a GitLab account and fork the repository, no particular position is required!

Establishing the chroot

alpine-chroot-install is a instrument that automates the guide steps of making a chroot. We will use it as follows:

$ alpine-chroot-install 
	-a x86_64       # structure
	-d alpine       # listing
	-p build-base   # set up build-base
	-p alpine-sdk    # set up alpine-sdk

In a few seconds, it should create a chroot and we will simply swap to it with the next script:

$ alpine/enter-chroot -u "$USER" <CMD>

alpine chroot

And right here we’ve Alpine Linux working inside Arch Linux!


Story Time

After I created the Alpine chroot, I performed round a bit and tried out completely different options of apk bundle supervisor. I put in a few of my favourite Rust instruments and every part was working easily.

Then I bought an thought: I ought to strive putting in these instruments in the course of the chroot set up. Fortunately, alpine-chroot-install has an possibility for it and you may merely use -p <pkg> for putting in packages.

In fact, I wished to take away the chroot listing I simply created earlier than creating one other chroot. For a second I assumed chroot was only a easy listing and tried to delete it with rm -rf.

Ouch.

Nonetheless, chroot was not an everyday listing. It has a bunch of issues mounted to it:

$ alpine-chroot-install

# ...
> Binding filesystems into chroot
mount: none mounted on /alpine/proc.
mount: /sys sure on /alpine/sys.
mount: /dev sure on /alpine/dev.

So once I deleted chroot, I additionally deleted /dev x_x

$ rm -rf /chroot

rm: WARNING: Round listing construction.
This nearly actually means that you've got a corrupted file system.
NOTIFY YOUR SYSTEM MANAGER.

Then every part began to fail:

$ ls

Did not open file to remap file descriptor (No such file or listing)

/dev/null was additionally gone and I bought errors like “permission denied: /dev/null” as nicely. Enjoyable.

Fortunately a easy reboot fixes this situation. The scariest half was when every part began to throw errors left and proper, I panicked and realized what I did. I used to be afraid I rm -rf‘d my complete system however fortunately it was simply the mount factors.

Lesson realized, I used the elimination script for deleting the chroot subsequent time: /chroot/destroy --remove.


Establishing the packaging surroundings

Let’s set up the mandatory packages for packaging/improvement on Alpine:

$ apk add alpine-sdk atools

After that, we have to configure the construct defaults in /and so forth/abuild.conf, particularly the packager data:

# PACKAGER and MAINTAINER are utilized by newapkbuild when creating new aports for
# the APKBUILD's "Contributor:" and "Maintainer:" feedback, respectively.
PACKAGER="Your Title <your@electronic mail.deal with>"
MAINTAINER="$PACKAGER"

Subsequent, we will configure the safety keys:

$ abuild-keygen --append --install

After this step, we at the moment are prepared for making ready APKBUILDs in keeping with this guide and construct them through abuild -r.


Establishing the repository

After forking the aports repository on GitLab, we will clone it someplace on our principal system and configure Git in keeping with the packager data we’ve supplied earlier in /and so forth/abuild.conf:

$ git clone https://gitlab.alpinelinux.org/<consumer>/aports
$ git config --global consumer.title "Your Title"
$ git config --global consumer.electronic mail "your@electronic mail.deal with"

Official documentation recommends including the next Git hook for routinely producing the commit message primarily based on the bundle that’s being dedicated:

$ cat <<-'_EOF_' >".git/hooks/prepare-commit-msg"
  #!/bin/sh
  case "$2,$3" in
    ,|template,)
      if git diff-index --diff-filter=A --name-only --cached HEAD 
          | grep -q '/APKBUILD$'; then
        meta()  sed 's/.*="?//;s/"$//';
        printf 'testing/%s: new aportnnpercentsnpercentsn' "$(meta pkgname)" 
          "$(meta url)" "$(meta pkgdesc)" "$(cat $1)" > "$1"
      else
        printf '%snnpercents' `git diff-index --name-only --cached HEAD 
          | sed -n 's//APKBUILD$//p;q'` "$(cat $1)" > "$1"
      fi;;
  esac
_EOF_
chmod +x ".git/hooks/prepare-commit-msg"

This hook will end in producing commit messages similar to:

testing/git-cliff: new aport

https://github.com/orhun/git-cliff
A extremely customizable changelog generator
testing/

Good.


Creating packages

Alpine Linux has a handy instrument referred to as newapkbuild for producing APKBUILD prototypes primarily based on the given parameters:

$ newapkbuild -h

newapkbuild 3.10.0-r0 - generate a brand new APKBUILD
Utilization: newapkbuild [-n PKGNAME] [-d PKGDESC] [-l LICENSE] [-u URL]
       [-a | -C | -m | -p | -y | -r] [-s] [-c] [-f] [-h]
       PKGNAME[-PKGVER] | SRCURL
Choices:
  -n  Set bundle title to PKGNAME (solely use with SRCURL)
  -d  Set bundle description to PKGDESC
  -l  Set bundle license to LICENSE, use identifiers from:
      <https://spdx.org/licenses/>
  -u  Set bundle URL
  -a  Create autotools bundle (use ./configure ...)
  -C  Create CMake bundle (Assume cmake/ is there)
  -m  Create meson bundle (Assume meson.construct is there)
  -p  Create perl bundle (Assume Makefile.PL is there)
  -y  Create python bundle (Assume setup.py is there)
  -r  Create rust bundle (Assume Cargo.toml is there)
  -s  Use sourceforge supply URL
  -c  Copy a pattern init.d, conf.d, and set up script
  -f  Pressure even when listing already exists
  -h  Present this assist

It’s particularly helpful if you happen to do not need to write the identical boilerplate capabilities over and over.

It may be used for Rust packages as follows:

$ newapkbuild -r 
              -u "https://github.com/orhun/git-cliff" 
              -d "A extremely customizable changelog generator" 
              -l "GPL-3.0-only" 
              "git-cliff"

It will generate the next APKBUILD in git-cliff listing:

# Contributor: Your Title <your@electronic mail.deal with>
# Maintainer: Your Title <your@electronic mail.deal with>
pkgname=git-cliff
pkgver=
pkgrel=0
pkgdesc="A extremely customizable changelog generator"
url="https://github.com/orhun/git-cliff"
arch="all"
license="GPL-3.0-only"
relies upon=""
makedepends="cargo"
checkdepends=""
set up=""
subpackages="$pkgname-dev $pkgname-doc"
supply=""
builddir="$srcdir/"

put together() {
	default_prepare

	cargo fetch --locked
}

construct() {
	cargo construct --frozen --release
}

verify() {
	cargo take a look at --frozen
}

bundle() {
	cargo set up --frozen --offline --path . --root="$pkgdir/usr"
	rm "$pkgdir"/usr/.crates*
}

You’ll be able to learn extra about APKBUILD capabilities/variables within the official reference. With some edits, we will match our venture into this template simply. Right here is the ultimate APKBUILD:

# Contributor: Orhun Parmaksız <orhunparmaksiz@gmail.com>
# Maintainer: Orhun Parmaksız <orhunparmaksiz@gmail.com>
pkgname=git-cliff
pkgver=1.1.2
pkgrel=0
pkgdesc="A extremely customizable changelog generator"
url="https://github.com/orhun/git-cliff"
# s390x, ppc64le, riscv64: blocked by ring crate
arch="all !s390x !ppc64le !riscv64"
license="GPL-3.0-or-later"
makedepends="
	cargo
	libgit2-dev
	"
subpackages="
	$pkgname-doc
	$pkgname-bash-completion
	$pkgname-zsh-completion
	$pkgname-fish-completion
	"
choices="internet"
supply="$pkgname-$pkgver.tar.gz::https://github.com/orhun/git-cliff/archive/v$pkgver.tar.gz"

put together() {
	default_prepare

	cargo fetch --target="$CTARGET" --locked
}

construct() {
	cargo construct --frozen --release
	mkdir -p man
	OUT_DIR=man/ "./goal/launch/$pkgname-mangen"
	mkdir -p completions
	OUT_DIR=completions/ "./goal/launch/$pkgname-completions"
}

verify() {
	cargo take a look at --frozen -- --skip "git_log"
}

bundle() {
	set up -Dm 755 "goal/launch/$pkgname" -t "$pkgdir/usr/bin"
	set up -Dm 644 README.md -t "$pkgdir/usr/share/doc/$pkgname"
	set up -Dm 644 "man/$pkgname.1" -t "$pkgdir/usr/share/man/man1"
	set up -Dm 644 "completions/$pkgname.bash" "$pkgdir/usr/share/bash-completion/completions/$pkgname"
	set up -Dm 644 "completions/$pkgname.fish" -t "$pkgdir/usr/share/fish/completions"
	set up -Dm 644 "completions/_$pkgname" -t "$pkgdir/usr/share/zsh/site-functions"
}

sha512sums="
f5564f1d6d492ea6527f2ac10eaa1dc90aa1846fb9b090224ff7a2c1cad78d8850a13364c5e4beae987c4ebf65891e804e0677fd9ab193e56d9565292d6cf2ba  git-cliff-1.1.2.tar.gz
"

After we’ve the APKBUILD, we will use the next instructions.

To generate checksums:

$ abuild checksum

To construct:

$ abuild -r

To lint:

$ apkbuild-lint APKBUILD

After the bundle is efficiently constructed, there will probably be an apk file within the $HOME/packages listing. It’s potential to listing the apk contents with the next command:

$ tar tvvf git-cliff-1.1.2-r0.apk
-rw-r--r-- 0/0             512 2023-03-22 19:08 .SIGN.RSA.orhunparmaksiz@gmail.com-641b3a67.rsa.pub
-rw-r--r-- root/root       754 2023-03-22 19:08 .PKGINFO
drwxr-xr-x root/root         0 2023-03-22 19:08 usr/
drwxr-xr-x root/root         0 2023-03-22 19:08 usr/bin/
-rwxr-xr-x root/root   7064056 2023-03-22 19:08 usr/bin/git-cliff
-rwxr-xr-x root/root    469160 2023-03-22 19:08 usr/bin/git-cliff-completions
-rwxr-xr-x root/root    440488 2023-03-22 19:08 usr/bin/git-cliff-mangen

To put in the regionally constructed bundle, we will replace the repository index (/and so forth/apk/repositories) to level to the native listing and set up it through apk:

$ cat /and so forth/apk/repositories

/residence/orhun/packages/orhun/
http://dl-cdn.alpinelinux.org/alpine/latest-stable/principal
http://dl-cdn.alpinelinux.org/alpine/latest-stable/neighborhood

$ apk add git-cliff

If every part works effective, then congratulations, you simply constructed your first Alpine bundle!


Submitting patches

Alpine Linux has 3 repositories:

  1. principal: Immediately supported official packages that are maintained by the Alpine core group.
  • Much like core/additional repositories in Arch Linux.
  1. neighborhood: Packages which might be created by the contributors and builders. Not totally supported, upkeep depends on the contributor exercise.
  • Identical as neighborhood repository on Arch Linux.
  1. testing: New packages which might be added by contributors. Packages from this repository are accepted into the neighborhood repository. This repository is simply obtainable on edge (improvement) department of Alpine.
  • Much like the AUR / testing repositories on Arch Linux.

Since we’ve simply created a new bundle, it should go to the testing repository. We will merely commit testing/<bundle>/APKBUILD after which create a merge request on GitLab.

$ cd aports/
$ git pull
$ git checkout -b aport/git-cliff
$ mkdir -p testing/git-cliff
$ cp /chroot/residence/orhun/git-cliff/APKBUILD testing/git-cliff/
$ git add testing/git-cliff
$ git commit
$ git push

And there we go: https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/45319

After the merge request is accredited/merged, our bundle will present up on https://pkgs.alpinelinux.org:

alpine package

Yay! git-cliff is now obtainable for Alpine Linux!


Automating (principally) every part with alpkg ????️

⭐ GitHub: https://github.com/orhun/alpkg

alpkg can create a chroot with preinstalled instruments in a matter of seconds, arrange aports repository, and fetch/replace packages. Most significantly, it supplies a break up format through Zellij for straightforward modifying/constructing APKBUILD information.

alpkg demo

alpkg does every part that’s talked about earlier on this put up and extra. For instance, within the GIF above:

  • an Alpine chroot is created. (alpkg init)
  • an present APKBUILD is fetched. (alpkg fetch)
  • APKBUILD is edited and constructed. (alpkg edit)
  • adjustments are dedicated to aports. (alpkg replace)

Let’s go over these options.

Making a chroot is as simple as working alpkg init. It additionally installs the SDK instruments that we’d like and units up the aports repository for us.

alpkg init

We will fetch and edit a APKBUILD through alpkg fetch. It should present a break up format for each modifying and different operations similar to working abuild -r.

alpkg fetch

To create a brand new APKBUILD, we will merely use alpkg edit.

alpkg edit

Lastly, if we need to commit the adjustments to aports, we will run alpkg replace.

alpkg update

You will get extra details about the instrument and see detailed utilization examples within the repository.


Endnote

Alpine Linux is neat. I am actually wanting ahead to oxidizing it (add extra Rust packages to their repositories) and studying extra about their implementation decisions to ultimately do extra improvement. I am glad how alpkg turned out and I am planning to enhance it primarily based on my wants and the suggestions from the Alpine neighborhood. I like automating issues.

Hope you loved studying and see you within the subsequent one!

$ docker run alpine echo "안녕히 가세요"

Source Link

What's Your Reaction?
Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0
View Comments (0)

Leave a Reply

Your email address will not be published.

2022 Blinking Robots.
WordPress by Doejo

Scroll To Top