Docker快速入门

Docker

安装 Docker

配置好 CentOS 系统后,我们进入控制台后,先执行如下命令(如果系统中存在旧的Docker,则先卸载)

shell 复制代码
yum remove docker \
    docker-client \
    docker-client-latest \
    docker-common \
    docker-latest \
    docker-latest-logrotate \
    docker-logrotate \
    docker-engine \
    docker-selinux 

配置 Docker 的 yum 库

shell 复制代码
yum install -y yum-utils

如果这一步执行错误,说 mirrorlist 识别不到之类的,看下面这篇文章

https://www.cnblogs.com/maowenqiang/articles/7728685.html

然后配置 Docker 的 yum 源为阿里云源的

shell 复制代码
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce/repo

之后安装 docker

shell 复制代码
yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

安装完成后,我们可以通过以下命令查看是否完成安装

shell 复制代码
# 查看Docker版本
docker -v

# 启动Docker
systemctl start docker

# 停止Docker
systemctl stop docker

# 重启
systemctl restart docker

# 设置开机自启
systemctl enable docker

# 执行docker ps命令,如果不报错,说明安装启动成功
docker ps

其中的 dokcer images 是 docker 的一个进程,后续会讲,只有它启动了才会有结果。

之后就是配置docker镜像加速,进入阿里云官网,选择容器镜像服务ACR

点击管理控制台

在里面选择镜像加速器,选择CentOS,按照提示进行配置

OK,结束

部署 Mysql

执行命令

shell 复制代码
docker run -d 
	--name mysql 
	-p 3306:3306 
	-e TZ=Asia/Shanghai
	-e MYSQL_ROOT_PASSWORD=mysql 
	mysql

第一句意思是本地没有 Mysql,然后就去下载了。

安装完成,注意那个密码根据自己的情况设置

可以在 CentOS 上输入 ip address 查看IP。

我们可以通过 Navicat 测试以下连接,结果成功了!

证明什么?它下载后就配置好并启动了!!!

当我们利用 Docker 安装应用时,Docker 会自动搜索并下载应用镜像(image) 。镜像不仅包含应用本身,还包含应用运行所需要的环境、配置、系统函数库。Docker 会在运行镜像时创建一个隔离环境,称为容器

  1. 我们知道软件都是要依赖于操作系统的,比如哪些软件在windows系统上用,哪些在CentOS系统上用,用64位还是32位。而 Docker 在下载应用本身时相其依赖的环境和系统函数库一并下载,就可以实现跨系统运行了。
  2. Docker 运行时会创建一个隔离环境,也就是会和其他进程隔绝开来。因为一台好的服务器通常会运行多个项目,创建隔离环境把不同的项目隔绝开来。这里我们可以测试以下,再开启一个 mysql
    改一下端口号和名字

    使用命令 docker ps 查看开启的服务,两个 mysql,一个mysql,一个mysql2。
    这个类似于什么呢?我们在电脑上登录两个QQ,但是它们之间的信息、聊天、会话都是相互之间不干扰的。

**镜像仓库:**存储和管理镜像的平台,Docker官方维护了一个公共仓库:Docker Hub

MySQL只要下载一次就可以了,前面提到的 mysql,mysql2 虽然创建了两次,但是只有第一次进行了下载,第二次并没有下载,而是直接拿来用的。

命令解读

shell 复制代码
docker run -d -p 8080:8080 --name tongue-java-after tongue-java-after
shell 复制代码
docker run -d 
	--name mysql 
	-p 3306:3306 
	-e TZ=Asia/Shanghai 
	-e MYSQL_ROOT_PASSWORD=mysql 
	mysql
  • docker run:创建并运行一个容器,

  • -d 是让容器在后台运行

  • --name mysql:给容器起个名字,必须唯一

  • -p 3306:3306:设置端口映射

  • -e KEY=VALUE:是设置环境变量

  • mysql :指定运行的镜像的名字

    镜像名称一般分两部分组成:[repository]:[tag]

    • repository 是镜像名
    • tag 是镜像的版本

    在没有指定 tag 时,默认是 latest,代表下载最新版本的镜像。如果想指定版本可以这么写 mysql:5.7

解释一下 -p 3306:3306,第一个参数就是宿主机的端口号,第二个是容器内端口,通常用该应用默认的端口号,mysql是3306,tomcat是8080,这些不用管,主要是修改第一个

