การติดตั้ง Docker

ดูซอร์สโค้ดใน GitHub

ติดตั้ง Docker

ใน Raspberry Pi

  1. ติดตั้ง Docker

    curl -sSL https://get.docker.com | sh
    
  2. หากต้องการใช้ Docker ในฐานะผู้ใช้ที่ไม่ใช่รูทโดยไม่ต้องใส่ sudo ไว้หน้าคำสั่งแต่ละรายการ ให้แก้ไขการตั้งค่าผู้ใช้ ออกจากระบบเพื่อให้การเปลี่ยนแปลงมีผล

    sudo usermod -aG docker $USER
    

  3. เริ่ม Docker หากยังไม่ได้ทําดังนี้

    sudo dockerd
    

เปิดใช้การส่งต่อ IP

โดยปกติแล้ว Linux จะปิดใช้การส่งต่อ IP โดยค่าเริ่มต้น เรียกใช้สคริปต์ setup-host เพื่อเปิดใช้การส่งต่อ IP ในระบบโฮสต์

curl -sSL
https://raw.githubusercontent.com/openthread/ot-br-posix/refs/heads/main/etc/docker/border-router/setup-host | bash

รับอิมเมจ Docker ของ OTBR

รับอิมเมจ Docker ของ OTBR โดยการดึงจาก OpenThread Docker Repo โดยตรง หรือโดยการโคลนที่เก็บ OTBR และสร้าง Dockerfile ที่รวมอยู่ในพื้นที่

ดึงข้อมูลอิมเมจจาก Docker Hub

  1. วิธีดึงรูปภาพ

    docker pull openthread/border-router:latest
    

  2. ตอนนี้รูปภาพควรปรากฏในรายการอิมเมจ Docker

    docker images
    REPOSITORY                 TAG       IMAGE ID       CREATED       SIZE
    openthread/border-router   latest    08666d77013d   2 hours ago   171MB
    

สร้าง Dockerfile

หากต้องการสร้างอิมเมจด้วยตนเอง ให้โคลนที่เก็บ OpenThread Border Router และสร้าง Dockerfile ที่รวมมาด้วย

  1. ติดตั้ง git

    sudo apt install git
    

  2. โคลนที่เก็บ OTBR

    git clone --depth=1 https://github.com/openthread/ot-br-posix
    cd ot-br-posix
    

  3. สร้าง Dockerfile โดยทำดังนี้

    docker build --no-cache -t openthread/border-router -f etc/docker/border-router/Dockerfile .
    

สร้างไฟล์การกําหนดค่า OTBR

สร้างไฟล์ otbr-env.list เพื่อจัดเก็บการกำหนดค่า Docker ของ OTBR

OT_RCP_DEVICE=spinel+hdlc+uart:///dev/ttyACM0?uart-baudrate=1000000
OT_INFRA_IF=wlan0
OT_THREAD_IF=wpan0
OT_LOG_LEVEL=7
  • OT_RCP_DEVICE: ระบุการเชื่อมต่อกับตัวประมวลผลร่วมแบบไร้สาย (RCP) ของเทรด

  • OT_INFRA_IF: อินเทอร์เฟซเครือข่ายที่ใช้สำหรับเครือข่ายโครงสร้างพื้นฐานที่อยู่ติดกัน (โดยทั่วไปคือ Wi-Fi หรืออีเทอร์เน็ต)

  • OT_THREAD_IF: ชื่ออินเทอร์เฟซเครือข่ายที่ใช้สำหรับเครือข่ายเทรด

  • OT_LOG_LEVEL: ระดับความละเอียดของบันทึกที่ OpenThread สร้างขึ้น

เริ่มคอนเทนเนอร์ Docker ของ OTBR

สร้างและเรียกใช้คอนเทนเนอร์ใหม่จากอิมเมจ OTBR

