基础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"]
}

镜像docker站 docker镜像服务_镜像docker站

镜像相关命令

1、搜索镜像
docker search java 2、下载镜像
docker pull java:8docker 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 lsdocker 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的架构图如下:

镜像docker站 docker镜像服务_运维_02

原理: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站 docker镜像服务_容器_03


镜像docker站 docker镜像服务_docker_04

查看容器资源使用情况的指令:

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"]
  1. 执行apt安装cron时注意加入-y --no-install-recommends
  2. 安装完成后执行rm -rf /var/lib/apt/lists/* && apt-get clean命令,可以有效减小镜像的体积
  3. 启动脚本来添加crontab的启动命令
  4. bash -l -c (-l 使bash就像被作为登录shell调用一样; -c 如果存在-c选项,则从字符串读取命令)

entrypoint.sh

#!/bin/bash
set -x

# 保存环境变量
env >> /etc/default/locale

#开启crontab服务
/etc/init.d/cron start
  1. /etc/init.d/cron start用于启动crontab服务,但这样启动的crontab服务中配置的定时命令是没有Dockerfile中设置的环境变量的。
  2. 在执行之前 env >> /etc/default/locale,这样有Dockerfile中通过ENV设置的环境变量在crontab中就可以正常读取了。