使用容器——也许是开发环境配置的终极解决方案

话题引入

在实际产品研发过程中,开发、测试和部署常常不在同一个平台下进行。为保证环境的一致性,常常需要在不同平台上配置相似的环境,这往往会出现配置的环境与平台本身结合度高,难以复用的情况。许多朋友在乏味的环境配置过程中浪费了大量的时间,并且逐渐失去了热情。博主本人曾经并且现在仍然深受其害,一直希望能找到一种能够一劳永逸的环境配置方法,让我早日脱离苦海,踏上研发的正轨。

实际需求

博主本人平时使用C++和Python进行开发,主要用到Pytorch进行神经网络的设计和训练、用到Opencv进行图像处理、用到ONNX或者TensorRT进行神经网络推理。除此之外,有时还会用到QT、PCL、ROS等。我希望能达到的一种状态是写的代码在各个平台上都能编译、DEBUG和运行。为实现这个目标,我目前为止尝试过虚拟环境包管理器(miniconda/vcpkg)、虚拟机(VMware/HyperV)、Vtoy虚拟磁盘等方法,这些方法各有千秋,但是都没能达到我的期望。最近,我接触到了容器技术,在使用了一段时间之后,发现它能完美满足我目前的工作需要,于是在此记录一下配置过程。

Docker技术及基础用法

Docker是一种基于操作系统层面的虚拟化技术,其依赖于Linux的系统内核(因此如果需要在Windows系统中使用,需要开启Windows子系统WSL)。Docker与其他虚拟化技术的区别在于,它不需要将整个计算机硬件或整个操作系统虚拟出来。相反,Docker利用操作系统的特性,如Linux内核的命名空间和控制组(cgroups),在宿主机操作系统上创建和管理轻量级的容器。每个容器都是一个独立的运行环境,拥有自己的文件系统、进程空间和网络接口。相对于传统的虚拟化技术,Docker容器的启动速度更快,资源占用更少,并且具有更高的可移植性和可伸缩性。由于容器共享主机操作系统内核,所以它们相对较轻量级,可以在相同的硬件上运行更多的容器。

每个Docker容器都基于Docker镜像。镜像是一个只读的模板,包含了构建和运行容器所需的文件系统、应用程序代码和依赖项。镜像可以根据需要进行部署,可以在本地构建,也可以从Docker Hub等镜像仓库中获取。容器可以根据镜像创建,并通过在容器中修改文件系统或运行特定的命令来定制。

Docker引擎和工作流

使用三张图描述docker技术:

有关docker架构的解释前人之述备已,这里不再过多赘述,提供以下参考链接:
https://cloud.tencent.com/developer/article/1611733?shareByChannel=link

https://blog.csdn.net/m0_51458935/article/details/119576548

操作Docker的基础命令

docker version	# 查看docker版本
docker ps	# 查看有哪些容器在运行之中
docker images	# 列出所有镜像
docker info 	# 列出docker的信息

docker search nginx # 搜索镜像
docker pull nginx:latest
docker image ls # 查看本地镜像有哪些
docker rmi d1a364dc548c	# 根据id号删除镜像
# 运行该nginx镜像,生成容器
docker run 参数 镜像名字/id
docker run -d -p 801:80 nginx # -d: 后台运行  -p 801:80将容器的80端口映射到宿主机的801端口
docker stop 容器id	# 停止容器,容器id可通过docker ps查看
docker start 容器名字/id 	# 开启容器
docker restart 容器名字/id 	# 重启容器

docker run -it 容器名字/id bash	# 进入容器以内,-i:交互操作 -t:新开一个终端, bash:bash环境
exit 退出容器空间

docker exec -it 容器名字/id bash	# 进入正在运行的一个docker空间

Docker镜像管理

