Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pipeline and scripts for custom node 18 build (with glibc 2.17) #4

Merged
merged 76 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from 62 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
ddddc28
feat: add scripts for building custom node distributions
delanni Jun 6, 2023
7e1ef7a
feat: add pipeline definition for the build
delanni Jun 7, 2023
b1fc304
feat: fix typos
delanni Jun 7, 2023
36f5f9f
feat: try fixing 'privileged mode is incompatible with user namespace…
delanni Jun 7, 2023
4dd173c
try without qemu
delanni Jun 7, 2023
260f10c
try creating a driver instead
delanni Jun 7, 2023
84e6a42
feat: remove --force flag
delanni Jun 7, 2023
8f86ed5
feat: increase timeouts and add wait between stages
delanni Jun 7, 2023
545d8d1
feat: fix bad param name in build script
delanni Jun 7, 2023
2104c0c
feat: push/pull images to docker.io/elastic
delanni Jun 8, 2023
d0ac37f
feat: use new images, branch in build script based on ARCH env variable
delanni Jun 8, 2023
3cca249
Try manual login/build/upload to elastic's docker repo
delanni Jun 9, 2023
5ac745d
add agent definition
delanni Jun 9, 2023
ef3d7bc
Load docker image before progressing to next step
delanni Jun 12, 2023
07a3796
Try building in the same step
delanni Jun 12, 2023
f375c10
List images, to see why they're not available
delanni Jun 12, 2023
10c26eb
Fix arm-amd mixup
delanni Jun 12, 2023
4859c07
Add +x flag to entrypoint scripts
delanni Jun 12, 2023
4e53748
List dirs, wonder why they're not accessible
delanni Jun 12, 2023
17acf35
Add Z flag, to access the directories
delanni Jun 12, 2023
4583258
Increase timeout, try build in different steps
delanni Jun 12, 2023
b45822e
Separate builds because 'ERROR: docker exporter does not currently su…
delanni Jun 12, 2023
15e9c59
Fix bad image names and conditionals
delanni Jun 12, 2023
43d3007
Try arm64 build
delanni Jun 13, 2023
1e0e916
use arm machines for arm build
delanni Jun 14, 2023
046ef03
Add a pre-checkout hook to try to fix github urls
delanni Jun 14, 2023
5d3db88
Add a few commands for discovery
delanni Jun 14, 2023
6e887aa
Add post-checkout hook to cleanup git configs
delanni Jun 14, 2023
a3c45fa
No post-checkout - it changes the kibana executors for good, might me…
delanni Jun 14, 2023
a7bac4e
Refactor, and prepare pipeline for upload
delanni Jun 14, 2023
7a08d5d
Retry after fixing access rights
delanni Jun 14, 2023
c3dd54d
Strip -glibc-217 variant from filenames to keep original naming
delanni Jun 14, 2023
c63603b
Plug in ARM build, try a complete build
delanni Jun 14, 2023
fa10326
Attempt build on the macos executor
delanni Jun 15, 2023
9b0d9f9
Retreat back to cross-compiling, while the agent is set up
delanni Jun 15, 2023
a20eefc
Fix arm64<->amd64 parameterization, names
delanni Jun 19, 2023
000e638
Allow all users to rwx on created artifacts, so external scripts can …
delanni Jun 19, 2023
805e765
Allow writing of the created dist folder, to allow for rename
delanni Jun 19, 2023
d3e6284
Try macos executor again
delanni Jun 20, 2023
75354d2
Re-add x64 build
delanni Jun 20, 2023
6b71765
Bump to build node 18.16.0
delanni Jun 20, 2023
3eb5955
Find where the node builds are running, for debugging
delanni Jun 20, 2023
2e589f5
More debug
delanni Jun 20, 2023
3eb345d
Try fast agents with cross-compilation
delanni Jun 20, 2023
b9916d1
Try building re2
delanni Jun 21, 2023
2785d83
Mkdir & new folder names to avoid clash
delanni Jun 21, 2023
c037b40
Fix docker image name
delanni Jun 21, 2023
133ccff
Centralize build image name, so there are no typos
delanni Jun 21, 2023
1813dec
Fix double slash typo in path
delanni Jun 21, 2023
922dec3
Use public URLs for the node distro
delanni Jun 21, 2023
42b4990
Use npm binary extracted locally
delanni Jun 21, 2023
c13eb22
Remove variant from extracted node folder if needed
delanni Jun 21, 2023
07f47df
Add SHA256 file fixing,remove variation, fix re2 artifact building
delanni Jun 21, 2023
edd9232
Re-add upload section
delanni Jun 22, 2023
bdd64e8
Use correct path for SHASUMS256.txt
delanni Jun 22, 2023
7a61c2e
Use spaces in shasum file, re-enable mac build, bump node version
delanni Jun 22, 2023
702ca66
Add SHASUM fixing as a last step after both agents finished
delanni Jun 22, 2023
58f0c0a
Add retry around node download.. node.js org is flaky
delanni Jun 22, 2023
e85ade7
Fix typo, temporarily disable build steps
delanni Jun 22, 2023
7dde65d
Re-enable build steps
delanni Jun 22, 2023
fecc714
Remove unnecessary files, add README/Context
delanni Jun 22, 2023
a05224f
Merge branch 'main' into docker-manual-upload
delanni Jun 22, 2023
1656a11
Update README.md
delanni Jun 23, 2023
21f14c0
Centralize the artifacts' upload bucket name
delanni Jun 26, 2023
68d258e
Remove RE2 aspects of the build
delanni Jun 27, 2023
ab58662
Remove traces of the ci-systems pipeline
delanni Jun 27, 2023
9957258
Rationalize timeouts for beefier runner instances
delanni Jun 27, 2023
12ed8d8
Rename pipeline-kibana to pipeline, as the default
delanni Jun 27, 2023
00a8b2f
Update .buildkite/pipeline.yml
delanni Jun 29, 2023
8997a62
Update .buildkite/pipeline.yml
delanni Jun 29, 2023
983da3e
try overriding node target version in command
delanni Jun 29, 2023
c18809e
Fix default value expression
delanni Jun 29, 2023
8e0ae33
Remove debug / exit statements
delanni Jun 29, 2023
5c1d41e
Centralize version override, add annotation for built version
delanni Jun 29, 2023
8c34500
Fix typo for --style
delanni Jun 29, 2023
7ce4d9b
Fix defaulting logic
delanni Jun 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .buildkite/pipeline-kibana.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
env:
TARGET_VERSION: 18.16.1
RE2_VERSION: 1.17.7
delanni marked this conversation as resolved.
Show resolved Hide resolved

