Eric Guo's blog.cloud-mes.com

Hoping writing JS, Ruby & Rails and Go article, but fallback to DevOps note

Install dify.ai at Rocky Linux 9.3 From Source Code

Permalink

Setup dify user account

adduser dify
gpasswd -a dify wheel
cd /etc/sudoers.d
# you can later change more limit like "dify ALL=(ALL) NOPASSWD:/usr/bin/systemctl"
echo "dify ALL=(ALL) NOPASSWD:ALL" > 96-dify-user
sudo su - dify
mkdir .ssh
chmod 700 .ssh
vi .ssh/authorized_keys
chmod 600 .ssh/authorized_keys

Install local python 3.10 for dify

sudo dnf install tar curl gcc openssl-devel bzip2-devel libffi-devel zlib-devel wget make -y
wget https://www.python.org/ftp/python/3.10.13/Python-3.10.13.tar.xz
tar -xf Python-3.10.13.tar.xz
cd Python-3.10.13
./configure --enable-optimizations
make -j 2
sudo make altinstall

Create a Virtual Environment in Python

Copy from guide

python3.10 -m venv dify_env
source dify_env/bin/activate # also add in .bash_profile

Install basic environment

following guide

cd dify/api
cp .env.example .env
openssl rand -base64 42
sed -i 's/SECRET_KEY=.*/SECRET_KEY=<your_value>/' .env
pip install -r requirements.txt
# if meet https://github.com/langgenius/dify/pull/707
pip install -r requirements.txt --upgrade --force-reinstall

Create postgresql db user

sudo su - postgres
createuser dify
psql
ALTER ROLE dify LOGIN;
CREATE DATABASE dify_prod WITH ENCODING='UTF8' OWNER=dify;
logout
flask db upgrade

Install ffmpeg as dify require it

following guide

sudo dnf install epel-release
sudo dnf config-manager --set-enabled crb
sudo dnf install --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-$(rpm -E %rhel).noarch.rpm -y
sudo dnf install --nogpgcheck https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-$(rpm -E %rhel).noarch.rpm -y
sudo dnf install ffmpeg ffmpeg-devel

Deploy Rails 7.1 and AnyCable 1.4 With RPC Services in Rocky Linux 9

Permalink

I’m using an brand new Rocky Linux 9 server, to deploy the pgac_demo project.

Install htop and atop

dnf -y install epel-release
dnf makecache
dnf -y install htop

If htop not found

dnf repolist
vi /etc/yum.repos.d/epel.repo # In the [epel] section, change enabled=0 to enabled=1
dnf -y install htop atop

Install nginx and certbot

dnf install nginx
dnf install certbot python3-certbot-nginx

Setup pgac user account

adduser pgac
gpasswd -a pgac wheel
cd /etc/sudoers.d
# you can later change more limit like "pgac ALL=(ALL) NOPASSWD:/usr/bin/systemctl"
echo "pgac ALL=(ALL) NOPASSWD:ALL" > 97-pgac-user
sudo su - pgac
mkdir .ssh
chmod 700 .ssh
vi .ssh/authorized_keys
chmod 600 .ssh/authorized_keys

Install ruby dep

sudo dnf -y install git make gcc curl openssl-devel zlib-devel libffi-devel readline-devel sqlite-devel
sudo dnf --enablerepo=crb -y install libyaml-devel gdbm-devel
sudo yum -y install gcc-c++ # required by grpc
sudo yum -y install rust # if need YJIT
sudo yum -y install git-lfs # if any repository using LFS to store picture

Install rbenv and ruby-build

cd # as a pgac
git clone https://github.com/rbenv/rbenv .rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
~/.rbenv/bin/rbenv init # also edit ~/.bash_profile
# As an rbenv plugin
mkdir -p "$(rbenv root)"/plugins
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
git clone https://github.com/andorchen/rbenv-china-mirror.git "$(rbenv root)"/plugins/rbenv-china-mirror

Install Ruby 3.2.3

rbenv install -l
rbenv install 3.2.3
rbenv global 3.2.3
rbenv shell 3.2.3
echo "gem: --no-document" > ~/.gemrc

create deploy folder

cd /var/www
sudo mkdir pgac
sudo chown pgac:pgac pgac/

The extra file for capistrano

The puma file which will lauch puma via system service.

