1. 程式人生 > >樹莓派(Raspberry Pi)使用Shell編寫的極簡Service

樹莓派(Raspberry Pi)使用Shell編寫的極簡Service

樹莓派(Raspberry Pi)執行的系統是基於Debian的,不僅可以執行Shell,還支援systemd和docker,可以編寫一個簡單的服務,讓其在啟動時執行,執行一些自動化的操作。這裡在RaspPi Zero W上使用shell、systemd和Docker 18.06.1完成,詳細步驟介紹如下。

1、初始化系統

從樹莓派官網(https://www.raspberrypi.org/)下載映象,燒寫到SD卡(我用Etcher)。

將SD卡插入樹莓派,加電啟動。

登入使用:pi,raspberry。

如果想要通過ssh遠端操作,還需要安裝和啟用sshd服務開機啟動(下面介紹)。

當然,首先是要開通WiFi,能夠聯網。

2、WiFi 設定

Wifi AP設定,使用命令 “nano /etc/wpa_supplicant/wpa_supplicant.conf” 編輯配置檔案,參照下面的方法新增WiFi熱點:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
	ssid="HiWiFi_xxxxxx"
	psk="mypassword"
}

建立服務需要使用靜態地址。修改檔案dhcpcd(使用nano /etc/dhcpcd),編輯如下內容:

interface wlan0
noipv6rs
noipv6
static ip_address=192.168.199.190
static routers=192.168.199.1
domain_name_servers=192.168.199.1 8.8.8.8 9.9.9.9

將上面的IP地址和DNS改為自己的,其中8.8.8.8/9.9.9.9為公共的DNS服務地址,不需修改。

重啟dhcpcd服務(或者需要重啟樹莓派)。

聯網成功後,執行軟體版本更新操作。如下:

sudo apt update && sudo apt upgrade -y 

3、編寫WatchDog和Service

建立一個自己的目錄,建立下面三個檔案:

  • sshp.service,由systemd呼叫的服務配置檔案。
  • sshp.daemon,執行服務控制(啟動、停止、狀態)的指令碼檔案。
  • sshp.worker,執行服務的任務指令碼檔案。

檔案的內容如下。

3.1 sshp.service檔案

[Unit]
Description=Secure Shell server proxy
After=network.target

[Service]
Type=forking
ExecStart=/home/pi/openthings/tutools/sshp.daemon start
ExecStop=/home/pi/openthings/tutools/sshp.daemon stop
TimeoutSec=0
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
Alias=sshp.service

3.2 sshp.daemon檔案

#!/bin/sh

echo "SSHP tools."
#=======================
start() {
  now=`date '+%Y-%m-%d %H:%M:%S'`
  echo "$now  Start SSHP worker ..." >> /home/pi/openthings/tutools/sshp.log
  nohup /home/pi/openthings/tutools/sshp.worker &
}

#=======================
stop() {
  PID=`ps -aux | grep "sshp.worker" | grep -v grep | awk -F " " '{print $2}'`
  kill -9 $PID
  echo "Stop SSHP worker, PID="$PID >> /home/pi/openthings/tutools/sshp.log
}

#=======================
restart() {
  echo "Restart Service..."
  Stop
  Start
  echo "Restarted SSHT worker, PID="$PID
}

#=======================
status() {
  now=`date '+%Y-%m-%d %H:%M:%S'`
  echo "$now  Service status ssht."
  ps -aux | grep "sshp.worker" | grep -v grep
}

case "$1" in
  start) start ;;
  stop)  stop  ;;
  restart) restart ;;
  status) status ;;
  *)
    echo "Usage: (start|stop|restart|status)"
    exit 1
    ;;
esac

echo "Service SSHP tools done."
exit 0

3.3 sshp.worker檔案

#!/bin/sh
while true; do
  sshpass -p mypassword ssh -o "ExitOnForwardFailure yes" -o "StrictHostKeyChecking no" -y -p 22000 -NgD *:5555 root@myserver
done
  • 這裡僅使用ssh演示worker編寫方法,具體可以參考:SSH 命令列引數詳解【英】
  • 這裡有個坑是,以服務啟動時的賬戶是root,與當前使用者pi的配置資訊和預設引數是不同的。

3.4 設為啟動時執行

使用下面的命令將剛才編寫的服務設為啟動時執行:

sudo systemctl enable sshp.service

檢視一下,系統裡的啟動執行服務:

# ls -l /etc/systemd/system/multi-user.target.wants/

