Alpine Linux软件开发环境构建
我在尝试 树莓派Raspberry Pi 3 + 树莓派Raspberry Pi 4 混合集群部署 K3s - 轻量级Kubernetes 时,读到 Setting Up a Software Development Environment on Alpine Linux ,发现很有启发,也是一个有趣的挑战。在一个轻量级的ARM环境中,实现软件开发、 DevOps ,并采用 边缘云计算构建 构建一个ARM集群。
为什么会选择 Alpine Linux
来构建软件开发环境呢?
从 Alpine Linux简介 可以看到,Alpine是一个非常非常轻量级的Linux系统,并且适合运行容器( Docker )。这对于我们开发者来说,是非常适合的 DevOps 环境。
构建思路:
树莓派Raspberry Pi 4 上安装 Alpine Linux ,然后安装 Docker ,此时系统占用磁盘空间约500MB
所有工作环境都在 Docker 容器中构建,并进一步迁移到 K3s - 轻量级Kubernetes 集群环境
保持 树莓派Raspberry Pi 4 物理主机上运行的OS最精简模式
Docker运行环境
在 Alpine Linux运行Docker ,然后采用 从Dockerfile构建Docker镜像
使用密码登陆的ssh容器
Dockerfile
:
FROM alpine:latest
RUN apk add --update --no-cache openssh sudo
RUN apk update && apk upgrade
RUN echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config
RUN adduser -u 502 -G wheel -h /home/huatai -s /bin/sh -D huatai
RUN echo -n 'huatai:some_password_here' | chpasswd
RUN echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
ENTRYPOINT ["/entrypoint.sh"]
EXPOSE 22
COPY entrypoint.sh /
并准备
entrypoint.sh
:
#!/bin/sh
ssh-keygen -A
exec /usr/sbin/sshd -D -e "$@"
然后执行构建镜像命令:
chmod +x -v entrypoint.sh docker build -t alpine-ssh .
使用以下命令启动容器:
docker run -itd --hostname x-dev --name x-dev -p 122:22 alpine-ssh:latest
安装编译环境
类似Ubuntu的 build-essential
, Alpine Linux 提供了 build-base
组合安装包,可以安装大多数常用build工具,包括 g++
make
和 binutils
。如果要开发 C++,则可以安装一些附加工具包,如 cmake
,以及 linux-headers
等。
安装编译环境
build-base
(占用 204MB)sudo apk add build-base
安装debug工具
gdb
以及strace
sudo apk add gdb strace
golang
通过仓库安装golang:
sudo apk add go
参考 Go快速起步 验证
rust
通过仓库安装rust:
sudo apk add rust
参考 Rust快速起步 验证
安装编辑器构建IDE
桌面
备注
我采用字符界面远程开发,所以没有安装桌面。不过作为轻量级Linux发行版,你可以对应安装一个轻量级的 xfce 桌面。参考文档是 alpine linux wiki: Xfce
或许以后我会尝试运行Alpine Linux桌面
原文作者采用了Xfce桌面,并且为了能够方便开发,安装了JetBrains IDE系列。原因是Alpine Linux使用musl库,如果使用 musl-glibc
兼容库非常费劲。而JetBrains是Java程序,OpenJDK(IcedTea项目)可以顺畅在Alpine Linux上运行,所以选择JetBrains全家桶可以非常方便开发工作。
此外,由于 Google 提供的 Android Studio就是基于JetBrains IDE,所以 在树莓派4上运行android studio开发 也是可行的(只不过为了通用方便,容器内通常运行 Ubuntu Linux )。
考虑到树莓派性能有限,并且在 边缘云计算架构(旧版) 我只有3台 树莓派Raspberry Pi 4 (后续横向扩容)需要部署 K3s - 轻量级Kubernetes 以及在此基础上集成 Rancher 系统,所以我没有部署任何桌面系统,而是将非常消耗计算资源的容器和虚拟机运行在 HPE ProLiant DL360 Gen9服务器 服务器部署的 私有云架构 中。
容器构建
经过验证后,可以将上述步骤添加到 Alpine Linux 的Dockerfile,以便后续重新构建开发环境,并一步步打磨完善:
最终完整的
x-dev
完整 Dockerfile:
FROM alpine:latest
RUN apk update && apk upgrade
RUN apk add --no-cache openssh sudo bind-tools
RUN apk add --no-cache build-base gdb strace
RUN apk add --no-cache go rust
RUN apk add --no-cache git vim htop
RUN echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config
RUN adduser -u 502 -G wheel -h /home/huatai -s /bin/sh -D huatai
RUN echo -n 'huatai:some_password_here' | chpasswd
RUN echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
ENTRYPOINT ["/entrypoint.sh"]
EXPOSE 22
COPY entrypoint.sh /
执行以下命令构建镜像并启动容器:
docker build -t alpine-dev .
docker run -itd --hostname x-dev --name x-dev -p 122:22 alpine-dev:latest
登陆容器:
ssh 127.0.0.1 -p 122
node容器构建案例
构建运行Node的容器环境案例:
FROM alpine:latest
RUN apk update && apk upgrade
RUN apk add --no-cache nodejs npm
RUN addgroup -S node && adduser -S node -G node
USER node
RUN mkdir /home/node/code
WORKDIR /home/node/code
COPY --chown=node:node app.js ./
USER root
EXPOSE 3000
CMD ["node", "app.js"]
准备一个
app.js
作为演示案例:
const http = require('http');
//const hostname = '127.0.0.1';
//容器化运行,node需要监听在所有端口才能publish port
const hostname = '0.0.0.0';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
执行以下命令构建镜像并启动容器:
docker build -t alpine-node .
docker run -itd --hostname x-node --name x-node -p 3000:3000 alpine-node:latest
备注
以上是构建node容器的案例,实际上通过容器运行node建议采用nodejs官方 nodejs / docker-node 来运行
镜像制作和迁移
在完成了容器内部应用升级和安装之后,执行以下命令保存镜像:
docker commit x-dev local:x-dev
然后将镜像导出备份,以及 无需Docker Registry传输Docker镜像
参考
Setting Up a Software Development Environment on Alpine Linux
Making Our Own Alpine Node.js Container 提供了一个构建node运行环境的容器案例,我在上文参考引用了文中Dockerfile