docker run --name=otbr --detach --network=host --cap-add=NET_ADMIN --device=/dev/ttyACM0 --device=/dev/net/tun --volume=/var/lib/otbr:/data --env-file=otbr-env.list --restart=always openthread/border-router
  • docker run: คำสั่งพื้นฐานสำหรับการเรียกใช้คอนเทนเนอร์ Docker

  • --name=otbr: กําหนดชื่อ "otbr" ให้กับคอนเทนเนอร์ที่กําลังทํางาน ซึ่งจะช่วยให้อ้างอิงถึงคอนเทนเนอร์ในภายหลังได้ง่ายขึ้นสำหรับการดำเนินการต่างๆ เช่น การหยุด เริ่มต้น หรือตรวจสอบ

  • --detach: เรียกใช้คอนเทนเนอร์ในโหมดแยก ซึ่งหมายความว่าจะทำงานอยู่เบื้องหลังและไม่แนบเทอร์มินัลกับสตรีมอินพุต เอาต์พุต หรือข้อผิดพลาดมาตรฐานของคอนเทนเนอร์

  • --network=host: ทําให้คอนเทนเนอร์ใช้สแต็กเครือข่ายของเครื่องโฮสต์โดยตรง ซึ่งมักจำเป็นสำหรับ OTBR เนื่องจากต้องเข้าถึงอินเทอร์เฟซเครือข่ายโดยตรง

  • --cap-add=NET_ADMIN: ให้สิทธิ์คอนเทนเนอร์ใช้NET_ADMIN ความสามารถ ซึ่งจำเป็นสำหรับคอนเทนเนอร์ในการดําเนินงานด้านการดูแลเครือข่าย เช่น การกําหนดค่าอินเทอร์เฟซเครือข่ายและการกําหนดเส้นทาง

  • --device=/dev/ttyACM0: แมปอุปกรณ์ /dev/ttyACM0 ของโฮสต์ลงในคอนเทนเนอร์ ซึ่งโดยปกติแล้วจะเป็นพอร์ตอนุกรมที่เชื่อมต่อกับตัวประมวลผลร่วมแบบไร้สายเทรด (RCP) ชื่ออุปกรณ์ที่เฉพาะเจาะจง (ttyACM0) อาจแตกต่างกันไปตามระบบของคุณ

  • --device=/dev/net/tun: แมปอุปกรณ์ /dev/net/tun ของโฮสต์ลงในคอนเทนเนอร์ ซึ่งจำเป็นต่อการสร้างและใช้อินเทอร์เฟซเครือข่ายเสมือนที่ OTBR นำมาใช้

  • --volume=/var/lib/otbr:/data: แมปไดเรกทอรีของโฮสต์ /var/lib/otbr ลงในคอนเทนเนอร์ที่ /data ซึ่งช่วยให้คอนเทนเนอร์เก็บข้อมูล เช่น การกําหนดค่าเครือข่าย ไว้ได้แม้ว่าจะหยุดหรือเริ่มคอนเทนเนอร์อีกครั้ง

  • --env-file=otbr-env.list: อ่านตัวแปรสภาพแวดล้อมจากไฟล์ที่ระบุและตั้งค่าภายในคอนเทนเนอร์ ตัวแปรสภาพแวดล้อมเหล่านี้อาจเป็นพารามิเตอร์การกําหนดค่าสําหรับ OTBR

  • --restart=always: กําหนดค่าเดรัม Docker ให้รีสตาร์ทคอนเทนเนอร์โดยอัตโนมัติหากหยุดทำงาน ซึ่งจะทำให้มั่นใจว่า OTBR จะทํางานอยู่เสมอ openthread/border-router: ระบุอิมเมจ Docker ที่จะใช้สำหรับคอนเทนเนอร์ ในกรณีนี้ รูปภาพคือรูปภาพอย่างเป็นทางการของ Border Router แบบ OpenThread

ดูบันทึก Docker

ใช้คำสั่งต่อไปนี้บนโฮสต์เพื่อดูบันทึก

docker logs otbr

หาก OTBR ทํางานสําเร็จ คุณควรเห็นเอาต์พุตที่คล้ายกับข้อมูลต่อไปนี้

