事情:nginx。tomcat。mysql。镜像从哪里来?
我们自己如何做一个镜像。微服务。SpringBoot。上云部署。最方便是Docker。
微服务打包成镜像。任何装了Docker。都可以下载使用。
应用–>Dockerfile—>打包成镜像—>上传到仓库(公有仓库,私有仓库)—>下载镜像—>启动运行。
移植:扩充服务器。
如何得到一个镜像
#nginx Dockerfile的示例
#alpine:3.11超迷你的linux 4mb;
#alpine:3.11 linux全目录 基于宿主机linux的一个统一接口。cpu,mem。主机。
FROM alpine:3.11
LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>"
#环境
ENV NGINX_VERSION 1.18.0
ENV NJS_VERSION 0.4.0
ENV PKG_RELEASE 1
RUN set -x \
# create nginx user/group first, to be consistent throughout docker variants
&& addgroup -g 101 -S nginx \
&& adduser -S -D -H -u 101 -h /var/cache/nginx -s /sbin/nologin -G nginx -g nginx nginx \
&& apkArch="$(cat /etc/apk/arch)" \
&& nginxPackages=" \
nginx=${NGINX_VERSION}-r${PKG_RELEASE} \
nginx-module-xslt=${NGINX_VERSION}-r${PKG_RELEASE} \
nginx-module-geoip=${NGINX_VERSION}-r${PKG_RELEASE} \
nginx-module-image-filter=${NGINX_VERSION}-r${PKG_RELEASE} \
nginx-module-njs=${NGINX_VERSION}.${NJS_VERSION}-r${PKG_RELEASE} \
" \
&& case "$apkArch" in \
x86_64) \
# arches officially built by upstream
set -x \
&& KEY_SHA512="e7fa8303923d9b95db37a77ad46c68fd4755ff935d0a534d26eba83de193c76166c68bfe7f65471bf8881004ef4aa6df3e34689c305662750c0172fca5d8552a *stdin" \
&& apk add --no-cache --virtual .cert-deps \
openssl \
&& wget -O /tmp/nginx_signing.rsa.pub https://nginx.org/keys/nginx_signing.rsa.pub \
&& if [ "$(openssl rsa -pubin -in /tmp/nginx_signing.rsa.pub -text -noout | openssl sha512 -r)" = "$KEY_SHA512" ]; then \
echo "key verification succeeded!"; \
mv /tmp/nginx_signing.rsa.pub /etc/apk/keys/; \
else \
echo "key verification failed!"; \
exit 1; \
fi \
&& apk del .cert-deps \
&& apk add -X "https://nginx.org/packages/alpine/v$(egrep -o '^[0-9]+\.[0-9]+' /etc/alpine-release)/main" --no-cache $nginxPackages \
;; \
*) \
# we're on an architecture upstream doesn't officially build for
# let's build binaries from the published packaging sources
set -x \
&& tempDir="$(mktemp -d)" \
&& chown nobody:nobody $tempDir \
&& apk add --no-cache --virtual .build-deps \
gcc \
libc-dev \
make \
openssl-dev \
pcre-dev \
zlib-dev \
linux-headers \
libxslt-dev \
gd-dev \
geoip-dev \
perl-dev \
libedit-dev \
mercurial \
bash \
alpine-sdk \
findutils \
&& su nobody -s /bin/sh -c " \
export HOME=${tempDir} \
&& cd ${tempDir} \
&& hg clone https://hg.nginx.org/pkg-oss \
&& cd pkg-oss \
&& hg up -r 474 \
&& cd alpine \
&& make all \
&& apk index -o ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz ${tempDir}/packages/alpine/${apkArch}/*.apk \
&& abuild-sign -k ${tempDir}/.abuild/abuild-key.rsa ${tempDir}/packages/alpine/${apkArch}/APKINDEX.tar.gz \
" \
&& cp ${tempDir}/.abuild/abuild-key.rsa.pub /etc/apk/keys/ \
&& apk del .build-deps \
&& apk add -X ${tempDir}/packages/alpine/ --no-cache $nginxPackages \
;; \
esac \
# if we have leftovers from building, let's purge them (including extra, unnecessary build deps)
&& if [ -n "$tempDir" ]; then rm -rf "$tempDir"; fi \
&& if [ -n "/etc/apk/keys/abuild-key.rsa.pub" ]; then rm -f /etc/apk/keys/abuild-key.rsa.pub; fi \
&& if [ -n "/etc/apk/keys/nginx_signing.rsa.pub" ]; then rm -f /etc/apk/keys/nginx_signing.rsa.pub; fi \
# Bring in gettext so we can get `envsubst`, then throw
# the rest away. To do this, we need to install `gettext`
# then move `envsubst` out of the way so `gettext` can
# be deleted completely, then move `envsubst` back.
&& apk add --no-cache --virtual .gettext gettext \
&& mv /usr/bin/envsubst /tmp/ \
\
&& runDeps="$( \
scanelf --needed --nobanner /tmp/envsubst \
| awk '{ gsub(/,/, "\nso:", $2); print "so:" $2 }' \
| sort -u \
| xargs -r apk info --installed \
| sort -u \
)" \
&& apk add --no-cache $runDeps \
&& apk del .gettext \
&& mv /tmp/envsubst /usr/local/bin/ \
# Bring in tzdata so users could set the timezones through the environment
# variables
&& apk add --no-cache tzdata \
# Bring in curl and ca-certificates to make registering on DNS SD easier
&& apk add --no-cache curl ca-certificates \
# forward request and error logs to docker log collector
&& ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log \
# make default server listen on ipv6
&& sed -i -E 's,listen 80;,listen 80;\n listen [::]:80;,' \
/etc/nginx/conf.d/default.conf
EXPOSE 80
STOPSIGNAL SIGTERM
CMD ["nginx", "-g", "daemon off;"]
# Dockerfile复原了我们在linux上安装nginx的过程。
XXX给我们准备好的文件。xxx.tar。可以通过硬盘传输使用。
2、上传项目到服务器。
3、进入项目,构建镜像到本地仓库;
- `docker build -t nginx:1.0 -f ./Dockerfile .` 别忘了最后的小数点。
- docker images 查看镜像
- docker exec -it 容器id /bin/bash;进入容器,修改容器
- docker commit -a “icoding” -m “nginxxx” 容器id mynginx:2.0
- docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
- OPTIONS说明:
- -a :提交的镜像作者;
- -c :使用Dockerfile指令来创建镜像;
- -m :提交时的说明文字;
- -p :在commit时,将容器暂停。
- docker login : 登陆到一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub
- docker login -u 用户名 -p 密码
- docker logout : 登出一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub
4、推送镜像到docker hub
- 标记镜像,docker tag local-image:tagname username/new-repo:tagname
- 上传镜像,docker push username/new-repo:tagname
5、保存镜像,加载镜像
- 可以保存镜像为tar,使用u盘等设备复制到任意docker主机,再次加载镜像
- 保存:docker save spring-boot-docker -o /home/spring-boot-docker.tar
- 加载:docker load -i spring-boot-docker.tar
6、阿里云操作
- 登录阿里云,密码就是开通镜像仓库时 的密码
- docker login --username=icoding registry.cn-hangzhou.aliyuncs.com
- 拉取镜像
- docker pull registry.cn-hangzhou.aliyuncs.com/icoding/i-nginx:v1.0
- 推送镜像
- docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/icoding/icoding-nginx:v2
- docker push registry.cn-hangzhou.aliyuncs.com/icoding/icoding-nginx:v2
Dockerfile详解
Dockerfile由一行行命令语句组成,并且支持以#开头的注释行。
一般而言,Dockerfile可以分为四部分
基础镜像信息
维护者信息
镜像操作指令
启动时执行指令
指令 | 说明 |
---|---|
FROM | 指定基础镜像 |
MAINTAINER | 指定维护者信息,已经过时,可以使用LABEL maintainer=xxx 来替代 |
RUN | 运行命令 v |
CMD | 指定启动容器时默认的命令 v |
LABEL | 指定生成镜像的元数据标签信息 v |
EXPOSE | 声明镜像内服务监听的端口 v |
ENV | 指定环境变量,可以在docker run的时候使用-e改变 v |
ADD | 复制指定的src路径下的内容到容器中的dest路径下,src可以为url会自动下载,可以为tar文件,会自动解压 |
COPY | 复制本地主机的src路径下的内容到镜像中的dest路径下,但不会自动解压等 |
ENTRYPOINT | 指定镜像的默认入口.运行命令 v |
VOLUME | 创建数据卷挂载点 |
USER | 指定运行容器时的用户名或UID |
WORKDIR | 配置工作目录,为后续的RUN、CMD、ENTRYPOINT指令配置工作目录 |
ARG | 指定镜像内使用的参数(如版本号信息等),可以在build的时候,使用–build-args改变 v |
OBBUILD | 配置当创建的镜像作为其他镜像的基础镜像是,所指定的创建操作指令 |
STOPSIGNAL | 容器退出的信号值 |
HEALTHCHECK | 健康检查 |
SHELL | 指定使用shell时的默认shell类型 |
1、RUN、CMD、ENTRYPOINT区别
- RUN 执行命令并创建新的镜像层RUN 经常用于安装软件包(在构建镜像时运行的)。
- CMD 设置容器启动后默认执行的命令及其参数但 CMD 能够被
docker run
后面跟的命令行参数替换。- ENTRYPOINT 配置容器启动时运行的命令。
- 以上命令都可以使用shell或者exec方式执行
CMD ["executable","param1","param2"]
(exec form, this is the preferred form)CMD ["param1","param2"]
(as default parameters to ENTRYPOINT)CMD command param1 param2
(shell form)
2、shell和exec方式
shell 是 /bin/sh -c 的方式,
- exec ["/bin/sh","-c",command] 的方式== shell方式
eg:shell方式
ENV name icoding
ENTRYPOINT echo "Hello, $name"
#输出 Hello icoding
ENTRYPOINT ["/bin/echo", "Hello, $name"]
#输出 Hello $name
ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]
#输出 Hello icoding
##建议:CMD 和 ENTRYPOINT 推荐使用 Exec 格式因为指令可读性更强更容易理解。RUN 则两种格式都可以。exec的时候要获取环境变量等值,就用/bin/sh -c 即可。
No ENTRYPOINT | ENTRYPOINT exec_entry p1_entry | ENTRYPOINT [“exec_entry”, “p1_entry”] | |
---|---|---|---|
No CMD | error, not allowed | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry |
CMD [“exec_cmd”, “p1_cmd”] | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry exec_cmd p1_cmd |
CMD [“p1_cmd”, “p2_cmd”] | p1_cmd p2_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry p1_cmd p2_cmd |
CMD exec_cmd p1_cmd | /bin/sh -c exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
实战Dockerfile
#1、ping命令小工具。
编写Dockerfile-->打包镜像--->根据这个镜像启动容器使用容器的功能
docker build -t hello .
-t:tag标签。镜像名字
.:在当前目录下工作
默认.这个目录下就得有一个 Dockerfile
FROM alpine
CMD ping baidu.com
#2、文件名不是Dockerfile。用-f 指定
docker build -f Dockerfile2 -t hello:v1.0 .
docker run -d --name hello hello;
#3、默认构建出来的镜像,放到了我们的本地镜像仓库。
1)、登陆到dockerhub
2)、dockehub国外,就算能Push,非常慢。阿里云加速的是下载。
#4、把这个镜像发布到Docker hub
1)、docker login -u icodingallen;登陆到docker hub
2)、docker push nginx:v1.0;推送过去。
太慢了
#5、搭建私有的镜像仓库。使用阿里云的镜像仓库(免费)。
1)、docker login --username=lyt_goodtogread@163.com registry.cn-hangzhou.aliyuncs.com
为了团队自治。只能看到自己的仓库的所有镜像。namespace;
创建镜像仓库。保存镜像各种版本,book: 1 2 3 4 5
docker tag hello:v1.0 registry.cn-hangzhou.aliyuncs.com/icodingdocker/hello:v1.3
docker push registry.cn-hangzhou.aliyuncs.com/icodingdocker/hello:v1.3
docker.io/libarary/hello:latest
registry.cn-hangzhou.aliyuncs.com/icodingdocker/hello:v1.0
镜像—》打包–》上传。
Dockerfile区分一些易混淆的指令
1、USER 执行cmd等之类命令的使用那个用户
alpine sudo gosu
FROM centos
RUN groupadd -r abc && useradd -r -g abc aaa
USER aaa
CMD whoami
# CMD 就是容器启动以后要执行的命令
2、ARG、ENV
- The
ARG
instruction defines a variable that users can pass at build-time to the builder with thedocker build
:arg在构建期间。docker build - The environment variables set using
ENV
will persist when a container is run from the resulting image. You can view the values usingdocker inspect
, and change them usingdocker run --env =
. env在运行是可以用到的
FROM alpine
ARG bbb haha
ENV abc 666
CMD echo $bbb
容器运行的时候arg的东西拿不到
CMD echo $abc
容器运行的时候env的能拿到
FROM alpine
ARG bbb haha
ENV abc=$bbb
CMD echo $abc
ARG指定的值,在镜像构建的后面位置,构建期间都可以使用到。
改变这些值行不行
docker build -f Dockerfile-arg-env -t file-arg --build-arg bbb=888 --build-arg abc=777 .
结果888
# 构建时 bbb=888 abc=777 ,cmd打印888.原因 构建时不能改变env
# 运行时
\ | ARG | ENV |
---|---|---|
build时 | √。–build-arg改变 构建参数(ARG声明) | 生效,能不能改(不能) |
运行时 | 不生效 | 生效。能改 -e abc |
最佳实战:
ARG:定义一些版本信息
FROM alpine
ARG version=1
RUN yum install nginx:$version
Env:运行时的环境变量。
ENV env = --spring.profile.active=prod
-e修改。sb java -jar xxx.jar $env
3、ADD和COPY
#构建了一个SpringBoot镜像。 xxx.jar
/opt
docker build -t hello .
ADD:将当前目录下的内容放到镜像里面一起打包。
COPY:将当前目录下的内容放到镜像里面一起打包。
ADD ["","",""] dest:容器里面的目录
可以指定很多种路径地址。自动下载,解压复制。
FROM alpine
ADD hello.tar /opt/hello
COPY hello.tar /opt/world/
CMD echo "1234"
这个东西构建的镜像为什么docker run -d 不行。因为容器运行的是ech 1234;
没有一个守护进程一直运行。
CMD ping baidu.com
4、VOLUME和WORKDIR
VOLUME:指定容器需要挂载的卷
WORKDIR:工作目录。
1、以后的其他命令在这个目录里面运行
2、exec进去都默认来到了 WORKDIR 指定的目录。sh
docker run -it --rm file-volume sh
WORKDIR
WORKDIR /root == RUN cd /root
挂载麻烦。自动挂载。
FROM alpine
WORKDIR /opt/a
VOLUME /opt/b
COPY hello.txt .
ADD hello.tar /opt/b
CMD whoami
volume声明的挂载目录,即使容器运行的时候,不用-v进行挂载。docker也会自动的进行匿名挂载。
nginx:
5、RUN、CMD、ENTRYPOINT
相同点:运行命令
不同点:
RUN:在构建镜像的时候运行的命令
**CMD、ENTRYPOINT:在容器启动运行的命令**
测试RUN;
#想构建一个具有git功能的镜像。
FROM centos
RUN yum install -y git
WORKDIR /opt/data
RUN git clone https://gitee.com/lanoox/luject.git
VOLUME /opt/data
CMD echo "git clone success"
#CMD 容器运行的时候CMD的命令才执行。
相同的镜像layer层发生变化,只有这层变化。
- -RUN指令的所有命令都在镜像docker build期间就执行
- CMD和ENTRYPOINT在容器启动时运行
- CMD 容器运行的时候CMD的命令才执行。docker run -it --rm file-run bash 能进容器中
- 替换为ENTRYPOINT。虽然指令运行了。但是 docker run -it --rm file-run bash 。最后的bash没有进去,失效了。
无论是CMD还是ENTRYPOINT还是RUN
- `RUN ` (*shell* form, the command is run in a shell, which by default is `/bin/sh -c` on Linux or `cmd /S /C` on Windows) RUN yum install -y git;`/bin/sh -c`可以动态获取一些变量
- `RUN ["executable", "param1", "param2"]` (*exec* form);无法动态获取一些变量
FROM centos
ARG soft=git
RUN ["yum install","-y","$soft"] #这是错误的。因为非`/bin/sh -c`方式,用不到前面声明的ARG,ENV
WORKDIR /opt/data
RUN git clone https://gitee.com/lanoox/luject.git
VOLUME /opt/data
ENTRYPOINT echo "git clone success"
# bash-c 和 数组方式的区别, 修改后的;安装正确。
FROM centos
ARG soft=git
RUN ["/bin/sh","-c","yum install -y $soft"]
#-c command:后免是完整命令
WORKDIR /opt/data
RUN git clone https://gitee.com/lanoox/luject.git
VOLUME /opt/data
ENTRYPOINT echo "git clone success"
RUN、CMD、ENTRYPOINT都支持一下两种方式
The exec form, which is the preferred form:
ENTRYPOINT [“executable”, “param1”, “param2”]
The shell form:
ENTRYPOINT command param1 param2
总结:
-
如果运行命令是。[]方式,默认不是bash -c就无法用变化,普通的方式RUN yum -install -y $soft可以使用变量。
-
CMD、ENTRYPOINT的最佳实战
- Dockerfile文件必须至少有一个
CMD
或者ENTRYPOINT
命令. ENTRYPOINT
用来定义容器如何运行.CMD
应该被用来作为给ENTRYPOINT
传递。默认参数的一种方式CMD
将会被覆盖,容器运行时指定参数的时候.ENTRYPOINT
命令不会被覆盖。- CMD多个只会有一个生效。
ENTRYPOINT
:不被传入的指令覆盖,但是多个也只有一个生效。
为什么我的指令Dockerfile写CMD的时候,docker run -it --rm file-run bash可以进控制台,而
ENTRYPOINT
不行?运行效果:
- Dockerfile是CMD;没打印git clone success。但是bash生效。
- Dockerfile文件必须至少有一个
Dockerfile 是 ENTRYPOINT;打印了git clone success但是没有进容器(bash没生效)
混写。CMD + ENTRYPOINT
FROM centos
ARG soft=git
RUN ["/bin/bash","-c","yum install -y $soft"]
WORKDIR /opt/data
RUN git clone https://gitee.com/lanoox/luject.git
VOLUME /opt/data
CMD ["nginx"] #CMD给entrypoint提供参数
ENTRYPOINT ["yum","install","-y"]
```powershell
运行:
docker run -it --rm file-run maven
FROM centos
ARG soft=git
RUN ["/bin/bash","-c",“yum install -y $soft”]
WORKDIR /opt/data
RUN git clone https://gitee.com/lanoox/luject.git
VOLUME /opt/data
CMD ["","","",""] #可以放空
ENTRYPOINT ["/bin/sh","-c",“yum install -y”]
#容器启动就是yum install -y “”;自己启动命令加上git
CMD 后面有N参数。传了参数替换N个还是最后一个?
docker run -it --rm file-run maven CMD [“maven”] 对
docker run -it --rm file-run maven CMD [“”,“”,“maven”] 错
目的:构建镜像。SpringBoot编写的微服务,怎么做镜像?
1、运行的业务的目标环境?SB服务。java环境。FROM
2、怎么启动业务的。得到jar包,java -jar xxx.jar --spring.profile.active=prod --server.port=8080;决定镜像的ENTRYPOINT怎么写。docker exec?docker run(第一次容器启动要执行)?
docker exec haha -it bash【和entrypoint,cmd没啥关系】;
3、业务运行的时候需要啥?java。jar。jar包就想办法放进镜像中。COPY 。ADD
4、业务的那些数据是需要做持久化。VOLUME怎么写。
```powershell
FROM java:8
#服务器只有dockerfile和jar在一起
COPY *.jar /app.jar
#即使运行没有-v,也会匿名挂载
VOLUME ["/logs"]
CMD ["--server.port=8080"]
EXPOSE ["8080"]
ENTRYPOINT ["java","-jar","/app.jar"]