这个 -e KEY=VALUE 从官网查就可以,hub.docker.com,搜索 mysql。注意哦,这里面的第一个蓝色链接也是

常见命令

Docker 最常见的命令就是操作镜像、容器的命令,详见官方文档:https://docs.docker.com

镜像仓库和本地镜像就相当于maven仓库和本地maven仓库

  • docker pull:远端镜像拉取到本地

  • docker images:查看本地所有镜像,images 单词意思为镜像

  • docker rmi:删除镜像

  • docker build:编写 dockerfile 文件,通过 docker build 命令自定义镜像

  • docker save:镜像打包,保存到一个压缩文件中

  • docker load:压缩文件加载到本地镜像

  • docker push:docker save + docker load 是镜像文件进行分享的一种方式。还有一种就是 push + pull,类似于 git 的,比较方便。

  • docker run:创建并运行容器,每次都会创建一个新的容器

  • docker stop:停止容器的运行,但是容器还在

  • docker start:启动容器

  • docker ps:查看当前容器的运行状态

  • docker rm:删除容器

  • docker logs:查看容器运行的日志

  • docker exec:进入容器做一些操作

docker save + docker load 或者 dokcer push + docker pull 实现镜像传递

还有很多命令,需要的时候直接去官网查就可以

案例演示

查看 DockerHub,拉去 Nginx 镜像,创建并运行 Nginx 容器

  • 在DockerHub中搜索Nginx镜像,查看镜像的名称

    在 dockerhub 中搜索 nginx,认准绿色的字样,代表nginx官方提供的,然后使用右边的命令进行拉取

  • 拉去Nginx镜像

    使用命令拉取镜像,不指定版本时默认使用最新的

  • 查看本地镜像列表

    可以看到镜像的名字,版本,镜像ID,大小等信息。

    下面可以测验一下镜像的保存和加载

    docker load -i nginx.tar 后会输出加载过程,加上 -q 会不让它输出

  • 创建并运行Nginx容器

    返回的一个长字符串即容器的ID

  • 查看容器

    通过 docker ps -a 可以查看所有的容器,使用命令 docker ps 只能查看正在运行的容器。这里使用 docker ps -a 发现 mysql 停了(因为我重启了虚拟机),所以我又重新把虚拟机打开了。

    这里显示比较杂乱,我们可以通过一个命令来格式化一下输出,让输出更简洁

    shell 复制代码
    docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"
  • 停止容器

    停止后,可以看到不再运行了。通过 -a 参数可以查看到 nginx 停止了

  • 再次启动日志

    docker start nginx。注意不能用 docker run。

  • 查看日志

    可以看到 nginx 容器的日志输出

    当你使用 docker logs -f nginx 查看日志时,意思是持续查看,当有nginx日志记录更新时会直接输出,只有 Ctrl+C 才会退出。

  • 进入Nginx容器

    进入容器内部与 nginx 以命令行的方式进行交互

    exit 退出 mysql,再 exit 退出容器

  • 删除容器

    这里举例删除 mysql2。注意,运行中的容器要删除,必须先 stop,再 rm。

    也可以直接使用 docker rm mysql2 -f 强制删除

部署完成后,我们输入IP地址就可以访问到 nginx 了。

数据加载卷

🐯 需求

  1. 创建 Nginx 容器,修改 nginx 容器内的 html 目录下的 index.html 文件内容
  2. 将静态资源部署到 nginx 的 html 目录

nginx 的静态资源目录在哪里呢,我们查看官方文档可以看到

位于 /usr/share/nginx/html 目录下,我们尝试进去并修改 index.html

无法修改!!!这是因为容器只包含它运行所需要的系统函数库和依赖,也就是该容器的大小是最小的,此处 vi 命令显然不需要。那我们想修改的时候怎么办?使用数据卷

数据集

数据集是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁。每个容器都有一个自己的文件目录

