我如何在Raspberry PI上的docker中配置服务的故事以及为什么这可能不是最好的主意。
简介(或一切开始的方式)
一切开始 很久以前几年前。碰巧的是,我最终来到了中国,不得不以某种方式与外界取得联系。我并不十分信任第三方VPN和代理,因此我决定通过代理来筹集DigitalOcean。碰巧的是,随着时间的流逝,具有代理服务器的服务器增长了不同的差异:从文件存储(Syncthing)到CI(Jenkins)。
回到俄罗斯后,决定离开DO进行某种形式的自我托管。我不想为此购买一台单独的服务器-它很昂贵,并且到目前为止没有必要,因此我选择了Raspberry PI 4B。自然,我必须将所有基本服务从DO转移到这台机器上,这将是本文的主题。
介绍性
有必要配置以下服务:
- 同步-文件同步
 - 詹金斯-CI
 - Telegraf-|
 - Influxdb-CPU,GPU等图形
 - 格拉法纳-|
 - 高格斯-git
 - Radicale-同步日历/联系人
 
除了:
- 本来应该以
USB3加密形式将文件和数据存储在一对闪存驱动器上(LUKS) - 所有Web界面都隐藏在Nginx反向代理后面
 
问题与细微之处
我想立即谈谈在组装整个过程中和/或现在出现的问题:
- Raspberry PI 1A, . , , —
 - RaspberryPI 4B ( ) USB . — / . USB3
 - , . ( ) ( " ")
 - — 
syncthing, , / - 60
 
— 502 ssh.
, Micro SD 16GB ( ) Raspbian. .
- Noobs
 - Micro SD Fat32
 - ( uNetbootin)
 - Raspberry PI
 
. : GUI . GUI, ssh GUI .
()
Elementary OS GUI (GParted disks) . , :
, .
— ext4 LUKS.
GParted
Device -> Create partition table...gptApplyext4
gnome-disks ( sudo apt install gnome-disk-utility) ( Disks):
- ()
 Format partition...Ext 4Password protect volumeNext- :
 
. , RaspberryPI . :
: /dev/sdb1 — , Device
dd if=/dev/urandom bs=4M count=1 of=/tmp/usb_decrypt_file
sudo cryptsetup luksAddKey /dev/sdb1 /tmp/usb_decrypt_file
.
: .
, . ()- /
Raspberry PI
, :
- (
sudo apt update && sudo apt -y dist-upgrade) - :
docker docker-compose (sudo apt -y install docker docker-compose)Nginx(sudo apt -y install nginx). reverse-proxy
 
- (, /root/cryptfiles; )
/etc/crypttab :
usb1_crypt UUID=___UUID /root/cryptfiles/_- luks
/etc/fstab
/dev/mapper/usb1_crypt /media/pi/usb1 ext4 defaults,nofail 0 2
:
/dev/mapper/usb1_crypt — /dev/mapper/ + ( ) /etc/crypttab/media/pi/usb1 — . (mkdir /media/pi/usb1). — , /mnt /media/$USER
,
Nginx
bash, reverse-proxy .
:
reverse-proxy nginx, — mydomain.com. nginx /etc/nginx, /etc/nginx/autocompile.
compile_apps_configs.sh#!/bin/bash
APPS=("syncthing" "grafana" "radicale" "git" "jenkins")
APPS_PROXIES=(http://localhost:8880 http://localhost:3000 http://localhost:8882 http://localhost:8883 http://localhost:8884)
HOSTNAMES=(my.domain)
conf_file="/etc/nginx/sites-available/autocompiled.conf"
ln_file="/etc/nginx/sites-enabled/autocompiled.conf"
echo "" > "$conf_file"
for app_index in ${!APPS[*]}
do
    app="${APPS[app_index]}"
    app_proxy="${APPS_PROXIES[app_index]}"
    for host in ${HOSTNAMES[*]}
    do
        echo "`./compile_config.sh "$host" "$app_proxy" $app`" >> "$conf_file"
        echo "" >> "$conf_file"
    done
done
ln -s "$conf_file" "$ln_file"
 compile_config.sh#!/bin/bash
DOMAIN_BASE="$1"
shift
PROXY_PATH=$(echo "$1" | sed -e "s/\//\\\\\//g")
PROXY_LOCATION=""
shift
HOSTNAME="$DOMAIN_BASE"
while [ -n "$1" ]
do
    case "$1" in
        "-pl") shift; PROXY_LOCATION="$(echo "$1" | sed -e "s/\//\\\\\//g")" ;;
        *) HOSTNAME="$1.$HOSTNAME" ;;
    esac
    shift
