2

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

 1 year ago
source link: https://www.v2ex.com/t/900487
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

V2EX  ›  Docker

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

  slove · 6 小时 56 分钟前 via iPhone · 1161 次点击
#基于 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
32 条回复    2022-12-06 20:41:47 +08:00
caocong

caocong      6 小时 55 分钟前

ubuntu:latest

ubuntu:latest
slove

slove      6 小时 53 分钟前 via iPhone

@caocong 英文标点符号我知道,这份是我手机打的
lxzxl

lxzxl      6 小时 44 分钟前

RUN alter user “root”@“localhost” identified with mysql_native_password by “12345”;

你是想 shell 里面跑 sql?
slove

slove      6 小时 34 分钟前 via iPhone

@lxzxl 是的,不可以使用 mysql 语句吗
lxzxl

lxzxl      6 小时 20 分钟前

@slove #4 换个问法,你是想 bash 里面执行 sql?
slove

slove      6 小时 12 分钟前 via iPhone

@lxzxl 你的问法我理解,我在主机上敲 mysql ,直接进入 mysql ,所以可以执行 sql 语法,直到敲下 exit ,才算退出 mysql
Dockerfile RUN mysql ,我理解就是在主机中启动 mysql ,然后进入数据库,后面的 sql 语句应该也是在数据库中执行,如果不是这样的,那 sql 语法应该写在哪里
kaedeair

kaedeair      6 小时 6 分钟前

bash 里用 mysql 命令可以 RUN mysql < cmd1;cmd2;cmd3; 大概是这么做我没试过,也可能是 bash -c ""这种
OP 的这种情景一般有两种变通方法
1.用 docker-compose 拉别人的镜像组成服务群,加入环境变量来配置
2.写一个 EntryPoint 脚本去判断是不是第一次运行
chloerei

chloerei      6 小时 3 分钟前

@slove RUN 一条命令之后,相当于退出 shell ,下一条 RUN 是打开另一个 shell ,不会保留同一个会话。

要执行 mysql 命令可以这样:

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

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

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

建议先学习 docker 的基本概念,它不是虚拟机。
slove

slove      6 小时 3 分钟前 via iPhone

@iyour 我回头试下,感谢
Mindzy

Mindzy      6 小时 0 分钟前

建议所有 SQL 指令用 ENTRYPOINT 运行个 sh 执行
hefish

hefish      5 小时 59 分钟前   ❤️ 2

这个不应该从 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

starqoq      5 小时 56 分钟前

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

slove      5 小时 54 分钟前 via iPhone

@kaedeair 感觉你说的应该可以执行,我回头测试下
slove

slove      5 小时 50 分钟前 via iPhone

@Mindzy 自学的 docker ,对 Dockerfile 的语法理解还是不透彻,我看网上很多把 sql 语句单独写一个文件,回头参考下别人的 Dockerfile
javalaw2010

javalaw2010      5 小时 48 分钟前

添加一个环境变量,ENV DEBIAN_FRONTEND=noninteractive 以避免软件安装过程中的交互出现,apt 安装的时候添加-y 参数,同样为了避免交互安装时出现交互。安装包控制镜像大小的一些小技巧前面的大佬们说过了,当然如果你不希望 DEBIAN_FRONTEND 在容器运行时也存在的话,可以 RUN DEBIAN_FRONTEND=noninteractive apt install -y XXX 。此外 ADD 命令并不会自动解压缩远程的压缩包,你得手动解压一下,至于 mysql 的问题,前面各位大佬也都说过了
slove

slove      5 小时 47 分钟前 via iPhone

@hefish 讲的很细了,感谢
wunonglin

wunonglin      5 小时 46 分钟前

这是把 docker 当虚拟机用了呀
slove

slove      5 小时 44 分钟前 via iPhone

@Puteulanus
a | b ,a 执行完结果扔给 b 执行,不知道我理解的对不对
deplivesb

deplivesb      5 小时 26 分钟前

你这个真把 docker 当成虚拟机用了,启动一个 ubuntu 系统,安装一个 Apache 再安装一个 MySQL ,你这个干啥呢?
slove

slove      5 小时 25 分钟前 via iPhone

@starqoq 感谢,虽然你说的很多不理解,感觉是大佬
@zhenrong 感谢
@wunonglin 学习环境,玩坏了,就直接删除,挺方便的
@lxzxl 我再认真看文档去,感谢

感谢以上所有人的回复,谢谢
slove

slove      5 小时 23 分钟前 via iPhone

@deplivesb 装个学习环境,玩坏了,就直接删库跑路,不会被抓,哈哈
dier

dier      4 小时 23 分钟前

你这个误区有点多,我一时不知道从哪讲起。既然你说想练习 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

hsfzxjy      4 小时 12 分钟前 via Android

建议先学 shell/bash 语法和相关知识,还是基础知识不够

如果你写成 shell 脚本能跑通,那改成 Dockerfile 基本也可以
slove

slove      4 小时 11 分钟前 via iPhone

@dier 嗯嗯,你的回复对我帮助很大,谢谢
dev436

dev436      2 小时 40 分钟前

您好,您给出的 Dockerfile 中存在一些语法错误和书写不规范的问题。我尝试纠正这些问题,并给出修改后的 Dockerfile 内容:
dev436

dev436      2 小时 40 分钟前

# 基于 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

slove      1 小时 41 分钟前

@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

g001      16 分钟前

FROM ubuntu:latest:您在使用 : 分隔镜像名称和标签时,应该使用英文的冒号而不是中文的冒号。正确的语法应该是 FROM ubuntu:latest 。
alter user “root”@“localhost”:您在使用字符串时,应该使用英文的双引号而不是中文的双引号。正确的语法应该是 alter user "root"@"localhost"。
mysql_native_password by “12345”;:您在定义密码时,应该使用英文的双引号而不是中文的双引号。正确的语法应该是 mysql_native_password by "12345"

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK