Tanzu Greenplum 7.8をOrbStack上のRocky Linux Machineにインストールするメモ
以前の記事でIntel MacのVMware Fusion上にGreenplumを構築しましたが、やっぱりApple SiliconのMac上で環境を作りたかったので、今回はOrbStackのLinux machines上で構築します。x86_64はRosettaによるエミュレートなので遅いですが、手軽さを優先しました。
Tanzu Greenplumのダウンロード
GreenplumのRPMパッケージをダウンロードします。Broadcomのアカウントが必要です。
ホストのMac上で~/greenplumディレクトリを作成します。
mkdir -p ~/greenplum
Broadcom Supportにログインして、Tanzu Greenplumのダウンロードページにアクセスします。
最新バージョンを選択します。

RHEL 9用のRPMパッケージをダウンロードします。必要に応じて他のパッケージもダウンロードしてください。

OrbStackでGreenplumクラスタの作成
Linux MachineのCloud Initで一気にGreenplumクラスタを作成します。
次のuser-data.ymlを作成します。
IPアドレスの192.168.139の部分や、rpmのパスGP_RPMは環境に合わせて変更してください。
#cloud-config
# ============================================================================
# Greenplum 7 cluster bootstrap — single-file cloud-config
#
# This file drives the entire procedure WITHOUT Ansible:
# - OS prep (packages, sysctl, limits, firewall, SELinux)
# - gpadmin user, sudoers, .bashrc
# - Static network configuration
# - Greenplum RPM download + install
# - /data directories per role
# - SSH key exchange between all nodes (gpssh-exkeys)
# - gpinitsystem (coordinator only)
#
# The role (coordinator / segment) is auto-detected from the hostname,
# so the same file works for all 4 nodes.
#
#
# Topology (default):
# gp-coordinator 192.168.139.200/24
# gp-segment1 192.168.139.201/24
# gp-segment2 192.168.139.202/24
# gp-segment3 192.168.139.203/24
#
# Boot order:
# Start all 4 VMs at the same time. The coordinator's runcmd waits up to
# 30 minutes per segment for SSH to come up before continuing.
# ============================================================================
manage_etc_hosts: false # we ship /etc/hosts via write_files
# ---------- SSH -------------------------------------------------------------
# Password auth must be enabled so that gpssh-exkeys / ssh-copy-id work
# during initial key exchange. Tighten afterwards if desired.
ssh_pwauth: true
disable_root: false
users:
- name: root
lock_passwd: false
ssh_authorized_keys:
# (*) your public key
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDBDv42W4u5e2bMHqOUukWbhvtUA84cSmatsaeHXuHq4m4KNK+gfh/5Wid4UDyuabW+5YR13CWTb5HbAYpDu+kPNgz7w2ESg7rQYcA1W0kAbp5YD8w6f7pQb+BfRXhZAMFkSzZqtDqYcGNGnXGoFvpi3q8711d6LSwQkffApyz0XrfxVzDeBzPEeEoOR36aVfs9QU+av2ud6gNx4A19IbD277a0ZUvLowJ1Ms+o4eU7X472Id4zE6UCfXwvkrPZkeX6YyVKbu3wjbBmp4DkQar9c8I8av0tBxrebSK6ELQwjA945IuGg7kkvmu60KCCvnmc8XaqUJdviG+6lr8PT+iBazZ4Wm8Xrr3GRWYiwUE+cqEvzefZpWdwXuJw8gcEuhIOTuWbEWMdy3N8KN9M/+5B+irJmXJXmTVdzCEAjukn5+QIsfTJp2DQYKSvlk8gOLk6PXWEUnlgytvaTKxG6Sq97UnLJMRUSebxpaCat37Zs26YFDfVnz7dsFbMT9gGAdMvZULkLc5Dt26uunaLr+NXcD/WUgEdWaEBLuOOSBMyjJulCca2FV38IPdpMBtf8ZvKuLesHnYum8TGxx8lS4+aWxm/OjGGkU4Rpvn/J2XiZY9Nm0xii8h+944RSqxzvKTRcVcr6wPJhVV31pSablshyL87KAobJBACQrd+DMZ5Qw==
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP1p/lDTw/mPvjTq1BVV6htcEQa+xSg+hG9tM0Ky9jYw
- name: gpadmin
primary_group: gpadmin
shell: /bin/bash
lock_passwd: false
sudo: "ALL=(ALL) NOPASSWD:ALL"
groups:
- gpadmin
chpasswd:
expire: false
users:
- {name: root, password: rocky, type: text}
- {name: gpadmin, password: Greenplum123, type: text}
# ---------- Packages --------------------------------------------------------
package_update: true
packages:
- apr
- apr-util
- bzip2
- curl
- iproute
- krb5-devel
- libcurl
- libevent
- libtiff
- libuuid
- libuv
- libxml2
- libyaml
- libzstd
- lsof
- openldap
- openssh
- openssh-clients
- openssh-server
- openssl
- openssl-libs
- perl
- python3
- python3-psycopg2
- python3-psutil
- python3-pyyaml
- python3.11
- python3.11-devel
- readline
- rsync
- sed
- tar
- which
- zip
- zlib
- sshpass
- java-21-openjdk-devel
- epel-release
# ---------- Static files ----------------------------------------------------
write_files:
- path: /etc/hosts
permissions: '0644'
content: |
127.0.0.1 localhost
192.168.139.200 gp-coordinator
192.168.139.201 gp-segment1
192.168.139.202 gp-segment2
192.168.139.203 gp-segment3
- path: /etc/sysctl.d/99-greenplum.conf
content: |
net.ipv4.ip_local_reserved_ports=65330
# file descriptor limits
- path: /etc/security/limits.d/99-greenplum.conf
content: |
* soft nofile 65536
* hard nofile 65536
# ----- Static network configuration -------------------------------------
- path: /usr/local/sbin/cloud-setup-network.sh
permissions: '0755'
owner: root:root
content: |
#!/bin/bash
set -eux
# Derive last octet from hostname: gp-coordinator -> 200, gp-segmentN -> 20N
HOST=$(hostname -s)
if [[ "$HOST" == "gp-coordinator" ]]; then
OCTET=200
elif [[ "$HOST" =~ ^gp-segment([0-9]+)$ ]]; then
OCTET=$((200 + BASH_REMATCH[1]))
else
echo "unknown host: $HOST" >&2; exit 1
fi
IPADDR="192.168.139.${OCTET}/24"
FALLBACK_GW="192.168.139.1"
DNS="8.8.8.8,1.1.1.1"
NIC=$(ip -o -4 route show default 2>/dev/null | awk '{print $5}' | head -n1)
GATEWAY=$(ip -o -4 route show default 2>/dev/null | awk '{print $3}' | head -n1)
[ -z "$NIC" ] && NIC=$(ls /sys/class/net | grep -E '^(en|eth)' | grep -v '^lo' | head -n1)
[ -z "$NIC" ] && { echo "no NIC found"; exit 1; }
[ -z "$GATEWAY" ] && GATEWAY="$FALLBACK_GW"
for con in $(nmcli -t -f NAME,DEVICE con show | awk -F: -v n="$NIC" '$2==n{print $1}'); do
nmcli con delete "$con" || true
done
nmcli con add type ethernet ifname "$NIC" con-name static \
ipv4.method manual ipv4.addresses "$IPADDR" \
ipv4.gateway "$GATEWAY" ipv4.dns "$DNS" \
ipv6.method disabled connection.autoconnect yes
nmcli con up static
# ----- Greenplum node provisioner (full procedure) ----------------------
# Determines role from hostname, installs Greenplum, prepares /data,
# and (on coordinator only) runs the cluster init.
- path: /usr/local/sbin/cloud-provision-greenplum.sh
permissions: '0755'
owner: root:root
content: |
#!/bin/bash
set -euxo pipefail
exec > >(tee -a /var/log/cloud-provision-greenplum.log) 2>&1
ulimit -SHn 65536 || true
echo "[provision] ulimit -n = $(ulimit -n) (hard: $(ulimit -Hn))"
# ===== Settings (edit if needed) ===================================
GP_RPM=/Users/toshiaki/greenplum/greenplum-db-7.8.1-el9-x86_64.rpm
GPADMIN_PW="Greenplum123"
COORDINATOR_HOST="gp-coordinator"
ALL_HOSTS=(gp-coordinator gp-segment1 gp-segment2 gp-segment3)
SEGMENT_HOSTS=(gp-segment1 gp-segment2 gp-segment3)
# ===================================================================
HOSTNAME_SHORT=$(hostname -s)
if [[ "$HOSTNAME_SHORT" == "$COORDINATOR_HOST" ]]; then
ROLE=coordinator
else
ROLE=segment
fi
echo "[provision] role=$ROLE host=$HOSTNAME_SHORT"
# ---- Java default ---------------------------------------------------
JAVA21=$(ls /usr/lib/jvm/java-21-openjdk-*/bin/java 2>/dev/null | head -n1 || true)
[ -n "$JAVA21" ] && alternatives --set java "$JAVA21" || true
# ---- firewalld / SELinux -------------------------------------------
systemctl disable --now firewalld 2>/dev/null || true
setenforce 0 2>/dev/null || true
sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config || true
# ---- Download & install Greenplum RPM ------------------------------
dnf install -y $GP_RPM
GPHOME=$(ls -d /usr/local/greenplum-db-* 2>/dev/null | sort | tail -n1)
chown -R gpadmin:gpadmin "$GPHOME"
# ---- gpadmin .bashrc -----------------------------------------------
su - gpadmin -c "
grep -q greenplum_path ~/.bashrc \
|| echo 'source $GPHOME/greenplum_path.sh' >> ~/.bashrc
"
# ---- /data directories ---------------------------------------------
if [[ "$ROLE" == "coordinator" ]]; then
mkdir -p /data/coordinator
else
mkdir -p /data/primary /data/mirror
fi
chown -R gpadmin:gpadmin /data
# ---- gpadmin SSH keypair -------------------------------------------
su - gpadmin -c '
[ -f ~/.ssh/id_rsa ] || ssh-keygen -m PEM -t rsa -b 4096 -q -N "" -f ~/.ssh/id_rsa
'
# ---- Coordinator-only: cluster init --------------------------------
if [[ "$ROLE" == "coordinator" ]]; then
echo "[provision] coordinator: waiting for all nodes to accept SSH..."
for h in "${ALL_HOSTS[@]}"; do
for i in $(seq 1 30); do
if sshpass -p "$GPADMIN_PW" ssh \
-o StrictHostKeyChecking=no \
-o ConnectTimeout=2 \
-o PasswordAuthentication=yes \
-o PreferredAuthentications=password \
gpadmin@"$h" true 2>/dev/null; then
echo "[provision] $h is up"
break
fi
[[ $i -eq 30 ]] && { echo "[provision] timeout waiting for $h"; exit 1; }
sleep 5
done
done
# SSH key exchange (per the original procedure)
for h in "${ALL_HOSTS[@]}"; do
su - gpadmin -c "
SSHPASS='$GPADMIN_PW' sshpass -e ssh-copy-id -o StrictHostKeyChecking=no $h
"
done
# gpssh-exkeys populates known_hosts cluster-wide
su - gpadmin -c "
printf '%s\n' ${ALL_HOSTS[*]} > ~/hostfile_exkeys
source $GPHOME/greenplum_path.sh
gpssh-exkeys -f ~/hostfile_exkeys
"
# gpinitsystem_config
su - gpadmin -c "
mkdir -p ~/gpconfigs
printf '%s\n' ${SEGMENT_HOSTS[*]} > ~/gpconfigs/hostfile_gpinitsystem
cp $GPHOME/docs/cli_help/gpconfigs/gpinitsystem_config ~/gpconfigs/
sed -i \
-e 's|^declare -a DATA_DIRECTORY=.*|declare -a DATA_DIRECTORY=(/data/primary /data/primary)|' \
-e 's|^#declare -a MIRROR_DATA_DIRECTORY=.*|declare -a MIRROR_DATA_DIRECTORY=(/data/mirror /data/mirror)|' \
-e 's|^#MIRROR_PORT_BASE=.*|MIRROR_PORT_BASE=7000|' \
-e 's|^COORDINATOR_HOSTNAME=.*|COORDINATOR_HOSTNAME=$COORDINATOR_HOST|' \
~/gpconfigs/gpinitsystem_config
"
# Initialize the cluster (non-interactive)
su - gpadmin -c "
ulimit -n 65536
source $GPHOME/greenplum_path.sh
gpinitsystem -a \
-c ~/gpconfigs/gpinitsystem_config \
-h ~/gpconfigs/hostfile_gpinitsystem
"
# Greenplum env vars for gpadmin
printf '%s\n' \
'export COORDINATOR_DATA_DIRECTORY=/data/coordinator/gpseg-1' \
'export PGPORT=5432' \
'export PGUSER=gpadmin' \
'export PGDATABASE=gpadmin' \
>> /home/gpadmin/.bashrc
chown gpadmin:gpadmin /home/gpadmin/.bashrc
fi
echo "[provision] done role=$ROLE"
# ---------- Boot sequence ---------------------------------------------------
runcmd:
# 0. Make sure sshd is running and enabled (minimal/container images often
# ship with it disabled, which would block gpssh-exkeys / ssh-copy-id)
- [systemctl, enable, --now, sshd]
# 1. Switch from DHCP to static IP
- /usr/local/sbin/cloud-setup-network.sh
# 2. Apply sysctl (limits picks up on next login automatically)
- [sysctl, --system]
# 3. Full Greenplum provisioning (coordinator also runs gpinitsystem)
- /usr/local/sbin/cloud-provision-greenplum.sh
# ---------- Final message ---------------------------------------------------
final_message: |
cloud-init finished in $UPTIME seconds.
See /var/log/cloud-provision-greenplum.log for Greenplum bootstrap output.
If this is the coordinator, run as gpadmin:
gpstate -s # cluster status
gpstate -e # mirror status
このuser-data.ymlを使ってCoordinatorとSegmentを一気に作ります。
orb create -a amd64 rocky:9 gp-coordinator -c user-data.yml
orb create -a amd64 rocky:9 gp-segment1 -c user-data.yml
orb create -a amd64 rocky:9 gp-segment2 -c user-data.yml
orb create -a amd64 rocky:9 gp-segment3 -c user-data.yml
構成の確認
Coordinatorにログインします。
orb shell -m gp-coordinator -u gpadmin -w /home/gpadmin
# クラスタ状態確認
gpstate -s
# セグメント詳細確認
gpstate -e
# ミラー状態確認
gpstate -m
セグメント詳細確認は次のように表示されます。
$ gpstate -e
20260522:13:19:42:014744 gpstate:gp-coordinator:gpadmin-[INFO]:-Starting gpstate with args: -e
20260522:13:19:42:014744 gpstate:gp-coordinator:gpadmin-[INFO]:-local Greenplum Version: 'postgres (Greenplum Database) 7.8.1 build commit:2ac9af769d652200c3a913cc8ae39d54d7d72ded'
20260522:13:19:42:014744 gpstate:gp-coordinator:gpadmin-[INFO]:-Coordinator Greenplum Version: 'PostgreSQL 12.22 (Greenplum Database 7.8.1 build commit:2ac9af769d652200c3a913cc8ae39d54d7d72ded) on x86_64-pc-linux-gnu, compiled by gcc (GCC) 11.5.0 20240719 (Red Hat 11.5.0-11), 64-bit compiled on May 15 2026 07:32:19 Bhuvnesh C.'
20260522:13:19:42:014744 gpstate:gp-coordinator:gpadmin-[INFO]:-Obtaining Segment details from coordinator...
20260522:13:19:42:014744 gpstate:gp-coordinator:gpadmin-[INFO]:-Gathering data from segments...
.....
20260522:13:19:51:014744 gpstate:gp-coordinator:gpadmin-[INFO]:-----------------------------------------------------
20260522:13:19:51:014744 gpstate:gp-coordinator:gpadmin-[INFO]:-Segment Mirroring Status Report
20260522:13:19:54:014744 gpstate:gp-coordinator:gpadmin-[INFO]:-----------------------------------------------------
20260522:13:19:54:014744 gpstate:gp-coordinator:gpadmin-[INFO]:-All segments are running normally
ミラー状態確認は次のように表示されます。
$ gpstate -m
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:-Starting gpstate with args: -m
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:-local Greenplum Version: 'postgres (Greenplum Database) 7.8.1 build commit:2ac9af769d652200c3a913cc8ae39d54d7d72ded'
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:-Coordinator Greenplum Version: 'PostgreSQL 12.22 (Greenplum Database 7.8.1 build commit:2ac9af769d652200c3a913cc8ae39d54d7d72ded) on x86_64-pc-linux-gnu, compiled by gcc (GCC) 11.5.0 20240719 (Red Hat 11.5.0-11), 64-bit compiled on May 15 2026 07:32:19 Bhuvnesh C.'
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:-Obtaining Segment details from coordinator...
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:--------------------------------------------------------------
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:--Current GPDB mirror list and status
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:--Type = Group
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:--------------------------------------------------------------
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:- Mirror Datadir Port Status Data Status
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:- gp-segment2 /data/mirror/gpseg0 7000 Passive Synchronized
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:- gp-segment2 /data/mirror/gpseg1 7001 Passive Synchronized
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:- gp-segment3 /data/mirror/gpseg2 7000 Passive Synchronized
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:- gp-segment3 /data/mirror/gpseg3 7001 Passive Synchronized
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:- gp-segment1 /data/mirror/gpseg4 7000 Passive Synchronized
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:- gp-segment1 /data/mirror/gpseg5 7001 Passive Synchronized
20260522:13:20:16:014786 gpstate:gp-coordinator:gpadmin-[INFO]:--------------------------------------------------------------
psqlでも構成を確認します。
psql -d postgres -c "SELECT content, role, preferred_role, hostname, port, datadir, status FROM gp_segment_configuration ORDER BY content, role;"
以下の構成になっていることを確認します。
content | role | preferred_role | hostname | port | datadir | status
---------+------+----------------+----------------+------+---------------------------+--------
-1 | p | p | gp-coordinator | 5432 | /data/coordinator/gpseg-1 | u
0 | m | m | gp-segment2 | 7000 | /data/mirror/gpseg0 | u
0 | p | p | gp-segment1 | 6000 | /data/primary/gpseg0 | u
1 | m | m | gp-segment2 | 7001 | /data/mirror/gpseg1 | u
1 | p | p | gp-segment1 | 6001 | /data/primary/gpseg1 | u
2 | m | m | gp-segment3 | 7000 | /data/mirror/gpseg2 | u
2 | p | p | gp-segment2 | 6000 | /data/primary/gpseg2 | u
3 | m | m | gp-segment3 | 7001 | /data/mirror/gpseg3 | u
3 | p | p | gp-segment2 | 6001 | /data/primary/gpseg3 | u
4 | m | m | gp-segment1 | 7000 | /data/mirror/gpseg4 | u
4 | p | p | gp-segment3 | 6000 | /data/primary/gpseg4 | u
5 | m | m | gp-segment1 | 7001 | /data/mirror/gpseg5 | u
5 | p | p | gp-segment3 | 6001 | /data/primary/gpseg5 | u
(13 rows)
構成のポイント:
- 合計6つのプライマリセグメント(content 0-5)
- 各プライマリに対応するミラーが別ホストに配置
- 各サーバーに2プライマリ + 2ミラー = 計4インスタンス
動作確認
テストデータベースを作成します。
createdb test
テーブルを作成し、動作確認します。
psql -d test -c "CREATE TABLE test_table (id int, name text) DISTRIBUTED BY (id);"
psql -d test -c "INSERT INTO test_table SELECT generate_series(1,1000), 'test_data';"
psql -d test -c "SELECT gp_segment_id, count(*) FROM test_table GROUP BY gp_segment_id ORDER BY gp_segment_id;"
次のように6つのセグメント(0-5)にデータが分散されていることを確認してください。
gp_segment_id | count
---------------+-------
0 | 172
1 | 163
2 | 182
3 | 164
4 | 168
5 | 151
(6 rows)
以上でセットアップ完了です。