一起跟着官方文档学习《docker》

Docker/容器
280
0
0
2023-08-10
标签   Docker

了解 Docker

看官方文档前我们得了解下docker

. Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。
. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,
   然后发布到任何流行的  Linux  机器上,也可以实现虚拟化。
. 容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),
   更重要的是容器性能开销极低。 

docker的优势

. 解决了操作系统和软件运行环境的依赖例如: nginx 和git需要安装的 openssl 版本不同,
   在同一台设备上安装会造成软件冲突. 对于开发人员来说,再也不用担心不会部署开发环境
. 开发环境,测试环境和生产环境高度一致。
. 容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。
   无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。
   因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。 

docker的架构

docker三个基本概念

1.镜像(Image)

2.容器(Container)

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

3.仓库(Repository)

仓库可看着一个代码控制中心,用来保存镜像。

跟着官方文档安装docker

官方文档链接

1.选择对应的docker发行版,我们直接用 CentOS 上手练习.

docker发行版

2.设置存储库

安装 yum- utils 包(提供 yum-config-manager 使用程序)并设置 稳定 存储库

  yum  install -y yum-utils 

设置官方repo源

 yum-config-manager --add-repo  

安装 Docker 引擎

1.安装最新版本的 Docker Engine 和 containerd

 yum install docker-ce docker-ce-cli containerd.io 

不能联网的小伙伴可下载npm包, 前往 并选择您的 CentOS 版本。然后浏览 x86 _64/stable/Packages/ 并下载

 yum install /path/to/package.rpm 

2.启动docker

 systemctl start  docker ;
systemctl enable docker; 

可使用systemctl status docker查看状态

3.通过运行 hello-world 映像验证 Docker Engine 是否已正确安装

“此命令下载测试映像并在容器中运行它。当容器运行时,它会打印一条消息并退出”

 docker run hello-world 

4.首次运行hello-world,由于本地没有该镜像,会自动下载,通过docker images可查看当前存在的镜像

 docker images 

5. 【可选】设置在服务器启动时启动

 chkconfig docker on 

卸载 Docker 引擎

一般用于删除旧版本或者重新安装时才会用到

1.卸载 Docker Engine、CLI 和 Containerd 包

 yum remove docker-ce docker-ce-cli containerd.io 

2. 主机上的映像、容器、卷或自定义配置文件不会自动删除。删除所有镜像、容器和卷

  rm -rf /var/lib/docker
 rm -rf /var/lib/containerd 

学习Docker Compose

官方文档

1.官方的描述

Compose 是一个用于定义和运行的容器 Docker 应用程序的工具。借助 Compose,您可以使用 YAML 文件来配置应用程序的服务。然后,使用单个命令,从配置中创建并启动所有服务。要了解有关 Compose 的所有功能的更多信息,请参阅功能列表。
Compose 适用于所有环境:生产、登台、开发、测试以及 CI 工作流

使用 Compose 基本上是一个三步过程:

. 使用 定义您的应用程序的环境,Dockerfile以便它可以在任何地方复制。
. 定义组成您的应用程序的服务,docker-compose.yml 以便它们可以在隔离的环境中一起运行。
. 运行docker compose up和Docker compose command 启动并运行你的整个应用程序。
   您也可以docker-compose up使用 docker-compose 二进制文件运行。 

安装 Compose V2

1.安装并指定 复制到 $HOME/.docker/cli-plugins

  mkdir  -p ~/.docker/cli-plugins/
curl -SL  -o ~/.docker/cli-plugins/docker-compose
 chmod  +x ~/.docker/cli-plugins/docker-compose 

“安装得有点久 QAQ”

2.查看版本

 docker compose version 

官方对应V2版本的描述

新的 Compose V2 支持该compose命令作为 Docker CLI 的一部分,可作为 Docker Desktop 3.6 版本的候选版本。
Compose V2 将 compose 功能集成到 Docker 平台中,继续支持之前的大部分docker-compose功能和标志。您可以通过简单地将破折号 ( -) 替换为空格并运行docker compose, 而不是来测试 Compose V2 docker-compose。
由于 Docker Compose V2 是一个候选版本,我们建议您在生产环境中使用它之前进行广泛的测试。

生产版本建议安装稳定版本 Compose

1.安装稳定版 compose

 curl -L " -s)-$(uname -m)" -o /usr/local/bin/docker-compose 

2. 对 二进制 文件应用可执行权限

 chmod +x /usr/local/bin/docker-compose 

