Docker容器如何通过DHCP,实现自动获取宿主机局域网IP

思路

  • Docker使用MacVLAN建立一个network
  • 容器中使用udhcpc自动获取IP
  • 宿主机配置MacVLAN Link来访问容器IP

Docker建立MacVLAN network

networks:
  lan:
    driver: macvlan
    driver_opts:
      parent: enp2s0

services:
  service_A:
    cap_add:
      - NET_ADMIN
    mac_address: "02:42:dd:cc:bb:aa"
    networks:
      - lan

这里使用docker-compose,先建立一个macvlan驱动的network,并且不配置subnetgateway
之所以这样做,是因为如果配置了外面局域网的网段,Docker会自动分配一个IP给容器,而这个IP很可能在外部局域网里已经存在了,且这个IP不被局域网路由器所管理。

以当前配置将容器启动之后,Docker会自动给lan network一个网段,自动给容器分配一个IP(和外部局域网网段不同)。

容器中使用udhcpc自动获取IP

在上一步容器启动之后,我们可以尝试进入运行中容器,看看是否有udhcpc命令,并且尝试通过DHCP获取局域网IP。

docker exec -it service_A bash

udhcpc

如果一切顺利,应该会看到类似下面的输出,说明就是成功从局域网DHCP获取到IP,并且这个IP可以通过路由器进行管理。
如果出现permission相关报错,可能是容器缺少NET_ADMIN权限。

udhcpc: started, v1.37.0
udhcpc: broadcasting discover
udhcpc: broadcasting select for 192.168.2.173, server 192.168.2.1
udhcpc: lease of 192.168.2.173 obtained from 192.168.2.1, lease time 43200

尝试成功之后,我们可以修改docker-compose.ymlserviceendpoint字段,让容器在启动时自动运行udhcpc来获取IP。
并且推荐在路由器上将这个IP设置为静态IP,和容器MAC绑定,方便我们下面做宿主机的MacVLAN Link。

宿主机添加MacVLAN Link

完成上面一步之后,我们会发现在局域网的其他设备可以通过容器IP访问容器的服务,但是在宿主机上不能通过容器IP访问容器。
这里我们需要配置MacVLAN Link来解决这个问题。
打开/etc/systemd/network文件夹,添加以下两个文件:

30-macvlan0.netdev

[NetDev]
Name=macvlan0
Kind=macvlan

[MACVLAN]
Mode=bridge

30-macvlan0.network

[Match]
Name=macvlan0

[Route]
Destination=192.168.2.173
Gateway=192.168.2.1
Metric=200

这里要注意,在.network文件里,Destination只能为容器IP,不然可能路由表会出错。
并且配置合适的Metric路由跃点。

最后,修改已有的DHCP接口配置,可能是这样的:
20-wired.network

[Match]
Name=enp2s0

[Network]
DHCP=yes
MACVLAN=macvlan0

[DHCP]
RouteMetric=100

在其中Network部分添加MACVLAN字段。
最后重启systemd-networkd服务,宿主机应该就可以访问容器IP了。
sudo systemctl restart systemd-networkd

QNAP NAS:安装Emby,使用MPD配合upmpdcli实现本机DLNA播放

概述

  • 安装一个影音管理软件,将NAS中的影片、音乐都统一管理起来,并且从网上自动获取影片、音乐的元数据
  • NAS直连音箱,使得NAS可以直接播放音乐,不需要开电脑

安装 Emby

由于我的机器是TS-532X,可能QNAP从App Center把Emby删掉了,只能从Emby官方网站去下载安装。
Emby Download | QNAP Version
选好适合自己机器架构的软件包,下载,通过App Center安装就行。

安装 MPD-UPNP镜像

为了能够通过NAS直接播放音乐,我们需要安装mpd。而QNAP的机器最好还是使用容器进行安装。
在此之外,为了使用DLNA功能,将我们的NAS改造成一个DLNA播放器(相当于给音箱上了个DLNA),我们还需要一个UPNP Render客户端。
这里,我选择自己Build一个mpd + upmpdcli的镜像来实现。
mpd-upnp镜像
Container Station里可以直接在Docker hub的源上搜索到该镜像。
比较重要的点有:
1. 开放端口
* 6600/tcp
* 49153/tcp
2. 共享主机设备
* Sound and ALSA (14, 116)
* 注意,务必打开容器的授权模式
3. 挂载共享文件夹
* /config -> /share/Container/config/mpd
* 这里的目标文件夹可以指定为你自己的文件夹

配置 MPD-UPNP

该镜像主要需要两个配置:
1. mpd.conf

bind_to_address                 "any"
port                            "6600"
password                        "yourpassword@read,add,control,admin"
max_playlist_length             "65535"
max_command_list_size           "65535"

volume_normalization            "yes"

audio_output {
    type            "alsa"
    name            "KAB-001"
    mixer_type      "hardware"      # optional
    mixer_control   "Speaker"
}
  1. upmpdcli.conf
pidfile = /var/run/upmpdcli.pid
friendlyname = Ricky-NAS
upnpav = 1
openhome = 0
lumincompat = 0
saveohcredentials = 1
checkcontentformat = 1

mpdhost = localhost
mpdport = 6600
mpdpassword = yourpassword
mpdtimeoutms = 2000
ownqueue = 1

保存好配置文件之后,直接启动容器即可。

使用Docker快速搭建NextCloud

