Week 9, 10 & 11 - CircuitVerse@GSOC'23

I am exploring the world of technology and playing with them. Like a kid, breaking them and modiy them.
Search for a command to run...

I am exploring the world of technology and playing with them. Like a kid, breaking them and modiy them.
No comments yet. Be the first to comment.
Finally, On July 14, I received this email about passing the midterm evaluation ππ. You can check out the blog on the phase 1 report here: https://blog.circuitverse.org/posts/tanmoy_sarkar_phase_1_report/ You should check other blogs here: https:/...
From last year (July~August), I am working on an open source PaaS to deploy and manage applications easily on any VPS. I have a motive to create a solution which you once setup on your cloud, you will get same kind of experience like other platforms ...

Finally, On July 14, I received this email about passing the midterm evaluation ππ. You can check out the blog on the phase 1 report here: https://blog.circuitverse.org/posts/tanmoy_sarkar_phase_1_report/ You should check other blogs here: https:/...

At the start, this week's main focus was completing the RBS integration. But that does not go well due to having issues with rbs_rails Gem. So I raised PR in rbs_rails the gem repository about the issue to get some hints from the maintainers. You can...

This week was more on learning rather than coding. The main objectives of this week were Learn RBS to start working on it Generate code coverage report and write the missing unit-tests Split Solargraph PR to small PRs for better review Learn RB...