如果 docker-compose 安装后命令失败,请检查您的路径。您还可以在路径 /usr/bin 中创建指向或任何其他目录的符号链接。

 ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose 

3.查看版本

 docker-compose --version 

卸载 Compose

如果您使用 curl 以下方式安装,则直接删除compose文件即可

 rm /usr/local/bin/docker-compose 

入门 Compose

官方文档

1.创建项目文件夹&新增docker-compose.yml

 mkdir docker_demo && cd docker_demo
touch docker-compose.yml 

2.配置一个官方redis镜像用于测试

编辑文件 vi docker-compose.yml

 version: ".9"
services:
 my-redis:
  image: " redis :alpine" 

3.使用 Compose 构建并运行redis

 docker-compose up 

Compose 会拉取一个 Redis 镜像,为您的代码构建一个镜像,并启动您定义的服务。在这种情况下,代码会在构建时静态复制到映像中。

4.新建一个ssh console,我们通过docker images查看镜像情况

可以看到存在redis镜像, TAG版本为alpine

5.由于当前未配置挂载,停止应用程序直接在 原始终端中按 CTRL+C

也可以在第二个终端的项目目录中运行 docker- compose down

后台运行 Compose

1. 如果您想在后台运行您的服务,您可以将 -d 标志(用于“分离”模式)

 docker-compose up -d 

2.查看当前运行的服务

 docker-compose ps 

3.停止服务

 docker-compose stop 

4. 使用以下 down 命令关闭所有内容,完全删除容器

 docker-compose down 

宿主机绑定redis端口 对外开放

1.修改docker-compose.yml文件, 写入ports

当前配置宿主机的6380端口绑定到my-redis容器端口6379
 version: ".9"
services:
  my-redis:
    image: "redis:alpine"
    ports:
      - ":6379" 

2.运行compose

 docker-compose up -d 

3.查看端口绑定情况

 docker ps 

通过PORTS可以看到6380->6379/tcp

 netstat -alpn|grep 

通过netstat查看本地6380端口,也可以看到监听情况

4.使用redis客户端连接 端口为6380

添加挂载项目文件夹

volumes将主机上的项目目录(当前目录)挂载到容器/code内部,允许您即时修改代码,而无需重新构建映像

1.创建redis项目目录,可存放如redis.conf配置文件

 mkdir -p conf/redis
touch conf/redis/redis.conf 

2.修改docker-compose.yml文件, 设置redis配置目录到/code/

 [root@iZwzf7wlklxqmxg8enulrZ conf]# cd redis/
version: ".9"
services:
  my-redis:
    image: "redis:alpine"
    volumes:
      - ./conf/redis/:/code/
    ports:
      - ":6379" 

3.运行compose

 docker-compose stop
docker-compose up -d 

4.通过sh命令进入容器,查看/code是否存在redis.conf文件

通过docker-compose ps查看容器ID/NAMES

通过exec命令,进入容器终端

命令格式 docker exec -it CONTAINER ID/NAMES 执行终端

 docker exec -it docker_demo_my-redis_ /bin/sh 

进入/code文件夹,可以看到redis.conf文件

5.测试在容器修改redis.conf,宿主机是否同步更新

编辑 redis.conf文件,我们输入test字符串用于测试

 test 

此时文件大写为5kb

进入宿主机的conf/redis可以看到redis.conf也存在test字符串

配置环境变量

官方文档

1.修改docker-compose.yml文件,设置environment环境变量

我们设置一个key为MY_ENV的环境变量,值为development; LANG为zh_CN.UTF-8

 version: ".9"
services:
  my-redis:
    image: "redis:alpine"
    volumes:
      - ./conf/redis/:/code/
    environment:
      MY_ENV: development
       LANG : zh_CN.UTF-8
    ports:
      - ":6379" 

2.运行compose

 docker-compose stop
docker-compose up -d 

3.通过sh命令进入容器

 docker exec -it docker_demo_my-redis_ /bin/sh 

通过 echo 命令可以看出,LANG和MY_ENV环境变量已写入

替换 Compose 文件中的环境变量

1.可使用当前用户环境配置变量 .bash_profile

1) 修改docker-compose.yml文件,通过${}格式读取环境变量

 version: ".9"
services:
  my-redis:
    image: "redis:alpine"
    volumes:
      - ./conf/redis/:/code/
    environment:
      MY_ENV: ${MY_ENV}
      LANG: zh_CN.UTF-
    ports:
      - ":6379" 

