在铁威马Nas上运行Rust多语言混合项目

15 8月

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2022/08/15/run-rust-multi-language-on-terra-master/



手上有一台铁威马Nas,4盘位双核CPU,X86架构的机器。铁威马的硬件还可以,性价比比较足,但是生态很一般,对于相册的管理方面,官方的不怎么满意,在外网找了几个要么功能太简陋,要么内存占用太高,带不动。

搞来搞去还是自己弄一个,考虑到性能和开销问题,最后选择的是Rust语言,想着横竖都能编译到机器上运行,实在不行Nas还支持Docker,也能解决一部分问题。由于照片太多,所以使用了Tensorflow框架配合MobileNetV2模型进行照片分类和人脸识别,模型都是S规模的,开销可控。

在开发机器上开发好以后直接打包成Docker准备试试,由于使用了Vue作为前端,所以打包分两部分,先构建前端,然后构建后端,最后产出最终镜像。Dockerfile文件如下:

FROM node:16 as front
WORKDIR /usr/src/pototd
COPY ./webapp ./webapp
RUN cd webapp && npm install && npm run build

FROM rust:1.62.1 as builder
COPY --from=front /usr/src/pototd/webapp/dist /usr/src/pototd/webapp/dist

RUN apt update && apt install -y libssl-dev musl-tools libsqlite3-dev && rustup target add x86_64-unknown-linux-musl

WORKDIR /usr/src/pototd
COPY . .
RUN cargo install --path . --target x86_64-unknown-linux-musl