done
cat template.conf | sed "s/HOSTNAME_BASE/$DOMAIN_BASE/g" | sed "s/HOSTNAME/$HOSTNAME/g" | sed "s/PROXYPATH/$PROXY_PATH/g" | sed "s/PROXYLOCATION/$PROXY_LOCATION/"
 location_template.conf    location /PROXYLOCATION {
        proxy_pass PROXYPATH;
    }
 template.confserver {
    server_name "HOSTNAME";
    ssl_certificate /etc/letsencrypt/live/HOSTNAME_BASE/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/HOSTNAME_BASE/privkey.pem;
    listen 443 ssl;
    keepalive_timeout 60;
    ssl on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "HIGH:!RC4:!aNULL:!MD5:!kEDH";
    add_header Strict-Transport-Security 'max-age=604800';
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    # set max upload size
    client_max_body_size 4000M;
    sendfile on;
    send_timeout 600s;
    proxy_connect_timeout 600;
    location /PROXYLOCATION {
        proxy_pass_request_headers on;
        proxy_pass_request_body on;
        proxy_pass PROXYPATH;
    }
}
 , ./compile_apps_configs.sh nginx: sudo systemd reload nginx.
 Docker
, docker docker-compose:
sudo apt install docker docker-compose
yml . :
├── doForAll
├── gogs
│   ├── docker-compose.yml
│   ├── Dockerfile
│   └── .env
├── grafana
│   ├── configs
│   │   ├── influxdb.conf
│   │   └── telegraf.conf
│   ├── docker-compose.yml
│   └── .env
├── jenkins
│   ├── docker-compose.yml
│   ├── .env
├── makeFullUpdate
├── radicale
│   ├── docker-compose.yml
│   └── .env
└── syncthing
    ├── docker-compose.yml
    └── .env
, ( grafana — , — influxdb). .
, :
.env DATA_PATHGrafana - :
Telegraf. .env INFLUXDB_WRITE_USER_PASSWORD, configs/telegraf.conf — passwordGrafana. .env INFLUXDB_READ_USER_PASSWORD, Grafana
.
root. :
sudo -i
mkdir -p /root/scripts/
touch "/root/scripts/monitor_startup_docker_container"
chmod 700 "/root/scripts/monitor_startup_docker_container"
nano "/root/scripts/monitor_startup_docker_container"
/root/scripts/monitor_startup_docker_container :
#!/bin/bash
function log() {
    echo `date`: "$@"
}
container_name="$1"
true=1
false=0
function restartContainer() {
    docker container restart "$1"
}
function checkContanerExitStatus() {
    container_name="$1"
    status_line="`docker container ps -a --filter "name=$container_name" --filter "exited=255" | grep "$container_name"`"
    [[ -z "$status_line" ]] && echo $false || echo $true
}
function checkContanerStatusIsEqual() {
    container_name="$1"
    container_dest_status="$2"
    status_line="`docker container ps -a --filter "name=$container_name" --filter "status=$container_dest_status" | grep "$container_name"`"
    [[ -z "$status_line" ]] && echo $false || echo $true
}
function isRunning() {
    echo "`checkContanerStatusIsEqual "$container_name" "running"`"
}
while [[ "`isRunning`" != "$true" ]]; do
    log check cycle "$container_name"
    if [ "`checkContanerStatusIsEqual "$container_name" "exited"`" == "$true" -o "`checkContanerStatusIsEqual "$container_name" "dead"`" == "$true" ]; then
        log restart "$container_name"
        restartContainer "$container_name"
    fi
    if [[ "`isRunning`" -eq "$false" ]]; then
        sleep 5
    else
        sleep 120
    fi
done
log started "$container_name"
crontab . root:
`crontab -e`@reboot rm /root/startup_docker_logs
1/10 * * * * /root/scripts/monitor_startup_docker_container telegraf >> /root/startup_docker_logs
2/10 * * * * /root/scripts/monitor_startup_docker_container influxdb >> /root/startup_docker_logs
3/10 * * * * /root/scripts/monitor_startup_docker_container grafana >> /root/startup_docker_logs
3/10 * * * * /root/scripts/monitor_startup_docker_container jenkins >> /root/startup_docker_logs
3/10 * * * * /root/scripts/monitor_startup_docker_container gogs >> /root/startup_docker_logs
1/10 * * * * /root/scripts/monitor_startup_docker_container radicale >> /root/startup_docker_logs
2/10 * * * * /root/scripts/monitor_startup_docker_container syncthing >> /root/startup_docker_logs
 , , 平均而言,几乎无需维护。本文未涵盖的内容:
我将很高兴发表评论和发表有用的评论。