• dockerfile避坑笔记(VMWare下使用Ubuntu在Ubuntu20.04基础镜像下docker打包多个go项目)


    一、docker简介

    docker是一种方便跨平台迁移应用的程序,通过docker可以实现在同一类操作系统中,如Ubuntu和RedHat两个linux操作系统中,实现程序的跨平台部署。比如我在Ubuntu中打包了一个go项目的docker镜像(镜像为二进制文件,相当于windows中的exe文件),这个镜像可以直接在另一台Ubuntu上运行,而无需再次配运行环境。下面这张图是我对docker的理解。
    原始程序迁移方式在这里插入图片描述
    docker镜像迁移方式
    在这里插入图片描述

    二、dockerfile编写

    将项目打包为docker镜像通过编写dockerfile来实现,dockerfile的写法类似于shell编程。
    PS:最终的dockerfile不易过长(但是调试时可以多些RUN,这样可以减少重复编译,提高调试速度),因为每个语句都会被编译为一个镜像,然后commit到一起形成一个最终的镜像。
    其基本的结构如下:

    FROM ***(指定基础镜像,即这个镜像在哪个操作系统下面运行)
    #示例:FROM  Ubuntu:20.04
    
    MAINTAINER ***(指定维护者信息,选填)
    #示例:MAINTAINER Tom
    
    LABEL ***(docker build的启动入口,可以不写)
    #示例:LABEL helloworld
    
    RUN ***(docker build时需要执行的命令,为shell指令)
    #RUN git clone github.com/xxxx.git
    
    ADD/COPY ***(将宿主机的文件拷贝到目标镜像中,ADD会自动解压,COPY不会)
    #示例:COPY 	. .
    #前一个目录为当前文件夹下的相对路径,后一个文件为dockerfile镜像中的路径
    
    WORKDIR ***(设置当前工作目录,相当于进入容器后在哪个目录里面)
    
    
    VOLUME ***(存放文件的地方,也叫挂载主机目录,分布式存储中使用)
    
    EXPOSE ***(指定对外的端口)
    
    CMD ***(指定容器启动后要做的事情)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    打包镜像:

    docker build -t demo/go-hello:1.0 -f dockerfile .
    #docker build为固定写法,-t表示生成目标镜像的名字以及版本号 -f表示dockerfile文件的名称,
    #最后的‘.’表示当前目录下构建docker
    
    • 1
    • 2
    • 3

    构建运行容器:

    docker run  -it -p xxx:xxx
    #-i 以交互模式运行,-t 为容器分配一个命令行
    #-p 容器端口映射到主机端口的模式
    
    
    • 1
    • 2
    • 3
    • 4

    三、docker build原理

    完成dockerfile后,需要运行docker build命令来执行程序。
    docker build的执行过程如下:

    1.将上下文打包发送到docker的守护进程

    2.docker build 命令向docker server 发送http请求,请求包含上下文信息。

    3.docker server开始构建镜像:
    ①创建一个临时目录,将上下文中的内容解压到临时目录下,然后读取dockerfile中的指令。
    ②将执行分发到不同的模块进行操作,为每一条指令构造一个临时容器并执行,执行完毕后commit。
    ③将所有commit的镜像合并,得到最终的镜像。

    这里需要注意,docker build会将当前文件下的所有文件发送到docker server,如果有些文件在docker过程中并不需要,可以在当前目录下创建忽略 .dockerignore 文件,并写入忽略文件的文件名。

    docker避坑笔记

    调试背景

    我在windows10下安装VMWare,WMware中安装了Ubuntu20.04,并使用桥接模式连接的windows10主机。(说明虚拟机与主机的IP地址互相独立,Ubuntu无法通过127.0.0.1访问Windos10),同时在Ubuntu20.04基础镜像下打包golang项目的镜像。

    问题1:docker build运行dockerfile报错,E: Unable to locate package xxx

    这里报错有很多原因,大概可以归为以下几类:
    1、当前的apt-get不是最新版,所以无法找到这个库
    解决方案,运行apt-get update

    apt-get update
    
    • 1

    2、使用上述方法后,仍然报错,可能就是真的没这个包,或者这个包在外网下载,国内无法访问或访问速度过慢。这里采用换源的方法,看看能不能解决。
    解决方案:在dockerfile中加入

    RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
    
    • 1

    问题2:dockerfile安装golang时报错,显示Do you want to continue? [Y/n] Abort.

    dockerfile运行过程中,无法接受用户的输入,但是有些软件包的安装过程需要用户进行交互,所以会出现问题。
    解决方案:在dockerfile中加入下面两句话:

    ENV DEBIAN_FRONTEND=noninteractive #关闭交互功能
    
    apt-get install -y xxx #-y表示所有的交互都是选择默认的选项,xxx为需要安装的包名
    
    • 1
    • 2
    • 3

    问题3:dockerfile运行apt-get install golang时报错,显示Undefined:any

    开发环境为golang1.21.3,但是是用apt-get install golang默认下载的版本小于golang1.18,,而any关键字是golang1.18以后才引入的关键字,所以会没法编译。
    解决方案:不使用apt-get install golang安装,更换下面的方式

    #指定版本安装golang
    RUN apt-get update && apt-get install -y wget && \
        wget https://mirrors.aliyun.com/golang/go1.21.3.linux-amd64.tar.gz && \
        tar -C /usr/local -xzf go1.21.3.linux-amd64.tar.gz && \
        rm go1.21.3.linux-amd64.tar.gz
    
    # 设置Go的环境变量
    ENV PATH=$PATH:/usr/local/go/bin
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    问题4:开启容器后,使用Ubuntu访问容器端口,发现连接被重置(等于容器的端口连不上)。

    这里涉及到了2个知识,
    第一个知识是,容器默认的网络模式是桥接,即容器内部具有独立的IP地址,通过0.0.0.0IP对外提供服务。所以,如果程序内部原来通过127.0.0.1:8888的方式对其他容器或者主机提供服务,那么需要改为0.0.0.0:8888。如果主机想要通过127.0.0.1::8888访问容器,需要更改docker run语句如下:

    docker run -d -p 127.0.0.1:8888:8888 <image_name>
    
    • 1

    这里说明了端口映射,将容器的0.0.0.0::8888端口映射到主机的127.0.0.1:8888端口。
    第二个知识是防火墙有可能会拦截请求,最好把Ubuntu的防火墙关了。

    #关闭防火墙服务
    sudo systemctl stop ufw.service
    
    #检查防护墙服务是否关闭
    sudo ufw status
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我试了前面两个办法都不行,只能上大招,重启容器的网卡服务。

    systemctl stop docker # 停止docker 服务
    pkill docker # 杀掉docker进程
    iptables -t nat -F # 清理iptables
    ip link set docker0 down # 停止docker0网卡
    brctl delbr docker0 # 删除docker0网卡--重点!
    systemctl start docker # 启动docker服务
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    问题5:上述方法可以实现容器与主机的通信,但是容器之间的通信还需要获取到容器的IP地址才可以实现

    但是我在本地编写的代码,都是用的127.0.0.1:xxxx的格式进行通讯,现在突然要换为容器的IP地址进行通讯,又需要更改代码,所以我采用了其他方式,将容器的网络模式更换为host模型,即与主机共享同一个IP空间。

    最终的dockerfile

    # 使用指定的基础镜像
    FROM ubuntu:20.04
    
    ENV DEBIAN_FRONTEND=noninteractive
    
    # 换为清华源
    # RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
    
    RUN apt-get update && apt-get install -y gcc git
    
    RUN apt-get update && apt-get install -y wget && \
        wget https://mirrors.aliyun.com/golang/go1.21.3.linux-amd64.tar.gz && \
        tar -C /usr/local -xzf go1.21.3.linux-amd64.tar.gz && \
        rm go1.21.3.linux-amd64.tar.gz
    
    # 设置Go的环境变量
    ENV PATH=$PATH:/usr/local/go/bin
    
    # 创建工作目录并拷贝你的 Go 项目代码到容器中
    WORKDIR /Cache
    COPY . /Cache
    
    # 构建Go项目
    RUN go build -o server2
    
    # 暴露应用程序所使用的端口
    EXPOSE 9528
    EXPOSE 8766
    
    # 定义容器启动命令,这里假设你的Go项目生成了一个名为server1的可执行文件
    CMD ["./server2"]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    最终的docker-compose.yml

    version: '3'
    
    services:
      service1:
        build: ./server1
        network_mode: "host"
    
      service2:
        build: ./server2
        network_mode: "host"
    
      service3:
        build: ./server3
        network_mode: "host"
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 相关阅读:
    【Jetson Nano】jetson nano一些基本功能命令
    【定时功能】消息的定时发送-基于RocketMQ
    国际减灾日 | 智慧减灾——百分点科技的数据科学视角
    Flink CEP(复杂事件处理)高级进阶
    数字化转型加快,低代码平台优势凸显
    用于交通事件前检测的实时视频监控系统
    2022年最新西藏建筑八大员(机械员)模拟考试题库及答案
    [小记]shell获取git最近一次提交信息
    u盘中删除的文件怎样才能恢复呢?
    包租团队怎样应用科技虚拟员工100%保证数据处理结果准确
  • 原文地址:https://blog.csdn.net/qq_45931661/article/details/134190127