FROM debian:buster-slim
RUN apt-get update && apt-get install -y libsqlite3-dev && rm -rf /var/lib/apt/lists/*
COPY --from=builder /usr/local/cargo/bin/pototd /usr/local/bin/pototd
COPY --from=builder /usr/src/pototd/log4rs.yml /log4rs.yml
EXPOSE 3000
CMD ["pototd", "server"]

运行报错提示Segmentation fault

由于铁威马Nas的系统版本很老旧,为了避免GLIBC兼容性问题,所以Rust构建我一般都用Musl,但是Tensorflow的so文件用的是Google预编译好的,估计这两者有冲突。

在Nas上执行ldd –version,确认版本为2.21,在ubuntu的几个TLS版本看了下,14版本是2.19,符合要求,所以改成镜像使用ubuntu:14.04,手动安装Rust进行编译。

FROM node:16 as front
WORKDIR /usr/src/pototd
COPY ./webapp ./webapp
RUN cd webapp && npm install && npm run build

FROM htynkn/pototd:native as native
RUN ls

FROM ubuntu:14.04 as builder
COPY --from=front /usr/src/pototd/webapp/dist /usr/src/pototd/webapp/dist

RUN apt update && apt install -y libssl-dev musl-tools libsqlite3-dev wget libssl-dev pkg-config software-properties-common
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt update && apt install gcc-9 -y

ENV RUSTUP_HOME=/usr/local/rustup \
    CARGO_HOME=/usr/local/cargo \
    PATH=/usr/local/cargo/bin:$PATH \
    RUST_VERSION=1.62.1

RUN set -eux; \
    dpkgArch="$(dpkg --print-architecture)"; \
    case "${dpkgArch##*-}" in \
        amd64) rustArch='x86_64-unknown-linux-gnu'; rustupSha256='3dc5ef50861ee18657f9db2eeb7392f9c2a6c95c90ab41e45ab4ca71476b4338' ;; \
        armhf) rustArch='armv7-unknown-linux-gnueabihf'; rustupSha256='67777ac3bc17277102f2ed73fd5f14c51f4ca5963adadf7f174adf4ebc38747b' ;; \
        arm64) rustArch='aarch64-unknown-linux-gnu'; rustupSha256='32a1532f7cef072a667bac53f1a5542c99666c4071af0c9549795bbdb2069ec1' ;; \
        i386) rustArch='i686-unknown-linux-gnu'; rustupSha256='e50d1deb99048bc5782a0200aa33e4eea70747d49dffdc9d06812fd22a372515' ;; \
        *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \
    esac; \
    url="https://static.rust-lang.org/rustup/archive/1.24.3/${rustArch}/rustup-init"; \
    wget "$url"; \
    echo "${rustupSha256} *rustup-init" | sha256sum -c -; \
    chmod +x rustup-init; \
    ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch}; \
    rm rustup-init; \
    chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \
    rustup --version; \
    cargo --version; \
    rustc --version;


WORKDIR /usr/src/pototd
COPY . .

RUN cargo install --path .

FROM ubuntu:14.04

RUN apt-get update && apt-get install -y libsqlite3-dev libssl-dev

COPY --from=builder /usr/local/cargo/bin/pototd /usr/local/bin/pototd
COPY --from=builder /usr/src/pototd/log4rs.yml /log4rs.yml

EXPOSE 3000
CMD ["pototd", "server"]

再次运行,提示Illegal instruction

这个就没有头绪了。手动安装GDB以后调试模式运行,程序中断在nsync::nsync_mu_init(nsync::nsync_mu_s_*),定位是libtensorflow。

结合Github上的代码来看,应该是预编译的指令集不对,最后在Tensorflow的网站上看到了这句话。

也就是说从1.6开始就需要CPU支持AVX指令了,那这款铁威马Nas是否支持呢。

在Nas上执行lscpu看下

Architecture:        x86_64
CPU op-mode(s):      32-bit, 64-bit
Byte Order:          Little Endian
CPU(s):              2
On-line CPU(s) list: 0,1
Thread(s) per core:  1
Core(s) per socket:  2
Socket(s):           1
NUMA node(s):        1
Vendor ID:           GenuineIntel
CPU family:          6
Model:               92
Model name:          Intel(R) Celeron(R) CPU J3355 @ 2.00GHz
Stepping:            9
CPU MHz:             922.186
CPU max MHz:         2500.0000
CPU min MHz:         800.0000
BogoMIPS:            3993.60
Virtualization:      VT-x
L1d cache:           24K
L1i cache:           32K
L2 cache:            1024K
NUMA node0 CPU(s):   0,1
Flags:               fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology tsc_reliable nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx est tm2 ssse3 sdbg cx16 xtpr pdcm sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave rdrand lahf_lm 3dnowprefetch cpuid_fault cat_l2 ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust smep erms mpx rdt_a rdseed smap clflushopt intel_pt sha_ni xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts md_clear arch_capabilities

可以看到在Flags下面确实没有AVX,Nas用的处理器是英特尔® 赛扬® 处理器J3355,16年的CPU了,确实比较老了。那这个确实没有办法,只有自己编译一份Tensorflow了。

Tensorflow需要Bazel,以我要编译的2.8.0为例,需要Bazel 4.2.1版本。重新开一个虚拟机,安装Ubuntu 14.04再安装Bazel,根据官方的文档还需要Python的依赖。我其实只需要最终的so文件,不太确定Python是否必须。这里安装的是Python 3.6。

编译参数的话,目前已知avx是一定要关闭的,但是其他的就需要具体分析了,这里由于我们目标明确,就是给Nas(J3355)使用,那么直接根据cpu类型编译。

J3355对应的类型是Goldmont,在GCC文档上确认下

Intel Goldmont CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, POPCNT, CX16, SAHF, FXSR, PCLMUL, PREFETCHW, RDRND, AES, SHA, RDSEED, XSAVE, XSAVEC, XSAVES, XSAVEOPT, CLFLUSHOPT and FSGSBASE instruction set support.

对照Nas中的CPU Flags对比都是有的,说明可以选择这个CPU类型。在configure执行的时候输入参数-march=goldmont -mtune=goldmont即可。

编译的时候遇到了GCC报错,说无法识别arch。根据CPU年代和GCC的release note,安装GCC 9解决。有GCC升级了,相对应的libstdc++等也要升级,最简单的还是在产出的Docker镜像中也安装GCC 9。

最终产出的so文件两个合计将近500M,为了方便其他人使用,也方便构建,我放在了另外一个Docker镜像中。最终Dockerfile如下

FROM node:16 as front
WORKDIR /usr/src/pototd
COPY ./webapp ./webapp
RUN cd webapp && npm install && npm run build

FROM htynkn/pototd:native as native
RUN ls

FROM ubuntu:14.04 as builder
COPY --from=front /usr/src/pototd/webapp/dist /usr/src/pototd/webapp/dist

RUN apt update && apt install -y libssl-dev musl-tools libsqlite3-dev wget libssl-dev pkg-config software-properties-common
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt update && apt install gcc-9 -y

ENV RUSTUP_HOME=/usr/local/rustup \
    CARGO_HOME=/usr/local/cargo \
    PATH=/usr/local/cargo/bin:$PATH \
    RUST_VERSION=1.62.1

RUN set -eux; \
    dpkgArch="$(dpkg --print-architecture)"; \
    case "${dpkgArch##*-}" in \
        amd64) rustArch='x86_64-unknown-linux-gnu'; rustupSha256='3dc5ef50861ee18657f9db2eeb7392f9c2a6c95c90ab41e45ab4ca71476b4338' ;; \
        armhf) rustArch='armv7-unknown-linux-gnueabihf'; rustupSha256='67777ac3bc17277102f2ed73fd5f14c51f4ca5963adadf7f174adf4ebc38747b' ;; \
        arm64) rustArch='aarch64-unknown-linux-gnu'; rustupSha256='32a1532f7cef072a667bac53f1a5542c99666c4071af0c9549795bbdb2069ec1' ;; \
        i386) rustArch='i686-unknown-linux-gnu'; rustupSha256='e50d1deb99048bc5782a0200aa33e4eea70747d49dffdc9d06812fd22a372515' ;; \
        *) echo >&2 "unsupported architecture: ${dpkgArch}"; exit 1 ;; \
    esac; \
    url="https://static.rust-lang.org/rustup/archive/1.24.3/${rustArch}/rustup-init"; \
    wget "$url"; \
    echo "${rustupSha256} *rustup-init" | sha256sum -c -; \
    chmod +x rustup-init; \
    ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch}; \
    rm rustup-init; \
    chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \
    rustup --version; \
    cargo --version; \
    rustc --version;


WORKDIR /usr/src/pototd
COPY . .
COPY --from=native /data/libtensorflow_framework.so.2.8.0 /usr/lib/libtensorflow_framework.so.2
COPY --from=native /data/libtensorflow.so.2.8.0 /usr/lib/libtensorflow.so.2
RUN ldconfig

RUN cargo install --path . --target x86_64-unknown-linux-gnu

FROM ubuntu:14.04

RUN apt-get update && apt-get install -y libsqlite3-dev libssl-dev pkg-config gdb software-properties-common
RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt update && apt install gcc-9 -y && rm -rf /var/lib/apt/lists/*

COPY --from=builder /usr/local/cargo/bin/pototd /usr/local/bin/pototd
COPY --from=builder /usr/src/pototd/log4rs.yml /log4rs.yml

COPY --from=native /data/libtensorflow_framework.so.2.8.0 /usr/lib/libtensorflow_framework.so.2
COPY --from=native /data/libtensorflow.so.2.8.0 /usr/lib/libtensorflow.so.2
RUN ldconfig

EXPOSE 3000
CMD ["pototd", "server"]

参考

https://www.tensorflow.org/install/source?hl=zh-cn

https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html



本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载自夜明的孤行灯

本文链接地址: https://www.huangyunkun.com/2022/08/15/run-rust-multi-language-on-terra-master/

发表回复

您的电子邮箱地址不会被公开。