Deploy Saleor Production บน Ubuntu 22.04
จากการตามอ่านใน stackoverflow.com และตามที่ต่างๆบนโลกอินเตอร์เน็ต ผมพอจะคลำทางวิธีการ Deploy Saleor Production mode บน Ubuntu 22.04 ตามนี้ครับ

ถ้าดูข้อมูลบนเว็บไซต์ของ saleor จะไม่มีรายละเอียดบอกถึงการ Deploy Saleor Production mode มีแต่เพียง Development mode จากการตามอ่านใน stackoverflow.com และตามที่ต่างๆบนโลกอินเตอร์เน็ต ผมพอจะคลำทาง วิธีการ Deploy Saleor Production mode บน Ubuntu 22.04 ได้ดังนี้ครับ
Saleor คือ?
Saleor เป็นโปรแกรมบริหารจัดการ E-Commerce แบบ Headless คือมันจะทำหน้าที่เป็นเพียงระบบหลังบ้านเท่านั้นครับ หรือ Back-End คอยจัดการระบบสินค้า ระบบรับชำระเงินออนไลน์ ระบบสต็อก ระบบโปรโมชั่นต่างๆ เช่น Gift Card หรือ ส่วนลด ที่คิดเป็น เปอร์เซ็นต์จากยอดขาย เป็นต้น ซึ่งจะเขียนด้วยภาษา Python/Django ทั้งนี้เราสามารถเขียนโค้ด Front-End มาเชื่อมต่อได้ โดยไม่ต้องกังวลว่า Front-End จะทำงานหนักเกินไปหรือเปล่า เพราะเราได้แยกส่วนของ E-Commerce ออกมาแล้ว ซึ่งจะคล้ายๆกับหลักการของ Micro Services นั่นเองครับ ซึ่งเทคโนโลยีที่ใช้เขียน Front-End เราสามารถใช้ NextJS หรือ ReactJS ก็ได้ครับ
Ubuntu 22.04 บน Linode
ก่อนอื่นก็ต้องสร้าง Ubuntu Server กันก่อนครับ ในที่นี้จะใช้ Ubuntu บน Linode เนื่องจากราคาจะถูกกว่า AWS EC2 โดยให้ทำตามขั้นตอนดังนี้ครับ
สมัครเป็นผู้ใช้งาน Linode โดยต้องยืนยันตัวตนผ่านบัตรเครดิต หรือบัตรเดบิต ก็ได้ครับ มีเงินติดอยู่ในบัตรเดบิต ซัก 50 บาท ก็น่าจะได้แล้วครับ ขั้นตอนการยืนยันตัวตน เขาจะ Hold เงินเอาไว้ 1USD พอยืนยันตัวตนเสร็จ เขาจะคืนเงินให้ครับ
ทั้งนี้ ลูกค้ารายใหม่จะได้รับเครดิต 100USD สามารถนำไปใช้ได้ภายใน 60 วัน ดังนั้นจึงไม่ต้องกังวัลครับ เราสามารถเข้ามาลองฝึกทักษะคอมพิวเตอร์ได้ โดยไม่ต้องจ่ายเงินเลยใน 60 วันแรกครับ
เมื่อล็อกอินเข้าไปได้แล้ว
1. ให้คลิ๊ก Linodes ตรง Sidebar ที่อยู่ด้านซ้าย
2. แล้วคลิ๊กปุ่ม Create ตามภาพประกอบครับ

3. จาก Drop Down Lists ให้เลือก Linode

4. Images เลือก Ubuntu 22.04 LTS
5. ตรง Region เลือก Singapore ครับ เพราะอยู่ใกล้เราสุดแล้ว
6. ต่อมา Linode Plan เลือกแท็บ Shared CPU แล้วเลือก Linode 4 GB จะประกอบด้วย RAM 4 GB CPUs 2 ซึ่งเป็นสเปกขั้นต่ำ ที่ใช้สำหรับ รัน Saleor ครับ โดยเขาจะคิดค่าใช้จ่ายต่อเดือนที่ 24USD ครับ ผมเข้าใจว่าถูกว่าของ AWS EC2

7. สร้างป้ายชื่อตรง Linode Label ใส่ชื่ออะไรก็ได้ ในที่นี้ตั้งชื่อเป็น Saleor
8. กำหนดรหัสผ่านสำหรับ Root user ครับ
นอกนั้นปล่อยตามค่า Default

