Docker运行Studio容器¶
基于Docker构建快速启用的开发环境,结合 github 保存的初始化配置以及脚本,来实现跨平台studio。
Docker镜像¶
fedoraproject Dockerfile 在GitHub上提供的 fedora-cloud/Fedora-Dockerfiles 现在已经不在持续开发。不过提供的Dockerfile可以作为参考(实际也不复杂)。
备注
现在Fedora的容器构建都是通过 containerbuildsystem 实现的,需要在 OpenShift Atlas 中部署OpenShift Build System(基于koji)实现容器构建。
Fedora项目提供的Dockerfile可以方便我们快速部署不同的运行环境,你可以通过 fedora-cloud/Fedora-Dockerfiles git仓库clone,也可以直接安装软件包:
sudo dnf -y install fedora-dockerfiles
ls /usr/share/fedora-dockerfiles
快速启动:
cd /usr/share/fedora-dockerfiles/ssh docker build -t fedora-ssh . docker run --name fedora-ssh --detach -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro fedora-ssh /usr/sbin/init
初始化镜像¶
先部署一个最基础的镜像fedora,验证运行,只包含最小化运行环境:
1# syntax = docker/dockerfile:1.3
2FROM fedora:34
3MAINTAINER huatai
4
5ENV container docker
6
7#RUN dnf -y update && dnf -y install systemd && dnf clean all
8#VOLUME [ "/sys/fs/cgroup", "/tmp", "/run" ]
9
10#CMD ["/sbin/init"]
11
12RUN --mount=type=bind,target=/sys/fs/cgroup \
13 --mount=type=bind,target=/sys/fs/fuse \
14 --mount=type=tmpfs,target=/tmp \
15 --mount=type=tmpfs,target=/run \
16 --mount=type=tmpfs,target=/run/lock \
17 dnf -y update && dnf -y install systemd && dnf clean all
18
19EXPOSE 22 80 443
20
21ENTRYPOINT [ "/usr/lib/systemd/systemd" ]
22CMD [ "log-level=info", "unit=sysinit.target" ]
构建镜像:
export DOCKER_BUILDKIT=1 docker build -t local:fedora34-systemd .
运行容器:
docker run --privileged=true --name fedora34-systemd -d -it local:fedora34-systemd
ssh服务容器(ssh)¶
由于fedora的容器镜像默认使用了systemd,安装和启动sshd服务非常容易:
1FROM fedora:34
2MAINTAINER vincent huatai <vincent@huatai.me>
3
4ENV container docker
5
6RUN --mount=type=bind,target=/sys/fs/cgroup \
7 --mount=type=bind,target=/sys/fs/fuse \
8 --mount=type=tmpfs,target=/tmp \
9 --mount=type=tmpfs,target=/run \
10 --mount=type=tmpfs,target=/run/lock \
11 dnf -y update && dnf -y install systemd && dnf clean all
12
13RUN dnf -y install openssh-server \
14 which net-tools iputils procps-ng
15
16# iputils: ping arping tracepath ...
17# net-tools: arp ifconfig route ...
18
19#RUN systemctl enable sshd
20
21# add account "admin" and give sudo privilege
22RUN groupadd -g 505 admin
23RUN useradd -g 505 -u 505 -d /home/admin -m admin
24RUN usermod -aG wheel admin
25RUN echo "%wheel ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
26
27# Add ssh public key for login
28RUN mkdir -p /home/admin/.ssh
29COPY authorized_keys /home/admin/.ssh/authorized_keys
30RUN chown -R admin:admin /home/admin/.ssh
31RUN chmod 600 /home/admin/.ssh/authorized_keys
32RUN chmod 700 /home/admin/.ssh
33
34EXPOSE 22 80 443
35
36ENTRYPOINT [ "/usr/lib/systemd/systemd" ]
37CMD [ "log-level=info", "unit=sysinit.target" ]
备注
ssh容器安装了系统工具,方便维护
构建带有ssh服务的镜像:
docker build -t local:fedora34-systemd-ssh .
访问虚拟机ssh¶
在macOS上运行的Docker容器实际上是运行在 xhyve - macOS平台的KVM 虚拟机中,这个虚拟机所运行的精简Linux操作系统 Alpine Linux ,使得在macOS主机上无法直接ssh到容器内部(需要通过虚拟机操作系统转发)。
这是比直接在Linux主机上运行docker容器要麻烦一些(多隔离了一层虚拟机),不能像Linux主机上,能够直接看到一个NAT网络接口在Linux物理主机(Linux端IP通常是 172.17.0.1
),这个NAT网络接口现在在 xhyve - macOS平台的KVM 虚拟机的Linx系统上,所以如果要实现macOS能够访问到容器,需要做一个端口映射(Port Mapping)。
你可以将这个Port Mapping看成Linux主机的端口映射,将容器内部端口映射到Linux虚拟机对外的网络接口上,由于Linux虚拟机对外网络接口和macOS是互通的,我们就能够通过映射访问到容器:
网络流量 => Linux虚拟机回环接口Port =端口映射=> 容器内部服务Port
我们修订以下运行容器命令,增加
-p 222:22
把端口从回环地址映射到容器上:docker run --privileged=true --hostname fedora34 --name fedora34 \ -p 122:22 -p 180:80 -p 1443:443 -dti local:fedora34-systemd-ssh
备注
在 Dockerfile 中 EXPOSE 的端口只能是完全相同的输出,只有 docker run
命令参数才能映射成不同端口
完成启动后检查:
docker ps
可以看到:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
57c7cde18f5c local:fedora34-systemd-ssh "/usr/lib/systemd/sy…" 2 seconds ago Up 1 second 0.0.0.0:122->22/tcp, :::122->22/tcp, 0.0.0.0:180->80/tcp, :::180->80/tcp, 0.0.0.0:1443->443/tcp, :::1443->443/tcp fedora34
新创建容器就是能通过
122
端口访问到容器:ssh admin@127.0.0.1 -p 122
则通过密钥认证可以登陆容器系统
登陆以后,可以检查验证 systemd
运行情况:
$ ps aux | grep systemd
root 1 0.0 0.0 20396 12044 ? Ss 17:19 0:00 /usr/lib/systemd/systemd log-level=info unit=sysinit.target
root 23 0.0 0.0 34224 14072 ? Ss 17:19 0:00 /usr/lib/systemd/systemd-journald
systemd+ 33 0.0 0.0 29468 17128 ? Ss 17:19 0:00 /usr/lib/systemd/systemd-resolved
root 39 0.0 0.0 17956 8896 ? Ss 17:19 0:00 /usr/lib/systemd/systemd-homed
root 40 0.0 0.0 17792 8944 ? Ss 17:19 0:00 /usr/lib/systemd/systemd-logind
root 68 0.5 0.0 17540 7724 ? Ss 17:24 0:00 /usr/lib/systemd/systemd-userdbd
root 69 0.0 0.0 18004 8552 ? S 17:24 0:00 systemd-userwork
root 70 0.0 0.0 18004 8580 ? S 17:24 0:00 systemd-userwork
root 71 0.0 0.0 18004 8528 ? S 17:24 0:00 systemd-userwork
admin 73 0.5 0.0 19548 11012 ? Ss 17:24 0:00 /usr/lib/systemd/systemd --user
root 86 0.6 0.0 17556 7588 ? Ss 17:24 0:00 /usr/lib/systemd/systemd-hostnamed
admin 100 0.0 0.0 10424 852 pts/1 S+ 17:24 0:00 grep --color=auto systemd
编译开发的软件安装(dev)¶
接下来我们在这个 fedora-ssh
基础上,添加各种常用的开发软件包,以便构成一个非常容易使用的开发环境,预计安装:
gcc
automake, autoconf
openjdk
python
go
swift
备注
swift语言开发包安装参考 在Linux环境开发Swift
FROM fedora:34
MAINTAINER vincent huatai <vincent@huatai.me>
ENV container docker
RUN --mount=type=bind,target=/sys/fs/cgroup \
--mount=type=bind,target=/sys/fs/fuse \
--mount=type=tmpfs,target=/tmp \
--mount=type=tmpfs,target=/run \
--mount=type=tmpfs,target=/run/lock \
dnf -y update && dnf -y install systemd && dnf clean all
RUN dnf -y install openssh-server which procps-ng nmap-ncat mlocate net-tools file \
iputils tmux bzip2 sysstat unzip nfs-utils parted lsof bind-utils
RUN dnf -y install gcc gcc-c++ make flex autoconf automake ncurses-devel zlib-devel git
# Python 3.9 is installed default
RUN dnf -y install java-latest-openjdk
RUN dnf -y install golang
RUN dnf -y install swift-lang
# add account "admin" and give sudo privilege
RUN groupadd -g 505 admin
RUN useradd -g 505 -u 505 -d /home/admin -m admin
RUN usermod -aG wheel admin
RUN echo "%wheel ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
# Add ssh public key for login
RUN mkdir -p /home/admin/.ssh
COPY authorized_keys /home/admin/.ssh/authorized_keys
RUN chown -R admin:admin /home/admin/.ssh
RUN chmod 600 /home/admin/.ssh/authorized_keys
RUN chmod 700 /home/admin/.ssh
# golang env
USER admin
RUN mkdir /home/admin/go
RUN echo 'export GOPATH=$HOME/go' >> $HOME/.bashrc
EXPOSE 22 80 443
ENTRYPOINT [ "/usr/lib/systemd/systemd" ]
CMD [ "log-level=info", "unit=sysinit.target" ]
备注
请注意,当前这个Dockerfile仅仅是安装了开发所需的一些软件包,并没有解决容器销毁以后数据的丢失,这样小心翼翼使用尚可,但是非常容易丢失数据。所以,我们需要通过 Docker 卷 把开发环境的数据持久化,并且能够直接输出到物理主机(macOS环境)中,方便我们数据备份和在物理主机上同样共享数据。
初始化镜像:
docker build -t local:fedora34-dev .
启动容器:
docker run --privileged=true --hostname fedora34-dev --name fedora34-dev \ -p 122:22 -p 180:80 -p 1443:443 -dti local:fedora34-dev
这里遇到一个奇怪的问题,我确实使用了 --privileged=true
,这个参数可以让我在之前运行 fedora34
(基于 local:fedora34-systemd-ssh
镜像) 没有问题,但是现在再次出现报错:
Failed to mount tmpfs at /run: Operation not permitted
[!!!!!!] Failed to mount API filesystems.
Exiting PID 1...
这个问题待查…
2020年的问题排查见 Docker Desktop for macOS文件共享
容器持久化数据存储(dev-data)¶
简单的bind mount¶
对于单机运行工作平台,直接将物理主机的 home 目录映射进容器内部:
docker run --privileged=true --hostname fedora34-dev --name fedora34-dev \
-p 222:22 -p 280:80 -p 2443:443 -v /home/huatai/dev:/home/admin/dev \
-dti local:fedora34-systemd-ssh
启动以后检查:
docker ps
可以看到:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abd0f1fc7ae6 local:fedora34-systemd-ssh "/usr/lib/systemd/sy…" 2 seconds ago Up 1 second 0.0.0.0:222->22/tcp, :::222->22/tcp, 0.0.0.0:280->80/tcp, :::280->80/tcp, 0.0.0.0:2443->443/tcp, :::2443->443/tcp fedora34-dev
为了能够在物理服务器重启时自动重启容器,设置 自动启动Docker容器 (修订运行命令):
docker run --privileged=true --hostname fedora34-dev --name fedora34-dev \ -p 222:22 -p 280:80 -p 2443:443 -v /home/huatai/dev:/home/admin/dev --restart unless-stopped \ -dti local:fedora34-systemd-ssh
多容器共享NFS¶
为了能够在容器销毁并重建等常见操作情况下,不丢失自己辛苦开发工作的数据,我构想了一个方案:
在macOS操作系统上配置 macOS系统NFS服务 ,将用户的
$HOME
目录下子目录home_admin
作为NFS服务卷输出给Docker环境(注意配置内部网络IP访问确保安全) - (遗憾,似乎不好实现)在Docker中配置 Docker容器使用NFS ,将容器的
/home/admin
目录bind到NFS挂载的目录下,这样所有容器中数据都能够直接存储到物理主机的macOS系统的用户目录为了避免多个容器
数据踩踏
,需要每个容器单独创建一个子目录,分别映射,例如dev1
容器使用的是home_admin/dev1
;dev2
容器使用是home_admin/dev2
如果是公用的数据目录,例如代码仓库,则采用共享的挂在目录
在物理主机上采用定时备份同步方法,能够实现数据不丢失
我在macOS上中尚未找到如何在物理主机和Docker VM之间共享NFS的方法,所以在macOS上修订成 Docker Desktop for macOS文件共享
在Linux主机上,非常容易构建NFS共享,所以这个方案可以采用 Docker容器使用NFS 来实现
开发环境框架搭建(studio)¶
在开发环境中,还有非常重要的部署框架:
数据库运行环境 - MySQL Atlas PostgreSQL Atlas ,也通过上述持久化数据存储到物理主机
web服务 - 构建 Nginx
开发框架 - Django Atlas - nodejs相关开发框架
我希望能够快速完成很多我学习和使用的开发环境构建,这块我会不断补充
备注
更为复杂的部署环境,可以集成到一个容器中,也可以分散到不同容器采用 Kubernetes Atlas 实现,这块将不在studio段落展开,我将构建一个部署到生产环境到持续集成,并且结合:
负载均衡
反向代理
缓存
消息队列