/var/www/pgac/shared/puma.rb
#!/usr/bin/env puma
directory '/var/www/pgac/current'
rackup "/var/www/pgac/current/config.ru"
environment 'production'
tag ''
pidfile "/var/www/pgac/shared/tmp/pids/puma.pid"
state_path "/var/www/pgac/shared/tmp/pids/puma.state"
stdout_redirect '/var/www/pgac/shared/log/puma_access.log', '/var/www/pgac/shared/log/puma_error.log', true
threads 0,16
bind 'unix:///var/www/pgac/shared/tmp/sockets/puma.sock'
workers 0
restart_command 'bundle exec puma'
prune_bundler
on_restart do
puts 'Refreshing Gemfile'
ENV["BUNDLE_GEMFILE"] = ""
end

The systemd service file.

/etc/systemd/system/puma_pgac.service
# This file tells systemd how to run Puma as a 24/7 long-running daemon.
#
# Customize this file based on your bundler location, app directory, etc.
# Customize and copy this into /usr/lib/systemd/system (CentOS) or /lib/systemd/system (Ubuntu).
# Then run:
# - systemctl enable puma_pgac
# - systemctl {start,stop,restart} puma_pgac
#
#
# Use `journalctl -u puma_pgac -rn 100` to view the last 100 lines of log output.
#
[Unit]
Description=Puma HTTP Server for pgac (production)
After=syslog.target network.target
[Service]
Type=simple
WatchdogSec=10
User=pgac
Environment=CABLE_URL=wss://pgac.redwoodjs.cn:3334/cable
WorkingDirectory=/var/www/pgac/current
ExecStart=/home/pgac/.rbenv/bin/rbenv exec bundle exec --keep-file-descriptors puma -C /var/www/pgac/shared/puma.rb
ExecReload=/bin/kill -USR1 $MAINPID
# if we crash, restart
RestartSec=10
Restart=on-failure
StandardOutput=append:/var/www/pgac/shared/log/puma.log
StandardError=append:/var/www/pgac/shared/log/puma.log
SyslogIdentifier=puma_pgac
[Install]
WantedBy=multi-user.target

The nginx conf files.