2) 设置环境变量.bash_profile,写入MY_ENV

 echo "export MY_ENV=development" >> ~/.bash_profile
source ~/.bash_profile
echo $MY_ENV 


3) 运行compose

 docker-compose stop
docker-compose up -d 

4) 检查环境变量是否生效

 docker exec -it docker_demo_my-redis_ echo $MY_ENV
docker exec -it docker_demo_my-redis_ echo $LANG 

2.使用.env文件

1) 新增.env文件

 echo "MY_ENV=test" > .env
echo " JAVA _HOME=/usr/local/java/jdk_1.8.1" >> .env 

2) 我们新增JAVA_HOME环境变量,用于验证.env文件和.bash_profile环境变量的优先级

修改docker-compose.yml

 version: ".9"
services:
  my-redis:
    image: "redis:alpine"
    volumes:
      - ./conf/redis/:/code/
    environment:
      MY_ENV: ${MY_ENV}
      JAVA_HOME: ${JAVA_HOME}
      LANG: zh_CN.UTF-
    ports:
      - ":6379" 

3) 运行compose

 docker-compose stop
docker-compose up -d 

4) 通过condig查看 替换环境变量后的docker-compose

 docker-compose config 

很明显,我们写入.env的环境变量并没有覆盖.bash_profile环境变量

“官方给出答案 shell 中的值优先于 .env 文件中指定的值

5) 如果我们删除.bash_profile环境变量的MY_ENV,则.env文件的环境变量不会被覆盖

3.使用–env-file指定环境文件

在实际使用中,我们可能会有多个环境,只有一个.env显然不能满足需求,可通过–env-file指定使用的.env环境文件

1) 新增.env.pro文件,用于存放生产环境参数

 echo "MY_ENV=pro" > .env.pro 

2) 启动compose时,指定.env.pro

 docker-compose stop
docker-compose --env-file .env.pro up -d 

3) 检查环境变量信息

 docker exec -it docker_demo_my-redis_ /bin/sh
echo $MY_ENV 

当前MY_ENV环境变量已改成pro

在 Compose 中使用配置文件

官方文档

1.配置文件profile属性官方给出的说法

1) 配置文件允许通过有选择地启用服务来针对各种用途和环境调整 Compose 应用程序模型。这是通过将每个服务分配给零个或多个配置文件来实现的。如果未分配,则始终启动该服务,但如果已分配,则仅在激活配置文件时才启动。
2) 这允许人们在单个docker-compose.yml文件中定义额外的服务,这些服务应该只在特定场景中启动,例如用于调试或开发任务。

按我理解,profiles用于给每个服务设置标签,例如 debug -用于开发调试/prod-用于生产;

profiles允许设置多个;

2.设置profiles

1) 修改docker-compose.yml, 加入nginx服务,并且设置profiles属性

 version: ".9"
services:
  my-redis:
    image: "redis:alpine"
    volumes:
      - ./conf/redis/:/code/
    environment:
      MY_ENV: ${MY_ENV}
      JAVA_HOME: ${JAVA_HOME}
      LANG: zh_CN.UTF-
    ports:
      - ":6379"
  my-nginx:
    image: "nginx:latest"
    profiles:
      - debug 

2) 启动compose,不指定profiles

 docker-compose stop
docker-compose up -d 

通过docker-compose可以看出,只有my-redis服务启动了

3) 启动compose,指定profiles为debug

 docker-compose stop
docker-compose --profile debug up -d 

通过docker-compose可以看出,my-redis和my-nginx服务都启动了

服务依赖配置

在实际场景中,我们往往依赖A服务启动后,才能启动B服务;
例如 微服务 架构中,注册中心必须优先启动,其他服务才能依次运行.

1.我们修改docker-compose.yml,新增nacos服务,修改redis依赖nacos服务

 version: ".9"
services:
  my-redis:
    image: "redis:alpine"
    volumes:
      - ./conf/redis/:/code/
    environment:
      MY_ENV: ${MY_ENV}
      JAVA_HOME: ${JAVA_HOME}
      LANG: zh_CN.UTF-
    ports:
      - ":6379"
  my-nacos:
    image: 'nacos/nacos-server:latest'
    profiles:
      - test
  my-nginx:
    image: "nginx:latest"
    depends_on:
      - my-nacos
    profiles:
      - debug 

2.启动compose,指定profiles为debug

 docker-compose down
docker-compose --profile debug up -d 

结果启动会报错,因为nacos的profiles配置为test,而且nginx依赖nacos

