把容器打包为镜像再迁移到其他服务器
【没整理好】

docker使用

docker run --name <容器名称> <镜像名称:镜像标签>,也可以添加参数-d表示后台运行。
docker stop <容器ID> 停止容器
docker rm <容器ID> 删除容器
docker ps 查看运行时容器列表
docker ps -a 查看所有容器列表

最朴实的打包方式

我想拉一个ubuntu:latest的镜像,容器化后把我代码和环境配好,最后再转为镜像。

拉取镜像:
因为服务器没网,所以我在自己电脑上pull了ubuntu:latest镜像,然后保存导入到服务器上。
拉取镜像:docker pull ubuntu:latest
把本地镜像保存为一个文件:docker save <镜像ID> > image.tar
把文件传到服务器后导入镜像:docker load < image.tar,然后会返回镜像的ID。
查看本地镜像:docker images
最新的:就是刚刚导入的镜像,可以改名:docker tag <镜像ID> ubuntu:latest

新建和运行容器:
新建:docker run -it --name test ubuntu:latest /bin/bash
-it中i是指交互,t是分配一个伪终端,/bin/bash使得容器保持运行。
如果已经新建好了,就docker exec -it test bash
复制宿主机文件到docker内部:docker cp <宿主机路径> <容器名称或ID>:<容器内部路径>

然后更新和安装一些东西:

apt-get update
apt-get install -y vim curl wget iputils-ping net-tools unzip

curl -LsSf https://astral.sh/uv/install.sh | sh  # 安装uv

shell配置文件.bashrc在/root目录下
普通用户在/home/用户名目录下

打包镜像

官方dockerfile
如何将自己的环境和代码打包成docker镜像
docker打包项目

通过dockerfile打包镜像

docker build -t 镜像名称:镜像标签 . -f <dockerfile路径>
.代表当前目录,可以修改。
镜像标签的意义是标识镜像的版本。

dockerfile写法:
FROM指定基于哪个镜像来构建, 如FROM xxxx
EXPOSE指定镜像内服务对外提供的端口号,如EXPOSE 8080
WORKDIR设定镜像的工作目录,后面的命令都基于这个目录,如WORKDIR /app
COPY可以从宿主机目录复制文件到容器内的指定目录,如COPY . /app
CMD设置容器启动后默认执行的命令,中括号数组形式,和vscode的launch.json的args写法类似。
ENV设置环境变量

注意点!

  1. 不要在Dockfile里做mv操作!mv操作会添加镜像大小。
  2. 不要单独RUN chown COPY过来的文件。COPY操作的时候直接chown会更好。参考

示例:

FROM ubuntu:latest

RUN apt-get update
RUN apt-get install -y vim curl wget iputils-ping net-tools unzip xz-utils libaio1t64 libnuma-dev
RUN ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/libaio.so.1

# 设置工作目录 用户ubuntu目录下 设置用户权限
USER ubuntu
WORKDIR /home/ubuntu
RUN chown -R ubuntu /home/ubuntu
RUN mkdir packages

# 复制数据
COPY packages /home/ubuntu/packages
# 安装软件的目录
RUN mkdir programs

# 安装neo4j (安装java) ########################################
RUN tar -zxf packages/neo4j/jdk-17_linux-x64_bin.tar.gz -C programs
ENV JAVA_HOME=/home/ubuntu/programs/jdk-17.0.7
ENV CLASSPATH=$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME
RUN tar -zxf packages/neo4j/neo4j-community-5.22.0-unix.tar.gz -C programs
ENV NEO4J_HOME=/home/ubuntu/programs/neo4j-community-5.22.0
ENV PATH=$JAVA_HOME/bin:$NEO4J_HOME/bin:$PATH
RUN cp packages/neo4j/apoc-5.22.0-core.jar $NEO4J_HOME/plugins/apoc-5.22.0-core.jar
# 加载数据
RUN neo4j-admin database load --from-path packages/neo4j/backup_complex neo4j2
# 修改conf文件,切换数据库+配置插件
RUN sed -i '1i initial.dbms.default_database=neo4j2' $NEO4J_HOME/conf/neo4j.conf
RUN sed -i '1i dbms.security.procedures.unrestricted=apoc.*,algo.*' $NEO4J_HOME/conf/neo4j.conf


# 安装elasticsearch ########################################
RUN tar -zxf packages/elasticsearch/elasticsearch-8.17.3-linux-x86_64.tar.gz -C programs
ENV ES_HOME=/home/ubuntu/programs/elasticsearch-8.17.3
ENV PATH=$ES_HOME/bin:$PATH
# 配置ES内部的jdk
RUN sed -i '1a export JAVA_HOME=$ES_HOME/jdk' $ES_HOME/bin/elasticsearch
RUN sed -i '2a export CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tool.jar' $ES_HOME/bin/elasticsearch
RUN sed -i '3a export PATH=$JAVA_HOME/bin:$PATH' $ES_HOME/bin/elasticsearch
# 安装分词器
RUN unzip packages/elasticsearch/elasticsearch-analysis-ik-8.17.3.zip -d $ES_HOME/plugins/ik