/etc/nginx/conf.d/pgac.conf
upstream puma_pgac_production {
server unix:/var/www/pgac/shared/tmp/sockets/puma.sock fail_timeout=0;
}
server {
if ($host = pgac.redwoodjs.cn) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name pgac.redwoodjs.cn;
return 301 https://$host$1$request_uri;
}
server {
listen 443 ssl http2; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/pgac.redwoodjs.cn/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/pgac.redwoodjs.cn/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
server_name pgac.redwoodjs.cn;
root /var/www/pgac/current/public;
try_files $uri/index.html $uri @puma_pgac_production;
client_max_body_size 4G;
keepalive_timeout 10;
error_page 500 502 504 /500.html;
error_page 503 @503;
location @puma_pgac_production {
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-Proto https;
proxy_pass http://puma_pgac_production;
# limit_req zone=one;
access_log /var/www/pgac/shared/log/nginx.access.log;
error_log /var/www/pgac/shared/log/nginx.error.log;
}
location ~ (/manifest.json|/favicon.ico|/*.txt|/*.png) {
access_log off;
expires 3d;
gzip_static on;
add_header Cache-Control public;
}
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location = /50x.html {
root html;
}
location = /404.html {
root html;
}
location @503 {
error_page 405 = /system/maintenance.html;
if (-f $document_root/system/maintenance.html) {
rewrite ^(.*)$ /system/maintenance.html break;
}
rewrite ^(.*)$ /503.html break;
}
if ($request_method !~ ^(GET|HEAD|PUT|PATCH|POST|DELETE|OPTIONS)$ ){
return 405;
}
if (-f $document_root/system/maintenance.html) {
return 503;
}
}

The systemd files for AnyCable Go/RPC service

Large following the AnyCable deployment document

Using redis as broadcast_adapter

/etc/systemd/system/pgac-anycable-rpc.service
[Unit]
Description=AnyCable gRPC Server for pgac
After=syslog.target network.target
[Service]
Type=simple
Environment=RAILS_ENV=production
Environment=ANYCABLE_REDIS_URL=redis://localhost:6379/5
Environment=ANYCABLE_REDIS_CHANNEL=__anycable__
WorkingDirectory=/var/www/pgac/current
ExecStart=/home/pgac/.rbenv/bin/rbenv exec bundle exec anycable
ExecStop=/bin/kill -TERM $MAINPID
User=pgac
RestartSec=9
Restart=on-failure
[Install]
WantedBy=multi-user.target

The anycable-go can download from release page

/etc/systemd/system/pgac-anycable-go.service
[Unit]
Description=anycable-go for pgac
After=syslog.target network.target
[Service]
Type=simple
Environment=ANYCABLE_HOST=pgac.redwoodjs.cn
Environment=ANYCABLE_PORT=3334
Environment=ANYCABLE_PATH=/cable
Environment=ANYCABLE_REDIS_URL=redis://localhost:6379/5
Environment=ANYCABLE_REDIS_CHANNEL=__anycable__
Environment=ANYCABLE_METRICS_HTTP=/metrics
WorkingDirectory=/var/www/pgac/current
ExecStart=/usr/local/bin/anycable-go --ssl_cert=/etc/letsencrypt/live/pgac.redwoodjs.cn/cert.pem --ssl_key=/etc/letsencrypt/live/pgac.redwoodjs.cn/privkey.pem
ExecStop=/bin/kill -TERM $MAINPID
User=pgac
LimitNOFILE=16384 # increase open files limit (see OS Tuning guide)
Restart=on-failure
[Install]
WantedBy=multi-user.target

You may need to fix access control for user pgac for letsencrypt key files.

Using http as broadcast_adapter

/etc/systemd/system/pgac-anycable-rpc.service
[Unit]
Description=AnyCable gRPC Server for pgac
After=syslog.target network.target
[Service]
Type=simple
Environment=RAILS_ENV=production
WorkingDirectory=/var/www/pgac/current
ExecStart=/home/pgac/.rbenv/bin/rbenv exec bundle exec anycable
ExecStop=/bin/kill -TERM $MAINPID
User=pgac
RestartSec=9
Restart=on-failure
[Install]
WantedBy=multi-user.target
/etc/systemd/system/pgac-anycable-go.service
[Unit]
Description=anycable-go for pgac
After=syslog.target network.target
[Service]
Type=simple
Environment=ANYCABLE_HOST=pgac.redwoodjs.cn
Environment=ANYCABLE_PORT=3334
Environment=ANYCABLE_PATH=/cable
Environment=ANYCABLE_METRICS_HTTP=/metrics
WorkingDirectory=/var/www/pgac/current
ExecStart=/usr/local/bin/anycable-go --ssl_cert=/etc/letsencrypt/live/pgac.redwoodjs.cn/cert.pem --ssl_key=/etc/letsencrypt/live/pgac.redwoodjs.cn/privkey.pem --broadcast_adapter=http --rpc_impl=grpc
ExecStop=/bin/kill -TERM $MAINPID
User=pgac
LimitNOFILE=16384 # increase open files limit (see OS Tuning guide)
Restart=on-failure
[Install]
WantedBy=multi-user.target

Convert Angular Project Module Manager From Npm to Yarn

Permalink

Rails’ default package manager for JS is yarn, and I like yarn because the package installation process on the China network is much more stable, and Capistrano’s support for yarn is also great.

However, Angular projects usually use npm as the default project manager. I used to believe it’s not changeable because every time I tried to switch, I failed. But yesterday, I found the correct way to do it, and here is how.

Run it in npm

Make sure the Angular project works normally in npm.

npm install
npm update
npm run start
npm run build

Import installed node modules in yarn.

This can be done via the import feature

rm package-lock.json # optional, but need it if yarn import failed
yarn import

Sync back to npm from yarn.lock

This is required to ensure Angular works after the yarn import. syncyarnlock is a tool that syncs yarn.lock versions into an existing package.json file.

npm -g install syncyarnlock
syncyarnlock -s -k
npm update
npm run start
npm run build

Run yarn update

After running yarn update, compare the yarn.lock file, add missing dependencies and devDependencies after the yarn update. I guess this is the key step to migrate from npm to yarn because npm dependencies are nested but yarn’s are flat.

yarn update
# check yarn.lock and add removed lines of the package to package.json

Now yarn works

yarn install
yarn update
yarn run start
yarn run build

You can keep package-lock.json or delete it, but your Angular project works with yarn now!

Install Gitea 1.21.3 From Source Code Into Rocky Linux 9

Permalink

Install dependency

Install htop and atop

sudo dnf update
sudo dnf install epel-release
sudo dnf install htop
sudo dnf install atop

Node.js v18

Using nodesource distribution

curl -fsSL https://rpm.nodesource.com/setup_18.x | bash -
dnf install -y nodejs
dnf groupinstall 'Development Tools'

Install yarn

curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
sudo yum install yarn

Go 1.20

Rocky Linux 9 including golang 1.20.

dnf install golang

Compile

Largely following official guide

Disable SELinux

vi /etc/selinux/config

Clone and build

git clone https://git.thape.com.cn/go-gitea/gitea.git
git checkout v1.21.3
npm config set registry https://registry.npmmirror.com/ --global
npm -g install webpack
TAGS="bindata" make build

Install Gitea

Install dependency

yum install redis
yum install memcached

Create git user

groupadd --system git
adduser \
--system \
--shell /bin/bash \
--comment 'Git Version Control' \
--gid git \
--home-dir /home/git \
--create-home \
git

Create required directory structure

Don’t forget change back to more strict setting.

mkdir -p /var/lib/gitea/{custom,data,log}
chown -R git:git /var/lib/gitea/
chmod -R 750 /var/lib/gitea/
mkdir /etc/gitea
chown root:git /etc/gitea
chmod 770 /etc/gitea

Create DB and DB user

sudo su - postgres
createuser gitea_t --pwprompt
psql
ALTER ROLE gitea_t LOGIN;
CREATE DATABASE gitea_staging WITH ENCODING='UTF8' OWNER=gitea_t;
logout
vi /var/lib/pgsql/16/data/pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
host gitea_staging gitea_t 0.0.0.0/0 scram-sha-256

Reload conf without restart DB

sudo su - postgres
/usr/pgsql-16/bin/pg_ctl reload

Open port to access and configure

sudo firewall-cmd --zone=public --add-port=3000/tcp
sudo firewall-cmd --zone=public --add-port=3000/tcp --permanent
sudo firewall-cmd --reload
sudo su - git
cd /var/lib/gitea/
gitea web -c /etc/gitea/app.ini

And open your server like http://172.16.1.47:3000 to configure

Binding to 443 and using https

Should following document, but if found cmd/web.go:353:listen() [E] Failed to start server: listen tcp 0.0.0.0:443: bind: permission denied error try below:

sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/gitea

Create DB ReadOnly User

createuser gitea_t_read --pwprompt
psql
ALTER ROLE gitea_t_read LOGIN;
GRANT USAGE ON SCHEMA public TO gitea_t_read;
SELECT 'GRANT SELECT ON ' || tablename || ' TO gitea_t_read;'
FROM pg_catalog.pg_tables
WHERE schemaname = 'public' AND tableowner = 'gitea_t';

Deploy Rails 7.1 and AnyCable 1.4 With RPC Services in the Existing CentOS 7

Permalink

I’m using the same server as post mention, to deploy the pgac_demo project.

Setup pgac user account

adduser pgac
gpasswd -a pgac wheel
cd /etc/sudoers.d
echo "pgac ALL=(ALL) NOPASSWD:ALL" > 97-pgac-user
sudo su - pgac
mkdir .ssh
chmod 700 .ssh
vi .ssh/authorized_keys
chmod 600 .ssh/authorized_keys

Install rbenv and ruby-build

cd # as a pgac
git clone https://github.com/rbenv/rbenv .rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
~/.rbenv/bin/rbenv init # also edit ~/.bash_profile
# As an rbenv plugin
mkdir -p "$(rbenv root)"/plugins
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build
git clone https://github.com/andorchen/rbenv-china-mirror.git "$(rbenv root)"/plugins/rbenv-china-mirror

Install Ruby 3.2.2

scl enable devtoolset-7 bash
rbenv install -l
rbenv install 3.2.2
rbenv global 3.2.2
rbenv shell 3.2.2
echo "gem: --no-document" > ~/.gemrc

create deploy folder

cd /var/www
sudo mkdir pgac
sudo chown pgac:pgac pgac/

The extra file for capistrano

The puma file which will lauch puma via system service.

/var/www/pgac/shared/puma.rb
#!/usr/bin/env puma
directory '/var/www/pgac/current'
rackup "/var/www/pgac/current/config.ru"
environment 'production'
tag ''
pidfile "/var/www/pgac/shared/tmp/pids/puma.pid"
state_path "/var/www/pgac/shared/tmp/pids/puma.state"
stdout_redirect '/var/www/pgac/shared/log/puma_access.log', '/var/www/pgac/shared/log/puma_error.log', true
threads 0,16
bind 'unix:///var/www/pgac/shared/tmp/sockets/puma.sock'
workers 0
restart_command 'bundle exec puma'
prune_bundler
on_restart do
puts 'Refreshing Gemfile'
ENV["BUNDLE_GEMFILE"] = ""
end

The systemd service file.

/etc/systemd/system/puma_pgac.service
# This file tells systemd how to run Puma as a 24/7 long-running daemon.
#
# Customize this file based on your bundler location, app directory, etc.
# Customize and copy this into /usr/lib/systemd/system (CentOS) or /lib/systemd/system (Ubuntu).
# Then run:
# - systemctl enable puma_pgac
# - systemctl {start,stop,restart} puma_pgac
#
#
# Use `journalctl -u puma_pgac -rn 100` to view the last 100 lines of log output.
#
[Unit]
Description=Puma HTTP Server for pgac (production)
After=syslog.target network.target
[Service]
Type=simple
WatchdogSec=10
User=pgac
Environment=CABLE_URL=wss://pgac.redwoodjs.cn:3334/cable
WorkingDirectory=/var/www/pgac/current
ExecStart=/home/pgac/.rbenv/bin/rbenv exec bundle exec --keep-file-descriptors puma -C /var/www/pgac/shared/puma.rb
ExecReload=/bin/kill -USR1 $MAINPID
# if we crash, restart
RestartSec=10
Restart=on-failure
StandardOutput=append:/var/www/pgac/shared/log/puma.log
StandardError=append:/var/www/pgac/shared/log/puma.log
SyslogIdentifier=puma_pgac
[Install]
WantedBy=multi-user.target

The nginx conf files.

/etc/nginx/conf.d/pgac.conf
upstream puma_pgac_production {
server unix:/var/www/pgac/shared/tmp/sockets/puma.sock fail_timeout=0;
}
server {
if ($host = pgac.redwoodjs.cn) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name pgac.redwoodjs.cn;
return 301 https://$host$1$request_uri;
}
server {
listen 443 ssl http2; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/pgac.redwoodjs.cn/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/pgac.redwoodjs.cn/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
server_name pgac.redwoodjs.cn;
root /var/www/pgac/current/public;
try_files $uri/index.html $uri @puma_pgac_production;
client_max_body_size 4G;
keepalive_timeout 10;
error_page 500 502 504 /500.html;
error_page 503 @503;
location @puma_pgac_production {
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-Proto https;
proxy_pass http://puma_pgac_production;
# limit_req zone=one;
access_log /var/www/pgac/shared/log/nginx.access.log;
error_log /var/www/pgac/shared/log/nginx.error.log;
}
location ~ (/manifest.json|/favicon.ico|/*.txt|/*.png) {
access_log off;
expires 3d;
gzip_static on;
add_header Cache-Control public;
}
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location = /50x.html {
root html;
}
location = /404.html {
root html;
}
location @503 {
error_page 405 = /system/maintenance.html;
if (-f $document_root/system/maintenance.html) {
rewrite ^(.*)$ /system/maintenance.html break;
}
rewrite ^(.*)$ /503.html break;
}
if ($request_method !~ ^(GET|HEAD|PUT|PATCH|POST|DELETE|OPTIONS)$ ){
return 405;
}
if (-f $document_root/system/maintenance.html) {
return 503;
}
}

The systemd files for AnyCable Go/RPC service

Large following the AnyCable deployment document

Using redis as broadcast_adapter

/etc/systemd/system/pgac-anycable-rpc.service
[Unit]
Description=AnyCable gRPC Server for pgac
After=syslog.target network.target
[Service]
Type=simple
Environment=RAILS_ENV=production
Environment=ANYCABLE_REDIS_URL=redis://localhost:6379/5
Environment=ANYCABLE_REDIS_CHANNEL=__anycable__
WorkingDirectory=/var/www/pgac/current
ExecStart=/home/pgac/.rbenv/bin/rbenv exec bundle exec anycable
ExecStop=/bin/kill -TERM $MAINPID
User=pgac
RestartSec=9
Restart=on-failure
[Install]
WantedBy=multi-user.target

The anycable-go can download from release page

/etc/systemd/system/pgac-anycable-go.service
[Unit]
Description=anycable-go for pgac
After=syslog.target network.target
[Service]
Type=simple
Environment=ANYCABLE_HOST=pgac.redwoodjs.cn
Environment=ANYCABLE_PORT=3334
Environment=ANYCABLE_PATH=/cable
Environment=ANYCABLE_REDIS_URL=redis://localhost:6379/5
Environment=ANYCABLE_REDIS_CHANNEL=__anycable__
Environment=ANYCABLE_METRICS_HTTP=/metrics
WorkingDirectory=/var/www/pgac/current
ExecStart=/usr/local/bin/anycable-go --ssl_cert=/etc/letsencrypt/live/pgac.redwoodjs.cn/cert.pem --ssl_key=/etc/letsencrypt/live/pgac.redwoodjs.cn/privkey.pem
ExecStop=/bin/kill -TERM $MAINPID
User=pgac
LimitNOFILE=16384 # increase open files limit (see OS Tuning guide)
Restart=on-failure
[Install]
WantedBy=multi-user.target

Using http as broadcast_adapter

/etc/systemd/system/pgac-anycable-rpc.service
[Unit]
Description=AnyCable gRPC Server for pgac
After=syslog.target network.target
[Service]
Type=simple
Environment=RAILS_ENV=production
WorkingDirectory=/var/www/pgac/current
ExecStart=/home/pgac/.rbenv/bin/rbenv exec bundle exec anycable
ExecStop=/bin/kill -TERM $MAINPID
User=pgac
RestartSec=9
Restart=on-failure
[Install]
WantedBy=multi-user.target
/etc/systemd/system/pgac-anycable-go.service
[Unit]
Description=anycable-go for pgac
After=syslog.target network.target
[Service]
Type=simple
Environment=ANYCABLE_HOST=pgac.redwoodjs.cn
Environment=ANYCABLE_PORT=3334
Environment=ANYCABLE_PATH=/cable
Environment=ANYCABLE_METRICS_HTTP=/metrics
WorkingDirectory=/var/www/pgac/current
ExecStart=/usr/local/bin/anycable-go --ssl_cert=/etc/letsencrypt/live/pgac.redwoodjs.cn/cert.pem --ssl_key=/etc/letsencrypt/live/pgac.redwoodjs.cn/privkey.pem --broadcast_adapter=http --rpc_impl=grpc
ExecStop=/bin/kill -TERM $MAINPID
User=pgac
LimitNOFILE=16384 # increase open files limit (see OS Tuning guide)
Restart=on-failure
[Install]
WantedBy=multi-user.target

Install Unleash Feature Flag Management OSS Software on Rocky Linux

Permalink

Unleash only depend on postgresql and recommand installation method including Docker/Docker-compose and pure Node.js. I using pm2 to do the daemon job and using a postgresql server seperatedly.

Install htop and atop

sudo dnf update
sudo dnf install epel-release
sudo dnf install htop
sudo dnf install atop

Setup unleash user account

adduser unleash
sudo su - unleash
mkdir .ssh
chmod 700 .ssh
vi .ssh/authorized_keys # and paste your public key
chmod 600 .ssh/authorized_keys

Install nginx

sudo dnf install nginx

Install node.js v18

Using nodesource distribution

curl -fsSL https://rpm.nodesource.com/setup_18.x | bash -
yum install -y nodejs
yum groupinstall 'Development Tools'

Install yarn

curl -sL https://dl.yarnpkg.com/rpm/yarn.repo | sudo tee /etc/yum.repos.d/yarn.repo
sudo yum install yarn

Disable firewall

firewall-cmd --zone=public --add-port=4242/tcp
firewall-cmd --permanent --zone=public --add-port=4242/tcp
firewall-cmd --reload
systemctl restart firewalld

Install Unleash

sudo su - unleash
git clone https://git.thape.com.cn/Eric-Guo/unleash.git
yarn
yarn run build

Run Unleash

node eric_server.js
eric_server
const unleash = require('./unleash/dist/lib/server-impl');
unleash
.start({
db: {
ssl: false,
host: '172.17.1.66',
port: 5432,
database: 'unleash_prod',
user: 'unleash',
password: 'password',
},
server: {
port: 4242,
unleashUrl: 'https://unleash.thape.com.cn',
baseUriPath: '/'
},
ui: { flags: { P: true } },
versionCheck: {
enable: false,
},
})
.then((unleash) => {
console.log(
`Unleash started on http://localhost:${unleash.app.get('port')}`,
);
});

Nginx conf

upstream unleash_proxy {
server 127.0.0.1:4242;
}
server {
listen 80;
server_name unleash.thape.com.cn;
return 301 https://unleash.thape.com.cn$request_uri;
}
server {
listen 443 ssl;
server_name unleash.thape.com.cn;
ssl_certificate /etc/ssl/cert/STAR_thape_com_cn_integrated.crt;
ssl_certificate_key /etc/ssl/private/STAR_thape_com_cn.key;
client_max_body_size 10M;
location / {
proxy_pass http://unleash_proxy;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
access_log /var/www/unleash/shared/log/nginx.access.log;
error_log /var/www/unleash/shared/log/nginx.error.log;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

Install PostgreSQL 16.1 on Rocky Linux 9.2 With Pgxn Client and Pgvector

Permalink

Install htop and atop

sudo dnf update
sudo dnf install epel-release
sudo dnf install htop
sudo dnf install atop

Install postgresql 16

yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm
yum update
yum install postgresql16-server
yum install -y glibc-langpack-en
localectl set-locale LANG=en_US.UTF-8
/usr/pgsql-16/bin/postgresql-16-setup initdb
systemctl start postgresql-16.service
systemctl status postgresql-16.service
systemctl enable postgresql-16.service

Install build tools

sudo yum install gcc-c++ make
sudo dnf --enablerepo=crb install perl-IPC-Run
sudo yum install postgresql16-devel
sudo yum install postgresql16-contrib # pg_trgm btree_gist require by gitlab

Install pip

Run as root

dnf install python3-pip
pip install pgxnclient --no-warn-script-location
export PATH=$PATH:/usr/pgsql-16/bin

Install pgvector extension

Run as root

yum install redhat-rpm-config
pgxnclient install vector

Install pg gem correctly

bundle config build.pg --with-pg-config=/usr/pgsql-16/bin/pg_config
bundle install

Disable SELinux

vi /etc/selinux/config

Disable firewall

firewall-cmd --zone=public --add-port=5432/tcp
firewall-cmd --permanent --zone=public --add-port=5432/tcp
firewall-cmd --reload
systemctl restart firewalld

Allow Remote Addresses

vi /var/lib/pgsql/16/data/postgresql.conf
listen_addresses = '*'

Create user and DB

sudo su - postgres
createuser kq_ai --pwprompt
psql
ALTER ROLE kq_ai LOGIN;
CREATE DATABASE kq_ai_db WITH ENCODING='UTF8' OWNER=kq_ai;
logout
vi /var/lib/pgsql/16/data/pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
host kq_ai_db kq_ai 0.0.0.0/0 scram-sha-256

Reload conf without restart DB

sudo su - postgres
/usr/pgsql-16/bin/pg_ctl reload

Enable vector

psql -d kq_ai_db
CREATE EXTENSION vector;
ALTER EXTENSION vector UPDATE;

check with normal user kq_ai sql

SELECT extversion FROM pg_extension WHERE extname = 'vector';

Export DB

pg_dump thape_forum_prod -O -x > thape_forum_prod_db.sql
zip thape_forum_prod_db.zip thape_forum_prod_db.sql

`

Import DB

psql --username=thape_forum --password --host=localhost -d thape_forum_prod -f thape_forum_prod_db.sql

2023 年的部门小结与 2024 年的计划

Permalink

2023 年马上要结束了,一眨眼 8 个月又过去了,参照2023 年的工作小结与计划的内容,先复盘一下 8 个月前的判断:

世界线

之前不看好阿里,现在回过头看没想到阿里会那么差,连市值也被只有其人数 1/10 的拼多多超过。之前判断鸿蒙失败了,这两天看到了急召鸿蒙开发工程师年薪 160 万的新闻,咋一看好像是鸿蒙非常红火,但其实我觉得只是在炒作,首先一个新兴客户端的年薪不可能那么高,其次如果真的鸿蒙生态起来了,必然开发者数量非常多,也开不了那么高,只能说明大家的眼睛是雪亮的,几乎没啥开发者在搞鸿蒙开发。当然这个肯定是主观判断,客观的也有,跨平台的 Taro 有一个 RFC,只有标题,没有内容,和其他类似的 RFC 提案相比较,我只能说我会持续关注。

经济方面,国内的房地产业大规模熄火已经导致了行业不景气,降本增效天天念就对了,就是得注意一下发言,别像阿里一样,搞成降本增笑。

今年最最火的还是 AI,也是唯一增长的领域。

IT 技术发展预测

语言

计算机语言的隔阂几乎被 GPT 4 完全打破了,一般的算法之类的,只要贴一种语言的表达,让 GPT 4 转化成另外一种语言,几乎都是可用的。甚至直接用人类语言编程也已经不是梦想,我在工作中也已经经常使用,但是这里有个问题,就是人类语言本身还是充满歧义,所以在需要精确表达的时候,还是发现应该用计算机语言。

数据库

本来以为 MySQL 和 PostgreSQL 是平分秋色的,现在看来 PG 已经远远的超过 MySQL,因为人工智能需要向量数据库等新的数据库形式,而这个现在只有 pgvector 是相对成熟和免费的,总的来看 PG 的插件体系太强了,甚至产生了PGXN这样的扩展插件管理工具,为了人工智能,现在只选 PG 就对了。

跨平台

Java 高版本 Oracle 开始收版权费了,dotNET 6 开始就完全跨平台了,WASM 也成为了 Web 的第二运行时(第一还是 JS),跨平台已经不是一个话题了,以后也不会再提。

Web 平台

作为平台之上的平台,Web 目前还是普通应用分发的第一选择。现在普通应用和生产力应用的区分更加模糊,比如现在的轻量看图已经是一种普通应用了。

Serverless、DevOps,运维自动化

随着国内阿里和滴滴的两次史诗级故障,Serverless 被证明只是找不到 Server 去修,而不是不会出错,而且每次故障都是人为的,所以运维自动化是必须的,DevOps 现在也扩展为 DevSecOps,以强调安全。

数据平台/中台

数据集中是对的,数据库是重要的,但是数据平台或者中台可能只是个 PPT 概念而已。

人工智能

GPT 4 出道半年了,基本可以确定现在的软件架构,最上面完全可以新加一层人工智能层,这一层将包含以下功能:

  • 无法写出程序的判断任务
  • 理解用户输入的自然语言意图和心情
  • 模拟人类的思考判断并执行

如何将这些任务所需要的数据送入这层,如何判断这层运算的结果,如果提取这些结果到执行层,这些都将是未来的核心任务。

但无论如何,人工智能需求是真的大,大到了连大的数据中心也一卡难求,所以大多数人都接受了 API 调用方式,而不是通常企业软件的 self-hosting,自部署。但从长期看,随着各种人工智能加速运算卡的普及已经用了公开的所有数据,所以当以后算力或者模型都不是瓶颈以后,数据将成为唯一的区分人工智能强弱的变量。

部门完成的工作小结

部门目前维护了22 个系统,今年新做的比较大的项目是 PLM 项目管理平台,PP 人员考核,PPT 协作,还有 SD 生图。合作商平台材料文本库和 Cybros 商务智能平台也在今年改动了很多。今年还做了不少临时性的需求,比如爬取侵犯我们官网的利用我们官网数据的网站,数据留痕便于起诉等。

比对之前的计划,在 API 互通上也做了好几个案例,特别是 PLM 这边和 DDS 还有会议预定系统的互联互通,迪峰和嘉鹏的合作值得肯定。用户体验方面,今年应该是最难的一年,因为人工智能的浪潮还没有卷到用户层,所以用户现在对 UI 的界面和交互停留在了历史最高点,等明年随着大规模的人工智能能力部署,人类用户应该没那么多闲情逸致吹毛求疵 UI 了,毕竟人工智能可不会嫌软件 UI 差而不用,相反,我们开发还可以将更多的经历投入到让人工智能代替人类用户的事物上。

2024 年的计划

完成开发至少两个人工智能应用

目前肯定能完成的是智能问答,数据现成,代码可控,只要接人工智能模型即可,这个跑通以后,后续天问搜索,材料库搜索都可以用类似的技术重做。

保证系统平稳运行

随着人员和硬件投入的进一步降低,要尽量避免出现类似阿里和滴滴这样的系统崩溃案例,平时的备份和维护还是要做好

引入安全审查和漏洞检测机制

随着人员和硬件投入的进一步降低,越来越多的项目将处于长期停止开发状态,要避免泛微或者 IE 11 造成的大规模安全事件,还是要从源头抓起,找出软件内使用组件的漏洞并修补是一个很好的切入点。

强调团队合作

随着人员和硬件投入的进一步降低,越来越少的人将维护越来越多的系统,原则上要鼓励扩展已有的系统满足需求或者系统相互调用满足需求,尽量避免再开发新的系统。