Docker应用单体容器化
1. 完整步骤
- 编写应用代码
- 创建Dockerfile,包括当前应用的描述,依赖,以及如何创建及使用什么命令运行这个应用
- 对Dockerfile进行docker image build操作
- 等待Docker将应用程序构建到Docker中
- 由镜像启动容器,运行应用
- 镜像导出保持:docker save > imagename.tar
2. Dockerfile 解析
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QJ8Bksb3-1606458203320)(C:\Users\86135\Desktop\未命名文件(3)].png)
- FROM:指定基础镜像:tips:构建过程中FROM过的基础镜像会单独存在于docker镜像库
- MAINTAINER:描述
- RUN:创建时执行的命令,导致创建新的镜像层
- COPY:将文件作为新的镜像层添加进镜像中,将本地文件拷贝进镜像哪个目录(这里将Dockfile中同目录下的项目代码拷贝进镜像ubuntu系统中与home同级的新建的pro文件夹)
- WORKDIR:设置工作路径
- CMD:可以设置一些启动容器时默认执行的命令,比如运行应用等,不过暂未深入研究,本次部署是进去之后一步一步在命令行设置的。shell exec格式的命令,只能有一条
- ENTRYPOINT:指定容器启动后默认要运行的程序,与CMD类似,shell exec格式的命令,与CMD有覆盖冲突,只能有一条,多条需要写sh,如[ENTRYPOINT[”./start.sh“]
- EXPOSE:指定用于记录应用所使用的端口
这也是镜像层逐渐增多的过程,FROM RUN COPY等每执行一条新建一个镜像层。
3. 创建过程
-
在应用代码目录同级创建并写好了Dockerfile
-
使用docker image build -t name:tag . 命令创建镜像
-
使用docker image ls 查看已经创建的镜像
-
一般这一步启动并开启命令行交互:docker container run -it name :tag /bin/bash
-
推送至仓库
docker login
docker image tag image_name:tag registry_name/image_name:tag
-
一般由此镜像启动容器后我们还需要进入容器进行配置,这导致内容的改变,一般配置完成后需要在新的容器基础上生成新的镜像,这里使用docker commit命令,由容器创建新镜像
4.第一层为基础ubuntu镜像开始创建常遇到的问题
问题:docker加速器
-
创建或修改
/etc/docker/daemon.json
sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://1nj0zren.mirror.aliyuncs.com", "https://docker.mirrors.ustc.edu.cn", "http://f1361db2.m.daocloud.io", "https://registry.docker-cn.com" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker
-
验证:docker info
Registry Mirrors: [...]
问题:docker部署系统apt不能使用
-
描述:docker中使用ubuntu镜像,需要更新apt,但是国外源巨慢,换源需要使用vim,but镜像中不带vim,陷入死循环,只能使用echo来写
echo "deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse" >>/etc/apt/sources.list echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse" >>/etc/apt/sources.list echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse" >>/etc/apt/sources.list echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse" >>/etc/apt/sources.list echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse" >>/etc/apt/sources.list echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse" >>/etc/apt/sources.list echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse" >>/etc/apt/sources.list echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse" >>/etc/apt/sources.list echo "deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse" >>/etc/apt/sources.list echo "deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse" >>/etc/apt/sources.list
问题:与宿主机传递文件
sudo docker cp /local/dirname <containername>:/dirname
Docker应用生产环境的多阶段构建
1.为什么要设置生产环境
- docker镜像过大会难以使用,更加脆弱以及遭受攻击
- 对于生产环境来讲,需要将其缩小到仅包含必需的内容即可
2. 现有解决方案
-
少用RUN等会导致镜像层增多的命令。多条RUN使用&& 和 \来进行包含
-
建造者模式:需要两个Dockerfile,一个用于开发环境,一个用于生产环境。Dockerfile.dev开发环境负责基于大型基础镜像拉去构建所需的工具.Dockerfile.prod负责基于较小的基础镜像进行构建,,并在开发环境容器中将应用的部分复制过来。
-
多阶段构建
3. 多阶段构建
3.1 概念
使用一个Dockerfile,其中包含多个FROM命令,每个命令都是一个新的构建阶段,并且可以很容易的复制之前阶段的构件,重点是COPY与FROM,
3.2 构建实例
-
实例地址:https://github.com/nigelpoulton/atsea-sample-shop-app
-
实例Dockerfile
FROM node:latest AS storefront WORKDIR /usr/src/atsea/app/react-app COPY react-app . RUN npm install RUN npm run build FROM maven:latest AS appserver WORKDIR /usr/src/atsea COPY pom.xml . RUN mvn -B -f pom.xml -s /usr/share/maven/ref/settings-docker.xml dependency:resolve COPY . . RUN mvn -B -s /usr/share/maven/ref/settings-docker.xml package -DskipTests FROM java:8-jdk-alpine RUN adduser -Dh /home/gordon gordon WORKDIR /static COPY --from=storefront /usr/src/atsea/app/react-app/build/ . WORKDIR /app COPY --from=appserver /usr/src/atsea/target/AtSea-0.0.1-SNAPSHOT.jar . ENTRYPOINT ["java", "-jar", "/app/AtSea-0.0.1-SNAPSHOT.jar"] CMD ["--spring.profiles.active=postgres"]
-
阶段0:storefront
拉取node镜像,复制一些应用代码,使用两个npm操作,最后生成三个镜像层
-
阶段1:appserver
拉取maven,两个COPY两个RUN,搞出四个镜像层,同样包含构建工具和少量应用代码
-
阶段2:production
拉取很小的java镜像,这个阶段会生成一个用户,设置工作目录,在前两个镜像中分别复制点应用程序代码进来。然后设置此程序为容器启动时的主程序
-
构建:与之前相同,使用docker image build -t <>:<> .命令就可以
-
tips:构建过程中FROM过的基础镜像会单独存在于docker镜像库
-
Docker应用容器化的最佳实践
1.利用构建缓存
1.1 观测方法
在一个干净的Docker主机上构建一个新的镜像,然后重复同样的构建
1.2 现象
第一次构建时拉取基础镜像会消耗一定的时间,但第二次重复构建时会很快完成
1.3 原理机制
docker image build 命令构建docker镜像时会逐层从上到下解析Dockerfile,每执行一条命令,docker主机都会检查缓存中是否已经有与之对应的镜像层,如果有,为缓存命中,直接使用;如果没有,即为缓存未命中,再执行构建。
2. 合并镜像
2.1 为什么合并?
镜像层过多时docker进行合并优化
2.2 优缺点
- 优:未来基于此镜像构建新镜像时,此镜像为一层
- 缺:无法共享镜像层,pull和push的成本增大
2.3 创建合并的镜像层
docker image build --squash
3.使用no-install-recommands
确保apt只安装核心依赖
4.不要安装MSI
在构建windows时不要安装MSI
应用容器化常用命令
commad | usage |
---|---|
docker image build -f -t | 构建镜像,-f指定dockerfile目录。-t指定构建名称 |
FROM | 导入基础镜像 |
RUN | 在镜像中执行命令,创建新镜像层 |
COPY | 将应用代码复制至镜像目录 |
EXPOSE | 指定镜像所使用的网络端口 |
ENTRYPOINT | 指定镜像以容器方式启动后默认运行程序 |