9. ตรง Add-ons จะเลือก Private IP ก็ได้นะครับ ในกรณีนี้จะเลือก Private IP ด้วยครับ
10. เมื่อมาถึงตรงนี้ก็กดปุ่ม Create Linode ได้เลยครับ

Linode จะมี Ubuntu ที่ติดตั้ง Docker และ Docker-Compose มาให้แล้วตรงแท็บ Marketplace แต่ผมขอติดตั้งเองทั้งหมด จึงไม่ได้ใช้ Ubuntu จากแท็บ Marketplace
ตอนนี้เราได้ Ubuntu 22.04 LTS เรียบร้อยแล้วครับ ขั้นตอนต่อไปติดตั้ง Docker และ Docker-Compose
ติดตั้ง Docker และ Plugin
เปิด Terminal บนเครื่องของเรา และเชื่อมต่อไปที่ Linode
ให้คัดลอกโค้ดนี้ไปที่ Terminal แล้วกด Enter ได้เลยครับ
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
ติดตั้ง Docker packages
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
ต่อด้วยการติดตั้ง docker-compose (Docker plugin)
sudo apt-get install docker-compose
ตรวจสอบว่าการติดตั้งเสร็จสมบูรณ์มั๊ยด้วยคำสั่ง
docker --version
docker-compose --version
Saleor สำหรับ Production
Saleor สำหรับ Production ที่จะกล่าวถึงในบทความนี้ มีทั้งหมด 2 ส่วนคือ
1. Saleor-Core
เราจะแก้โค้ดนิดหน่อย แล้วสร้าง Image สำหรับแต่ละส่วนครับ
Saleor Core หรือ API
เป็นส่วนสำหรับทำงานหลังบ้าน หรือ Back-End หรือเป็นส่วนที่ดูแล ฐานข้อมูล การดึงข้อมูลจากฐานข้อมูลมาใช้งาน ผ่าน Graphql เพราะ Saleor นำเทคโนโลยี Graphql มาใช้ในการจัดการข้อมูลนั่นเองครับ
ตามคำแนะนำของ Saleor เขาไม่แนะนำให้ใช้โค้ดที่ branch main เนื่องจากเป็น branch ที่ใช้สำหรับ Development แต่เขาให้เราไปดึงโค้ดมาจาก releases เพราะมันทำงานเสถียรแล้วนั่นเอง ไปที่
https://github.com/saleor/saleor/releases/
คลิ๊กขวาตรง Source code (zip) เลือก Copy Link Address

