基础docker 镜像、容器
docker
官网 https://www.docker.com/
仓库 https://hub.docker.com/
docker 镜像加速器
登录阿里云(https://cr.console.aliyun.com/#/accelerator)
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
}
镜像相关命令
1、搜索镜像docker search java
2、下载镜像docker pull java:8
docker pull nginx
3、列出镜像docker images
4、删除本地镜像docker rmi java
删除所有镜像docker rmi $(docker images -q)
容器相关命令
1、新建并启动容器
使用以下docker run命令即可新建并启动一个容器,该命令是最常用的命令,它有很多选项,下面将列举一些常用的选项。
-d选项:表示后台运行
-P选项:随机端口映射
-p选项:指定端口映射,有以下四种格式。
– ip:hostPort:containerPort
– ip::containerPort
– hostPort:containerPort
– containerPort
–net选项:指定网络模式,该选项有以下可选参数:
–net=bridge:默认选项,表示连接到默认的网桥。
–net=host:容器使用宿主机的网络。
–net=container:NAME-or-ID:告诉 Docker让新建的容器使用已有容器的网络配置。
–net=none:不配置该容器的网络,用户可自定义网络配置。
docker run -d --name mynginx -p 91:80 nginx
2、列出容器docker ps
3、停止容器docker stop mynginx
4、强制停止容器docker kill mynginx
5、启动已停止的容器docker start mynginx
6、查看容器所有信息docker inspect mynginx
7、查看容器日志docker container logs mynginx
8、查看容器里的进程docker top mynginx
9、容器与宿主机相互复制文件docker cp mynginx:/etc/nginx/nginx.conf /mydata/nginx
从容器里面拷文件到宿主机:
docker cp 容器id:要拷贝的文件在容器里面的路径 宿主机的相应路径
从宿主机拷文件到容器里面:
docker cp 要拷贝的宿主机文件路径 容器id:要拷贝到容器里面对应的路径
10、进入容器docker exec -it mynginx /bin/bash (有的容器需要把 /bin/bash 换成 sh)
11、容器内安装vim、ping、ifconfig等指令
apt-get update
apt-get install vim #安装vim
apt-get install iputils-ping #安装ping
apt-get install net-tools #安装ifconfig
12、删除容器
删除已停止的容器,如需删除正在运行的容器,可使用-f参数docker rm mynginx
强制删除所有容器docker rm -f $(docker ps -a -q)
13、查看网络docker network ls
docker network inspect docker-compose_default
将微服务运行在docker上
使用Dockerfile构建Docker镜像
vim Dockerfile
FROM ruby:2.6.5-alpine3.11
RUN apk add git curl htop zsh build-base mariadb-dev tzdata file imagemagick \
&& rm -rf /var/cache/apk/* \
&& bundle config git.allow_insecure true \
&& gem install bundler --version=1.17.3 \
&& sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" \
&& sed -i 's/robbyrussell/cloud/g' /root/.zshrc \
&& ln -sf /bin/zsh /bin/sh
ENV LANG C.UTF-8
WORKDIR /srv/app-api
COPY engines ./engines
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]
docker build -t app-api:v5 .
docker run --name run-api \
--network xxxx-bridge --network-alias run-api \
-p 5000:3000 --privileged=true \
-e APP_NAME=xxxxx \
-e APP_URL='http://xxxx.xxxxxx.com/' \
-v /data/run-api/log:/srv/run-api/log \
-d app-api:v5
Dockerfile常用指令
命令 | 用途 |
FROM | 基础镜像文件 |
RUN | 构建镜像阶段执行命令 |
ADD | 添加文件,从src目录复制文件到容器的dest,其中 src可以是 Dockerfile所在目录的相对路径,也可以是一个 URL,还可以是一个压缩包 |
COPY | 拷贝文件,和ADD命令类似,但不支持URL和压缩包 |
CMD | 容器启动后执行命令 |
EXPOSE | 声明容器在运行时对外提供的服务端口 |
WORKDIR | 指定容器工作路径 |
ENV | 指定环境变量 |
ENTRYPINT | 容器入口, ENTRYPOINT 和 CMD指令的目的一样,都是指定 Docker容器启动时执行的命令,可多次设置,但只有最后一个有效。 |
USER | 该指令用于设置启动镜像时的用户或者 UID,写在该指令后的 RUN、 CMD以及 ENTRYPOINT指令都将使用该用户执行命令。 |
VOLUME | 指定挂载点,该指令使容器中的一个目录具有持久化存储的功能,该目录可被容器本身使用,也可共享给其他容器。当容器中的应用有持久化数据的需求时可以在 Dockerfile中使用该指令。格式为: VOLUME[“/data”] |
注意:
RUN命令在 image 文件的构建阶段执行,执行结果都会打包进入 image 文件;
CMD命令则是在容器启动后执行;
一个 Dockerfile 可以包含多个RUN命令,但是只能有一个CMD命令
注意,指定了CMD命令以后,docker container run命令就不能附加命令了(比如前面的/bin/bash),否则它会覆盖CMD命令
demo
1、将jar包上传linux服务器/usr/local/docker-app/docker-demo/app/eureka目录
2、在jar包所在目录创建名为Dockerfile的文件
Dockerfile
# 基于哪个镜像
From java:8
# 复制文件到容器
ADD microservice-eureka-server-0.0.1-SNAPSHOT.jar /app.jar
# 声明需要暴露的端口
EXPOSE 8761
# 配置容器启动后执行的命令
ENTRYPOINT java ${JAVA_OPTS} -jar /app.jar
3、使用docker build命令构建镜像
docker build -t microservice-eureka-server:0.0.1 .
4、启动镜像,加-d可在后台启动
docker run -d -p 8761:8761 microservice-eureka-server:0.0.1
使用 -v 可以挂载一个主机上的目录到容器的目录
docker run -d -p 8761:8761 -v /log:/container-log microservice-eureka-server:0.0.1
加上JVM参数:# --cap-add=SYS_PTRACE 这个参数是让docker能支持在容器里能执行jdk自带类似jinfo,jmap这些命令,如果不需要在容器里执行这些命令可以不加
docker run -e JAVA_OPTS='-Xms1028M -Xmx1028M -Xmn512M -Xss512K -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M' --cap-add=SYS_PTRACE -d -p 8761:8761 microservice-eureka-server:0.0.1
将微服务镜像发布到远程镜像仓库
1、制作好了微服务镜像,一般需要发布到镜像仓库供别人使用
自建镜像仓库
docker官方镜像仓库 https://hub.docker.com/
2、要把镜像推送到镜像仓库,需要将镜像前面加个分组名(一般就是docker hub的账户名),执行如下命令修改镜像名字
docker tag microservice-eureka-server:0.0.1 zhuge666/microservice-eureka-server:0.0.1
3、将镜像推送到远程仓库
docker push zhuge666/microservice-eureka-server:0.0.1
登录到docker镜像查看下刚刚推送的镜像
docker PS VM
docker利用的是宿主机的内核,而不需要Guest OS
当新建一个容器时, docker不需要和虚拟机一样重新加载一个操作系统内核。避免了寻址、加载操作系统内核这些比较费时费资源的过程
当新建一个虚拟机时, 虚拟机软件需要加载Guest OS,这个新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了这个过程,因此新建一个docker容器只需要几秒钟。
特性 | 容器 | 虚拟机 |
启动 | 秒级 | 分钟级 |
硬盘 | 一般为MB | 一般为GB |
性能 | 接近原生 | 弱 |
系统支持量 | 单机支持上千容器 | 一般几十个 |
Docker是如何将机器的资源进行隔离的?
答案是联合文件系统,常见的有AUFS、Overlay、devicemapper、BTRFS和ZFS等。
以Overlay2举例说明,Overlay2的架构图如下:
原理:overlayfs在linux主机上只有两层,一个目录在下层,用来保存镜像(docker),另外一个目录在上层,用来存储容器信息。在overlayfs中,底层的目录叫做lowerdir,顶层的目录称之为upperdir,对外提供统一的文件系统为merged。当需要修改一个文件时,使用COW(Copy-on-write)将文件从只读的Lower复制到可写的Upper进行修改,结果也保存在Upper层。在Docker中,底下的只读层就是image,可写层就是Container。
写时复制 (CoW) 技术详解
所有驱动都用到的技术—写时复制,Cow全称copy-on-write,表示只是在需要写时才去复制,这个是针对已有文件的修改场景。
比如基于一个image启动多个Container,如果每个Container都去分配一个image一样的文件系统,那么将会占用大量的磁盘空间。
而CoW技术可以让所有的容器共享image的文件系统,所有数据都从image中读取,只有当要对文件进行写操作时,才从image里把要写的文件复制到自己的文件系统进行修改。
所以无论有多少个容器共享一个image,所做的写操作都是对从image中复制到自己的文件系统的副本上进行,并不会修改image的源文件,且多个容器操作同一个文件,会在每个容器的文件系统里生成一个副本,每个容器修改的都是自己的副本,互相隔离,互不影响。
使用CoW可以有效的提高磁盘的利用率。所以容器占用的空间是很少的。
查看容器占用磁盘大小指令:
# 查看所有容器的大小
cd /var/lib/docker/containers # 进入docker容器存储目录
du -sh * # 查看所有容器的大小
du -sh <容器完整id> #查看某一个容器的大小
用时分配 (allocate-on-demand)
用时分配是针对原本没有这个文件的场景,只有在要新写入一个文件时才分配空间,这样可以提高存储资源的利用率。比如启动一个容器,并不会为这个容器分配一些磁盘空间,而是当有新文件写入时,才按需分配新空间
docker中的镜像分层技术的原理是什么呢?
docker使用共享技术减少镜像存储空间,所有镜像层和容器层都保存在宿主机的文件系统/var/lib/docker/中,由存储驱动进行管理,尽管存储方式不尽相同,但在所有版本的Docker中都可以共享镜像层。在下载镜像时,Docker Daemon会检查镜像中的镜像层与宿主机文件系统中的镜像层进行对比,如果存在则不下载,只下载不存在的镜像层,这样可以非常节约存储空间。
查看容器资源使用情况的指令:
docker stats # 返回容器资源的实时使用情况,1秒刷新一次
docker stats --no-stream # 返回容器当时的资源使用情况
默认情况下,stats 命令会每隔 1 秒钟刷新一次输出的内容直到你按下 ctrl + c。下面是输出的主要内容:
[CONTAINER]:以短格式显示容器的 ID。
[CPU %]:CPU 的使用情况。
[MEM USAGE / LIMIT]:当前使用的内存和最大可以使用的内存。
[MEM %]:以百分比的形式显示内存使用情况。
[NET I/O]:网络 I/O 数据。
[BLOCK I/O]:磁盘 I/O 数据。
[PIDS]:PID 号。
注意:容器的内存使用最大限制默认可以接近宿主机的物理内存,可以通过"-m"参数限制容器可以使用的最大内存:
docker run -m 500M redis #限制容器的最大使用内存为500M
Docker 中运行 crontab
Docker tag slim 版本默认没有安装cron
Dockerfile 安装 cron
FROM ruby:2.6.5-slim-stretch
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
&& cron \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
ENV LC_ALL C.UTF-8
......
RUN echo "*/1 * * * * /bin/bash -l -c 'cd /srv/worker-api && RAILS_ENV=production bundle exec rake CrontabSystemServiceTest >> log/cron.log 2>&1'" >> /etc/crontab
RUN chmod +x ./entrypoint.sh
ENTRYPOINT ["./entrypoint.sh"]
- 执行apt安装cron时注意加入-y --no-install-recommends
- 安装完成后执行
rm -rf /var/lib/apt/lists/* && apt-get clean
命令,可以有效减小镜像的体积 - 启动脚本来添加crontab的启动命令
- bash -l -c (-l 使bash就像被作为登录shell调用一样; -c 如果存在-c选项,则从字符串读取命令)
entrypoint.sh
#!/bin/bash
set -x
# 保存环境变量
env >> /etc/default/locale
#开启crontab服务
/etc/init.d/cron start
-
/etc/init.d/cron start
用于启动crontab服务,但这样启动的crontab服务中配置的定时命令是没有Dockerfile中设置的环境变量的。 - 在执行之前
env >> /etc/default/locale
,这样有Dockerfile中通过ENV设置的环境变量在crontab中就可以正常读取了。