V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
slove
V2EX  ›  Docker

自学 docker,自己写的 Dockerfile 语法编译通过不了,有哪些错误,请前辈指正

  •  
  •   slove · 2022-12-06 14:01:54 +08:00 via iPhone · 2803 次点击
    这是一个创建于 498 天前的主题,其中的信息可能已经有所发展或是发生改变。
    #基于 ubuntu 最新版镜像
    FROM ubuntu:latest
    #更新安装包列表
    RUN apt update
    #安装 apache2
    RUN apt install apache2
    #安装 mysql-server
    RUN apt install mysql-server
    #启动 mysql
    RUN service mysql start
    #登陆 mysql
    RUN mysql
    #修改 root 密码
    RUN alter user “root”@“localhost” identified with mysql_native_password by “12345”;
    #root 密码生效
    RUN flush privileges ;
    #新建数据库
    RUN create database wordoress ;
    #新建用户
    RUN create user “solve”@“localhost” identufied by “888888”;
    #配置数据库用户
    RUN grant all on wordpress.* to “slove”@“localhost” with grant option ;
    #配置生效
    RUN flush privileges ;
    #退出数据库
    RUN exit
    #下载 wordpress 最新版到指定 /var/www/html/
    ADD https://cn.wordpress.org/latest-zh_CN.tar.gz /var/www/html
    #开放端口号
    EXPOSE 80
    CMD
    38 条回复    2023-03-02 15:49:45 +08:00
    caocong
        1
    caocong  
       2022-12-06 14:03:14 +08:00
    ubuntu:latest

    ubuntu:latest
    slove
        2
    slove  
    OP
       2022-12-06 14:04:44 +08:00 via iPhone
    @caocong 英文标点符号我知道,这份是我手机打的
    lxzxl
        3
    lxzxl  
       2022-12-06 14:14:00 +08:00
    RUN alter user “root”@“localhost” identified with mysql_native_password by “12345”;

    你是想 shell 里面跑 sql?
    slove
        4
    slove  
    OP
       2022-12-06 14:24:07 +08:00 via iPhone
    @lxzxl 是的,不可以使用 mysql 语句吗
    lxzxl
        5
    lxzxl  
       2022-12-06 14:38:20 +08:00
    @slove #4 换个问法,你是想 bash 里面执行 sql?
    slove
        6
    slove  
    OP
       2022-12-06 14:46:21 +08:00 via iPhone
    @lxzxl 你的问法我理解,我在主机上敲 mysql ,直接进入 mysql ,所以可以执行 sql 语法,直到敲下 exit ,才算退出 mysql
    Dockerfile RUN mysql ,我理解就是在主机中启动 mysql ,然后进入数据库,后面的 sql 语句应该也是在数据库中执行,如果不是这样的,那 sql 语法应该写在哪里
    iyour
        7
    iyour  
       2022-12-06 14:46:25 +08:00
    用 chatgpt 试了一下,仅供参考
    [![ChatGPTaa6dca183f7b22f3.md.png]( https://img.picgo.net/2022/12/06/ChatGPTaa6dca183f7b22f3.md.png)]( https://www.picgo.net/image/Ul2mJ)
    kaedeair
        8
    kaedeair  
       2022-12-06 14:51:55 +08:00
    bash 里用 mysql 命令可以 RUN mysql < cmd1;cmd2;cmd3; 大概是这么做我没试过,也可能是 bash -c ""这种
    OP 的这种情景一般有两种变通方法
    1.用 docker-compose 拉别人的镜像组成服务群,加入环境变量来配置
    2.写一个 EntryPoint 脚本去判断是不是第一次运行
    Puteulanus
        9
    Puteulanus  
       2022-12-06 14:54:32 +08:00
    chloerei
        10
    chloerei  
       2022-12-06 14:54:37 +08:00   ❤️ 1
    @slove RUN 一条命令之后,相当于退出 shell ,下一条 RUN 是打开另一个 shell ,不会保留同一个会话。

    要执行 mysql 命令可以这样:

    ```
    RUN mysql -e "SQL"
    ```

    但是不建议这样做,容器内容是固化的,持久化数据应该放在 volume 。对应数据库就是它的 data 目录要挂到 volume ,这样在 dockerfile 里面执行的 sql 语句会被清空。

    而且不建议一个容器启动多个服务进程。

    建议先学习 docker 的基本概念,它不是虚拟机。
    slove
        11
    slove  
    OP
       2022-12-06 14:55:25 +08:00 via iPhone
    @iyour 我回头试下,感谢
    Mindzy
        12
    Mindzy  
       2022-12-06 14:57:44 +08:00
    建议所有 SQL 指令用 ENTRYPOINT 运行个 sh 执行
    hefish
        13
    hefish  
       2022-12-06 14:58:52 +08:00   ❤️ 3
    这个不应该从 ubuntu:latest 开始构建。
    个人认为 docker 和微服务是相辅相成的。 相应的应用,也应该微服务化。OP 的这些应用至少可以分成三个服务。
    一个 mysql 服务,一个 php-fpm+httpd 服务。分两个容器跑,相互调用。 而不是在一个容器里跑三个服务。

    mysql 的服务,可以基于 mysql:8 来构建,具体可以参考 hub.docker.com 上的文档,用环境变量来指定默认的 root 密码。
    php-fpm 和 httpd 服务,可以基于 ubuntu:latest ,但容器里不能把进程跑在后台,要跑在前台,否则容器会自动退出。所以一般我喜欢是用 nginx 作 httpd ,然后用 supervised 来管理 php-fpm 和 nginx 两个服务,具体可以查询 supervised 相应的用法,配置文件还是比较简单的。

    做好容器之后,具体的应用数据,应该是在创建容器的时候,挂到容器里去,这样在容器销毁之后,数据可以保留下来。

    大致先讲这么多。
    starqoq
        14
    starqoq  
       2022-12-06 15:01:56 +08:00   ❤️ 1
    1. Always combine RUN apt-get update with apt-get install in the same RUN statement.
    Best practices for writing Dockerfiles
    https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

    For example:
    RUN apt-get update && apt-get install -y \
    package-bar \
    package-baz \
    package-foo \
    && rm -rf /var/lib/apt/lists/*
    Using apt-get update alone in a RUN statement causes caching issues and subsequent apt-get install instructions fail.

    2. 数据库应该和 docker layout 分开,新建用户之类的操作,应该在 enterpoint.sh 里面进行

    3. 如果你真的特别想在 mysql 里面执行应该这样
    RUN echo "CMD1 \n CMD2\n CMD3\n" | mysql
    把 CMD1~3 发送到 mysql 的输入里执行

    RUN 命令是执行 elf 而不是在终端里输入然后回车。你可以认为每句话都在一个新的终端里执行
    slove
        15
    slove  
    OP
       2022-12-06 15:03:32 +08:00 via iPhone
    @kaedeair 感觉你说的应该可以执行,我回头测试下
    slove
        16
    slove  
    OP
       2022-12-06 15:08:26 +08:00 via iPhone
    @Mindzy 自学的 docker ,对 Dockerfile 的语法理解还是不透彻,我看网上很多把 sql 语句单独写一个文件,回头参考下别人的 Dockerfile
    javalaw2010
        17
    javalaw2010  
       2022-12-06 15:10:10 +08:00
    添加一个环境变量,ENV DEBIAN_FRONTEND=noninteractive 以避免软件安装过程中的交互出现,apt 安装的时候添加-y 参数,同样为了避免交互安装时出现交互。安装包控制镜像大小的一些小技巧前面的大佬们说过了,当然如果你不希望 DEBIAN_FRONTEND 在容器运行时也存在的话,可以 RUN DEBIAN_FRONTEND=noninteractive apt install -y XXX 。此外 ADD 命令并不会自动解压缩远程的压缩包,你得手动解压一下,至于 mysql 的问题,前面各位大佬也都说过了
    slove
        18
    slove  
    OP
       2022-12-06 15:11:03 +08:00 via iPhone
    @hefish 讲的很细了,感谢
    zhenrong
        19
    zhenrong  
       2022-12-06 15:11:55 +08:00
    用这个校验: https://www.fromlatest.io
    wunonglin
        20
    wunonglin  
       2022-12-06 15:12:11 +08:00
    这是把 docker 当虚拟机用了呀
    lxzxl
        21
    lxzxl  
       2022-12-06 15:13:44 +08:00
    slove
        22
    slove  
    OP
       2022-12-06 15:13:50 +08:00 via iPhone
    @Puteulanus
    a | b ,a 执行完结果扔给 b 执行,不知道我理解的对不对
    deplivesb
        23
    deplivesb  
       2022-12-06 15:31:48 +08:00
    你这个真把 docker 当成虚拟机用了,启动一个 ubuntu 系统,安装一个 Apache 再安装一个 MySQL ,你这个干啥呢?
    slove
        24
    slove  
    OP
       2022-12-06 15:33:25 +08:00 via iPhone
    @starqoq 感谢,虽然你说的很多不理解,感觉是大佬
    @zhenrong 感谢
    @wunonglin 学习环境,玩坏了,就直接删除,挺方便的
    @lxzxl 我再认真看文档去,感谢

    感谢以上所有人的回复,谢谢
    slove
        25
    slove  
    OP
       2022-12-06 15:34:36 +08:00 via iPhone
    @deplivesb 装个学习环境,玩坏了,就直接删库跑路,不会被抓,哈哈
    dier
        26
    dier  
       2022-12-06 16:35:03 +08:00   ❤️ 3
    你这个误区有点多,我一时不知道从哪讲起。既然你说想练习 Dockerfile 语法,那我先从 Docker 的理解说起
    Docker 推荐一个容器只运行一个服务,例如你这个环境的最优做法是 MySQL 服务构建一个镜像,Apache 服务再构建一个镜像。
    原因就是容器在运行时必须要有一个主服务进程在前台持续运行,一般建议这个进程就是容器要运行的服务进程。当这个服务的进程停止时,容器会以为这个服务运行结束,容器则结束运行退出。
    如果你在一个容器里运行了多个服务,比如 MySQL 和 Apache ,你以其中一个服务为主服务使其在前台运行,如果另外一个服务意外终止了,你排查时会发现这个容器的状态还是运行状态。就没办法从容器的状态直接判断出来服务是否正常(简单的比喻就是你明明结束了 MySQL 的进程,但用其它命令查看 MySQL 端口发现它还在监听,你觉得是还在运行还是已经结束了?)。因为容器在运行时,你从外部是不容易观察到容器内的运行情况。

    再说 Dockerfile;
    用再说 Dockerfile 构建镜像时,Dockerfile 中的每个以大写开头的 FROM\RUN\ADD\COPY\CMD 都会像是一层饼,如果你要通过 RUN 做一些操作,就尽量写在这一个 RUN 下,以减少镜像的层数,同时也能防止一个镜像最后体积变得很大。
    例如:
    ```shell
    RUN apt update && \
    apt install aptech curl bash && \
    rm /tmp/*.gz
    ```
    另外,练习 Dockerfile 可以到 hub.docker.com 上去看看一些服务官方的镜像。基本上都有附 Dockerfile 的 github 的地址。建议先基于官方的 Dockerfile 来改着试试理解怎么写 Dockerfile

    最后,Dockerfile 排错。在使用 docker build 构建时,你每写的一个大写开头的命令都是一层,会从上到下依次执行,如果哪一层有问题,会提示准确的行级信息来供你排查是哪些命令编写有问题。
    hsfzxjy
        27
    hsfzxjy  
       2022-12-06 16:46:06 +08:00 via Android
    建议先学 shell/bash 语法和相关知识,还是基础知识不够

    如果你写成 shell 脚本能跑通,那改成 Dockerfile 基本也可以
    slove
        28
    slove  
    OP
       2022-12-06 16:46:57 +08:00 via iPhone
    @dier 嗯嗯,你的回复对我帮助很大,谢谢
    dev436
        29
    dev436  
       2022-12-06 18:17:49 +08:00
    您好,您给出的 Dockerfile 中存在一些语法错误和书写不规范的问题。我尝试纠正这些问题,并给出修改后的 Dockerfile 内容:
    dev436
        30
    dev436  
       2022-12-06 18:18:04 +08:00
    # 基于 ubuntu 最新版镜像
    FROM ubuntu:latest

    # 更新安装包列表
    RUN apt update

    # 安装 apache2
    RUN apt install -y apache2

    # 安装 mysql-server
    RUN apt install -y mysql-server

    # 启动 mysql
    RUN service mysql start

    # 登录 mysql
    RUN mysql -u root

    # 修改 root 密码
    RUN alter user "root"@"localhost" identified with mysql_native_password by "12345";

    # root 密码生效
    RUN flush privileges;

    # 新建数据库
    RUN create database wordpress;

    # 新建用户
    RUN create user "solve"@"localhost" identified by "888888";

    # 配置数据库用户
    RUN grant all on wordpress.* to "solve"@"localhost" with grant option;

    # 配置生效
    RUN flush privileges;

    # 退出数据库
    RUN exit

    # 下载 wordpress 最新版到指定 /var/www/html/
    ADD https://cn.wordpress.org/latest-zh_CN.tar.gz /var/www/html

    # 开放端口号
    EXPOSE 80

    CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
    slove
        31
    slove  
    OP
       2022-12-06 19:17:07 +08:00
    @dev436 这个语句到# 修改 root 密码 RUN alter user "root"@"localhost" identified with mysql_native_password by "12345";就不行了。二楼说的对,RUN 命令执行完就结束了,sql 命令没在 mysql 里执行,网上搜了下,基本是单独做个 shell 脚本,引入 sql 语句,再执行数据库操作。
    有没有大佬知道单独语句怎么写,这样写不知对不对:RUN /bin/sh -c mysql -uroot <"alter user "root"@"localhost" identified with mysql_native_password by "12345"";
    g001
        32
    g001  
       2022-12-06 20:41:47 +08:00
    FROM ubuntu:latest:您在使用 : 分隔镜像名称和标签时,应该使用英文的冒号而不是中文的冒号。正确的语法应该是 FROM ubuntu:latest 。
    alter user “root”@“localhost”:您在使用字符串时,应该使用英文的双引号而不是中文的双引号。正确的语法应该是 alter user "root"@"localhost"。
    mysql_native_password by “12345”;:您在定义密码时,应该使用英文的双引号而不是中文的双引号。正确的语法应该是 mysql_native_password by "12345"
    slove
        33
    slove  
    OP
       2022-12-06 21:13:26 +08:00
    @g001 中英文是我在车上手机编辑的,主要问题不在这里,我的意思还是在 Dockerfile 里使用 sql 命令创建和修改用户权限
    slove
        34
    slove  
    OP
       2022-12-07 20:54:30 +08:00
    https://ibb.co/t8vMj7b
    https://ibb.co/4tswdv8
    https://ibb.co/WyLyQN7
    我把代码用这种方式重新写了,大佬帮忙看下,可有问题,抱拳感谢
    slove
        37
    slove  
    OP
       2022-12-07 21:14:44 +08:00
    不会贴图
    ---------Dockerfile--------------
    FROM ubuntu:latest
    COPY run.sh /root/test/run.sh
    COPY my.sql /root/test/my.sql
    RUN apt update
    RUN apt install mysql-server -y
    EXPOSE 3306
    CMD ["sh", "/root/test/run.sh"]


    ---------run.sh--------------
    #!bin/bash
    #查看 mysql 运行状态
    echo '1.查看 mysql 服务状态...'
    service mysql status
    echo '2.启动 mysql 服务...'
    service mysql start
    echo '3.导入 sql 命令...'
    mysql < /root/test/my.sql
    echo '4.执行完毕...'
    ---------my.sql--------------
    use mysql;
    #修改 root 密码
    alter user 'root'@'localhost' identified with mysql_native_password by '123456';
    #创建数据库 wordpress
    create database Wordpress;
    #创建用户 slove
    create user 'slove'@'localhost' identified by '888888';
    #设置 wordpress 数据库用户
    grant all on wordpress.* to 'slove'@'localhost' with grant option;
    #配置生效
    flush privileges;
    qq296015668
        38
    qq296015668  
       2023-03-02 15:49:45 +08:00
    简单的看了下,按照 op 给出的部分代码,简单的给出大致样本,但是有几个问题需要解决
    1. `service mysql start` 这条命令无法在构建是启动
    2. 缺少 `php` 依赖,就算构建成功也无法访问 wordpress
    3. 就算补全了 `php` 相关依赖,apache2 也缺少配置

    总之,只能给出一个大致的样本供参考。另外 `wordpress` 有 [官方镜像]( https://hub.docker.com/_/wordpress)


    ```Dockerfile

    FROM ubuntu:22.04

    ARG MYSQL_ROOT_PASSWORD 12345
    ARG DB_PASSWORD 888888

    ARG DEPENDENCIES=" \
    apache2 \
    mysql-server \
    wget"

    RUN apt-get update && \
    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    apt-get install -y --no-install-recommends ${DEPENDENCIES} && \
    rm -rf /var/lib/apt/lists/*

    RUN service mysql start # 无法执行成功

    RUN mysql -uroot -e "\
    create database wordoress; \
    create user 'solve'@'localhost' identufied by '${DB_PASSWORD}'; \
    grant all on wordoress.* to 'solve'@'localhost'; \
    alter user 'root'@'localhost' identified with mysql_native_password by '${MYSQL_ROOT_PASSWORD}'; \
    flush privileges;"

    WORKDIR /var/www/html
    RUN wget https://cn.wordpress.org/latest-zh_CN.tar.gz && \
    tar -xf latest-zh_CN.tar.gz \
    rm -f latest-zh_CN.tar.gz

    EXPOSE 80
    CMD ["/bin/bash"]
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4388 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 04:10 · PVG 12:10 · LAX 21:10 · JFK 00:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.