total 0
lrwxrwxrwx 1 root root 40 Nov 29  2017 avahi-daemon.service -> /lib/systemd/system/avahi-daemon.service
lrwxrwxrwx 1 root root 41 Nov 29  2017 console-setup.service -> /lib/systemd/system/console-setup.service
lrwxrwxrwx 1 root root 38 Apr 12 05:45 containerd.service -> /lib/systemd/system/containerd.service
lrwxrwxrwx 1 root root 32 Nov 29  2017 cron.service -> /lib/systemd/system/cron.service
lrwxrwxrwx 1 root root 34 Nov 29  2017 dhcpcd.service -> /lib/systemd/system/dhcpcd.service
lrwxrwxrwx 1 root root 34 Dec 25  2017 docker.service -> /lib/systemd/system/docker.service
lrwxrwxrwx 1 root root 35 Nov 29  2017 hciuart.service -> /lib/systemd/system/hciuart.service
lrwxrwxrwx 1 root root 38 Nov 29  2017 networking.service -> /lib/systemd/system/networking.service
lrwxrwxrwx 1 root root 37 Nov 29  2017 nfs-client.target -> /lib/systemd/system/nfs-client.target
lrwxrwxrwx 1 root root 48 Nov 29  2017 raspberrypi-net-mods.service -> /lib/systemd/system/raspberrypi-net-mods.service
lrwxrwxrwx 1 root root 36 Nov 29  2017 remote-fs.target -> /lib/systemd/system/remote-fs.target
lrwxrwxrwx 1 root root 33 Nov 29  2017 rsync.service -> /lib/systemd/system/rsync.service
lrwxrwxrwx 1 root root 35 Nov 29  2017 rsyslog.service -> /lib/systemd/system/rsyslog.service
lrwxrwxrwx 1 root root 40 Apr 12 15:43 sshp.service -> /home/pi/openthings/tutools/sshp.service
lrwxrwxrwx 1 root root 31 Apr 12 12:40 ssh.service -> /lib/systemd/system/ssh.service
lrwxrwxrwx 1 root root 37 Nov 29  2017 sshswitch.service -> /lib/systemd/system/sshswitch.service
lrwxrwxrwx 1 root root 40 Nov 29  2017 triggerhappy.service -> /lib/systemd/system/triggerhappy.service
lrwxrwxrwx 1 root root 47 Dec 25  2017 unattended-upgrades.service -> /lib/systemd/system/unattended-upgrades.service
lrwxrwxrwx 1 root root 40 Mar 24  2018 wifi-country.service -> /lib/systemd/system/wifi-country.service
lrwxrwxrwx 1 root root 42 Apr 12 05:46 wpa_supplicant.service -> /lib/systemd/system/wpa_supplicant.service

3.5 測試服務啟停

使用下面的命令來控制服務。

# 檢視服務執行狀態。
sudo systemctl status

# 啟動服務。
sudo systemctl start
# 然後,可以使用ps -aux檢視ssh程序是否已經啟動。

# 停止服務。
sudo systemctl stop
# 然後,可以使用ps -aux檢視ssh程序是否已經關閉。

這裡設定了一個日誌檔案,為上面的目錄下sshp.log,可以檢視輸出的資訊。

可以修改上面的指令碼,新增自己的日誌資訊輸出。

4、Docker安裝

也可以把任務放到Docker中執行。我這裡用於建立一個Nginx服務,然後執行pac資訊提供者,為iPhone等裝置提供網路配置引數時使用。

獲取docker自動安裝指令碼並執行:

wget https://get.docker.io -O docker.sh
sudo chmod docker.sh
./docker.sh

目前,最新的Docker版本是18.09,但是執行時有Bug,暫時還沒有解決。

我們使用18.06.1版。安裝指定的Docker版本:

sudo apt install docker-ce=18.06.1-ce

將版本鎖定,以避免apt upgrade時自動升級到最新版本,命令如下:

sudo echo "docker-ce hold" | sudo dpkg --set-selections

測試一下Docker,看看安裝是否成功:

docker info

5 構建PAC服務

pac是什麼?

pac是一種網路配置的機制,客戶端通過獲取pac檔案來自動獲取一系列配置引數,從而對網路進行初始化設定。

編寫一個pac檔案,如下:

function FindProxyForURL(url, host)
{ 
     return "SOCKS 192.168.199.190:5555";
}

pac服務構建

然後,將pac檔案放入Web伺服器,構建一個檔案服務(也可以動態生成)。

這裡使用Nginx的Docker映象來提供服務(注意Nginx有多種Docker映象,只有為樹莓派編譯的才可以在上面執行)。

執行:

docker run --name nginx -v /home/pi/openthings/web:/usr/share/nginx/www:ro -d -p 80:80 akkerman/rpi-nginx

這個安裝說明運行了後,所編寫的檔案並沒有釋出出來,進去看是因為Nginx預設路徑為/var/www/html,而不是/usr/share/nginx/www。可以修改上面的命令為:

docker run --name nginx -v /home/pi/openthings/web:/var/www/html:ro -d -p 80:80 akkerman/rpi-nginx

或者執行Exec進入Docker進行修改,如下:

docker exec -it nginx /bin/sh

檢視Nginx的service目錄:

cat /etc/nginx/sites-available/default

建立軟連線:

ln -s /usr/share/nginx/www /var/www/html

在目錄下,建立一個index.html檔案,然後到瀏覽器輸入http://my-raspberrypi-ip,看是否能夠釋出出來。

然後,將上面的pac檔案放到該釋出目錄下

6、測試可用性

現在,可以測試一下,上面建立的服務是否可用。

  • 使用瀏覽器

開啟setting頁面,進入網路設定,勾選sokcs5,填入上面的pac地址,勾選dns over https等選項。

輸入任何想要訪問的地址,等待奇蹟出現。

  • 使用iPhone

進入setting,選擇網路設定,裡面有個“自動”選項,填入上面的pac地址。

7、小結

編寫一個Linux服務還是有一些難度的,上面提供了一個極簡的框架。

樹莓派體積雖小,執行一些控制性服務也是足夠了,關鍵是功耗足夠低,還沒有任何噪音。

一些定期執行的任務,如縮時攝影、溫溼度監測、自動澆水等等有趣的事都可以使用上面的機制來完成。

8、更多參考