This blog is coming after a long time [almost 3 weeks].
Throughout this week, the main tasks involved were -
Update the docker setup to make it more convenient
Test the docker setup in all OS [Linux, Mac, Windows]
Rewrite Documentation
The main problems with the current setup are -
In the docker file, it copies all the source code and installs dependencies
The image and process inside the container run as root user
For this reason, whenever some dependencies or codebase changes the docker image rebuild and which takes lots of time
As the process runs as a root user, some file changes from the container give permission errors in a code editor.
As we install all the dependencies at the time of building the image, there is no possibility to cache the dependencies
Solution -
The solution is inspired by the GitHub Codespaces working principle.
π How do codespaces work?
It has a Dockerfile of the application
It starts the container with a sleep infinity to prevent it from terminating after the start
Then, it uses attach or exec to attach the container
Then, it runs a setup.sh to install all dependencies and prepare the4 environment
Then it runs boot.sh to start the application
π Let's do the same for CircuitVerse project
Prepare the Dockerfile. This will only contain the ruby and nodejs environment. As well as it will have a non-root user with the same user id and group id of the host.
We will provide host's group id and user id by build arguments
FROM ruby:3.2.1
# Args
ARG NON_ROOT_USER_ID
ARG NON_ROOT_GROUP_ID
ARG NON_ROOT_USERNAME
ARG NON_ROOT_GROUPNAME
ARG OPERATING_SYSTEM
# Check mandatory args
RUN test -n "$NON_ROOT_USER_ID"
RUN test -n "$NON_ROOT_GROUP_ID"
RUN test -n "$OPERATING_SYSTEM"
RUN test -n "$NON_ROOT_USERNAME"
RUN test -n "$NON_ROOT_GROUPNAME"
# Create app directory
RUN mkdir /circuitverse
# Create non-root user directory
RUN mkdir /home/${NON_ROOT_USERNAME}
# Create non-root vendor directory
RUN mkdir /home/vendor
RUN mkdir /home/vendor/bundle
# set up workdir
WORKDIR /circuitverse
# Set shell to bash
SHELL ["/bin/bash", "-c"]
# install dependencies
RUN apt-get update -qq && \
apt-get install -y imagemagick shared-mime-info libvips sudo make cmake netcat libnotify-dev git chromium-driver chromium --fix-missing && apt-get clean
# Setup nodejs and yarn
RUN curl -sL https://deb.nodesource.com/setup_16.x | bash \
&& apt-get update && apt-get install -y nodejs && rm -rf /var/lib/apt/lists/* \
&& curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update && apt-get install -y yarn && rm -rf /var/lib/apt/lists/*
# If OPERATING_SYSTEM is Linux, create non-root user
RUN if [[ "$OPERATING_SYSTEM" == "linux" ]]; then \
# create non-root user with same uid:gid as host non-root user
groupadd -g ${NON_ROOT_GROUP_ID} -r ${NON_ROOT_GROUPNAME} && useradd -u ${NON_ROOT_USER_ID} -r -g ${NON_ROOT_GROUPNAME} ${NON_ROOT_USERNAME} \
&& chown -R ${NON_ROOT_USERNAME}:${NON_ROOT_GROUPNAME} /circuitverse \
&& chown -R ${NON_ROOT_USERNAME}:${NON_ROOT_GROUPNAME} /home/${NON_ROOT_USERNAME} \
&& chown -R ${NON_ROOT_USERNAME}:${NON_ROOT_GROUPNAME} /home/vendor \
&& chown -R ${NON_ROOT_USERNAME}:${NON_ROOT_GROUPNAME} /home/vendor/bundle \
# Provide sudo permissions to non-root user
&& adduser ${NON_ROOT_USERNAME} sudo \
&& echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers ;\
fi
# Switch to non-root user
USER ${NON_ROOT_USERNAME}
For
macOSandwindowswe don't need non-root users because the volume mounting is worked as shared storage. So the permission error will not come
Next, we create a setup.sh which will install dependencies and migrate the database
# !/bin/sh
# Remove tmp folder
rm -rf /circuitverse/tmp
# Install ruby dependencies
gem install bundler
bundle config set --local without "production"
bundle config set --local path "/home/vendor/bundle"
bundle install
# Install node dependencies
yarn
# Setup database
bundle exec rails db:create
bundle exec rails db:schema:load
bundle exec rails db:migrate
bundle exec rails db:seed
# generate key-pair for jwt-auth
# if private.pem and public.pem does not exists
if [ ! -f "/circuitverse/config/private.pem" ] && [ ! -f "/circuitverse/config/public.pem" ]; then
openssl genrsa -out /circuitverse/config/private.pem 2048
openssl rsa -in /circuitverse/config/private.pem -outform PEM -pubout -out /circuitverse/config/public.pem
fi
Then we create a boot.sh to initiate setup.sh and then start the server
#!/bin/bash
# Delete server.pid if it exists
rm -f /circuitverse/tmp/pids/server.pid 2>&1
# Run setup
echo "Setup project"
./bin/docker/setup
if [[ "$OPERATING_SYSTEM" == "linux" || "$OPERATING_SYSTEM" == "mac" ]]; then
if [ ! -d "${HOST_CURRENT_DIRECTORY%/*}" ]; then
sudo mkdir -p "${HOST_CURRENT_DIRECTORY%/*}"
fi
# Setup symbolic link for solargraph
if [ ! -L "$HOST_CURRENT_DIRECTORY" ]; then
sudo ln -s -T /circuitverse "$HOST_CURRENT_DIRECTORY"
fi
# Start solargraph server in background
bundle exec solargraph socket --host="0.0.0.0" --port=3002 &> /dev/null &
fi
# Start server
./bin/dev
# Start bash if previous command exits
/bin/bash
Now, we need to prepare the docker-compose.yml. As you can see still now we haven't copied the source code in the image or anywhere.
We will mount the codebase to the container at /circuitverse location to make it easy to edit files and keep all files in sync
....
web:
build:
context: .
dockerfile: Dockerfile
args:
- NON_ROOT_USER_ID=${CURRENT_UID}
- NON_ROOT_GROUP_ID=${CURRENT_GID}
- OPERATING_SYSTEM=${OPERATING_SYSTEM}
- NON_ROOT_USERNAME=${NON_ROOT_USERNAME}
- NON_ROOT_GROUPNAME=${NON_ROOT_GROUPNAME}
command: sleep infinity
volumes:
- .:/circuitverse:rw
- ./config/database.docker.yml:/circuitverse/config/database.yml:rw
- ruby_bundle:/home/vendor/bundle:rw
cap_add:
- SYS_ADMIN
ports:
- "3000:3000"
- "3001:3001"
- "3002:3002"
- "3035:3035"
- "3036:3036"
depends_on:
- db
- redis
environment:
REDIS_URL: "redis://redis:6379/0"
CIRCUITVERSE_USE_SOLR: "false"
DOCKER_ENVIRONMENT: "true"
NODE_ENV: "development"
HOST_CURRENT_DIRECTORY: $PWD
OPERATING_SYSTEM: $OPERATING_SYSTEM
....
Everything is ready. But there is an issue, we can't run this using docker-compose up. We need to set the NON_ROOT_USER_ID NON_ROOT_GROUP_ID OPERATING_SYSTEM environment variables. Also, need to start the server by attaching to it. So write a script for that
#!/bin/bash
# Detect operating system [linux, macos] with uname
DETECTED_OS=$(uname -s | tr '[:upper:]' '[:lower:]')
# If operating system is linux
if [ "$DETECTED_OS" = "linux" ]; then
# Set environment variables temporary
export CURRENT_GID=$(id -g)
export CURRENT_UID=$(id -u)
export NON_ROOT_USERNAME="user"
export NON_ROOT_GROUPNAME="user"
export OPERATING_SYSTEM="linux"
# Check if docker and docker compose are installed
if ! command -v docker &>/dev/null; then
echo "Docker is not installed. Install docker : https://docs.docker.com/engine/install/"
exit 0
fi
# Check if rootless docker is available
if docker ps &>/dev/null; then
# Run docker-compose up
docker compose up -d --build
# Run docker-compose exec web bash
docker compose exec web bin/docker/boot
# Run docker-compose down
docker compose down
else
# Run docker-compose up as root user
sudo docker compose up -d --build
# Run docker-compose exec web bash as root user
sudo docker compose exec web bin/docker/boot
# Run docker-compose down as root user
sudo docker compose down
fi
fi
# If operating system is macos
if [ "$DETECTED_OS" = "darwin" ]; then
# Set environment variables temporary
export CURRENT_GID="0"
export CURRENT_UID="0"
export NON_ROOT_USERNAME="root"
export NON_ROOT_GROUPNAME="root"
export OPERATING_SYSTEM="mac"
# Check if docker and docker compose are installed
if ! command -v docker &>/dev/null; then
echo "Docker is not installed. Install docker : https://docs.docker.com/engine/install/"
exit 0
fi
# Run docker-compose up
docker compose up -d --build
# Run docker-compose exec web bash
docker compose exec web bin/docker/boot
# Run docker-compose down
docker compose down
fi
This one script is responsible to fetch user id and group id and set temporary environment variables.
This will start the container and then run bin/docker/boot inside the container. And after the container got exited, it run docker compose down to stop other containers as well.
π That's all.
We have tested this docker setup in
Windows [both Hyper-V and WSL2]
Linux
MacOS
It works on all os without any issues.
For Windows, we have written a PowerShell script to support it as well.
# Set environment variables
$env:NON_ROOT_USERNAME = "root";
$env:NON_ROOT_GROUPNAME = "root";
$env:OPERATING_SYSTEM = "windows";
$env:PWD = (Get-Location).Path;
$env:CURRENT_UID = "0";
$env:CURRENT_GID = "0";
# Check if docker is available
if (Get-Command -Name "docker" -ErrorAction SilentlyContinue) {
# Run docker-compose up
docker compose up -d --build
# Run docker-compose exec to boot the image
docker compose exec web bin/docker/boot
# Run docker-compose down
docker compose down
}
else {
Write-Output "Docker is not available. Follow this documentation to install docker: https://docs.docker.com/desktop/install/windows-install/"
}
You can get more details in this PR - https://github.com/CircuitVerse/CircuitVerse/pull/3913/
Many changes were made to the project for improving the development experience. So it's very important to update the documentation as well.
We have written the documentation for Remote Development Platforms, as well as separate documentation for each operating system for setting up a docker-based environment + local installation.
Additionally, working on the reviewed PRs. Making some changes on the PR to make it ready to merge.
That's all for this blog. If you liked this subscribe to the newsletter.
π Finally, my project SwiftWave has been published on GitHub.
SwiftWave is a self-hosted lightweight PaaS solution to deploy and manage your applications on any VPS without any hassle
GitHub Link - https://github.com/swiftwave-org/swiftwave
If you like the initiative, starβ the project on GitHub.