参考官方文档:Dockerfile
构建Docker镜像是使用的Dockerfile,然后把所有的依赖包放到Dockerfile的同级目录。
为什么需要都放到当前目录?
因为docker build的第一个步骤就是将此次构建的工作目录发给docker daemon。
Dockerfile类似机器码,一个命令是一行,分成几类。
COPY和ADD
比如ADD jdk-11.0.7 /opt/sonar/jdk
,就是将当前目录下jdk-11.0.7
的全部内容放到/opt/sonar/jdk
目录下,目录如果不存在,会自动建。
COPY和ADD的主要区别就是ADD多了个功能就是可以从远程下载文件放到docker镜像里。这在自动化构建时,比如你的程序包是放在远程文件系统中时,是比较有用的。
特殊用法:
FROM golang:1.17.6
# 容器工作目录
WORKDIR /go/src/sigs.k8s.io/scheduler-plugins
# 这里的copy . .的意思是拷贝当前工作目录(Dockerfile所在的目录)到容器工作目录(WORKDIR)
COPY . .
ARG ARCH
RUN make build-controller.$ARCH
ENV hello world
ENV hello=world
容器中运行的应用可以通过环境变量获取到ENV
定义的值。Docker引入这个特殊的命令,就是为了规范环境变量向容器的注入。不要把环境变量放到/etc/profile
里。
ARG和ENV的区别?作用域不同,ARG只能Dockerfile里使用(构建时),ENV除了可以在构建时,也可以被运行时容器当作系统环境变量读到。
我构建JDK镜像包时,发现PATH变量可以引用构建镜像的当前宿主机的PATH变量。
像下面这样使用行内替换语法:
# 这里${PATH}引用宿主机的PATH变量,这种引用叫inline replacement
ENV PATH=${PATH}:/opt/sonar/sonar/bin/linux-x86-64
两种语法格式,RUN命令可以有多个。
# bash -c
RUN chown -R sonar:sonar /opt/sonar
# json格式
RUN ["echo","hello"]
有些应用程序不能以root运行,docker默认用户是root。要更改用户:
# 切换到用户sonar
USER sonar
# 之后的命令都是以sonar用户权限运行
RUN whoami
或者使用docker run的–add-host指令
--add-host="" : Add a line to /etc/hosts (host:IP)
docker-compose.yaml
services:
service-a:
environment:
- DEBUG=1
extra_hosts:
- test.gitlab.com:192.168.10.8
CMD和ENTRYPOINT
我认为没必要搞出这两个语法,有啥意义呢?都是一样的。ENTRYPOINT是JSON格式的语法。
# json格式
ENTRYPOINT ["echo","hello"]
一个Dockerfile里写一个ENTRYPOINT
就可以了。不要写多个,否则会覆盖。
长期运行的容器需要这种命令。不过难受的是,你的命令如果是后台运行,容器启动就闪退了。这是因为容器中后台运行的应用没有阻塞,进程正常终止的返回值为0。
sonarqube是一个web应用,用于代码分析。其使用JDK-11,以非root用户运行。
# 以Centos 7.5为基础镜像
FROM centos:centos7.5.1804
MAINTAINER oneslide
# 镜像元信息,可以忽略
LABEL os.version="centos"
LABEL build.date="2020-07-07"
LABEL who.build.this="oneslide"
# 创建一个非root用户sonar
RUN useradd sonar -d /opt/sonar -s /sbin/nologin
# jdk11复制到/opt/sonar/jdk
ADD jdk-11.0.7 /opt/sonar/jdk
# 配置java环境变量
ENV JAVA_HOME /opt/sonar/jdk
ENV PATH=${PATH}:${JAVA_HOME}/bin
# 添加sonarqube(web应用)的包
ADD sonarqube-8.3.1.34397 /opt/sonar/sonar
# 设置当前工作目录,意味着ls会列出/opt/sonar文件夹下的文件
WORKDIR /opt/sonar
# 再次设置环境变量,因为web应用的启动脚本需要放在PATH下
ENV PATH=${PATH}:/opt/sonar/sonar/bin/linux-x86-64
RUN chown -R sonar:sonar /opt/sonar
# 以sonar用户运行
USER sonar
# 暴露web应用的端口(容器端口),这个不是随便写的,你的应用监听哪个端口,就写哪个
EXPOSE 9000
# 后台启动web,并一直查看日志
CMD sonar.sh start && tail -f sonar/logs/sonar.log
然后我的目录结构是这样的:
[root@oneslide jdk11-centos]# tree -L 1
.
├── Dockerfile
├── jdk-11.0.7
├── jdk-11.0.7_linux-x64_bin.tar.gz
├── sonarqube-8.3.1.34397
├── sonarqube-8.3.1.34397.zip
└── sonarqube8.tar
构建镜像:
# .代表当前目录,-t是镜像的tag,格式是name:version
docker build -t sonarqube:1.0v .
Docker镜像上传到Dockerhub的方式,分为手动和自动。
手动方式是本地构建好了docker镜像之后,使用docker push
命令推送到dockerhub;
自动方式是让Dockerhub监听Github远程仓库的变更,自动构建Docker镜像并推
送。
# 复制本地镜像local-image:tagname,并将标签重贴为new-repo:tagname
docker tag local-image:tagname new-repo:tagname
# 推送到Registry
docker push new-repo:tagname