﻿# 使用 VSCode 的 Remote Container 建立 SAP Commerce 123 開發環境

最近承接了一個相當有趣的專案，客戶採用了一個在台灣相對冷門的 [SAP Commerce](https://help.sap.com/docs/SAP_COMMERCE) (SAP Hybris) 電商平台(基於 Java 與 Spring Boot 框架)，由於建立開發環境的過程經常會卡關，使用不同的作業系統與 JDK 版本都可能會遇到跟官網文件說明不太一樣的地方。這時我就在想，如何果把整個開發環境全部弄進 Linux 容器中執行，那不就簡單多了？所以我就嘗試了一下，也相當順利的整理出 SOP 標準作業流程，未來建立開發環境就不用鬼打牆兩三天了！👍

![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/228307236bd554c90f1a-192200139-8246d60a-4a51-48fe-bbc4-0ede81970ded.png)

> 本文使用 SAP Commerce (Hybris) v6.6.0.0 版本與官方的 [SAP Commerce 123](https://help.sap.com/docs/SAP_COMMERCE/3fb5dcdfe37f40edbac7098ed40442c0/a1ef894ac89545e79c470c726b487d13.html?version=6.6.0.0) 文件做為示範。

### 準備可在 VS Code 開發 Java 程式的 Remote Container 環境

在容器化技術的幫助下，基本上你只要有 [Visual Studio Code](https://code.visualstudio.com/) 與 [Docker Desktop](https://www.docker.com/products/docker-desktop/) 就可以打造出任何類型的開發環境，為了消彌開發人員之間的環境差異，我覺得採用 Remote Container 是非常理想的，尤其是開發環境與運行版本特別複雜的情況下更為適合。

1.  先將**主要檔案**複製到 `G:\hybris123` 資料夾
    
    這三份壓縮檔 `hybris123.zip`、`images.zip` 與 `HYBRISCOMM6600P_6-70003031.zip` 只能從 SAP 官網下載，必須是 SAP Commerce 客戶才能下載的到。
    
2.  使用 `Remote-Containers: Open Folder in Container` 開啟 `G:\hybris123` 資料夾
    
    由於 SAP Commerce (Hybris) v6.6.0.0 版本主要使用 Java 8 進行建置，所以我們必須選擇 Java 8 為基底開發環境
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/2c94c1002bf0197c1fc9-192108913-727161d3-c4da-463a-a35d-aed86594333e.png)
    
    我們在實作 SAP Commerce 的過程中需要透過 Selenium 跑測試，因此你一定要選 `bullseye` ([Debian 11](https://www.debian.org/releases/bullseye/)) 才能在之後的步驟安裝所需的 Chromium 最新版
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/33d5a820d96945aedbf5-192108915-c7ff8045-9e8d-4886-81bd-00df00bdb202.png)
    
    SAP Commerce 123 用不太到 [Node.js](https://nodejs.org/) (若日後需要可以再透過 `apt-get` 進行安裝)
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/63d7f62121a4948feb22-192108918-8dcd58e0-3ebf-47a5-8896-602cfb5f4888.png)
    
    實作過程中會需要用到 [Apache Maven](https://maven.apache.org/) 來進行程式建置
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/c4e2c4a505af4c625061-192108923-bd436e94-a9f5-409c-9a1f-2eeffaafdb12.png)
    
    > 命令完成後，會自動重啟 VSCode 並開始建立容器 image 並執行起來，你可以事後手動調整 `.devcontainer/devcontainer.json` 檔案內容，並加入 [Essential Spring Boot Snippets](https://marketplace.visualstudio.com/items?itemName=doggy8088.spring-boot-snippets) 擴充套件 (`doggy8088.spring-boot-snippets`)。
    
3.  修正 Git 設定
    
    因為 Visual Studio Code 的 **Remote Container** 在建置的過程中會自動從目前本機(Windows)取得 Git 設定值，這樣會遇到 `CRLF` 的問題，必須手動調整！
    
    ```bash
    git config --global core.autocrlf false
    git config --global core.editor vi
    ```
    
4.  注意事項
    
    你每次透過 VSCode 開啟這個含有 `.devcontainer/devcontainer.json` 檔案的工作目錄時，VSCode 都會提示你要不要重新在容器中開啟。但 VSCode 又是如何知道目前這個資料夾要開啟哪一個容器呢？是的，VSCode 將目前開發目錄的路徑寫到 Container 的 Label 裡面去了，只要有找到一樣的路徑，就會直接啟動容器執行，而不會重新執行 `docker build` 建置新的 image！
    

### 安裝 SAP Commerce 123 Interactive

SAP Commerce 123 Interactive 是一個學習網站，根據該網站的教學內容，可以幫助你快速上手 SAP Commerce 這個電商平台。

1.  解壓縮**主要檔案**到 `/opt` 目錄下
    
    ```bash
    cd /workspaces/hybris123
    
    # 修正 /opt 目錄擁有人
    sudo chown vscode.vscode /opt
    
    # 解壓縮 hybris123.zip 到 ${HYBRIS_HOME_DIR}/hybris123 (壓縮檔中包含 hybris123 資料夾)
    unzip hybris123.zip -d ${HYBRIS_HOME_DIR}
    
    # 解壓縮 hybris123 所需圖片
    unzip images.zip -d ${HYBRIS_HOME_DIR}/hybris123/src/main/webapp
    
    # 解壓縮 HYBRISCOMM6600P_6-70003031.zip (此為 SAP Commerce 平台程式)
    unzip HYBRISCOMM6600P_6-70003031.zip -d ${HYBRIS_HOME_DIR}
    ```
    
2.  調整環境變數與常用 Bash Alias
    
    ```bash
    # 新增幾個 Hybris 相關環境變數
    cat <<EOF >> ~/.profile
    export HYBRIS_HOME_DIR=/opt/HYBRISCOMM6600P_6-70003031
    export ANT_HOME=\${HYBRIS_HOME_DIR}/hybris/bin/platform/apache-ant-1.9.1
    export PATH=\${PATH}:\${ANT_HOME}/bin
    export INITIAL_ADMIN=nimda
    EOF
    
    # 設定幾個好用的 alias 命令
    cat <<EOF >> ~/.bashrc
    shopt -s direxpand
    shopt -s no_empty_cmd_completion
    
    alias ll='ls --color -lAFh --group-directories-first'
    alias ..='cd ..'
    alias ...='cd ../../'
    alias certinfo='openssl x509 -text -noout -in \$1'
    
    ditto() { directory=\$(dirname \$2); mkdir -p \$directory; cp "\$1" "\$2"; }
    EOF
    
    source ~/.profile
    ```
    
3.  安裝 SAP Commerce 123 (`hybris123`) 跑**測試**時所需的軟體
    
    ```bash
    # 跑測試時需要 Java 11 才能跑
    sdk install java 11.0.16.1-tem < /dev/null
    # 其他時候都需要 Java 8 環境，因此改回 Java 8 當成系統預設值
    sdk default java 8.0.345-tem && sdk use java 8.0.345-tem
    
    # 安裝 hybris123.zip 跑測試時所需的 Chromium 瀏覽器 (用來做端對端測試之用)
    sudo apt-get update
    sudo apt-get -y install chromium
    ```
    
4.  確認環境基本條件
    
    ```bash
    echo '>>>> Java 8 Software Development Kit <<<<'
    javac -version
    echo $JAVA_HOME
    
    echo '>>>> Apache Maven <<<<'
    mvn -version
    echo $M2
    
    echo '>>>> Git <<<<'
    git version
    
    echo '>>>> Ant (請使用 SAP Commerce 123 v6.6.0 提供的版本) <<<<'
    ant -version
    
    echo '>>>> Gradle (請使用 SAP Commerce 123 v6.6.0 提供的版本) <<<<'
    cd ${HYBRIS_HOME_DIR}/installer; ./gradlew -version
    
    echo '>>>> Chromium <<<<'
    chromium -version
    ```
    
5.  建置 **SAP Commerce 123 Interactive** 網站
    
    該專案使用 Java 11 為主要建置環境，請另外**開啟一個新的 Terminal 視窗**，切換一下 Java 版本：
    
    ```bash
    sdk use java 11.0.16.1-tem
    ```
    
    建置 WAR 檔
    
    ```bash
    cd $HYBRIS_HOME_DIR/hybris123; mvn clean package -DskipTests
    ```
    
    執行 WAR 檔
    
    ```bash
    cd $HYBRIS_HOME_DIR/hybris123; java -jar target/hybris123.war
    ```
    
    開啟 [http://127.0.0.1:8080/](http://127.0.0.1:8080/) 網站，就會有完整的指引你學習 SAP Commerce 平台的基本開發方法！
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/f2006a48c87199077d11-192198900-24b469f7-f87e-486d-9135-1b8e07a979ff.png)
    
    > 注意: 你若使用 [http://localhost:8080/](http://localhost:8080/) 很有可能會連不上，建議改用 [http://127.0.0.1:8080/](http://127.0.0.1:8080/) 進行連線！
    

### 建置 SAP Commerce Accelerator

1.  先執行一次測試程式 (acceptance test)
    
    由於 `hybris123.zip` 範例專案的原始碼中有 `3` 個嚴重錯誤(Bug)，必須事先修正才能順利的建置與執行測試，底下是第 `1` 個，等等還有 `2` 個要修！
    
    修正 `/opt/HYBRISCOMM6600P_6-70003031/hybris123/src/main/java/com/hybris/hybris123/runtime/helper/Version.java` 錯誤，加入 `V6606` 到 `enum Version` 列舉清單中！
    
    執行以下測試命令：
    
    ```bash
    export INITIAL_ADMIN=nimda
    cd $HYBRIS_HOME_DIR/hybris123; mvn -Dtest=com.hybris.hybris123.runtime.tests.Hybris123Tests#testAcceleratorQuickDiveIsOk test
    ```
    
    由於我們的 hybris server 尚未啟動，所以執行結果一定會出現**連線被拒絕**(`net::ERR_CONNECTION_REFUSED`)等錯誤：
    
    ```
    [ERROR] Failures:
    [ERROR]   Hybris123Tests.testAcceleratorQuickDiveIsOk:119->fail:650 Connect Exception: unknown error: net::ERR_CONNECTION_REFUSED (Session info: headless chrome=105.0.5195.125)
    ```
    
    > **別相信沒有失敗過的程式** 🔥
    
2.  安裝、初始化、啟動 [B2B Accelerator](https://help.sap.com/docs/SAP_COMMERCE/4c33bf189ab9409e84e589295c36d96e/1903a88ad0c34cf6b7faae621ebef3a8.html) (B2B 加速器)
    
    啟動 hybris server 需要使用 Java 8 來執行初始化任務，所以必須切換回去 Java 8 執行環境 (或是切回原本的 Terminal 視窗也可以)
    
    ```bash
    sdk use java 8.0.345-tem
    ```
    
    執行安裝任務，這個過程至少要 15 分鐘才能完成：
    
    ```bash
    # 先進入 $HYBRIS_HOME_DIR/installer 資料夾
    cd $HYBRIS_HOME_DIR/installer
    
    # Sets up system but leaves it uninitialized (約 20 秒完成)
    ./install.sh -r b2b_acc setup
    
    # Initializes system (可能需要 10 分鐘才能初始化完畢)
    ./install.sh -r b2b_acc initialize
    
    # Starts the hybris server (以下命令會跑在前景，可能需要 5 分鐘才能啟動伺服器)
    ./install.sh -r b2b_acc start
    ```
    
    你可以另開一個 Terminal 視窗，並執行以下命令，藉此瞭解 hybris server 是否已經成功啟動
    
    ```bash
    time curl --insecure 'https://localhost:9002/'
    ```
    
    > 注意: 這份教學用的 SAP Commerce 平台程式有 30 天的使用限制，時間到就要重建環境：
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/eedd469b26e6841f6e4d-192126745-f39d4a78-5f8d-4dfa-9317-b30be22e641e.png)
    
3.  啟用 Hybris Management Console (hMC) 介面的方法 (SAP Hybris version 6.x)
    
    SAP Commerce (Hybris) 早期都是以 hMC 介面來管裡電商資料為主，未來的新版可能會把 hMC 介面移除，這個版本要額外設定才能使用。
    
    加入 Hybris Management Console (hMC) 介面的擴充功能
    
    ```bash
    vi $HYBRIS_HOME_DIR/hybris/config/localextensions.xml
    ```
    
    加入 `<extension name='hmc' />` 擴充設定。
    
    請記得先關閉正在執行中的 Hybris 伺服器
    
    ```bash
    cd $HYBRIS_HOME_DIR/hybris/bin/platform
    . ./setantenv.sh
    ./hybrisserver.sh stop
    ```
    
    重建專案
    
    ```bash
    ant clean all
    ```
    
    重啟 hybris 伺服器 (以下命令會跑在背景，通常需要 5 分鐘才能啟動)
    
    ```bash
    ./hybrisserver.sh start
    ```
    
    由於啟動時間要 5 分鐘，以下是查詢啟動記錄的方法
    
    ```bash
    tail -f $HYBRIS_HOME_DIR/hybris/log/tomcat/console-*.log
    ```
    
    > 詳見: [Re-enable HMC in SAP Hybris version 6.x](https://www.stackextend.com/hybris/re-enable-hmc-in-sap-hybris-6-x/)
    
4.  設定 VSCode 的 POSTS 埠號轉送 (Port forwarding)
    
    設定對應本機的 Port `9002` 對應到容器中的 Port `9002`
    
5.  開啟 **Storefront** 電商前台
    
    預設使用者資料放在以下路徑：
    
    ```bash
    $HYBRIS_HOME_DIR/hybris/bin/ext-commerce/b2bapprovalprocess/resources/b2bapprovalprocess/test/organizationdata.csv
    ```
    
    你可以拿這組來測試登入：
    
    帳號: `mark.rivers@rustic-hw.com` / 預設密碼: `12341234`
    
    使用 `localhost` 一定要從這個網址進去才能瀏覽網站: [https://localhost:9002/yb2bacceleratorstorefront/?site=powertools&clear=true](https://localhost:9002/yb2bacceleratorstorefront/?site=powertools&clear=true)
    
    如果用自訂域名就可以直接連結進去: https://powertools.localhost:9002/yb2bacceleratorstorefront/
    
6.  開啟 **Backoffice** 電商後台
    
    帳號: `admin` / 預設密碼: `nimda`
    
    管裡後台有好幾個入口，分別有不同的功能：
    
    -   Hybris Administratoion Console (HAC)
        
        這是專門給**系統管理員**操作的管裡主控台介面，提供各種平台的管裡功能。
        
        [https://localhost:9002/](https://localhost:9002/)
        
        ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/29367ce844cd7a36c3b5-192231791-5807774f-48a3-481d-a532-fb6c2a822fe9.png)
        
    -   Hybris Backoffice
        
        這是專門給**電商管裡者**操作的管裡後台，所有管裡功能都會集中到這個介面中。
        
        [https://localhost:9002/backoffice](https://localhost:9002/backoffice)
        
        ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/2ce265acf7657d6a6a34-192232228-e576394f-f04a-4032-a1f2-111570d918a7.png)
        
        > Hybris 早期有很多 `Cockpit` 管裡介面散落在不同的管裡介面下。
        
        > `Cockpit` is an intuitive web application and a central tool that enables the [SAP CC (Convergent Charging)](https://help.sap.com/doc/d847860d561a47568a936d5f3cbeb9da/4.1/en-US/sapcc_uis/index.html) administrators and pricing specialists to manage the SAP Convergent Charging 2020 systems and data quickly and efficiently.
        
    -   Hybris Commerce Cockpit (Multichannel Cockpit)
        
        這個介面可說是專門給**電商管裡者**專用的入口網站，登入後會出現以下圖示，協助你連結到所有 `Cockpit` 管裡介面。所有的 `Cockpit` 管裡介面包含商品管裡、頻道管裡、平台管裡、行銷工具管裡等等。
        
        [https://localhost:9002/mcc](https://localhost:9002/mcc)
        
        ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/2bb0b84e893a510fe276-192135746-afe6d0ad-b4e7-44e3-ae44-85be9e3b1d7a.png)
        
    -   Hybris Management Console (hMC)
        
        這是給**電商管裡者**操作的介面，他提供很多 `Cockpit` 介面，開發人員可以客製化這個管裡介面。
        
        [https://localhost:9002/hmc/hybris](https://localhost:9002/hmc/hybris)
        
    -   Hybris Administration Cockpit (hAC)
        
        [https://localhost:9002/admincockpit](https://localhost:9002/admincockpit)
        
7.  再跑一遍自動化測試
    
    由於 SAP Commerce 123 提供的測試程式(acceptance test)採用 [Selenium](https://www.selenium.dev/) 做為瀏覽器自動化測試的工具，然而因為這份 `hybris123.zip` 有兩個嚴重的 Bugs 需要修復才能成功執行測試。
    
    修正 `/opt/HYBRISCOMM6600P_6-70003031/hybris123/src/main/java/com/hybris/hybris123/runtime/helper/SeleniumHelper.java` 錯誤，把 `url = "https://localhost:9002/login";` 改成 `url = "https://localhost:9002/login.jsp";` 即可修正錯誤！
    
    修正 `/opt/HYBRISCOMM6600P_6-70003031/hybris123/src/main/java/com/hybris/hybris123/runtime/tests/Hybris123Tests.java` 錯誤，把所有 `https://localhost:9002` 全部取代成 `https://powertools.localhost:9002` 即可修正錯誤！
    
    接著就可以重跑程式了：
    
    ```bash
    export INITIAL_ADMIN=nimda
    cd $HYBRIS_HOME_DIR/hybris123; mvn -Dtest=com.hybris.hybris123.runtime.tests.Hybris123Tests#testAcceleratorQuickDiveIsOk test
    ```
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/fa11a40c07845e2fc1fc-192199912-9b152f1b-66e9-436f-92c5-8932751a225b.png)
    

### 總結

我在使用 Visual Studio Code 的 Remote Container 架設多次開發環境後，慢慢整理出一些心得，真心覺得只要能在 Linux 建立出開發環境/執行環境，搭配 Windows 或 macOS 桌面環境下的 Visual Studio Code 編輯器/開發工具，無論前端或後端，全部都可以整合在一起。

由於整個開發環境都在容器中完成，這意味著所有開發人員之間擁有完全一致的開發環境，因此可以完整消彌各種環境的差異，其中我覺得最主要的差異，還是在「作業系統」部分。例如你開發前端，在我們公司就有一半人用 macOS，另一半人用 Windows，版控引發的問題一年也會出現個幾次。再者，後端開發，無論你寫 .NET 或 Java，現在也都可以跨平台了，所以各種「路徑問題」不時的困擾的大家，一下 `/` 一下 `\` 的，真的煩不勝煩。若要真的提到最煩的，我想應該就是 Command Prompt、Windows PowerShell 與 Bash 之間的切換了，這真的是神煩！😅

所以，只要是可以跨平台的開發環境，我覺得都可以考慮用 Visual Studio Code 的 Remote Container 來架設開發環境！ 👍

### 相關連結

-   [SAP Commerce 123 (v6.6.0) | SAP Help Portal](https://help.sap.com/docs/SAP_COMMERCE/3fb5dcdfe37f40edbac7098ed40442c0/a1ef894ac89545e79c470c726b487d13.html?version=6.6.0.0)
-   Dev Containers
    -   [Get started with development Containers in Visual Studio Code](https://code.visualstudio.com/docs/remote/containers-tutorial)
    -   [Developing inside a Container using Visual Studio Code Remote Development](https://code.visualstudio.com/docs/remote/containers)
    -   [Create a development container using Visual Studio Code Remote Development](https://code.visualstudio.com/docs/remote/create-dev-container)
    -   [https://github.com/devcontainers/images/tree/main/src/java-8](https://github.com/devcontainers/images/tree/main/src/java-8)
    -   [https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/java-8](https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/java-8)
