Skip to content

Commit 82ac506

Browse files
committed
partial backup
1 parent 124f558 commit 82ac506

9 files changed

Lines changed: 600 additions & 0 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
---
2+
title: Environment setup
3+
weight: 2
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
9+
Create two VMs in the same Azure region with matching OS and tooling so differences are attributable to architecture, not configuration drift.
10+
11+
This path was validated with Ubuntu 24.04 LTS VMs in `westus2`:
12+
13+
| | x86 | Arm |
14+
|---|---|---|
15+
| **VM size** | Standard_D2s_v6 | Standard_D2ps_v6 |
16+
| **vCPUs** | 2 | 2 |
17+
18+
## Log in and create VMs
19+
20+
```bash
21+
az login --use-device-code
22+
az account set --subscription <your-subscription>
23+
```
24+
25+
Create both VMs in the same resource group and region.
26+
27+
## Install tools on each VM
28+
29+
```bash
30+
sudo apt-get update -y
31+
sudo apt-get install -y git curl jq ca-certificates gnupg docker.io
32+
sudo usermod -aG docker "$USER"
33+
34+
sudo add-apt-repository ppa:dotnet/backports -y
35+
sudo apt-get update -y
36+
sudo apt-get install -y dotnet-sdk-9.0
37+
```
38+
39+
Verify:
40+
41+
```bash
42+
uname -m
43+
dotnet --version
44+
docker --version
45+
```
46+
47+
Expected output: `x86_64` on the x86 VM, `aarch64` on the Arm VM. Both should report the same .NET SDK version (9.0.x).
48+
49+
## PostgreSQL prerequisite for nopCommerce install
50+
51+
nopCommerce migrations on PostgreSQL require the `citext` extension. Create it before running the installer:
52+
53+
```bash
54+
docker run -d --name nop-postgres \
55+
-e POSTGRES_USER=nop \
56+
-e POSTGRES_PASSWORD=<password> \
57+
-e POSTGRES_DB=nopcommerce \
58+
-p 5432:5432 postgres:16
59+
60+
docker exec nop-postgres psql -U nop -d nopcommerce \
61+
-c "CREATE EXTENSION IF NOT EXISTS citext;"
62+
```
63+
64+
## Optional: script-driven remote execution
65+
66+
```bash
67+
az vm run-command invoke \
68+
-g <resource-group> \
69+
-n <vm-name> \
70+
--command-id RunShellScript \
71+
--scripts @./your-test-script.sh
72+
```
73+
74+
This was used to run identical commands on both VMs.
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
---
2+
title: Build and baseline
3+
weight: 3
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
9+
Pin nopCommerce to a reproducible release, build on both architectures, and capture a baseline that includes core storefront paths.
10+
11+
## Clone and pin the source
12+
13+
```bash
14+
git clone https://github.com/nopSolutions/nopCommerce.git
15+
cd nopCommerce
16+
git fetch --tags --prune
17+
git checkout release-4.90.3
18+
git rev-parse --short=10 HEAD # expect 9beda11c42
19+
```
20+
21+
## Restore and build
22+
23+
```bash
24+
dotnet restore src/Presentation/Nop.Web/Nop.Web.csproj
25+
dotnet build src/Presentation/Nop.Web/Nop.Web.csproj -c Release --no-restore
26+
```
27+
28+
## Start the application
29+
30+
```bash
31+
cd src/Presentation/Nop.Web
32+
dotnet run -c Release --no-build --urls http://0.0.0.0:5000
33+
```
34+
35+
## Baseline methodology
36+
37+
Do not rely on `/install` alone. Baseline at least:
38+
39+
- Home page
40+
- Search
41+
- Product page
42+
- Cart
43+
- Checkout
44+
45+
Prerequisite: complete nopCommerce setup first (database configured and installer finished). Otherwise, storefront paths redirect to the install flow and do not represent real behavior.
46+
47+
Use a valid product URL from your seeded catalog (for example, `/apple-macbook-pro`), not a hard-coded slug that may not exist in your dataset.
48+
49+
Quick smoke probe (pre-install, useful as a connectivity check only):
50+
51+
```bash
52+
for p in / \
53+
'/search?q=book' \
54+
'/apple-macbook-pro' \
55+
'/cart' \
56+
'/checkout'; do
57+
echo "== $p =="
58+
for i in $(seq 1 20); do
59+
curl -sS -o /dev/null -w '%{time_total}\n' "http://127.0.0.1:5000$p"
60+
done
61+
done
62+
```
63+
64+
Before installation is complete, all storefront paths redirect to setup (`302`). Those numbers confirm reachability but are not valid performance baselines.
65+
66+
## Installed-store endpoint baseline (validated)
67+
68+
After fixing PostgreSQL setup (`citext`) and completing installation on both machines, the same endpoint benchmark was executed with `wrk` (`-t2 -c32 -d20s`) across this set:
69+
70+
- `/`
71+
- `/search?q=book`
72+
- `/electronics`
73+
- `/apple-macbook-pro`
74+
- `/cart`
75+
- `/checkout`
76+
77+
Storefront pages returned `200`; `/checkout` returned `302` (expected without an authenticated session).
78+
79+
Requests/second comparison:
80+
81+
| Endpoint | x86 | Arm | Arm vs x86 |
82+
|---|---:|---:|---:|
83+
| `/apple-macbook-pro` | 35.40 | 32.28 | -8.8% |
84+
| `/electronics` | 99.52 | 76.07 | -23.6% |
85+
| `/search?q=book` | 28.18 | 27.40 | -2.8% |
86+
87+
Different endpoints show different gaps. Avoid reducing migration performance to a single number — use per-endpoint baselines to guide architecture-specific optimizations.
88+
89+
## Arm MCP accelerator (optional)
90+
91+
Use MCP to script repeated baseline runs and summarize deltas, but keep the manual baseline commands as your ground truth.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
---
2+
title: Audit dependencies
3+
weight: 4
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
9+
Use a manual-first audit, then use the Arm MCP server to accelerate checks.
10+
11+
## Manual workflow (required)
12+
13+
### 1. Map direct references
14+
15+
```bash
16+
rg -n "<PackageReference|<ProjectReference" src
17+
```
18+
19+
### 2. List transitive dependencies
20+
21+
```bash
22+
dotnet list src/Presentation/Nop.Web/Nop.Web.csproj package --include-transitive
23+
```
24+
25+
### 3. Generate an SBOM (required)
26+
27+
```bash
28+
dotnet tool install --global CycloneDX
29+
dotnet CycloneDX src/Presentation/Nop.Web/Nop.Web.csproj -o sbom/
30+
```
31+
32+
If tool installation is blocked, treat `dotnet list --include-transitive` plus `*.deps.json` evidence as a temporary fallback, not the final state.
33+
34+
### 4. Inspect package internals for native payloads
35+
36+
```bash
37+
mkdir -p /tmp/nupkg-audit
38+
cp ~/.nuget/packages/<package>/<version>/<package>.<version>.nupkg /tmp/nupkg-audit/
39+
cd /tmp/nupkg-audit
40+
unzip -l <package>.<version>.nupkg | rg "runtimes/|native/"
41+
```
42+
43+
This is how you catch hidden architecture-specific binaries.
44+
45+
## Dependency cascade rule
46+
47+
Treat dependencies as a chain, not isolated items:
48+
49+
- App depends on library A
50+
- Library A depends on library B
51+
- Library B is architecture-sensitive
52+
53+
You must resolve B first, then validate A, then validate the app. In nopCommerce, `iTextSharp` and `System.Drawing` are an example of this chain.
54+
55+
## Arm MCP accelerator (optional)
56+
57+
After manual evidence is collected, use MCP tools to speed repetitive checks:
58+
59+
- `knowledge_base_search` for package compatibility
60+
- `skopeo` or `check_image` for container image architecture coverage
61+
- `migrate_ease_scan` where scanner support exists
62+
63+
Keep manual outputs as the source of truth. Use MCP to prioritize and scale, not to skip evidence.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
title: Replace platform-specific code
3+
weight: 5
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
9+
Use one decision framework for every architecture-sensitive dependency.
10+
11+
## Manual workflow (required)
12+
13+
### 1. Find references
14+
15+
```bash
16+
rg -n "System\.Drawing|ColorTranslator" src
17+
```
18+
19+
### 2. Decide using the 4-option framework
20+
21+
1. Keep it and test it deeply.
22+
2. Replace it with a managed cross-platform alternative.
23+
3. Replace it with a native equivalent that has feature parity.
24+
4. Remove the feature if business value is low.
25+
26+
The workflow is the same for every dependency.
27+
28+
### 3. Apply to nopCommerce
29+
30+
- `System.Drawing` image paths: use option 2 with ImageSharp.
31+
- `iTextSharp` PDF color usage: start with option 1 (keep and test), then evaluate option 2 or 3 if you need full decoupling.
32+
33+
```bash
34+
dotnet add src/Libraries/Nop.Services/Nop.Services.csproj package SixLabors.ImageSharp
35+
```
36+
37+
## Baseline: exercise `System.Drawing.Common` first
38+
39+
Before replacing code, run a direct image-operation baseline that uses `System.Drawing.Common` and `ImageSharp` on both x86 and Arm.
40+
41+
Validated Azure results (150 resize+encode operations each) showed:
42+
43+
- `System.Drawing.Common` lower average latency in this microbenchmark.
44+
- `ImageSharp` higher average latency in this microbenchmark.
45+
46+
| Architecture | System.Drawing.Common avg (ms) | ImageSharp avg (ms) |
47+
|---|---:|---:|
48+
| x86 | 15.528 | 32.329 |
49+
| Arm | 15.941 | 70.512 |
50+
51+
This does not invalidate the migration recommendation. Performance is only one dimension.
52+
53+
## Why ImageSharp still improves the migration
54+
55+
A second validated test removed `libgdiplus` on each VM:
56+
57+
- With `libgdiplus` installed: both libraries succeeded.
58+
- Without `libgdiplus`: `System.Drawing.Common` failed (`TypeInitializationException`), ImageSharp still succeeded.
59+
60+
`System.Drawing.Common` depends on `libgdiplus`, a native library that can break portability and behave inconsistently across platforms. ImageSharp is fully managed, so it runs identically on x86 and Arm Linux without native dependencies. For this migration, portability and predictable runtime behavior are the primary goals; then tune and benchmark ImageSharp paths as needed.
61+
62+
### 4. Handle cascade dependencies
63+
64+
Do not patch only the top-level project. If a transitive dependency is architecture-sensitive, fix it first, then retest consumers up the chain.
65+
66+
## Arm MCP accelerator (optional)
67+
68+
Use MCP to accelerate candidate discovery and compatibility research, then validate with manual tests:
69+
70+
- `knowledge_base_search` for replacement candidates
71+
- `migrate_ease_scan` where supported
72+
73+
## Upstream contribution path
74+
75+
When you fix architecture issues in shared code, upstream the change.
76+
77+
- Open a PR with Arm/x86 validation evidence.
78+
- Include benchmark and compatibility notes.
79+
- Track maintainer feedback and update migration docs with the final accepted approach.
80+
81+
This has high leverage: each upstream fix reduces work for future migrations.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
title: Containerize the application
3+
weight: 6
4+
5+
### FIXED, DO NOT MODIFY
6+
layout: learningpathall
7+
---
8+
9+
Use a manual-first container workflow, then add MCP checks.
10+
11+
## Manual workflow (required)
12+
13+
### 1. Dockerfile path
14+
15+
```bash
16+
docker build -f Dockerfile -t nop-web:dockerfile-test .
17+
```
18+
19+
The nopCommerce Dockerfile uses `FROM --platform=$BUILDPLATFORM`, which is a BuildKit feature. The legacy Docker builder does not inject `$BUILDPLATFORM`, causing:
20+
21+
```
22+
failed to parse platform : "" is an invalid OS component of ""
23+
```
24+
25+
Fix by switching to buildx:
26+
27+
```bash
28+
docker buildx create --use --name nopx || true
29+
docker buildx build --platform linux/amd64,linux/arm64 -t nop-web:multiarch --push .
30+
```
31+
32+
If you cannot use buildx, create a simplified Dockerfile that removes the `--platform=$BUILDPLATFORM` argument and builds for the host architecture only.
33+
34+
### 2. .NET SDK publish path (single architecture)
35+
36+
```bash
37+
dotnet publish src/Presentation/Nop.Web/Nop.Web.csproj \
38+
-c Release \
39+
/t:PublishContainer \
40+
-p:ContainerImageTag=publish-test
41+
```
42+
43+
Validated outputs in this project:
44+
45+
- x86 image: `591 MB`
46+
- Arm image: `623 MB`
47+
48+
### 3. .NET SDK multi-arch path
49+
50+
Define multi-arch runtime identifiers in the project file, then publish once.
51+
52+
```xml
53+
<PropertyGroup>
54+
<ContainerRuntimeIdentifiers>linux-x64;linux-arm64</ContainerRuntimeIdentifiers>
55+
</PropertyGroup>
56+
```
57+
58+
```bash
59+
dotnet publish src/Presentation/Nop.Web/Nop.Web.csproj -c Release /t:PublishContainer
60+
```
61+
62+
This is the scalable path for one image definition across both architectures.
63+
64+
## Arm MCP accelerator (optional)
65+
66+
Use MCP image tools after manual build succeeds:
67+
68+
- `skopeo` to inspect manifest architecture coverage
69+
- `check_image` for a quick architecture report
70+
71+
## Recommendation
72+
73+
Use SDK publish as the default migration path. Keep Dockerfile for advanced layer control or custom build logic.

0 commit comments

Comments
 (0)