ไปที่ Terminal แล้ววางลิงค์ไว้ข้างหลังคำสั่ง wget ดังนี้ครับ
wget https://github.com/saleor/saleor/archive/refs/tags/3.18.9.zip
เราจะได้ไฟล์ 3.18.9.zip วางบนโฟลเดอร์ Root
ติดตั้ง โปรแกรม Unzip บน Ubuntu
sudo apt-get install zip unzip
เสร็จแล้วใช้คำสั่ง unzip ที่โฟลเดอร์ Root ที่เราดาวน์โหลดไฟล์ Zip มาครับ
unzip 3.18.9.zip
เราจะได้โฟลเดอร์ saleor-3.18.9
ให้เปลี่ยนชื่อ โฟลเดอร์เป็น saleor-api ด้วยคำสั่ง
cp -r saleor-3.18.9 saleor-api
ลบไฟล์ 3.18.9.zip ทิ้ง ด้วยคำสั่ง
rm 3.18.9.zip
และลบโฟลเดอร์ saleor-3.18.9
rm -rf saleor-3.18.9
หรือจะให้ง่ายกว่านั้น ให้ใช้คำสั่ง Move
mv saleor-3.18.9 saleor-api
แก้ไข saleor-api > Dockerfile
เปิดโฟลเดอร์ saleor-api ด้วย VSCode แล้วไปที่ Dockerfile
ให้แก้โค้ดใน saleor-api > Dockerfile ตามนี้ครับ
### Build and install packages
FROM python:3.9 as build-python
RUN apt-get -y update \
&& apt-get install -y gettext \
# Cleanup apt cache
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
WORKDIR /app
RUN --mount=type=cache,mode=0755,target=/root/.cache/pip pip install poetry==1.7.0
RUN poetry config virtualenvs.create false
COPY poetry.lock pyproject.toml /app/
RUN --mount=type=cache,mode=0755,target=/root/.cache/pypoetry poetry install --no-root
### Final image
FROM python:3.9-slim
RUN groupadd -r saleor && useradd -r -g saleor saleor
RUN apt-get update \
&& apt-get install -y \
libcairo2 \
libgdk-pixbuf2.0-0 \
liblcms2-2 \
libopenjp2-7 \
libpango-1.0-0 \
libpangocairo-1.0-0 \
libssl3 \
libtiff6 \
libwebp7 \
libxml2 \
libpq5 \
shared-mime-info \
mime-support \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN echo 'image/webp webp' >> /etc/mime.types
RUN echo 'image/avif avif' >> /etc/mime.types
RUN mkdir -p /app/media /app/static \
&& chown -R saleor:saleor /app/
COPY --from=build-python /usr/local/lib/python3.9/site-packages/ /usr/local/lib/python3.9/site-packages/
COPY --from=build-python /usr/local/bin/ /usr/local/bin/
COPY . /app
WORKDIR /app
ARG DATABASE_URL
ENV DATABASE_URL ${DATABASE_URL:-postgres://your-user:your-password@localhost:5432/your-db-name}
ARG STATIC_URL
ENV STATIC_URL ${STATIC_URL:-/static/}
RUN SECRET_KEY=aAT2HyCQ7zi60309QM5EnToQZ0dwk4vq STATIC_URL=${STATIC_URL} python3 manage.py collectstatic --no-input
EXPOSE 8001
ENV PYTHONUNBUFFERED 1
LABEL org.opencontainers.image.title="saleor/saleor" \
org.opencontainers.image.description="\
A modular, high performance, headless e-commerce platform built with Python, \
GraphQL, Django, and ReactJS." \
org.opencontainers.image.url="https://saleor.io/" \
org.opencontainers.image.source="https://github.com/saleor/saleor" \
org.opencontainers.image.authors="Saleor Commerce (https://saleor.io)" \
org.opencontainers.image.licenses="BSD 3"
CMD ["gunicorn", "--bind", ":8001", "--workers", "4", "--worker-class", "saleor.asgi.gunicorn_worker.UvicornWorker", "saleor.asgi:application"]
ผมแก้แค่ 3 จุดครับ คือ
1. EXPOSE 8000 แก้เป็น EXPOSE 8001
2. CMD \["gunicorn", "--bind", ":8000", ...\] เป็น CMD \["gunicorn", "--bind", ":8001", ...\]
3. เพิ่มโค้ดนี้เข้าไปครับ เพื่อระบุ DATABASES
ARG DATABASE_URL
ENV DATABASE_URL ${DATABASE_URL:-postgres://your-user:your-password@localhost:5432/your-db-name}
ดูวิธีสร้างฐานข้อมูล ได้ที่ บทความนี้
แก้ไข แค่นั้นเองครับสำหรับไฟล์ saleor-api > Dockerfile
แก้ไข saleor-api > saleor > settings.py
1. ให้ค้นหาคำว่า ALLOWED_HOSTS แล้วแก้ตามนี้ครับ
ALLOWED_HOSTS = [".localhost", "127.0.0.1", "[::1]",".your-domain.com"]
ALLOWED_HOSTS คือ ชื่อโดเมนของ Saleor-API ครับ เช่น saleor-api.your-domain.com
อย่าลืมเปลี่ยน ".your-domain.com" เป็นชื่อโดเมนของคุณนะครับ
2. ต่อด้วย DATABASES ให้แก้ตามนี้ครับ
DATABASES = {
DATABASE_CONNECTION_DEFAULT_NAME: dj_database_url.config(
# default="postgres://saleor:saleor@localhost:5432/saleor",
default=env("DATABASE_URL"),
conn_max_age=DB_CONN_MAX_AGE,
),
DATABASE_CONNECTION_REPLICA_NAME: dj_database_url.config(
# default="postgres://saleor:saleor@localhost:5432/saleor",
default=env("DATABASE_URL"),
# TODO: We need to add read only user to saleor platform,
# and we need to update docs.
# default="postgres://saleor_read_only:saleor@localhost:5432/saleor",
conn_max_age=DB_CONN_MAX_AGE,
),
}
ในเบื้องต้นให้แก้ไขไฟล์ settings.py แค่นี้ก่อนครับ
สร้าง Saleor API image สำหรับ Production
ให้ไปที่โฟลเดอร์ saleor-api (หรือ saleor-core ตั้งชื่อตามใจชอบครับ) เราจะเห็นไฟล์ Dockerfile

เราจะสร้าง Image สำหรับ Production ที่ตรงนี้ครับ ให้รันคำสั่ง
docker build --tag 'saleor-core-v1' .
เสร็จแล้วเราจะได้ชื่อ Image ตรงบรรทัดสุดท้าย หลังจาก Docker ประมวลผลเสร็จครับ ให้จดชื่อ Image ไว้ครับ

เช่น
docker.io/library/saleor-core-v1
Saleor Dashboard
ขั้นตอนต่อไปจะติดตั้ง Dashboard สำหรับ Admin เอาไว้ทำงาน หรือเชื่อมต่อกับ Saleor Core (API) ซึ่งขั้นตอนจะคล้ายๆกันครับ
ติดตั้ง NVM
เนื่องจากโปรแกรม Saleor Dashboard เป็นส่วนของ Front-End นะครับ เพียงแต่จำกัดเฉพาะ Admin เท่านั้นที่เข้าใช้ได้ และโปรแกรมนี้เขียนด้วยภาษา JavaScript เราจึงต้องติดตั้ง NodeJS ครับ เพื่อให้สะดวก เราจะติดตั้งผ่าน NVM ครับ ให้ติดตั้ง NVM ด้วยคำสั่ง
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
restart bash หรือ zsh ด้วยคำสั่ง
source ~/.bashrc
หรือ
source ~/.zshrc
ติดตั้ง NodeJS
เนื่องจาก Saleor แนะนำให้ใช้ NodeJS เวอร์ชั่น 18 ไม่เกิน เวอร์ชั่น 19 ผมจึงขอใช้ เวอร์ชั่น 18.19.0 หรือ nvm เรียกว่า lts/hydrogen
พิมพ์คำสั่งนี้บน Terminal
nvm install lts/hydrogen
nvm use lts/hydrogen
จะได้คำตอบแบบนี้ครับ แสดงว่าตอนนี้เราใช้ NodeJS เวอร์ชั่น 18.19.0 แล้วครับ
Now using node v18.19.0 (npm v10.2.3)
Clone Saleor Dashboard
ต่อไปก็ Clone Saleor Dashboard repo มาไว้ที่ Ubuntu โฟลเดอร์ Root ครับ
git clone https://github.com/saleor/saleor-dashboard.git
cd saleor-dashboard
สั่งติดตั้ง NodeJS packages ด้วยคำสั่ง
npm i
ผมลองใช้คำสั่ง
pnpm iผมพบ Error คือมันหาบาง Dependencies ไม่เจอครับ แนะนำให้ใช้npm i
ถ้าต้องการทดสอบโค้ดบนเครื่องของเรา สามารถใช้คำสั่ง
npm run dev
แต่เนื่องจากผมจะสั่งทำงานผ่าน Docker จึงข้ามตรงนี้ไปครับ
แก้ไข saleor-dashboard > Dockerfile
เปิดไฟล์ Dockerfile ด้วย VSCode แล้วค้นหาคำว่า ENV API_URI
ให้แก้ตรง http://localhost:8000/graphql/ เป็น https://saleor-api.your-domain.com/graphql/ ตามโค้ดด้านล่างนี้
ENV API_URI ${API_URI:-https://saleor-api.your-domain.com/graphql/}
ตรวจดูโค้ดให้ได้ตามนี้ครับ
FROM node:18-alpine as builder
RUN apk --no-cache add bash
WORKDIR /app
COPY package*.json ./
ENV CI 1
RUN npm ci --legacy-peer-deps
COPY nginx/ nginx/
COPY assets/ assets/
COPY locale/ locale/
COPY scripts/ scripts/
COPY vite.config.js ./
COPY tsconfig.json ./
COPY sw.js ./
COPY *.d.ts ./
COPY schema.graphql ./
COPY introspection.json ./
COPY introspection*.json ./
COPY .featureFlags/ .featureFlags/
COPY src/ src/
ARG API_URI
ARG APP_MOUNT_URI
ARG APPS_MARKETPLACE_API_URI
ARG APPS_TUNNEL_URL_KEYWORDS
ARG STATIC_URL
ARG SKIP_SOURCEMAPS
ENV API_URI ${API_URI:-https://saleor-api.your-domain.com/graphql/}
ENV APP_MOUNT_URI ${APP_MOUNT_URI:-/dashboard/}
ENV APPS_MARKETPLACE_API_URI ${APPS_MARKETPLACE_API_URI:-https://apps.saleor.io/api/v2/saleor-apps}
ENV APPS_TUNNEL_URL_KEYWORDS ${APPS_TUNNEL_URL_KEYWORDS}
ENV STATIC_URL ${STATIC_URL:-/dashboard/}
ENV SKIP_SOURCEMAPS ${SKIP_SOURCEMAPS:-true}
RUN npm run build
FROM nginx:stable-alpine as runner
WORKDIR /app
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
COPY ./nginx/replace-api-url.sh /docker-entrypoint.d/50-replace-api-url.sh
COPY --from=builder /app/build/ /app/
LABEL org.opencontainers.image.title="saleor/saleor-dashboard" \
org.opencontainers.image.description="A GraphQL-powered, single-page dashboard application for Saleor." \
org.opencontainers.image.url="https://saleor.io/" \
org.opencontainers.image.source="https://github.com/saleor/saleor-dashboard" \
org.opencontainers.image.revision="$COMMIT_ID" \
org.opencontainers.image.version="$PROJECT_VERSION" \
org.opencontainers.image.authors="Saleor Commerce (https://saleor.io)" \
org.opencontainers.image.licenses="BSD 3"
อย่าลืมเปลี่ยน your-domain.com เป็นชื่อโดเมนของคุณนะครับ
สร้าง Saleor Dashboard image สำหรับ Production
ไปที่โฟลเดอร์ saleor-dashboard ให้ดูว่าเรามองเห็นไฟล์ Dockerfile หรือไม่ ถ้ามองเห็นก็แสดงว่า ถูกแล้ว

ให้สร้าง Image โดยมีขั้นตอนเหมือนกันกับ Saleor Core (API) คือรันคำสั่งดังนี้ครับ
docker build --tag 'saleor-dashboard-v1' .
เมื่อประมวลผลเสร็จแล้ว ให้ดูบรรทัดสุดท้าย จะมีชื่อ Image อยู่ ให้จดชื่อไว้เหมือนเดิมครับ จะได้ชื่อประมาณนี้นะครับ
docker.io/library/saleor-dashboard-v1
Saleor Platform สำหรับ Production
ตอนนี้เราได้ Images มา 2 Images แล้วนะครับ คือ
docker.io/library/saleor-dashboard-v1
docker.io/library/saleor-core-v1
ต่อไปเราจะสั่ง Run Images ทั้ง 2 นี้ ด้วยคำสั่ง docker-compose แต่เราต้องไปดึง Repository สำหรับ Saleor Platform มาก่อนครับ ด้วยคำสั่ง
git clone https://github.com/saleor/saleor-platform.git
cd saleor-platform
ตอนนี้ ณ โฟลเดอร์ Root เราจะมีโฟลเดอร์ทั้งหมด 3 โฟลเดอร์แล้วนะครับ ที่ผมใส่ตัวเลขเอาไว้ตามภาพประกอบด้านล่างครับ

แก้ไขไฟล์ docker-compose.yml
เมื่อไปที่โฟลเดอร์ saleor-platform ให้เปิดไฟล์ docker-compose.yml แล้วแก้ไขไฟล์ตามนี้ครับ
version: "3.4"
services:
api:
# image: ghcr.io/saleor/saleor:3.18
image: docker.io/library/saleor-core-v1
ports:
- 8001:8001
restart: unless-stopped
networks:
- saleor-backend-tier
stdin_open: true
tty: true
depends_on:
- db
- redis
- jaeger
volumes:
# shared volume between worker and api for media
- saleor-media:/app/media
env_file:
- common.env
- backend.env
environment:
- ALLOWED_CLIENT_HOSTS=localhost,127.0.0.1,.your-domain.com,139.162.1.83,76.76.21.93
- ALLOWED_GRAPHQL_ORIGINS=*
- ENABLE_DEBUG_TOOLBAR=True
- RSA_PRIVATE_KEY="""-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAwq4CiHZeAfLY4Bj25XwRavq9M2Zz2j1yvTwLuhoCK7UVR1RG\nMWnHTXncNOL6uUXZdvQJpUrix3oMVcWW2l+7HDzw/crdCpIMUsirAU1biddeG6UI\nLKIlPw1NKM+SMKo5SIhiZTw0FklP1mh20voGCbs1rpmRtk5Mvu45t1/VMciCkot2\n1ldSZ9QmG4tnSEOZT3Flv/zreF01vq70qjQ/xBq4dDUnw3JoeJEmLGjudM2fG/+I\nqwH3cbH8Ems/EbcXFaYXrm1VTJ1k5rQnH0tcTTnIzcbX3+t+xs0FFGSfLzfv6y9C\nsl2uIblJVpUPTJBVqXgkME1MB58xvP4DS/M8xQIDAQABAoIBAAQ5La1jsfzlVY6h\nBAQs+ZzCRUX+8D75C8ruqUt3gnoLwuMqAR7TzmLQJLaSAQHxcbsKpsXq9roAnBFl\nSLVCk+bULJ843iw7SGCoYUtVMAnwveYoIaIEP34bbgPXYvLC0pzP9qB/GpssKnr6\nh69ihKyD3vGDe92CW9hdhyuC/PdIOlfOZ3Xf2C+PB2hiR0Z6oG05Ka+TKg7RXsUF\nbse2nSfSzb0KTajKwlWIHkaJTK9MvZ+tCLntPAKp1JGUzQdgF8viUkueXI2CdR8L\nSJZqt806Avu9Tf9MjRtXu4MAV2CgVsFeY7ImzXG5bLeUFdmy7tQWIfJrnqK4PASv\n19obCFkCgYEA61n2oqJPxPPi+9Wks1+11MmwDyA8KUtkL5hMye+DBVhM4xW4RgO7\nxt/zir++CBECJhKq88ZBU0ndJB7tEQEuTcKCV1GTPfpRD7Myh7pyKOA3st1O4Uxg\nS76xFeim2FTYbUKg/XCS3pvH4Q/JUBwi/qAHdsalMbcsqq/SC8uR+7kCgYEA08KN\nfQyWJik5PXcRqdLfzUhLMMTIQIktIrV+m2uewCv67WPh0H2w78eerVuMYpF0EUrA\n80CAAtcl9rZXT+3Z09FAFBnuc7chOt3+vZAZCalzqmX+6555QV2TkK/6B1H73lyL\nYMD1sVA4AFYi9B7dgyXlh7nFcURcm4CdcUaxB20CgYALO6gB6y1TgTB8RJ4v0Ymk\nNlwo3KkCb47AlsxTdxMR1j0VOZwp+1OjEl1VagFv8R/hIVL3f6buir/7UV6PSTck\njvwZntMgSipETZFD2SpJuSnvZ5C0QCj4dImPOiN8f9A0ptF4Rz87UMQhgddh83XY\nIVs52BFaZhvDqdCkr3qwQQKBgFX1VI/dSxnkg/rCWaYxFm3zGaqLRqqDxJGhUOpw\nDjn94Fb6w5BpZSiARJYkYmEkoBPg32Ae35fHk/6I1/p3F4QXHcbLG/NW9CM8OArk\n8nTslyolSwyEAL6a6KrD9F+CVRZXRLCaw2Edqg3g6UFlQg/Zk0m8DDzFPj5VQBPa\nWUQlAoGBANCAAyqQe8LuruDZ22kJFg3qr55qeFUDCMrmXz6R+4qRnCHqQXCnfZEX\nT4Xlzsm2UqVzqtTT32KMVoIuL1frRpVHVFDqoq1hXOs93CNq10aToweM0opwWBa4\nyveNltcElLVK+n7ZjtL/ruF9EbEYYKTinLKhvqOowfmjnVZ5L1YS\n-----END RSA PRIVATE KEY-----"""
# - RSA_PRIVATE_PASSWORD
- DEBUG=False
# Original
- JAEGER_AGENT_HOST=jaeger
# - DASHBOARD_URL=http://localhost:9001/
- DASHBOARD_URL=https://saleor-api.your-domain.com/dashboard/
- STOREFRONT_URL=https://www.your-domain.com
- ALLOWED_HOSTS=localhost,api,.your-domain.com
- DEFAULT_COUNTRY=TH
- DEFAULT_CURRENCY=THB
- PUBLIC_URL=https://saleor-api.your-domain.com/
- SECRET_KEY=oAT2HyCQ7zi60309QM5EnToQZ0dwk4vs
dashboard:
# image: ghcr.io/saleor/saleor-dashboard:latest
image: docker.io/library/saleor-dashboard-v3.18.2
ports:
- 9001:80
restart: unless-stopped
# Custom
environment:
- API_URL=https://saleor-api.your-domain.com/graphql/
db:
image: library/postgres:13-alpine
ports:
- 5434:5432
restart: unless-stopped
networks:
- saleor-backend-tier
volumes:
- saleor-db:/var/lib/postgresql/data
- ./replica_user.sql:/docker-entrypoint-initdb.d/replica_user.sql
environment:
- POSTGRES_USER=saleor
- POSTGRES_PASSWORD=saleor
redis:
image: library/redis:7.0-alpine
ports:
- 6379:6379
restart: unless-stopped
networks:
- saleor-backend-tier
volumes:
- saleor-redis:/data
worker:
# image: ghcr.io/saleor/saleor:3.18
image: docker.io/library/saleor-api-3.18.12
command: celery -A saleor --app=saleor.celeryconf:app worker --loglevel=info -B
restart: unless-stopped
networks:
- saleor-backend-tier
env_file:
- common.env
- backend.env
depends_on:
- redis
- mailpit
volumes:
# shared volume between worker and api for media
- saleor-media:/app/media
jaeger:
image: jaegertracing/all-in-one
ports:
- "5775:5775/udp"
- "6831:6831/udp"
- "6832:6832/udp"
- "5778:5778"
- "16686:16686"
- "14268:14268"
- "9411:9411"
restart: unless-stopped
networks:
- saleor-backend-tier
mailpit:
image: axllent/mailpit
ports:
- 1025:1025 # smtp server
- 8025:8025 # web ui. Visit http://localhost:8025/ to check emails
restart: unless-stopped
networks:
- saleor-backend-tier
volumes:
saleor-db:
driver: local
saleor-redis:
driver: local
saleor-media:
networks:
saleor-backend-tier:
driver: bridge
1. กล่าวโดยสรุปคือ ผมจะต้องบอก docker-compose ว่าผมจะใช้ พอร์ต 8001 ที่ Saleor Core (ผมจะเก็บพอร์ต 8000 ไว้สำหรับโปรแกรมตัวอื่น) และอย่าลืมแก้ API_URL=https://saleor-api.your-domain.com/graphql/ เป็นชื่อโดเมนของคุณนะครับ
2. ใช้พอร์ต 9001 สำหรับ Saleor Dashboard และอย่าลืมแก้ - DASHBOARD_URL=https://dashboard-your-domain.com/ เป็นชื่อโดเมนที่คุณใช้สำหรับ Dashboard URL นะครับ
3. สำหรับ STOREFRONT_URL อาจเป็น https://www.your-domain.com หรือ https://store.your-domain.com ขึ้นอยู่กับว่า เราจะตั้งชื่อโดเมนของเราอย่างไร ซึ่ง STOREFRONT_URL คือ URL ที่เราใช้โชว์สินค้า และรับชำระเงินค่าสินค้านั่นเองครับ
เมื่อแก้ไขไฟล์ docker-compose.yml ในโฟลเดอร์ saleor-platform เสร็จแล้ว ให้รันคำสั่งต่อไปนี้ทีละคำสั่ง
docker compose build
docker compose run --rm api python3 manage.py migrate
ในกรณีที่ต้องการ สร้างฐานข้อมูล ตัวอย่าง ให้รันคำสั่งนี้เพิ่มเข้าไปครับ
docker compose run --rm api python3 manage.py populatedb
ขั้นตอนสุดท้าย สร้าง superuser ครับ
docker compose run --rm api python3 manage.py createsuperuser
เหลืออีกคำสั่งคือคำสั่ง docker-compose up -d เป็นคำสั่งให้ Run Images ทั้ง 2 Images คือ
docker.io/library/saleor-dashboard-v1
docker.io/library/saleor-core-v1
ให้ทำงานพร้อมกัน แต่เราจะแวะไปสร้าง Proxy Server ด้วย Nginx ก่อนครับ
Nginx Reverse Proxy
ติดตั้ง Nginx และเปิด Firewall สำหรับ Nginx
sudo apt-get install nginx
sudo systemctl start nginx
sudo ufw allow 'Nginx Full'
Gunicorn และ Uvicorn
Saleor Core (API) เขียนบน Django (Python) เมื่อพูดถึง Django App ก็จะต้องพูดถึง Gunicorn ให้สร้างไฟล์ต่อไปนี้ครับ
1. สร้างไฟล์ gunicorn.socket ด้วยคำสั่ง
sudo nano /etc/systemd/system/gunicorn.socket
ใส่โค้ดนี้เข้าไปครับ
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
2. สร้างอีกไฟล์หนึ่ง ชื่อว่า gunicorn.service ด้วยคำสั่ง
sudo nano /etc/systemd/system/gunicorn.service
แล้วคัดลอกโค้ดนี้เข้าไปครับ
[Unit]
Description=gunicorn daemon
Requires=gunicorn.socket
After=network.target
[Service]
User=root
Group=www-data
WorkingDirectory=/root/saleor-api
Environment="PATH=/root/saleor-api/env/bin"
ExecStart=/root/saleor-api/env/bin/gunicorn \
--access-logfile - \
--workers 4 \
--bind unix:/run/gunicorn.sock \
-k uvicorn.workers.UvicornWorker \
saleor.asgi:application
[Install]
WantedBy=multi-user.target
Nginx config
สร้างไฟล์ saleor-api ด้วยคำสั่ง
sudo nano /etc/nginx/sites-available/saleor-api
เพิ่มโค้ดนี้เข้าไปในไฟล์ saleor-api
server {
# replace example.com with your domain name
server_name saleor-api.your-domain.com;
listen 80;
listen [::]:80;
location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
root /root/saleor-api;
}
location /media/ {
root /root/saleor-api;
}
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /dashboard/ {
proxy_pass http://127.0.0.1:9001;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
สามารถตั้งชื่อได้ตามใจชอบนะครับ อย่าลืมเปลี่ยน your-domain.com เป็นชื่อโดเมนของคุณนะครับ
และที่สำคัญอย่าลืมไปเพิ่ม A Record ในระบบ DNS ด้วยนะครับ โดยนำ IP Address ของ Linode ไปใส่ในช่อง A Record
สุดท้ายให้คัดลอกไฟล์จาก sites-available ไปที่ sites-enabled ด้วยคำสั่ง
sudo ln -s /etc/nginx/sites-available/saleor-api /etc/nginx/sites-enabled/saleor-api
Enable SSL โดย Certbot
ให้ขอ Certificate สำหรับ
saleor-api.your-domain.com
เพื่อ Enable HTTPS (SSL) นะครับ
ติดตั้ง Certbot สำหรับ Nginx
sudo apt-get install certbot python3-certbot-nginx
ต่อไปรันคำสั่ง
sudo certbot --nginx
วิธีแก้ปัญหาขอ Certificate จาก Certbot ไม่สำเร็จ
1. Pain point: ปัญหามาจาก ชื่อโดเมนครับ
Solution: ให้เช็คชื่อโดเมนของเราว่าสามารถมองเห็นบนโลกอินเตอร์เน็ตหรือเปล่า ได้ที่ https://letsdebug.net/ และ https://unboundtest.com/
2. Pain point: ปัญหามาจาก การลืมรีสตาร์ท Nginx
Solution: ให้รีสตาร์ท Nginx ครับ ด้วยคำสั่ง
sudo systemctl reload nginx
3. Pain point: ปัญหามาจากการสะกดชื่อโดเมนผิด
Solution: ให้กลับไปตรวจสอบชื่อโดเมนในไฟล์ /etc/nginx/sites-available/your-domain ให้ตรงกันกับ ชื่อโดเมนใน DNS ครับ
การบำรุงรักษา
1. ต้องการลบ Docker container ที่ไม่ได้ใช้งาน ให้ใช้คำสั่ง
docker ps --filter status=exited -q | xargs docker rm
Run docker-compose up -d
เมื่อเราสร้าง Reverse Proxy ด้วย Nginx และ Enable SSL ด้วย Certbot ให้เว็บไซต์ของเราเรียบร้อยแล้ว เราสามารถสั่ง Run เว็บไซต์ของเราได้เลยครับ ด้วยคำสั่ง
docker-compose up -d
เมื่อเข้าไปที่ URL saleor-api.your-domain.com/graphql/ จะได้หน้าจอแบบนี้ครับ หรือหน้าจอ Graphql (API) นั่นเองครับ

และถ้าเข้า URL saleor-api.your-domain.com/dashboard/ จะได้หน้าจอแบบนี้ครับ หรือหน้าจอ Dashboard นั่นเองครับ

สรุปการ Deploy Saleor Production
เราจะทำงานบน 3 Repositories คือ
1. saleor-core
โดยใน Repository saleor-core และ saleor-dashboard จะมีไฟล์ Dockerfile เพื่อเอาไว้สร้าง Docker Image
และใน Repository saleor-platform จะมีไฟล์ docker-compose.yml เอาไว้ Run Docker Images (สามารถ run พร้อมกันหลาย Images)
ในกรณีที่เราต้องการเปลี่ยนพอร์ตการทำงาน เราก็ต้องไปแก้ใน Repository ของ saleor-core และ saleor-dashboard ก่อนจะสั่ง run Images
การแก้ไข ค่า environment ที่ใช้สำหรับ Production สามารถแก้ไขได้ที่ไฟล์ backend.env และ common.env ในโฟลเดอร์ saleor-platform
หรือแก้โดยตรงที่ไฟล์ docker-compose.yml