0x00 概述

由于先前的个人云盘需求,所以想要搭建一个NextCloud。再加上租的房子有公网IP,因此决定使用ArchLinux虚拟机来跑一个NextCloud的Docker容器实现个人云盘的需求。(关于为何不使用Docker for Windows,原因是我需要使用VMware而不是Hyper-V

0x01 准备

  • Linux环境
  • Docker
  • Docker-Compose(可以使用pip进行安装)

安装local-persist

curl -fsSL https://raw.githubusercontent.com/CWSpear/local-persist/master/scripts/install.sh | sudo bash

0x02 Docker Compose文件的编写

在这里,我选择使用Docker Compose进行容器的编排。至少需要启用两个容器:Mysql与Nextcloud(内置Apache2版本)。

version: "3.7"

volumes:
    mysql:
        driver: local-persist
        driver_opts:
            mountpoint: /home/ricky/nextcloud/mysql
    mysql_config:
        driver: local-persist
        driver_opts:
            mountpoint: /home/ricky/nextcloud/mysql_config
    data:
        driver: local-persist
        driver_opts:
            mountpoint: /mnt/I/nextcloud/data
    config:
        driver: local-persist
        driver_opts:
            mountpoint: /mnt/I/nextcloud/config
    apps:
        driver: local-persist
        driver_opts:
            mountpoint: /mnt/I/nextcloud/custom_apps
    apache:
        driver: local-persist
        driver_opts:
            mountpoint: /mnt/I/nextcloud/apache
services:
    db:
        image: mariadb
        user: "1000:50"
        restart: always
        volumes:
          - type: volume
            source: mysql
            target: /var/lib/mysql
          - type: volume
            source: mysql_config
            target: /etc/mysql/conf.d
        environment:
          - MYSQL_ROOT_PASSWORD=password
          - MYSQL_DATABASE=nextcloud

    app:
        image: nextcloud:15.0.2
        user: root
        links:
          - db
        volumes:
          - type: volume
            source: apache
            target: /etc/apache2/sites-enabled
          - type: volume
            source: data
            target: /var/www/html/data
          - type: volume
            source: config
            target: /var/www/html/config
          - type: volume
            source: apps
            target: /var/www/html/custom_apps
          - "/mnt/I/nextcloud/apache2-ssl.sh:/usr/local/bin/apache2-ssl.sh"
        ports:
          - target: 443
            published: 8443
            protocol: tcp
            mode: host
        command:
          - apache2-ssl.sh

        restart: always

这是我的docker-compose.yml文件。下面将描述各个模块的功能:
* version:指定Docker Compose版本
* volumes:使用的Docker volume,其中这里的local-persist需要自己去GitHub上下载插件进行安装(用于指定挂载路径)。
* services:服务定义
* db:服务名称
* image:使用镜像
* user:使用用户,这里注意对于Mariadb需要指定用户,不然会出现权限错误
* restart:始终重启
* volumes:数据卷挂载
* environment:环境变量
* ports:对外开放的端口,可以进行端口转发
* command:覆盖镜像中原本的CMD命令

0x03 开启Apache的SSL模块

这里我们会遇到一个问题,在NextCloud官方镜像中,ApacheSSL模块是默认禁用的。因此我们需要写一个apache2-ssl.sh来启用它(这里的文件名字需要以apache2-开头)。

#! /bin/bash
a2enmod ssl
service apache2 restart
exec "apache2-foreground"

非常简单,最重要的是最后要重新运行原本的exec "apache2-foreground"命令来启动Apache
关于ApacheSSL设置,我们还需要设置其网站配置文件。

LoadModule headers_module /usr/lib/apache2/modules/mod_headers.so
ServerName pc.rickyhao.com

<IfModule mod_ssl.c>
    <VirtualHost _default_:443>
        ServerAdmin root@rickyhao.com
        DocumentRoot /var/www/html
        Header always set Strict-Transport-Security "max-age=15552000; includeSubdomains;"

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        SSLEngine on

        SSLCertificateFile    /etc/apache2/sites-enabled/ssl/server.pem
        SSLCertificateKeyFile /etc/apache2/sites-enabled/ssl/server.key

        <FilesMatch "\.(cgi|shtml|phtml|php)$">
                SSLOptions +StdEnvVars
        </FilesMatch>
        <Directory /usr/lib/cgi-bin>
                SSLOptions +StdEnvVars
        </Directory>
    </VirtualHost>
</IfModule>
  • header:为之后安全Strict-Transport-Security头做准备

0x04 自启动

在这里,我使用的是systemctl进行自启动服务的管理。

[Unit]
Description=Nextcloud docker compose
After=docker.service

[Service]
ExecStart=docker-compose -f /home/ricky/nextcloud/docker-compose.yml up
ExecStop=docker-compose -f /home/ricky/nextcloud/docker-compose.yml stop

[Install]
WantedBy=multi-user.target

最后使用sudo systemctl daemon-reload重载服务文件,sudo systemctl enable nextcloud启用自启动即可。

0x05 后记

其实我原先一开始是使用nextcloud-fpm版本的镜像,配上nginx来食用的。但是会出现奇怪的性能上的问题,最后还是选择了自带的Apache
最后的最后,想了想自己的Office 365订阅及只用了几百M的1TOneDrive云盘,还是选择了使用OneDrive来储存照片等个人文件(巨硬大法好!)