遇到profiles不一致,但又想都启动的情况,可以使用指定多个–profile

 docker-compose --profile debug --profile test up -d 

在生产中使用 Compose

1.在不同环境中,我们可以为每个环境创建不同的docker-compose.ym副本

1) 例如创建一份prod生产配置

创建docker-compose-prod.yml

 touch docker-compose-prod.yml 

写入服务配置

 version: ".9"
services:
  my-redis:
    image: "redis:alpine"
    volumes:
      - ./conf/redis/:/code/
    environment:
      MY_ENV: ${MY_ENV}
      JAVA_HOME: ${JAVA_HOME}
      LANG: zh_CN.UTF-
    ports:
      - ":6379"
  my-nacos:
    image: 'nacos/nacos-server:latest' 

2) 运行compose

 docker-compose down
docker-compose -f docker-compose-prod.yml up -d 

通过docker-compose ps可以看出,运行了prod配置的my-nacos和my-redis

2.可以同时执行多个docker-compose.yml服务

1) 新增docker-compose-debug.yml服务

 version: ".9"
services:
  my-nginx:
    image: "nginx:latest" 

2) 运行compose

 docker-compose down
docker-compose -f docker-compose-debug.yml -f docker-compose-prod.yml up -d 

通过docker-compose ps 可以看出三个服务均正常运行

那么问题来了,如果有重复的配置,谁能覆盖谁? — 我们测试下

3) 修改prod配置,新增my-nginx环境变量

 version: ".9"
services:
  my-redis:
    image: "redis:alpine"
    volumes:
      - ./conf/redis/:/code/
    environment:
      MY_ENV: ${MY_ENV}
      JAVA_HOME: ${JAVA_HOME}
      LANG: zh_CN.UTF-
    ports:
      - ":6379"
  my-nacos:
    image: 'nacos/nacos-server:latest'
  my-nginx:
    image: "nginx:latest"
    environment:
      MY_ENV: prod 

4) 修改debug配置,增加环境变量

 version: ".9"
services:
  my-nginx:
    image: "nginx:latest"
    environment:
      MY_ENV: debug 

5) 启动compose

 docker-compose down
docker-compose -f docker-compose-debug.yml -f docker-compose-prod.yml up -d 

通过docker-compose ps 可以看出三个服务均正常运行

6) 检查my-nginx环境变量

 docker exec -it docker_demo_my-nginx_ /bin/sh
echo $MY_ENV 

结果MY_ENV环境变量为prod,后者覆盖前者配置

服务启动时,执行指定命令

command命令示例, 此示例最终执行command为 java -jar test.jar

command会覆盖默认的cmd命令

 version: ".9"
services:
  my-nginx:
    image: "nginx:latest"
    volumes:
      - ./conf/nginx/:/code/
    environment:
      MY_ENV: debug
    command:
      - java 
      - -jar
      - test.jar 

容器启动后,执行指定名

可通过entrypoint指定需要执行的命令或脚本

 version: ''
services:
  db:
    image: 'mysql:.7'
    container_name: mysql
    environment:
      - TZ=Asia/Shanghai
      - LANG=en_US.UTF-
    ports:
      - ':3307'
    entrypoint: /mysql.sh 

设置容器名

1.细心的同学应该发现,服务名名格式目前是{当前项目名}_{服务ID}_1

通过配置container_name可指定名称

修改docker-compose.xml文件

 version: ".9"
services:
  my-redis:
    image: "redis:alpine"
    container_name: mredis
    volumes:
      - ./conf/redis/:/code/
    environment:
      MY_ENV: ${MY_ENV}
      JAVA_HOME: ${JAVA_HOME}
      LANG: zh_CN.UTF-
    ports:
      - ":6379"
  my-nacos:
    image: 'nacos/nacos-server:latest'
    container_name: mnacos
  my-nginx:
    image: "nginx:latest"
    container_name: mnginx 

2.运行compose

 docker-compose down
docker-compose up -d 

通过docker-compose ps 可以看出服务名已变更为我们指定的名称

docker网络

官方文档

默认情况下,Compose为您的应用程序设置单个 网络 。服务的每个容器都加入默认网络,并且 可以 被该网络上的其他容器 访问 ,并且可以在与容器名称相同的主机名上被它们 发现

1.Docker有以下网络类型

bridge:多由于独立container之间的通信
host: 直接使用宿主机的网络,端口也使用宿主机的
overlay:当有多个docker主机时,跨主机的container通信
macvlan:每个container都有一个虚拟的MAC地址
none: 禁用网络