steps:
- label: Build node.js 18 with glibc 2.17 for x64
command:
- scripts/create_build_images.sh
- scripts/build_nodejs.sh
- scripts/upload_nodejs_artifacts.sh
- scripts/build_re2.sh
delanni marked this conversation as resolved.
Show resolved Hide resolved
- scripts/upload_re2_artifacts.sh
env:
ARCH: amd64
agents:
queue: c2-16
timeout_in_minutes: 300 # 5 hrs

- label: Build node.js 18 with glibc 2.17 for arm64
command:
- scripts/create_build_images.sh
- scripts/build_nodejs.sh
- scripts/upload_nodejs_artifacts.sh
- scripts/build_re2.sh
delanni marked this conversation as resolved.
Show resolved Hide resolved
- scripts/upload_re2_artifacts.sh
env:
ARCH: arm64
agents:
# queue: macos-arm # disabled while the git cloning doesn't work
queue: c2-60 # cross-compiling takes a while
delanni marked this conversation as resolved.
Show resolved Hide resolved
timeout_in_minutes: 720 # 12 hrs

- wait

- label: Fix SHASUMS256.txt with newly built files' hashes
command: scripts/replace_sha_hashes.sh
agents:
queue: kibana-default
18 changes: 2 additions & 16 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,3 @@
agents:
provider: aws
instanceType: m6g.xlarge
imagePrefix: drivah-ubuntu-2204-aarch64

steps:
- label: ":buildah: Building Container Images for ARM64"
branches: "*"
command: |
buildah --version
drivah build --changed-since=main ./containers/arm64

# - label: ":buildah: Building Container Images for AMD64"
# branches: "*"
# command: |
# buildah --version
# drivah build --changed-since=main ./.buildkite/containers/amd64
- command: echo "OK"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to remove this file?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question -
This is part of the elastic's ci-systems build pipeline from the research where I tried to pre-build docker images, and use those as agents in buildkite. It seems that wasn't the ultimate direction, so if we're going with this kibana-buildkite pipeline, then I can clean up this other pipeline.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brianseeders just to double check here, can we move on for now without using the ci-systems pipeline ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's up to you, but you'll have to migrate eventually. What are you not able to do?