如果想自定义一个镜像,需要做以下工作:

  1. 获取基础镜像,选择以恶搞发行版平台(Ubuntu,centos)
  2. 在环境中安装所需要的润建
  3. 导出镜像文件

  • 获取镜像

    • 默认的docker的仓库,dockerhub,有大量优质的镜像
    • docker search 镜像 :标签​​ 搜索镜像
    • docker run -it --rm centos bash​​ --rm :退出时删除该容器

  • 查看镜像
  • 删除镜像

    • docker rmi 镜像名/id(id的前三位即可)​​ 删除image的时候不能有依赖的容器
    • ​docker rm 容器​​ 删除容器

  • 镜像管理综合

    • 导出镜像:先提交之后再导出镜像,docker image save centos:7.8.2003 > /opt/111.tgz​​
    • 导入镜像:docker image load-i /opt/111.tgz​
    • 查看镜像的详细信息:docker image inspect 镜像id​​

Docker容器管理

docker run 镜像名/id​​ 创建并启动容器,如果镜像不在本地,则下载

容器内的进程必须处于前台运行状态,否则容器就会直接退出,自己部署的容器命令,命令不得至于后台。
如果在容器内什么都不做,容器也会自动退出

docker run centos	# 运行之后直接退出容器,因为容器内没有执行任务
# 多次运行容器会产生多次容器记录
docker ps -a # 查看所有容器记录
### 针对宿主机:前台运行 ###
docker run -it centos bash # 运行容器且进入容器内,容器不会退出
docker run -it centos ping baidu.com # 运行容器且进入容器内运行一个程序
### 针对宿主机:后台运行 ###
docker run -it -d centos ping baidu.com
docker run -it -d --rm centos ping baidu.com #运行之后删掉容器记录
docker run -it -d --name abc centos ping baidu.com	# --name为容器起名
docker log -f 容器id	# 查看容器日志,并实时刷新
ps -ef 显示正在运行的进程
docker containter inspect 容器id	 # 查看容器详细的信息
docker run nginx	# 会执行根目录下的docker-entrypoint.sh文件
docker port 容器id	# 查看容器的端口转发情况
### 容器的提交 ###
# 在容器内修改完之后,提交,之后再运行
docker commit 容器id 新的镜像名(通常这样写heene/new)

dockerfile

dockerfile主要组成部分:

  • 基础镜像信息:FROM centos:6.8
  • 制作镜像时候的操作:RUN yum install mysql-server
  • 容器启动时执行指令:CMD ["/bin/bash"]

dockerfile命令:

指令 功能 指令 功能
FROM 指定基础镜像 WORKDIR 切换工作目录
MAINTAINER 指定维护者信息,可选 VOLUME 设置卷,挂载主机目录
RUN 运行指定命令 EXPOSE 对外暴露的端口
ADD 拷贝文件到容器内(自动解压),支持URL地址 CMD 容器启动之后需要执行的命令
COPY 拷贝文件到容器内

挂载主机上的目录,使用 -v D://1:/home/ ​​参数

额外命令

# dockerfile挂载目录
VOLUME /data # 多个挂载目录使用VOLUME ["dir1","dir2",...],将宿主机上的目录挂载到docker中
# 运行时对外暴露端口
docker port 容器
docker run -p 宿主机端口:容器端口
# 切换用户
USER root
USER heene

使用Tips