s6-rc: info: service mdns: starting
s6-rc: info: service s6rc-oneshot-runner: starting
Starting mDNSResponder...
Default: mDNSResponder (Engineering Build) (Mar 26 2025 19:39:09) starting
s6-rc: info: service mdns successfully started
s6-rc: info: service s6rc-oneshot-runner successfully started
s6-rc: info: service fix-attrs: starting
s6-rc: info: service fix-attrs successfully started
s6-rc: info: service legacy-cont-init: starting
s6-rc: info: service legacy-cont-init successfully started
s6-rc: info: service otbr-agent: starting
Configuring OpenThread firewall...
Configuring OpenThread NAT64...
Starting otbr-agent...
[NOTE]-AGENT---: Running 0.3.0-da4b5cf
[NOTE]-AGENT---: Thread version: 1.4.0
[NOTE]-AGENT---: Thread interface: wpan0
[NOTE]-AGENT---: Radio URL: spinel+hdlc+uart:///dev/ttyACM0?uart-baudrate=1000000
[NOTE]-AGENT---: Radio URL: trel://wlan0
[NOTE]-ILS-----: Infra link selected: wlan0
[INFO]-RCP_HOS-: OpenThread log level changed to 5
49d.18:38:43.301 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:0, cmd:RESET
49d.18:38:43.301 [D] P-SpinelDrive-: Waiting response: key=0
49d.18:38:43.311 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:0, cmd:PROP_VALUE_IS, key:LAST_STATUS, status:RESET_POWER_ON
49d.18:38:43.311 [I] P-SpinelDrive-: co-processor reset: RESET_POWER_ON
49d.18:38:43.311 [C] P-SpinelDrive-: Software reset co-processor successfully
49d.18:38:43.311 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:1, cmd:PROP_VALUE_GET, key:PROTOCOL_VERSION
49d.18:38:43.311 [D] P-SpinelDrive-: Waiting response: key=1
49d.18:38:43.312 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:1, cmd:PROP_VALUE_IS, key:PROTOCOL_VERSION, major:4, minor:3
49d.18:38:43.312 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:1, cmd:PROP_VALUE_GET, key:NCP_VERSION
49d.18:38:43.312 [D] P-SpinelDrive-: Waiting response: key=2
49d.18:38:43.313 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:1, cmd:PROP_VALUE_IS, key:NCP_VERSION, version:OPENTHREAD/7a25828-dirty; NRF52840; Mar 25 2025 15:51:02
49d.18:38:43.313 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:1, cmd:PROP_VALUE_GET, key:CAPS
49d.18:38:43.313 [D] P-SpinelDrive-: Waiting response: key=5
49d.18:38:43.314 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:1, cmd:PROP_VALUE_IS, key:CAPS, caps:COUNTERS UNSOL_UPDATE_FILTER 802_15_4_2450MHZ_OQPSK CONFIG_RADIO MAC_RAW RCP_API_VERSION RCP_MIN_HOST_API_VERSION OPENTHREAD_LOG_METADATA 
49d.18:38:43.376 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:1, cmd:PROP_VALUE_GET, key:HWADDR
49d.18:38:43.376 [D] P-RadioSpinel-: Wait response: tid=1 key=8
49d.18:38:43.376 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:1, cmd:PROP_VALUE_IS, key:HWADDR, eui64:f4ce3693ab886040
49d.18:38:43.376 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:2, cmd:PROP_VALUE_GET, key:RCP_API_VERSION
49d.18:38:43.376 [D] P-RadioSpinel-: Wait response: tid=2 key=176
49d.18:38:43.377 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:2, cmd:PROP_VALUE_IS, key:RCP_API_VERSION, version:11
49d.18:38:43.377 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:3, cmd:PROP_VALUE_GET, key:RCP_MIN_HOST_API_VERSION
49d.18:38:43.377 [D] P-RadioSpinel-: Wait response: tid=3 key=177
49d.18:38:43.378 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:3, cmd:PROP_VALUE_IS, key:RCP_MIN_HOST_API_VERSION, min-host-version:4
49d.18:38:43.378 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:4, cmd:PROP_VALUE_GET, key:RADIO_CAPS
49d.18:38:43.378 [D] P-RadioSpinel-: Wait response: tid=4 key=4619
49d.18:38:43.379 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:4, cmd:PROP_VALUE_IS, key:RADIO_CAPS, caps:255
49d.18:38:43.410 [D] P-Trel--------: platformTrelInit(aTrelUrl:"trel://wlan0")
49d.18:38:43.410 [D] P-Trel--------: otSysTrelInit(aInterfaceName:"wlan0")
[DEBG]-TrelDns-: Initialized on netif "wlan0"
[DEBG]-TrelDns-: Netif wlan0 is ready: index = 3
49d.18:38:43.411 [I] P-Netif-------: Sent request#1 to set addr_gen_mode to 1
00:00:00.000 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:5, cmd:PROP_VALUE_GET, key:PHY_CHAN_SUPPORTED
00:00:00.000 [D] P-RadioSpinel-: Wait response: tid=5 key=34
00:00:00.001 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:5, cmd:PROP_VALUE_IS, key:PHY_CHAN_SUPPORTED, channelMask:0x07fff800
00:00:00.001 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:6, cmd:PROP_VALUE_SET, key:PHY_ENABLED, enabled:1
00:00:00.001 [D] P-RadioSpinel-: Wait response: tid=6 key=32
00:00:00.003 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:6, cmd:PROP_VALUE_IS, key:PHY_ENABLED, enabled:1
00:00:00.003 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:7, cmd:PROP_VALUE_SET, key:MAC_15_4_PANID, panid:0xffff
00:00:00.003 [D] P-RadioSpinel-: Wait response: tid=7 key=54
00:00:00.003 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:7, cmd:PROP_VALUE_IS, key:MAC_15_4_PANID, panid:0xffff
00:00:00.003 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:8, cmd:PROP_VALUE_SET, key:MAC_15_4_SADDR, saddr:0x0000
00:00:00.003 [D] P-RadioSpinel-: Wait response: tid=8 key=53
00:00:00.004 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:8, cmd:PROP_VALUE_IS, key:MAC_15_4_SADDR, saddr:0x0000
00:00:00.004 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:9, cmd:PROP_VALUE_GET, key:PHY_RX_SENSITIVITY
00:00:00.004 [D] P-RadioSpinel-: Wait response: tid=9 key=39
00:00:00.005 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:9, cmd:PROP_VALUE_IS, key:PHY_RX_SENSITIVITY, sensitivity:-100
00:00:00.005 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:10, cmd:PROP_VALUE_SET, key:RCP_MAC_KEY, keyIdMode:8, keyId:1, prevKey:***, currKey:***, nextKey:***
00:00:00.005 [D] P-RadioSpinel-: Wait response: tid=10 key=2048
00:00:00.007 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:10, cmd:PROP_VALUE_IS, key:LAST_STATUS, status:OK
00:00:00.007 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:11, cmd:PROP_VALUE_SET, key:MAC_15_4_LADDR, laddr:a2566e135ad5df32
00:00:00.007 [D] P-RadioSpinel-: Wait response: tid=11 key=52
00:00:00.008 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:11, cmd:PROP_VALUE_IS, key:MAC_15_4_LADDR, laddr:a2566e135ad5df32
00:00:00.008 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:12, cmd:PROP_VALUE_SET, key:MAC_15_4_SADDR, saddr:0xfffe
00:00:00.008 [D] P-RadioSpinel-: Wait response: tid=12 key=53
00:00:00.009 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:12, cmd:PROP_VALUE_IS, key:MAC_15_4_SADDR, saddr:0xfffe
00:00:00.009 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:13, cmd:PROP_VALUE_SET, key:MAC_SRC_MATCH_SHORT_ADDRESSES, saddr:none
00:00:00.009 [D] P-RadioSpinel-: Wait response: tid=13 key=4868
00:00:00.010 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:13, cmd:PROP_VALUE_IS, key:LAST_STATUS, status:OK
00:00:00.011 [D] P-SpinelDrive-: Sent spinel frame, flg:0x2, iid:0, tid:14, cmd:PROP_VALUE_SET, key:MAC_SRC_MATCH_EXTENDED_ADDRESSES, extaddr:none
00:00:00.011 [D] P-RadioSpinel-: Wait response: tid=14 key=4869
00:00:00.012 [D] P-SpinelDrive-: Received spinel frame, flg:0x2, iid:0, tid:14, cmd:PROP_VALUE_IS, key:LAST_STATUS, status:OK
00:00:00.012 [I] CslTxScheduler: Set frame request ahead: 6200 usec
00:00:00.012 [I] ChildSupervsn-: Timeout: 0 -> 190
00:00:00.013 [D] P-Trel--------: PrepareSocket()
[DEBG]-TrelDns-: Start browsing _trel._udp services ...
00:00:00.013 [I] TrelInterface-: Enabled interface, local port:52346
00:00:00.013 [I] RoutingManager: Initializing - InfraIfIndex:3
00:00:00.013 [I] InfraIf-------: Init infra netif 3
00:00:00.013 [N] RoutingManager: No valid /48 BR ULA prefix found in settings, generating new one
00:00:00.038 [I] Settings------: Saved BrUlaPrefix fd92:6043:f0e2::/48
00:00:00.038 [N] RoutingManager: BR ULA prefix: fd92:6043:f0e2::/48 (generated)
00:00:00.038 [I] RoutingManager: Generated local OMR prefix: fd92:6043:f0e2:1::/64
00:00:00.038 [I] RoutingManager: Generated local NAT64 prefix: fd92:6043:f0e2:2:0:0::/96
00:00:00.038 [N] RoutingManager: Local on-link prefix: fdde:ad00:beef:cafe::/64
00:00:00.038 [I] InfraIf-------: State changed: NOT RUNNING -> RUNNING
00:00:00.038 [I] RoutingManager: Enabling
00:00:00.038 [I] Nat64---------: IPv4 CIDR for NAT64: 192.168.255.0/24 (actual address pool: 192.168.255.1 - 192.168.255.254, 254 addresses)
[INFO]-UTILS---: Set state callback: OK
00:00:00.039 [I] Nat64---------: NAT64 translator is now NotRunning
[DEBG]-TrelDns-: mDNS Publisher is Ready
[INFO]-TrelDns-: TREL DNS-SD Is Now Ready: Netif=wlan0(3), SubscriberId=1, Register=!
[INFO]-MDNS----: Subscribe service ._trel._udp (total 1)
[INFO]-MDNS----: DNSServiceBrowse _trel._udp
[INFO]-BA------: Start Thread Border Agent
[INFO]-ADPROXY-: Started
[INFO]-DPROXY--: Started
[INFO]-APP-----: Co-processor version: OPENTHREAD/7a25828-dirty; NRF52840; Mar 25 2025 15:51:02
00:00:00.039 [I] Notifier------: StateChanged (0x40038210) [MLAddr NetData PanId NetName ExtPanId Nat64]
00:00:00.041 [I] Platform------: Execute command `ipset flush otbr-ingress-allow-dst-swap` = 0
00:00:00.042 [I] Platform------: Execute command `ipset flush otbr-ingress-deny-src-swap` = 0
00:00:00.044 [I] Platform------: Execute command `ipset add otbr-ingress-deny-src-swap fdde:ad00:beef:0::/64 -exist` = 0
00:00:00.046 [I] Platform------: Execute command `ipset swap otbr-ingress-deny-src-swap otbr-ingress-deny-src` = 0
00:00:00.047 [I] Platform------: Execute command `ipset swap otbr-ingress-allow-dst-swap otbr-ingress-allow-dst` = 0
00:00:00.047 [I] P-Netif-------: NAT64 CIDR updated to 192.168.255.0/24.
00:00:00.047 [I] P-Netif-------: Sent request#2 to delete route 192.168.255.0/24
00:00:00.047 [I] P-Netif-------: Deleting route for NAT64
00:00:00.047 [I] RouterTable---: Route table
00:00:00.047 [I] TrelInterface-: Registering DNS-SD service: port:52346, txt:"xa=a2566e135ad5df32, xp=dead00beef00cafe"
[DEBG]-TrelDns-: Register _trel._udp service: port=52346, TXT=24 bytes
[DEBG]-TrelDns-: Using instance name a2566e135ad5df32
[INFO]-MDNS----: Registering service a2566e135ad5df32._trel._udp
00:00:00.058 [I] Settings------: Saved BorderAgentId {id:27a9a3c44dd733402e8a940a20fc1051}
[INFO]-BA------: Result of decoding MeshCoP TXT data from OT: OK
[INFO]-BA------: Publish meshcop service OpenThread BorderRouter #DF32._meshcop._udp.local.
[INFO]-MDNS----: Registering service OpenThread BorderRouter #DF32._meshcop._udp
00:00:00.059 [I] P-Netif-------: Host netif is down
00:00:00.059 [I] P-Netif-------: Succeeded to process request#1
00:00:00.060 [W] P-Netif-------: Failed to process request#2: No such process
s6-rc: info: service otbr-agent successfully started
...