# 安装mysql ########################################
RUN tar -xf packages/mysql/mysql-8.4.5-linux-glibc2.28-x86_64.tar.xz -C programs
ENV MYSQL_HOME=/home/ubuntu/programs/mysql-8.4.5-linux-glibc2.28-x86_64
ENV PATH=$MYSQL_HOME/bin:$PATH
RUN cp packages/mysql/my.cnf $MYSQL_HOME/my.cnf
RUN mysqld --defaults-file=$MYSQL_HOME/my.cnf --initialize-insecure --user=ubuntu

# 安装UV
RUN mkdir cache
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
ENV UV_CACHE_DIR=/home/ubuntu/cache/uv/download
ENV UV_PYTHON_INSTALL_DIR=/home/ubuntu/cache/uv/install
ENV UV_LINK_MODE=hardlink
ENV PATH=/home/ubuntu/.local/bin/:$PATH


RUN mkdir project
RUN cp -r packages/military project/military
RUN cp -r packages/resources project/resources
RUN mkdir project/models


WORKDIR /home/ubuntu/project/military
RUN uv venv --python=python3.11.7
RUN uv sync
RUN uv pip install lotus-ai
RUN uv pip install urllib3==1.25.11
RUN . .venv/bin/activate
ENV PATH=/home/ubuntu/project/military/.venv/bin:$PATH

USER root
把运行时容器打包为镜像:commit

把一个运行中的容器的当前状态打包为一个镜像:commit命令
docker commit <容器id|容器名称> 镜像名称:镜像标签

容器和宿主机交互

文件挂载

参数-v <宿主机目录>:<docker目录>

注意-v参数要在镜像前面。
参考:

docker run -it --name test3 -v /data1/ztshao/pretrained_models:/home/ubuntu/programs military:v3  /bin/bash 
容器内部访问宿主机API

端口映射
参考1
参考2
参考3

比如访问ollama接口,本来是http://localhost:11434/v1

第一步,确认宿主机ip
首先,查找宿主机在 Docker 网络中的 IP 地址。可以在外部操作docker network inspect bridge,查找里面的IPAM->Config->Gateway字段。

简单测试,比如我的宿主机ip是172.17.0.1
docker容器上测试能否访问宿主机:ping 172.17.0.1
宿主机上的ollama测试:curl http://localhost:11434
docker容器上的ollama测试:curl http://172.17.0.1:11434

第二步,确认宿主机监听端口
查看宿主机ollama监听端口ipnetstat -tlnp | grep 11434,输出结果:

tcp6       0      127.0.0.1:11434                :::*                    LISTEN      3864287/ollama

可以发现监听ip是127.0.0.1,但是docker链接的宿主机ip是172.17.0.1,所以要把监听ip改成0.0.0.0,(127.0.0.1是个环回地址,是IP,并不表示“本机”,0.0.0.0才是真正表示网路中的本地)

因此需要修改ip。
官方有ollama作为systemd service运行的ip修改做法
但是因为我ollama不是作为systemd service运行,所以可以直接添加环境变量:export OLLAMA_HOST=0.0.0.0:11434即可。

然后就可以正常测试了:curl http://172.17.0.1:11434

同理
neo4j:
修改安装目录的conf/neo4j.conf,添加监听地址dbms.default_listen_address=0.0.0.0

elasticsearch:
在安装目录的config/elasticsearch.yml中添加配置http.host:0.0.0.0

mysql:
在安装目录的my.cnf的[mysqld]中添加配置bind-address=0.0.0.0
此外,由于mysql有用户限制,处理更麻烦一点,参考。

mysql -uroot 
use mysql;
select user, host from mysql;
update user set host = '%' where user = 'root';

litellm
如果要访问ollama接口,要配置环境变量OLLAMA_API_BASE=http://172.17.0.1:11434

可能的问题

不能显示中文

比如sql新建table不能加中文
https://loesspie.com/2018/03/15/docker-chinese-error/
https://blog.csdn.net/weixin_44455388/article/details/109092222
解决1(dockerfile):
dockerfile里加一行ENV LANG C.UTF-8
解决2(命令行):

export LANG=C.utf8
export LC_ALL=C.utf8

代码环境分离docker

记录:

第一步、安装软件和环境的代码:注意都要在/home/ubuntu/datas路径下,不能改。因为有些配置这个路径写死了。
注意 elasticsearch和mysql需要ubuntu全选,uv需要root权限。代码真实测试需要换到ubuntu。

FROM ubuntu:latest
ENV LANG C.UTF-8

RUN apt-get update
RUN apt-get install -y vim curl wget iputils-ping net-tools unzip xz-utils libaio1t64 libnuma-dev libncurses6
RUN ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/libaio.so.1