使用docker命令创建数据卷,数据卷会在宿主机创建真实文件,/var/lib/docker/volumes/*/_data 这个路径是固定的。然后让容器的 /html 目录和 html 卷进行挂载,容器的 /conf 目录和 conf 卷挂载。挂载成功后,那么容器的 /conf 目录和宿主机的 /conf/_data 目录以及容器的 /html 和宿主机的 /html/_data 就进行了双向绑定。注意是双向绑定(和Vue的双向绑定一样)。这样想修改容器中的内容直接修改宿主机的就可以了。

常用命令

命令 说明
docker volume create 创建数据卷
docker volume ls 查看所有数据卷
docker volume rm 删除指定数据卷
docker volume inspect 查看某个数据卷的详情
docker volume prune 清除数据卷

我们可以直接通过 docker volume --help 命令查看

实例

那么如何完成我们开头的需求,来修改nginx容器内的文件内容呢?

🍈 在执行 docker run 命令时,使用 -v 数据卷:容器内目录 可以完成数据卷挂载,如果容器创建好了,那就没办法挂载了(所以此处需要删除nginx容器重新创建)。此外,当创建容器时,如果挂载了数据卷且数据卷不存在,会自动创建数据卷(也就是说 docker volume create 命令没必要了)

如此映射关系就有了

宿主机目录 数据卷 容器目录
/var/lib/docker/volumes/html/_data html /usr/share/nginx/html

我们来到这个宿主机目录下查看

确实就是 nginx 的两个 html 文件。我们直接用 Xftp 连接,修改文件

保存,刷新网页,查看结果

成功!我们再测试一下(用 Xshell 吧,比在虚拟机上敲命令看的更清晰)

网页上是可以直接访问到的

自定义镜像

镜像就是包含了应用程序、程序运行的系统函数库、运行配置等文件的文件包。构建镜像的过程其实就是把上述文件打包的过程。

准备 Linux 运行环境是为了让JVM虚拟机在任何环境下都能运行,所以直接把运行环境准备一份

镜像分层的好处是可以把镜像需要的东西更加细化,便于共享重复使用。举例如下,我们原先下载过 nginx 和 mysql 的镜像,我们再下载 redis 试试,发现有一部分是不用下载的,已经有的

制作镜像的时候别忘了定义入口

Dockerfile

Dockerfile 就是一个文本文件,其中包含一个个的指令,用指令来说明要执行什么操作来构建镜像。将来Docker可以根据Dockerfile帮我们构建镜像。常见指令如下:

指令 说明 示例
FROM 指定基础镜像 FROM centos:6
ENV 设置环境变量,可在后面指令使用 ENV key value
COPY 拷贝本地文件到镜像的指定目录 COPY ./jrell.tar.gz /tmp
RUN 执行Linux的shell命令,一般是安装过程的命令 RUN tar -zxvf /tmp/jrell.tar.gz && EXPORTS path=/tmp/jrell:$path
EXPOSE 指定容器运行时监听的端口,是给镜像使用者看的(最终还是 run 的时候通过 -p 指定才算,这里只是用来作提示作用) EXPOSE 8080
ENTRYPOINT 镜像中应用的启动命令,容器运行时调用 ENTRYPOINT java -jar xx.jar

详细语法参考 https://docs.docker.com/engine/reference/builder

当编写好了 Dockerfile,可以利用下面命令来构建镜像

shell 复制代码
docker build -t myImage:1.0 .
  • -t:给镜像起名,格式依然是 repository:tag 的格式,不指定 tag 时,默认为 latest

  • .:最后的一个小点,是指定 dockerfile 所在目录,如果就在当前目录,则指定为 . 。此外还要注意,我们 dockerfile 中的一些操作是和目录有关的,比如

    shell 复制代码
    COPY docker.deom.jar /app.jar

    是相对路径,所以你在执行的时候要把这个 docker-demo.jar 也放在这个目录下。

实例

我们在打包前需要修改配置文件

注意这里的 mysql8,是后面自定义网络中定义的容器名

然后编写Dockerfile文件,注意这里就是文件,不加后缀名

sql 复制代码
# 基础镜像
FROM openjdk:17
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝 jar 包
COPY tongue-after.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]

然后我们在根下创建文件夹 tongue,进行构建

然后启动

shell 复制代码
docker run -d -p 8080:8080 --name tongue-java-after tongue-java-after

启动后将 mysql8 和 tongue-java-after 加到同一个自定义网络中,这样这两个容器间就可以相互访问了,根据容器名就可以

shell 复制代码
docker network create tongue-network
docker network connect tongue-network mysql8
docker network connect tongue-network tongue-java-after

注意前面 Java 中配置文件里写的 mysql8 就是因为这里定义的名字为 mysql8

yaml 复制代码
spring:
	datasource:
		druid:
			url: jdbc:mysql://mysql8:3306/tongue

-- 这里可能要开放端口8080和3306,不知道需不需要哈。

然后就可以访问了

容器网络互连

容器是有自己独立的环境的,每个容器都有自己虚拟的IP地址,各个容器之间都是在一个网段中,有相同的网关。也就是说可以相互访问

我们需要自定义一个网络,让某些容器之间可以相互访问。

命令 说明
docker network create 创建一个网络
docker network ls 查看所有网络
docker network rm 删除指定网络
docker network prune 清除未使用的网络
docker network connect 使指定容器连接加入了某网络
docker network disconnect 使指定容器连接离开某网络
docker network inspect 查看网络详细信息

比如前面,我们想让 SpringBoot 程序的容器访问 mysql 容器,就必须如此

shell 复制代码
docker network create tongue-network
docker network connect tongue-network mysql8
docker network connect tongue-network tongue-java-after # 这样,mysql8和tongue-java-after 可以互相访问了

并且注意:加入自定义网络的容器才可以通过容器名互相访问,所以前面我们访问 mysql IP地址的时候直接使用的 mysql8,也就是容器的名字

Java应用部署

前面 1.5.2 已经说过怎么部署了,但是这里再提一个小技巧。就是开发环境与生产环境的变量配置,我们直接新建两个配置文件

application-dev.yaml

yaml 复制代码
tongue:
  db:
    host: mysql8 # docker中的容器名
    password: mysql

application-local.yaml

yaml 复制代码
tongue:
  db:
    host: 127.0.0.1
    password: mysql

这样我们在 application.yaml 中的配置就为

yaml 复制代码
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource # 使用 druid 连接池
    druid:
      username: root
      password: ${tongue.db.password}
      url: jdbc:mysql://${tongue.db.host}:3306/tongue
      driver-class-name: com.mysql.cj.jdbc.Driver

这样我们就不需要来回修改 application.yaml 文件了,当我们在本地继续编写代码时就读取的 application-local.yaml 文件的 host 和 password。当我们把项目部署上去,那就是读取的 application-dev 中的,非常方便。

部署前端

这里改一下配置之类的东西,首先是前端的

ts 复制代码
const request = axios.create({
    baseURL: '/tongue',
    timeout: 5000
}); // baseURL 注意

然后是 nginx.conf 的编写

js 复制代码
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/json;

    sendfile        on;
    
    keepalive_timeout  65;

    server {
        listen       8081; // 前端页面在这个端口启动
        # 指定前端项目所在的位置
        location / {
            root /usr/share/nginx/html/tongue-dist;  // 在容器中的位置
        }

        location /tongue {
	    rewrite /tongue/(.*) /$1 break; # 发起的所有 /tongue 在后端都将去掉
            proxy_pass http://tongue-java-after:8080;  // 请求发向后端
        }
    }
}

比如发送 /tongue/drink/data 映射到后端就是 /drink/data

所以Java后端的 yaml 配置

yaml 复制代码
# 去掉
#server:
#  servlet:
#    context-path: /tongue

以及之前配置的跨域的内容也去掉。

然后将前端的项目部署到某个目录下,这里放在了 /root/nginx 目录下

包括一个 html 文件夹和一个 nginx.conf 文件

html 文件夹放了我打包的前端项目,也就是打包后生成的 dist 文件,这里我重命名为 tongue-dist

然后新建一个 nginx 容器

shell 复制代码
docker run -d
	--name tongue-nginx
	-p 8081:8081
	-v /root/nginx/html:/usr/share/nginx/html
	-v /root/nginx/nginx.conf:/etc/nginx/nginx.conf # 映射关系的定义
	--network tongue-network # 加入到原来的 mysql 与 springboot 所在的网络
	nginx

DockerCompose

Docker Compose 通过一个单独的 docker-compose.yml 模板文件来定义一组相关联的应用容器(前端、后端、redis、中间件、nginx、网络互联等),帮助我们实现多个相互关联的 Docker 容器的快速部署。

最终都是为了运行,所以进行对比,基本上 docker-compose 中的内容和 docker run 差不多,只是语法不同

我们的 docker-compose.yml 文件可以这样写

yaml 复制代码
version: "3.8"

services:
  mysql8:  # compose 中的服务名
    image: mysql:8.0
    container_name: mysql8  # 真正创建出来的容器名
    ports:
      - "3306:3306"
    environment:
      TZ: Asia/Shanghai
      MYSQL_ROOT_PASSWORD: mysql
    volumes:
      - ./mysql/conf:/etc/mysql/conf.d  # 前面写我们宿主机上真实的地址
      - ./mysql/data:/var/lib/mysql
      - ./mysql/init:/docker-entrypoint-initdb.d
    networks:
      - tongue-network
    restart: always

  tongue-java-after:
    build:
      context: .  # 读取当前目录下的 dockerfile
      dockerfile: Dockerfile  # 还是用 dockerfile 构建 Java 应用
    container_name: tongue-java-after
    ports:
      - "8080:8080"
    depends_on:
      - mysql8  # 依赖于 mysql8,会先创建 mysql8
    networks:
      - tongue-network
    restart: always

  tongue-nginx:
    image: nginx:latest
    container_name: tongue-nginx
    ports:
      - "8081:8081"
    volumes:
      - /root/nginx/html:/usr/share/nginx/html
      - /root/nginx/nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - tongue-java-after
    networks:
      - tongue-network
    restart: always

networks:
  tongue-network: # compose 文件中用这个名字来引用
    name: tongue-network  # 真正创建网络时的名字
    driver: bridge  # 默认值,可省略

注意,无论是在 Java 程序中用数据库还是 Nginx 反向代理,都用这个里面的服务名而不是容器名!

docker compose 的命令格式如下

bash 复制代码
docker compose [OPTIONS] [COMMAND]
类型 参数或指令 说明
Options -f 指定 compose 文件的路径和名称,不指定则默认当前目录
Options -p 指定 project 名称
Commands up 创建并启动所有 service 容器
Commands down 停止并移除所有容器、网络
Commands ps 列出所有启动的容器
Commands logs 查看指定容器的日志
Commands stop 停止某个容器
Commands start 启动某个容器
Commands restart 重启某个容器
Commands top 查看运行的进程
Commands exec 在指定的运行中容器中执行命令

下面做一下,我们就可以把之前创建的所有 images, container 全部删除。

执行命令

bash 复制代码
docker compose up -d  # -d 后台运行

之后输入 docker compose ps 大概输出如下

bash 复制代码
NAME                IMAGE                 COMMAND                  SERVICE             STATUS          PORTS
mysql8              mysql:8.0             "docker-entrypoint.s..."   mysql8              Up              0.0.0.0:3306->3306/tcp
tongue-java-after   xxx-tongue-java-after "java -jar app.jar"      tongue-java-after   Up              0.0.0.0:8080->8080/tcp
tongue-nginx        nginx:latest          "/docker-entrypoint...."   tongue-nginx        Up              0.0.0.0:8081->8081/tcp

Compose 会用 project 名称来区分不同项目创建出来的容器、网络、卷等资源。

-p 的作用就是来指定你这个项目名,这样在执行 docker compose psdocker compose down 的时候知道是要操作哪个项目

如果我们没指定 container_name,那 Compose 会自动生成容器名,一般就是

bash 复制代码
项目名-服务名-序号

默认会用 compose 文件所在的目录名作为 project 名,也可以用 -p 手动指定,所以也可以理解为啥在 compose 下,容器之间互相访问是用 service 名而不是容器名了,因为容器名可能会变动。

还可以做集群部署

相关推荐
Shadow(⊙o⊙)1 小时前
进程间通信0.0-pipe()匿名管道,详细分析进程池调度队列执行逻辑,进程池模拟实现。
linux·运维·服务器·开发语言·c++
CQU_JIAKE1 小时前
6.6aaaaaa
linux·运维·服务器
VX_181 小时前
Docker镜像直接部署JumpServer
运维·docker·容器
丑过三八线1 小时前
Umi 配置文件 .umirc.ts 详解
linux·运维·ubuntu·react.js
咖啡星人k1 小时前
用 MonkeyCode 构建全栈应用:从需求到部署的AI自动化实践
运维·人工智能·自动化
努力搬砖的咸鱼1 小时前
容器编排底层原理:Kubernetes 网络模型与 CNI 插件
网络·微服务·云原生·容器·架构·kubernetes
Plastic garden1 小时前
K8s介绍(2)POD架构
云原生·容器·kubernetes
稷下元歌2 小时前
7天学会plc加机器视觉关于运动控制部份,配套视频在bib
开发语言·c++·git·vscode·python·docker·pip
团象科技2 小时前
中小出海团队运维观察:WordPress站点境外云环境搭建实操路径梳理
大数据·运维·人工智能