Also, just FYI, I'm not on the CI systems team anymore

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll wait on @delanni to let you know about the challenges he found on using the ci-systems but in case we are allowed to continue with the kibana pipeline, I think we can proceed like that until we are forced to migrate eventually.

Thanks for letting me know Brian, I didn't realised before you have changed teams 🙌

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The track using this pipeline was a bit different than what we ultimately took. I think the ci-systems way would have been a bit better modularised in the sense that we build the agent images separately, and the build job only builds the binaries, and not the images.

I got stuck because with drivah, I couldn't really build multiarch images, and building separate images for separate platforms was also difficult, because docker didn't find the right base images for the centos:7/arm64 combination (whereas it worked locally). This is when I back-tracked, and went on another route.

The two approaches are probably mostly orthogonal, so if we're eventually moving over, then maybe I'll keep the pipeline in place, and try to work out the docker/centos issue later.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe what you're trying to do with docker should work fine with the ci-systems agents, as long as you are using a vm-based agent and not a k8s one.

You may need to create a custom agent image with the dependencies installed to do multiarch (if you didn't already), and you might also need enableNestedVirtualization: true on your agents: config in your pipeline. I'm guessing the multiarch virtualization stuff in Docker would need it.

You can also just install the dependencies at runtime to test to see if it works before committing to it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, we agreed with @mistic that it would be probably a waste as of now to try to fit this build on the ci-systems agents. It's probably not going to live for more than 1 year, we'll probably still have the kibana CI available to create new patch versions if needed, and hopefully the unofficial node releases will take over. (nodejs/unofficial-builds#83)

label: Blank command, placeholder
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.vscode
.idea

workdir
workdir/
workdir_re2/
delanni marked this conversation as resolved.
Show resolved Hide resolved
47 changes: 46 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,47 @@
# kibana-custom-nodejs-builds
Contains configuration and sources to build node.js for custom platforms
Contains configuration and sources to build node.js

The main usecase right now is building `node.js@18+` with `glibc@2.17`, which is required for some older platforms. (More context: https://github.com/nodejs/unofficial-builds/pull/69)

## Running locally
You can run most scripts locally on Mac/Linux. You'll need a few of the build/infra tools:
- Docker
- node.js
- gsutil (`brew install google-cloud-sdk`)

Export some env variables required for the builds
```sh
export ARCH="arm64"
export TARGET_VERSION="18.16.1"
export RE2_VERSION="1.17.7"
delanni marked this conversation as resolved.
Show resolved Hide resolved
```

Then run individual scripts locally:
```sh
./scripts/create_build_images.sh
./scripts/build_nodejs.sh
```

## Docker image for node.js builds
One of the main components we need to create in this step is a docker image for an environment that's set up for building `node.js`.

The bits for this component are in the [build-image-config](./build-image-config/) folder.

The docker image uses mounted directories as working directories, as well as outputting the artifacts in these directories.


## Scripts for running the builds
Most of the buildkite logic is sheltered in the [scripts](./scripts/) directory.



## Context
During development, we found some more information that can be helpful as context, should anyone find this repo again

- This repository is only needed until
delanni marked this conversation as resolved.
Show resolved Hide resolved
- centos:7 / RHEL7 is supported by Elastic, and we ship node.js with Kibana
- the unofficial-builds repo accepts a linux/arm64 build (https://github.com/nodejs/unofficial-builds/pull/83)
- The created Docker images needn't be pushed
- they can be used once for the build, then rebuilt in case we need to run it again
- I decided to remove the `VARIATION` attribute on the node.js:
- build would result in the variation showing up in the file and folder names, making the logistics more difficult, if we want to keep this mostly transparent for Kibana
31 changes: 31 additions & 0 deletions build-image-config/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
FROM centos:7

ARG GROUP_ID=1000
ARG USER_ID=1000

RUN groupadd --force --gid $GROUP_ID node
RUN adduser --gid $GROUP_ID --uid $USER_ID node

RUN ulimit -n 1024 \
&& yum install -y epel-release \
&& yum install -y centos-release-scl-rh \
&& yum upgrade -y \
&& yum install -y \
git \
curl \
make \
python2 \
python3 \
ccache \
xz-utils \
devtoolset-9 \
glibc-devel

COPY --chown=node:node entrypoint.sh /home/node/entrypoint.sh
COPY --chown=node:node re2_entrypoint.sh /home/node/re2_entrypoint.sh
delanni marked this conversation as resolved.
Show resolved Hide resolved

USER node

VOLUME /home/node/workdir

ENTRYPOINT [ "/home/node/entrypoint.sh" ]
38 changes: 38 additions & 0 deletions build-image-config/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env bash

set -e
set -x

release_url_base="$1"
full_version="$2"
config_flags=${3:-""} #"--without-dtrace --without-npm --without-etw"
delanni marked this conversation as resolved.
Show resolved Hide resolved

if [[ $(arch) == x86_64 ]]; then
architecture="x64";
else
architecture="arm64"
fi

ls -la "/home/node/workdir/src"
ls -la "/home/node/workdir/src/node-${full_version}"

cd "/home/node/workdir/src/node-${full_version}"

# Compile from source
export CCACHE_DIR="/home/node/workdir/.ccache-${architecture}"
export CC="ccache gcc"
export CXX="ccache g++"

. /opt/rh/devtoolset-9/enable

make -j"$(getconf _NPROCESSORS_ONLN)" binary V= \
DESTCPU="$architecture" \
ARCH="$architecture" \
DISTTYPE="release" \
RELEASE_URLBASE="$release_url_base" \
CONFIG_FLAGS="$config_flags"

mkdir -p /home/node/workdir/dist/
chmod a+w /home/node/workdir/dist
mv node-*.tar.?z /home/node/workdir/dist/
chmod a+rwx /home/node/workdir/dist/*
57 changes: 57 additions & 0 deletions build-image-config/re2_entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
delanni marked this conversation as resolved.
Show resolved Hide resolved

set -e
set -x

re2_full_version="$1"
node_full_version="$2"
node_download_base_url="$3"

if [[ $(arch) == x86_64 ]]; then
architecture="x64";
else
architecture="arm64"
fi

cd /home/node/workdir
mkdir -p dist/
mkdir -p src/

## Download and unpack Node.js binary if needed.
node_folder_name="node-${node_full_version}-linux-${architecture}"
npm_binary="/home/node/workdir/${node_folder_name}/bin/npm"
if [ ! -f "$npm_binary" ]; then
if [ ! -f "/home/node/workdir/$node_folder_name.tar.xz" ]; then
curl -fsSLO --compressed "${node_download_base_url}/${node_folder_name}.tar.xz"
fi

tar -xf "/home/node/workdir/${node_folder_name}.tar.xz"
fi

cd src

## Download re2 source if needed.
re2_source_folder="/home/node/workdir/src/node-re2-${re2_full_version}"
if [ ! -d "$re2_source_folder" ]; then
git clone --recurse-submodules --depth 1 --branch $re2_full_version https://github.com/uhop/node-re2.git "${re2_source_folder}"
fi

cd "$re2_source_folder"
export PATH="/home/node/workdir/${node_folder_name}/bin:$PATH"
export DEVELOPMENT_SKIP_GETTING_ASSET=true

export CCACHE_DIR="/home/node/workdir/.ccache-re2-${architecture}"
export CC="ccache gcc"
export CXX="ccache g++"

. /opt/rh/devtoolset-9/enable

$npm_binary i --unsafe-perm=true
$npm_binary run build --if-present
$npm_binary test

mkdir -p /home/node/workdir/dist/
chmod a+w /home/node/workdir/dist
cp "${re2_source_folder}/build/Release/re2.node" "/home/node/workdir/dist/linux-${architecture}-108"
gzip -f "/home/node/workdir/dist/linux-${architecture}-108"
chmod a+rwx /home/node/workdir/dist/*
29 changes: 29 additions & 0 deletions scripts/build_nodejs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/bin/bash
set -euo pipefail

source ./scripts/common.sh

# TARGET_VERSION provided in env
# ARCH provided in env
assert_correct_arch $ARCH

TARGET_NODE_VERSION="v$TARGET_VERSION"
BUILD_IMAGE_NAME=$(get_build_image_name)
TARGET_PLATFORM="linux/$ARCH"
RELEASE_URL_BASE="https://unofficial-builds.nodejs.org/download/release/"

echo "Running node.js build in folder: `pwd`"

echo '--- Downloading node source'
retry 5 15 curl --create-dirs --output-dir ./workdir/src -fsSLO --compressed \
https://nodejs.org/download/release/$TARGET_NODE_VERSION/node-$TARGET_NODE_VERSION.tar.xz
tar -xf ./workdir/src/node-$TARGET_NODE_VERSION.tar.xz -C ./workdir/src
chmod -R a+rwx ./workdir/


echo "--- Buidling node for $TARGET_PLATFORM"
docker run --rm -it --platform $TARGET_PLATFORM \
-v ./workdir:/home/node/workdir:Z \
$BUILD_IMAGE_NAME \
$RELEASE_URL_BASE \
$TARGET_NODE_VERSION
24 changes: 24 additions & 0 deletions scripts/build_re2.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/bin/bash
delanni marked this conversation as resolved.
Show resolved Hide resolved
set -euo pipefail

source ./scripts/common.sh

# TARGET_VERSION provided in env
# ARCH provided in env
assert_correct_arch $ARCH

BUILD_IMAGE_NAME=$(get_build_image_name)
RE2_FULL_VERSION=${RE2_VERSION:-1.17.7} # $1
NODE_FULL_VERSION="v$TARGET_VERSION" # $2
NODE_DOWNLOAD_BASE_URL="https://storage.googleapis.com/kibana-custom-node-artifacts/node-glibc-217/dist/v$TARGET_VERSION"
TARGET_PLATFORM="linux/$ARCH"

echo "--- Building RE2 for $TARGET_PLATFORM"
mkdir -p ./workdir_re2/
chmod -R a+rwx ./workdir_re2/
docker run --rm -it --platform $TARGET_PLATFORM --entrypoint /home/node/re2_entrypoint.sh \
-v ./workdir_re2:/home/node/workdir \
$BUILD_IMAGE_NAME \
$RE2_FULL_VERSION \
$NODE_FULL_VERSION \
$NODE_DOWNLOAD_BASE_URL
70 changes: 70 additions & 0 deletions scripts/common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@

function assert_correct_arch() {
ARCH=$1

if [[ "$ARCH" == "arm64" || "$ARCH" == "amd64" ]]; then
# we're good, supported architecture
echo "Building for architecture: $ARCH"
else
echo "ARCH (=$ARCH) env variable is not one of: arm64, amd64"
exit 1
fi
}

function get_build_image_name() {
NODE_VERSION=${1:-$TARGET_VERSION}
PLATFORM=${2:-$ARCH}

echo "docker.elastic.co/elastic/nodejs-custom:$NODE_VERSION-$PLATFORM"
}

function retry() {
local retries=$1; shift
local delay=$1; shift
local attempts=1

until "$@"; do
retry_exit_status=$?
echo "Exited with $retry_exit_status" >&2
if (( retries == "0" )); then
return $retry_exit_status
elif (( attempts == retries )); then
echo "Failed $attempts retries" >&2
return $retry_exit_status
else
echo "Retrying $((retries - attempts)) more times..." >&2
attempts=$((attempts + 1))
sleep "$delay"
fi
done
}

function replace_shasums_in_folder() {
local working_directory=$1

cd $working_directory

# Check if SHASUMS256.txt file exists
if [ ! -f "./SHASUMS256.txt" ]; then
echo "SHASUMS256.txt file does not exist in folder: $working_directory"
exit 1
fi

# Loop through files in folder
for file in *; do
if [ "$file" != "SHASUMS256.txt" ] && [ -f "$file" ]; then
# Calculate SHA256 hash
new_sha256=$(shasum -a 256 "$file" | cut -d' ' -f1)
# Replace hashes in SHASUMS256.txt
node -e """
lines = fs.readFileSync('SHASUMS256.txt').toString().split('\n')
output = lines.map(l => l.endsWith('$file') ? '$new_sha256 $file' : l)
fs.writeFileSync('SHASUMS256.txt', output.join('\n'))
"""
fi
done

echo "`pwd`/SHASUMS256.txt updated"

cd -
}
Loading