# COPY Program Data
RUN mkdir /home/ubuntu/datas
RUN mkdir /home/ubuntu/datas/resources /home/ubuntu/datas/programs
COPY --chown=ubuntu resources /home/ubuntu/datas/resources
ENV RESOURCE_PATH=/home/ubuntu/datas/resources

# INSTALL neo4j & java########################################
RUN tar -zxf $RESOURCE_PATH/neo4j/jdk-17_linux-x64_bin.tar.gz -C /home/ubuntu/datas/programs
ENV JAVA_HOME=/home/ubuntu/datas/programs/jdk-17.0.7
ENV CLASSPATH=$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME
RUN tar -zxf $RESOURCE_PATH/neo4j/neo4j-community-5.22.0-unix.tar.gz -C /home/ubuntu/datas/programs
ENV NEO4J_HOME=/home/ubuntu/datas/programs/neo4j-community-5.22.0
ENV PATH=$JAVA_HOME/bin:$NEO4J_HOME/bin:$PATH
RUN cp $RESOURCE_PATH/neo4j/apoc-5.22.0-core.jar $NEO4J_HOME/plugins/apoc-5.22.0-core.jar
# Modify .conf Swith database & plugin
RUN sed -i '1i initial.dbms.default_database=neo4j2' $NEO4J_HOME/conf/neo4j.conf
RUN sed -i '1i dbms.security.procedures.unrestricted=apoc.*,algo.*' $NEO4J_HOME/conf/neo4j.conf

# INSTALL elasticsearch ########################################
RUN tar -zxf $RESOURCE_PATH/es_docs/elasticsearch-8.17.3-linux-x86_64.tar.gz -C /home/ubuntu/datas/programs
ENV ES_HOME=/home/ubuntu/datas/programs/elasticsearch-8.17.3
ENV PATH=$ES_HOME/bin:$PATH
# INSTALL jdk in ES
RUN sed -i '1a export JAVA_HOME=$ES_HOME/jdk' $ES_HOME/bin/elasticsearch
RUN sed -i '2a export CLASSPATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tool.jar' $ES_HOME/bin/elasticsearch
RUN sed -i '3a export PATH=$JAVA_HOME/bin:$PATH' $ES_HOME/bin/elasticsearch
# INSTALL tokenizer
RUN unzip $RESOURCE_PATH/es_docs/elasticsearch-analysis-ik-8.17.3.zip -d $ES_HOME/plugins/ik


# INSTALL mysql ########################################
RUN tar -xf $RESOURCE_PATH/mysql/mysql-8.4.5-linux-glibc2.28-x86_64.tar.xz -C /home/ubuntu/datas/programs
ENV MYSQL_HOME=/home/ubuntu/datas/programs/mysql-8.4.5-linux-glibc2.28-x86_64
ENV PATH=$MYSQL_HOME/bin:$PATH
RUN cp $RESOURCE_PATH/mysql/my.cnf $MYSQL_HOME/my.cnf
RUN chown -R ubuntu:ubuntu /home/ubuntu/datas/programs
USER ubuntu
RUN mysqld --defaults-file=$MYSQL_HOME/my.cnf --initialize-insecure --user=ubuntu --basedir=$MYSQL_HOME --datadir=$MYSQL_HOME/data

USER root

# INSTALL UV
RUN curl -LsSf https://astral.sh/uv/install.sh | sh
ENV UV_CACHE_DIR=/home/ubuntu/datas/programs/uv/download
ENV UV_PYTHON_INSTALL_DIR=/home/ubuntu/datas/programs/uv/install
ENV UV_LINK_MODE=hardlink
ENV PATH=/root/.local/bin/:$PATH


WORKDIR /home/ubuntu/datas/military
COPY --chown=ubuntu pyproject.toml /home/ubuntu/datas/military/pyproject.toml
COPY --chown=ubuntu deploy_start.sh /home/ubuntu/datas/military/deploy_start.sh
COPY --chown=ubuntu deploy_stop.sh /home/ubuntu/datas/military/deploy_stop.sh
RUN uv venv --python=python3.11.7
RUN uv sync
RUN uv pip install lotus-ai
RUN uv pip install urllib3==1.25.11
RUN . .venv/bin/activate
ENV PATH=/home/ubuntu/datas/military/.venv/bin:$PATH
RUN chown -R ubuntu:ubuntu /home/ubuntu/datas/military

第二步、打包:

docker build -t env:v4 . -f env_file

打包好后查看镜像id
在这里插入图片描述

第三步、测试镜像:

docker run -it --name tst_env_v4_2 env:v4 /bin/bash
-it中i是指交互,t是分配一个伪终端,/bin/bash使得容器保持运行。
如果已经新建好了,就docker exec -it tst_env_v2 bash
复制宿主机文件到docker内部:docker cp <宿主机路径> <容器名称或ID>:<容器内部路径>

第四步、保存镜像:

docker save <镜像ID> > image_env_v4.tar

比如docker save 0626f6deb74c > image_env_v4.tar
然后进行漫长的镜像保存!

我在00:24的时候开始保存的。00:42、1:43完成了

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