การติดตั้ง 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 ในระบบโฮสต์

โดยค่าเริ่มต้น สคริปต์ setup-host จะใช้อินเทอร์เฟซ wlan0 และเรียกใช้ได้ตามที่แสดงด้านล่าง

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

หากคุณใช้อินเทอร์เฟซโครงสร้างพื้นฐานอื่น (เช่น eth0) คุณต้อง ระบุโดยการตั้งค่าตัวแปรสภาพแวดล้อม INFRA_IF_NAME ก่อนเรียกใช้สคริปต์ เช่น

INFRA_IF_NAME=eth0 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 Hub โดยตรง หรือโดยการโคลนที่เก็บ 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   132MB
    

สร้าง 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: ระบุการเชื่อมต่อกับ Thread Radio Co-Processor (RCP)

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

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

  • 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 ของโฮสต์ลงใน คอนเทนเนอร์ โดยปกติแล้วจะเป็นพอร์ตอนุกรมที่เชื่อมต่อกับ ตัวประมวลผลร่วมวิทยุ Thread (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 Daemon ให้รีสตาร์ทคอนเทนเนอร์โดยอัตโนมัติ หากคอนเทนเนอร์หยุดทำงาน ซึ่งจะช่วยให้ OTBR ทำงานอยู่เสมอ openthread/border-router: ระบุอิมเมจ Docker ที่จะใช้สำหรับคอนเทนเนอร์ ในกรณีนี้คืออิมเมจ OpenThread Border Router อย่างเป็นทางการ

ดูบันทึก 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
...