2. Docker在默认情况下,分别会建立一个bridge、一个host和一个none的网络

3.默认的bridge网络与自建bridge网络有以下区别:

1. 端口不会自行发布,必须使用-p参数才能为外界访问,而使用自建的bridge网络时,container的端口可直接被相同网络下的其他container访问。
2. container之间的如果需要通过名字访问,需要–link参数,而如果使用自建的bridge网络,container之间可以通过名字互访。
3. 更多的区别官方文档 #differences-between-user-defined-bridges-and-the-default-bridge

创建自定义网络并使用

1.创建自定义网络

创建名为my_network 的bridge网络,指定子网段172.20.0.0

 docker network create --driver=bridge --subnet=.20.0.0/16 my_network  

通过docker network ls 可以看到 已创建my_network网络


2.修改docker-compose.yml配置

 version: ".9"
services:
  my-nginx:
    image: "nginx:latest"
    volumes:
      - ./conf/nginx/:/code/
    environment:
      MY_ENV: debug
    command:
      - java 
      - -jar
      - test.jar

networks:
  my_network:
    external: true
    name: my_network 

3.运行compose

 docker-compose down
docker-compose up -d 

4.测试容器间的网络

 docker exec -it mnacos sh 

通过ping mnginx 和 ping mredis 可以看出,容器内部可以使用别名进行通信

使用重启策略

官方文档

Docker 建议您使用重启策略,并避免使用进程管理器来启动容器。

docker-compose.yml也可配置restart参数

 version: ".9"
services:
  my-redis:
    image: "redis:alpine"
    container_name: mredis
    ports:
      - ":6379"
    networks:
      - my_network
    restart: always 

制作自己的镜像

1.注册 Docker Hub账号


2.创建公共资源库(个人账号私有库只能一个,练习就用公开的)

3.从官方找一个纯净的CentOS系统

 docker search centos 

也可以从Docker Hub官网搜索

4.拉取镜像

 docker pull centos 

5.查看镜像信息

 docker images

6.创建并进入容器

格式:docker run -dit –name=容器名 镜像 id /bin/bash

 docker run -dit --name=test_centos centos /bin/bash 

通过docker ps可查看已经启动容器 名为test_centos

7.进入容器

 docker exec -it test_centos /bin/bash 

创建一个readme.md文件用于测试

 echo "hello world" > readme.md 

8.将容器制作成镜像

-m 来指定提交的说明信息,跟我们使用的版本控制工具一样;-a 可以指定更新的用户信息;之后是用来创建镜像的容器的 ID;最后指定目标镜像的仓库名和 tag 信息

 docker commit -m 'test' -a 'me' test_centos/panda_cn:v1 

通过docker images可看到已存在镜像并且版本为v1

9.将制作好的镜像推送到Docker Hub

 docker push/panda_cn:v1 

如果提示“ denied: requested access to the resource is denied

需要登录Docker HUB账号才行

 docker login -u 你的docker hub账号 

用DockerFile制作镜像

使用 docker commit 扩展一个镜像比较简单,但是不方便在一个团队中分享;
我们可以使用DockerFile构建镜像

1.创建DockerFile模板

 touch Dockerfile 

2.写入内容

FROM: 使用基础镜像

MAINTAINER: 作者

RUN: 开头的指令会在创建中运行,比如安装一个软件包

CMD: 执行命令

 # base image
FROM centos

# MAINTAINER
MAINTAINER test@.com

# install telnet
RUN yum install telnet -y

CMD echo "Hello world! This is my first Docker image." 

3.生成镜像

格式 docker build -t <your_username>/my-private-repo .

注意命令最后还有个 “ . 表示DockerFile位置处于当前路径

 docker build -t/panda_cn:V2 . 

通过docker ps查看镜像信息

4.测试镜像

格式 docker run <your_username>/my-private-repo

 docker run/panda_cn:V2 

4.推送镜像至Docker Hub

格式 docker push <your_username>/my-private-repo

 docker push/panda_cn:V2 

至此,docker你学废了吗

学得差不多了,我们来总结下

1.docker的镜像分层

2.镜像与容器的联系

3.镜像存储核心技术:写时复制(COW)

引入写时复制(copy-on-write),需要修改文件操作时,会先从镜像里把要写的文件复制到自己的文件系统(容器的读写层)中进行修改。源镜像层中的文件不会发生变化。