​docker build --no-cache -t 'heene/test_docker' .​​ -t:在构建时指定镜像名称。–no-cache:不使用之前的缓存,可以避免一些问题

  1. 在编写dockerfile的时候,一个RUN​​​会产生一层,为了减少层数,可以将多个步骤合并到一个RUN​​​里面,例如 RUN apt-get update && apt-get install -y \ bzr \ git \ vim && rm -rf /var/lib/apt/lists/* (最后面,在安装完包之后记得删除缓存)
  2. 为更好的利用缓存,在一些情况下应该添加新的层,比如在后期添加新的软件时可以新开一个RUN​​​
  3. 使用dive​​​工具可以很方便地查看docker image的内部构成
  4. 运行中拷贝文件:docker cp [OPTIONS] LOCAL_SRC_PATH CONTAINER:DEST_PATH​​

运行docker并打开bash,将docker container的22端口映射到宿主机的8011端口,容器运行结束之后自动清理,挂载E盘的projects文件夹到/root/projects:docker run -it -p 8011:22 --rm -v E:\projects:/root/projects images_name bash

Docker && Cuda && Pytorch && opencv && C++ && Neovim环境配置

我的dockerfile文件内容:

# FROM ubuntu:20.04
## 这里需要注意,11.8以上的cuda版本才支持40系显卡,配了两天11.7😭
FROM nvidia/cuda:11.8.0-cudnn8-devel-ubuntu22.04
WORKDIR /root
ENV DEBIAN_FRONTEND=noninteractive
# 设置环境变量
ENV LANG=zh_CN.UTF-8 \
    LANGUAGE=zh_CN:en \
    LC_ALL=zh_CN.UTF-8 
    
RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \
    && sed -i 's/cn.archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \
    && sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \
    && apt-get -y update \
    && echo "tzdata tzdata/Areas select Asia" | debconf-set-selections \
    && echo "tzdata tzdata/Zones/Asia select Shanghai" | debconf-set-selections \
    && apt-get -y install \
    cmake \
    libpq-dev \
    zip \
    tree \
    curl \
    locales \
    build-essential \
    clang-format \
    openssh-server \
    git \
    xsel \
    ripgrep \
    nodejs npm \
    llvm \
    clang \
    screen \
    language-pack-zh-hans \
    && apt-get -y autoclean && \
    apt-get -y autoremove && \
    rm -rf /var/lib/apt/lists/*
RUN git clone https://gitee.com/heren/nerd-fonts.git/ \
    && cd nerd-fonts \
    && chmod +x install.sh \
    && ./install.sh Hack \
    && cd .. \
    && mkdir -p .config/data/debug/ \
    && mkdir -p osc52/bin \
    && mkdir /var/run/sshd \
    && echo 'root:123456bbb' | chpasswd \
    && sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
WORKDIR /root/.config
COPY ./codelldb-x86_64-linux.vsix /root/.config/
COPY nvim-linux64.tar.gz pytorch20.yaml /root/
COPY clipboard-provider /root/osc52/bin
RUN git clone https://gitee.com/fanzhuoxuan/my-nvim-config.git \
    && mv my-nvim-config/* ./ \
    && unzip -q -d data/debug/ codelldb-x86_64-linux.vsix \
    && tar xzf ../nvim-linux64.tar.gz -C ../ \
    && echo export PATH="$HOME/nvim-linux64/bin:$HOME/osc52/bin:$PATH" >> ~/.bashrc \
    && sed -i -e 's/# zh_CN.UTF-8 UTF-8/zh_CN.UTF-8 UTF-8/' /etc/locale.gen \
    && locale-gen && update-locale LANG=zh_CN.UTF-8
## pytorch
WORKDIR /root/
ENV PATH=/root/miniconda/bin:$PATH
COPY ./Miniconda3-latest-Linux-x86_64.sh /root/
RUN  chmod +x Miniconda3-latest-Linux-x86_64.sh \
    && bash Miniconda3-latest-Linux-x86_64.sh -b -p $HOME/miniconda \
    && ./miniconda/bin/conda init \
     && rm Miniconda3-latest-Linux-x86_64.sh \
    && apt-get update \
    && apt install libsqlite3-dev 
## ffmpeg opencv
RUN apt-get update && apt-get -y install libavcodec-dev libavformat-dev libswscale-dev \
    libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev \
    libgtk-3-dev libeigen3-dev \
    mesa-common-dev libgl1-mesa-dev libglu1-mesa-dev \
    libpng-dev libjpeg-dev libopenexr-dev libtiff-dev libwebp-dev \
    libxvidcore-dev libx264-dev ffmpeg \
    libatlas-base-dev gfortran \
    && git clone https://github.com/opencv/opencv.git \
    && git clone https://github.com/opencv/opencv_contrib.git \
    && cd ~/opencv && mkdir build && cd build \
    && cmake \
        -D CMAKE_BUILD_TYPE=RelWithDebInfo \
        ## 这里会有一个问题,我这里CMAKE_INSTALL_PREFIX明明写的是/usr/local,但是可能安装的时候安装到opencv4里面去了,需要执行以下操作
        ## 在/usr/local/lib/pkgconfig/opencv4.pc将.../include/opencv4改成.../include
        ## ln -s /usr/local/include/opencv4 /usr/local/include/opencv2
        -D CMAKE_INSTALL_PREFIX=/usr/local \
        -D INSTALL_PYTHON_EXAMPLES=OFF \
        -D INSTALL_C_EXAMPLES=OFF \
        -D BUILD_DOCS=OFF \
        -D BUILD_PERF_TESTS=OFF \
        -D BUILD_TESTS=OFF \
        -D BUILD_PACKAGE=OFF \
        -D BUILD_EXAMPLES=OFF \
        -D WITH_TBB=ON \
        -D ENABLE_FAST_MATH=1 \
        -D CUDA_FAST_MATH=1 \
        -D WITH_CUDA=ON \
        -D WITH_CUBLAS=ON \
        -D WITH_CUFFT=ON \
        -D WITH_NVCUVID=ON \
        -D WITH_IPP=OFF \
        -D WITH_V4L=ON \
        -D WITH_1394=OFF \
        -D WITH_GTK=ON \
        -D WITH_QT=OFF \
        -D WITH_OPENGL=ON \
        -D WITH_EIGEN=ON \
        -D WITH_FFMPEG=ON \
        -D WITH_GSTREAMER=ON \
        -D BUILD_JAVA=OFF \
        ## 不启用python支持,因为没有进行交叉编译的需要
        -D BUILD_opencv_python3=OFF \ 
        -D BUILD_opencv_python2=OFF \
        -D BUILD_NEW_PYTHON_SUPPORT=OFF \
        -D OPENCV_SKIP_PYTHON_LOADER=OFF \
        ## 不启用python支持
        -D OPENCV_GENERATE_PKGCONFIG=ON \
        -D OPENCV_ENABLE_NONFREE=ON \
        -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \
        -D WITH_CUDNN=ON \
        -D OPENCV_DNN_CUDA=ON \
        ## 7.5:10系显卡支持  8.9:40系显卡支持
        -D CUDA_ARCH_BIN="7.5,8.9" \
        # -D CUDA_ARCH_PTX=8.6 \
        ## 不启用python支持
        # -D CUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-11.7/ \
        # -D PYTHON_DEFAULT_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \
        # -D PYTHON3_EXECUTABLE=$(python3 -c "import sys; print(sys.executable)") \
        # -D PYTHON3_NUMPY_INCLUDE_DIRS=$(python3 -c "import numpy; print (numpy.get_include())") \
        # -D PYTHON3_PACKAGES_PATH=$(python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") \
         .. \
         && make -j"$(nproc)" && make install \
         && mv /usr/local/include/opencv4/opencv2/* /usr/local/include/ \
         && touch /etc/ld.so.conf.d/opencv.conf && echo "/usr/local/lib" >> /etc/ld.so.conf.d/opencv.conf  \
         && ldconfig && echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig" >> /etc/bash.bashrc \
         && echo "export PKG_CONFIG_PATH" >> /etc/bash.bashrc && source ~/.bashrc
EXPOSE 22
# 启动ssh

我也将配置好的docker镜像传至DockerHub上,这里也提供相关链接:

https://hub.docker.com/repository/docker/heene/cuda11.8-pytorch-opencv-cpp-nvim/general

使用方法

  1. 打开Docker Desktop(在Windows环境下,请确保WSL2以开启,并安装Docker Desktop 1.9以上的版本以支持GPU)
  2. 下载镜像:docker push heene/cuda11.8-pytorch-opencv-cpp-nvim:tagname 这里的tagname 改成我仓库里面有的标签。
  3. 启动容器:docker run -it -p 8011:22 --rm -v E:\projects:/root/projects images_name bash
  4. 手动打开ssh(原因是在写这篇文字的时候我还没有将启动ssd服务器的命令加到CMD里面):/usr/sbin/sshd -D
  5. 使用任意一个终端软件连接上容器,我这里使用的是tabby terminal,它可以选择自动连接上本机的容器,或者你也可以使用ssh连接:ssh root@localhost -p 8011 密码为123456
  6. Enjoy! nvim的配置文件在~/.config/nvim目录中

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