Docker安装 {#Docker安装}
卸载 {#卸载}
如果之前有安装过旧版本的Docker,则通过命令卸载旧版本的Docker
|---------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11
| yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-selinux \ docker-engine-selinux \ docker-engine \ docker-ce
|
没有任何匹配,说明没装过docker
安装 {#安装}
首先需要虚拟机联网,安装yum工具
|---------------|---------------------------------------------------------------------------------------|
| 1 2 3
| yum install -y yum-utils \ device-mapper-persistent-data \ lvm2 --skip-broken
|
运行耐心等待一下,安装完成(最后显示 完毕!)
然后更新本地镜像源:配置阿里云的仓库
|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8
| # 设置docker镜像源 yum-config-manager \ --add-repo \ https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo yum makecache fast
|
安装docker
|-----------|----------------------------------|
| 1
| yum install -y docker-ce
|
docker-ce: 社区版
启动Docker {#启动Docker}
防火墙设置
|---------------------|----------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6
| # 关闭 systemctl stop firewalld # 禁止开机启动防火墙 systemctl disable firewalld # 可以查看防火墙状态 systemctl status firewalld
|
启动
|-------------------|-------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5
| systemctl start docker # 启动docker服务 systemctl stop docker # 停止docker服务 systemctl restart docker # 重启docker服务
|
查看docker状态
|-----------|---------------------------------|
| 1
| systemctl status docker
|
查看docker版本
|-----------|-------------------|
| 1
| docker -v
|
配置镜像加速 {#配置镜像加速}
docker官方镜像仓库网速较差,我们需要设置国内镜像服务:
参考阿里云的镜像加速文档: https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
|-------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8
| sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<- 'EOF' { "registry-mirrors" : [ "https://gtxivg4h.mirror.aliyuncs.com" ] } EOF sudo systemctl daemon-reload sudo systemctl restart docker
|
部署MySQL {#部署MySQL}
先停掉虚拟机中的MySQL,确保虚拟机已经安装Docker,且网络开通的情况下,执行下面命令即可安装MySQL
|---------------------|-------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6
| docker run -d \ --name mysql \ -p 3306:3306 \ -e TZ=Asia/Shanghai \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql
|
解读:
docker run -d :创建并运行一个容器,**-d**则是让容器以后台进程运行
--name mysql : 给容器起个名字叫mysql,必须唯一
-p 3306:3306 : 设置端口映射。(后面这个是容器内MySQL默认端口,前面是映射出去的端口(宿主机),比如3307)
容器是隔离环境,外界不可访问。但是可以将宿主机端口映射容器内到端口,当访问宿主机指定端口时,就是在访问容器内的端口了。
容器内端口往往是由容器内的进程决定,例如MySQL进程默认端口是3306,因此容器内端口一定是3306;而宿主机端口则可以任意指定,一般与容器内保持一致。
格式: -p 宿主机端口:容器内端口,示例中就是将宿主机的3306映射到容器内的3306端口
-e TZ=Asia/Shanghai : 配置容器内进程运行时的一些参数(e-->environment)
格式:**-e KEY=VALUE**,KEY和VALUE都由容器内进程决定
案例中,TZ=Asia/Shanghai是设置时区;MYSQL_ROOT_PASSWORD=123456是设置MySQL默认密码
mysql : 设置镜像名称,Docker会根据这个名字搜索并下载镜像
格式:REPOSITORY:TAG,例如mysql:8.0,其中REPOSITORY可以理解为镜像名,TAG是版本号
在未指定TAG的情况下,默认是最新版本,也就是mysql:latest
连接远程数据库 {#连接远程数据库}
打开数据库连接工具
如果出现 没有权限 ,则在Docker容器中,输入指令, 进入容器,查看容器内目录
|-----------|--------------------------------------------------|
| 1
| docker exec -it container_name /bin/bash
|
登录MySQL
|-----------|--------------------------|
| 1
| mysql -u root -p
|
修改权限
|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5
| ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456'; # 更新user为root,host为% 的密码为123456 ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456'; # 更新user为root,host为localhost 的密码为123456
|
刷新权限
|-----------|---------------------------------|
| 1
| FLUSH PRIVILEGES; #刷新权限
|
最后查询用户信息 (查看root用户)
|-----------|------------------------------------------------------------------------|
| 1
| select host,user,plugin,authentication_string from mysql.user;
|
连接成功则可以像在Windows操作本地数据库一样的了
Docker基础 {#Docker基础}
常见命令 {#常见命令}
| 命令 | 说明 | |----------------|---------------------| | docker pull | 拉取镜像 | | docker push | 推送镜像到DockerRegistry | | docker images | 查看本地镜像 | | docker rmi | 删除本地镜像 | | docker run | 创建并运行容器(不能重复创建) | | docker stop | 停止指定容器 | | docker start | 启动指定容器 | | docker restart | 重新启动容器 | | docker rm | 删除指定容器 | | docker ps | 查看容器 | | docker logs | 查看容器运行日志 | | docker exec | 进入容器 | | docker save | 保存镜像到本地压缩文件 | | docker load | 加载本地压缩文件到镜像 | | docker inspect | 查看容器详细信息 | | docker stats | 查看容器资源使用情况(通过容器id) |
Docker文档 Docker Docs
案例 {#案例}
以拉取Nginx为例:
需求:
- 在DockerHub中搜索Nginx镜像,查看镜像的名称
- 拉取Nginx镜像
- 查看本地镜像列表
- 创建并运行Nginx容器
- 查看容器
- 停止容器
- 再次启动容器
- 进入Nginx容器
- 删除容器
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| # 1.访问Docker Hub搜索镜像 # 2.拉取Nginx镜像,不指定版本即默认为latest最新 docker pull nginx # 3.查看本地镜像列表 docker images # 结果如下 [root@localhost ~] # docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx latest 605c77e624dd 22 months ago 141MB mysql latest 3218b38490ce 22 months ago 516MB # 4.创建并运行Nginx容器 docker run -d --name nginx -p 80:80 nginx # 5.查看容器 docker ps # 5.1查看容器格式化(格式会更加清爽) docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}" # 结果 [root@localhost ~] # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES b83c1bfa9956 nginx "/docker-entrypoint...." 2 minutes ago Up 2 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp nginx [root@localhost ~] # docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}" CONTAINER ID IMAGE PORTS STATUS NAMES b83c1bfa9956 nginx 0.0.0.0:80->80/tcp, :::80->80/tcp Up 2 minutes nginx # 6.停止容器 docker stop nginx # 6.1查看所有容器 docker ps -a docker ps -a --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}" # 结果:(刚刚停止的Nginx的状态为Exited) [root@localhost ~] # docker ps -a --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}" CONTAINER ID IMAGE PORTS STATUS NAMES b83c1bfa9956 nginx Exited (0) 3 minutes ago nginx 107a163cba71 mysql 3306/tcp, 33060/tcp Created xenodochial_allen b32527ef7193 mysql Exited (0) 25 hours ago mysql # 7.启动容器 docker start nginx # 8.进入容器,查看容器内目录 docker exec -it nginx bash # ecec:执行 -it:模拟可输入终端 bash:命令行交互 # 9.查看日志 docker logs nginx # 查看nginx日志 docker logs -f nginx # 一直查看Nginx日志 # 10.退出容器 exit # 11.删除容器 docker rm nginx # 在运行的容器删除会提示 # 无法删除,则需要先停止(stop在rm),或者 docker rm -f nginx
|
命令别名 {#命令别名}
比如在前面的案例中,我们需要对docker ps显示的内容进行格式化(format),指令过长,每一次都要输入这么多, 非常麻烦
|---------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 修改/root/.bashrc文件 vi /root/.bashrc 内容如下: # .bashrc # User specific aliases and functions alias rm = 'rm -i' alias cp = 'cp -i' alias mv = 'mv -i' alias dps= 'docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"' alias dis= 'docker images' # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi
|
然后,执行命令使别名生效:
|-----------|------------------------------|
| 1
| source /root/.bashrc
|
所以当我们设置了这个, 如果需要查看镜像的情况, 则可以使用dps格式化别名指令
数据卷 {#数据卷}
容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部,我们要读写容器内的文件非常不方便 (比如我们进入到容器中使用vi指令修改index.html会提示没有指令).
数据卷(volume) 是一个虚拟目录,是 容器内目录 与 宿主机目录 之间映射的桥梁
以Nginx为例,众所周知
- html: 放静态资源
- conf: 放配置文件
如果我们要让Nginx代理我们的静态资源,最好是放到 html
目录;如果我们要修改Nginx的配置,最好是找到 conf
下的 nginx.conf
文件
但是非常遗憾的一点是, 不能直接去修改它(原容器), 容器运行的Nginx所有的文件都在容器内部。所以我们必须利用数据卷将两个目录与宿主机目录关联,方便我们操作。如图:
上图解答:
我们创建了两个数据卷html和conf
其中html对应nginx容器中的/html, 通过数据卷指向了宿主机中的文件/html, _data是用来存放数据自动创建的, 这样一来容器和宿主机就被 关联 起来了了, 称之为 挂载
这样我们就可以在宿主机中的 /var/lib/docker/volumes/html/_data 存放资源, 那么容器中的数据也会被容器相对应的目录所映射
当前操作为 双向绑定 , 宿主机自动映射到容器
/var/lib/docker/volumes目录为默认存放所有容器数据卷的目录, 在下根据数据卷的名称创建新目录, 例如: /数据卷名称/_data
数据卷命令 {#数据卷命令}
| 命令 | 说明 | |-----------------------|------------| | docker volume create | 创建数据卷 | | docker volume ls | 查看所有数据卷 | | docker volume rm | 删除指定数据卷 | | docker volume inspect | 查看某个数据卷的详情 | | docker volume prune | 清除数据卷 |
Docker文档 Docker Docs
注意: 容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且 创建容器的过程中,数据卷会自动创建 。
案例 {#案例-1}
需求;
- 创建Nginx容器, 修改nginx容器内的html目录下的index.html文件内容
- 将静态资源部署到nginx的html目录
提示: 在执行docker run 命令时, 使用 -v 数据卷:容器内目录 可以完成数据卷挂载
当创建容器时, 如果挂载了数据卷且数据卷不存在, 则会自动创建数据卷
|------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| # 1.首先创建容器并指定数据卷,注意通过 -v 参数来指定数据卷 docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx # 2.然后查看数据卷 docker volume ls # 结果 [root@localhost ~] # docker volume ls DRIVER VOLUME NAME local a8bcfc131404273c3d5a5a450fbcc270dbf414d1367648190e864eebfc7802ad local html # 刚刚创建的卷在这 # 3.查看数据卷详情 docker volume inspect html # 结果 [root@localhost ~] # docker volume inspect html [ { "CreatedAt" : "2023-11-05T21:18:52+08:00" , "Driver" : "local" , "Labels" : null, "Mountpoint" : "/var/lib/docker/volumes/html/_data" , # 宿主机位置(映射) "Name" : "html" , "Options" : null, "Scope" : "local" } ] # 4.查看/var/lib/docker/volumes/html/_data目录 [root@localhost ~] # ll /var/lib/docker/volumes/html/_data 总用量 8 -rw-r--r--. 1 root root 497 12月 28 2021 50x.html -rw-r--r--. 1 root root 615 12月 28 2021 index.html # 5.进入该目录,并随意修改index.html内容 [root@localhost ~] # cd /var/lib/docker/volumes/html/_data #修改 [root@localhost _data] # vi index.html # 6.进入容器内部,查看/usr/share/nginx/html目录内的文件是否变化 docker exec -it nginx bash cd /usr/share/nginx/html
|
如果不指定挂载目录,自动会为你挂载到/usr/lib下
挂载本地目录或文件 {#挂载本地目录或文件}
数据卷的目录结构较深,如果我们去操作数据卷目录会不太方便。在很多情况下,我们会直接将容器目录与宿主机指定目录挂载。挂载语法与数据卷类似:
|-----------------|-------------------------------------------------------|
| 1 2 3 4
| # 挂载本地目录 -v 本地目录:容器内目录 # 挂载本地文件 -v 本地文件:容器内文件
|
注意: 本地目录或文件必须以 `/` 或 `./`开头,如果直接以名字开头,会被识别为数据卷名而非本地目录名。
|-------------|-------------------------------------------------------------------------------------------------------------------------------|
| 1 2
| -v mysql:/var/lib/mysql # 会被识别为一个数据卷叫mysql,运行时会自动创建这个数据卷 -v ./mysql:/var/lib/mysql # 会被识别为当前目录下的mysql目录,运行时如果不存在会创建目录
|
案例需求:
- 挂载
/root/mysql/data
到容器内的/var/lib/mysql
目录 - 挂载
/root/mysql/init
到容器内的/docker-entrypoint-initdb.d
目录(初始化的SQL脚本目录 ---> 只有第一次才生效) - 挂载
/root/mysql/conf
到容器内的/etc/mysql/conf.d
目录(这个是MySQL配置文件目录)
解释: init为SQL脚本初始化, conf为配置文件, 其中配置文件主要是配置一些MySQL默认编码, utf8mb4
我们在虚拟机创建对应的目录,data, init, conf
本地目录挂载:(关于MySQL的挂载详情直达 MySQL Image | Docker Hub )
|---------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| # 1.删除原来的MySQL容器 docker rm -f mysql # 2.进入root目录(:需要设置挂载的目录,提前创建好挂载目录) cd ~ # 3.创建并运行新的MySQL容器,并且挂载(-v)到本地目录 # 当前使用的路径为全路径 /root/mysql, 也可以./root/mysql docker run -d \ --name mysql \ -p 3306:3306 \ -e TZ=Asia/Shanghai \ -e MYSQL_ROOT_PASSWORD=123456 \ -v /root/mysql/data:/var/lib/mysql \ -v /root/mysql/conf:/etc/mysql/conf.d \ -v /root/mysql/init:/docker-entrypoint-initdb.d \ mysql # 4.查看MySQL容器内数据 # 查看data目录,会发现里面有大量数据库数据,说明数据库完成了初始化 ls -l data # 4.1 进入MySQL docker exec -it mysql bash # 4.2 登录mysql # 4.3 查看编码表 show variables like "%char%" # 结果,发现编码是预设的utf8mb4没有问题 +--------------------------+--------------------------------+ | Variable_name | Value | +--------------------------+--------------------------------+ | character_set_client | utf8mb4 | | character_set_connection | utf8mb4 | | character_set_database | utf8mb4 | | character_set_filesystem | binary | | character_set_results | utf8mb4 | | character_set_server | utf8mb4 | | character_set_system | utf8mb3 | | character_sets_dir | /usr/share/mysql-8.0/charsets/ | +--------------------------+--------------------------------+ # 5.查看数据(其实就是SQL语言了)
|
镜像 {#镜像}
在这之前, 前面都是pull别人的镜像, 如果我也需要部署一个自己的镜像, 那么该怎么做呢?
镜像结构 {#镜像结构}
在构建镜像之前, 我们需要先了解镜像的结果.
镜像之所以可以让我们 快速 跨操作系统部署应用而忽略其运行环境、配置,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依赖。
所以不容易看出, 自定义镜像的本质就是依次准备好程序运行的基础环境、依赖、应用本身、运行配置等文件,并且打包而成
镜像是由 层级结构 组成: (在我们pull镜像的时候就不难看出)
Dockerfile {#Dockerfile}
Dockerfile就是一个文本文件, 其中包含了一个个的 指令(Instruction) , 用指令来说明要执行什么操作来构建镜像。将来Docker可以根据Dockerfile来帮我们构建镜像。常见指令如下:
| 指令 | 说明 | 示例 | |----------------|----------------------------|-----------------------------| | FROM | 指定基础镜像 | from centos:6 | | ENV | 设置环境变量,可在后面指令使用 | enu alue | | COPY | 拷贝本地文件到镜像的指定目录 | copy ./xx.jar /tmp/app.jar | | RUN | 执行Linux的shell命令,一般是安装过程的命令 | run yum install gcc | | EXPOSE | 指定容器运行时监听的端口,是给镜像使用者看的 | expose 8080 | | ENTRYPOINT | 镜像中应用的启动命令,容器运行时调用 | entrypoint java -jar xx.jar |
更多详细语法, 请参考官方文档 Dockerfile reference | Docker Docs
例如需要基于Ubuntu构建一个Java应用, 其中Dockerfile内容如下
|---------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| # 指定基础镜像 FROM ubuntu:16.04 # 配置环境变量,JDK的安装目录、容器内时区 ENV JAVA_DIR=/usr/local ENV TZ=Asia/Shanghai # 拷贝jdk和java项目的包 COPY ./jdk8.tar.gz $JAVA_DIR / COPY ./docker-demo.jar /tmp/app.jar # 设定时区 RUN ln -snf /usr/share/zoneinfo/ $TZ /etc/localtime && echo $TZ > /etc/timezone # 安装JDK RUN cd $JAVA_DIR \ && tar -xf ./jdk8.tar.gz \ && mv ./jdk1.8.0_144 ./java8 # 配置环境变量 ENV JAVA_HOME= $JAVA_DIR /java8 ENV PATH= $PATH : $JAVA_HOME /bin # 指定项目监听的端口 EXPOSE 8080 # 入口,java项目的启动命令 ENTRYPOINT [ "java" , "-jar" , "/app.jar" ]
|
对于JDK镜像配置, 我们可以使用别人提供的JDK基础镜像, 简化Dockerfile
|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9
| # 基础镜像 FROM openjdk:11.0-jre-buster # 省去JDk配置 # 设定时区 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/ $TZ /etc/localtime && echo $TZ > /etc/timezone # 拷贝jar包 COPY docker-demo.jar /app.jar # 入口 ENTRYPOINT [ "java" , "-jar" , "/app.jar" ]
|
最后相对于上面那个, 下面这个简洁了很多了
构建镜像 {#构建镜像}
当Dockerfile编写好之后, 就可以使用命令来构建镜像了, 例如在当前目录下准备好了一个 Dockerfile
文件和 ClickCount.jar
项目jar包
|-----------------|----------------------------------------------------------------------|
| 1 2 3 4
| # 进入存放文件的目录 cd /root/demo # 开始构建 docker build -t click:1.0 .
|
命令说明:
docker build
: 构建一个docker镜像-t
:是给镜像起名, 格式一人撒repository:tag的格式, 如果不指定tag,则默认为latest.
:最后的点代表当前目录(Dockerfile所在目录), 也可以指定其他目录的Dockerfile
|-------------|--------------------------------------------------------------------------------------|
| 1 2
| # 例如指定/root/dockerfile_demo目录 docker build -t click:1.0 /root/dockerfile_dem
|
查看镜像列表
|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7
| # 查看镜像列表: docker images # 结果 REPOSITORY TAG IMAGE ID CREATED SIZE click 1.0 d6ab0b9e64b9 10 minutes ago 89MB nginx latest 605c77e624dd 16 months ago 141MB mysql latest 3218b38490ce 17 months ago 517MB
|
网络 {#网络}
在上面的案例, 我们已经创建了Java项目的容器, 其中往往Java项目需要访问其他容器中间件(MySQL,Redis等), 他们需要访问则需要通过网络
默认情况下, 所有容器都是以bridge(网桥)方式连接到Docker的一个虚拟网桥上
|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 1.用基本命令,寻找Networks.bridge.IPAddress属性 docker inspect mysql # 也可以使用format过滤结果 docker inspect --format= '{{range .NetworkSettings.Networks}}{{println .IPAddress}}{{end}}' mysql # 得到IP地址如下: 172.17.0.2 # 2.然后通过命令进入dd容器 docker exec -it dd bash # 3.在容器内,通过ping命令测试网络 ping 172.17.0.2 # 结果 PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data. 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.053 ms 64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.059 ms 64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.058 ms
|
发现Ping通, 并没有什么问题
但是,容器的网络IP其实是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP会发生变化,连接会失败
官方文档 docker network | Docker Docs
常见网络命令有:
| 命令 | 说明 | 文档地址 | |---------------------------|--------------|-------------------------------------------------------------------------------------------------------| | docker network create | 创建一个网络 | docker network create | | docker network ls | 查看所有网络 | docs.docker.com | | docker network rm | 删除指定网络 | docs.docker.com | | docker network prune | 清除未使用的网络 | docs.docker.com | | docker network connect | 使指定容器连接加入某网络 | docs.docker.com | | docker network disconnect | 使指定容器连接离开某网络 | docker network disconnect | | docker network inspect | 查看网络详细信息 | docker network inspect |
自定义网络 {#自定义网络}
|---------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| # 1.首先通过命令创建一个网络 docker network create qlh # 2.然后查看网络 docker network ls # 结果: NETWORK ID NAME DRIVER SCOPE e070f0159014 bridge bridge local cfb0c477c4dc host host local 9393a7da1c50 none null local f5084a25485a qlh bridge local # 其中,除了qlh以外,其它都是默认的网络 # 3.让dd和mysql都加入该网络,注意,在加入网络时可以通过--alias给容器起别名 # 这样该网络内的其它容器可以用别名互相访问! # 3.1.mysql容器,指定别名为db,另外每一个容器都有一个别名是容器名 docker network connect qlh mysql -- alias db # 3.2.db容器,也就是我们的java项目 docker network connect qlh dd # 4.进入dd容器,尝试利用别名访问db # 4.1.进入容器 docker exec -it dd bash # 4.2.用db别名访问 ping db # 结果 PING db (172.18.0.2) 56(84) bytes of data. 64 bytes from mysql.qlh (172.18.0.2): icmp_seq=1 ttl=64 time=0.070 ms 64 bytes from mysql.qlh (172.18.0.2): icmp_seq=2 ttl=64 time=0.056 ms # 4.3.用容器名访问 ping mysql # 结果: PING mysql (172.18.0.2) 56(84) bytes of data. 64 bytes from mysql.qlh (172.18.0.2): icmp_seq=1 ttl=64 time=0.044 ms 64 bytes from mysql.qlh (172.18.0.2): icmp_seq=2 ttl=64 time=0.054 ms
|
现在可以通过别名(例如: db)访问
总结:
- 在自定义网络中,可以给容器起多个别名,默认的别名是容器名本身
- 在同一个自定义网络中的容器,可以通过别名互相访问
(旧)项目部署示例 {#旧-项目部署示例}
尝试部署黑马商城
项目结构:
- hmall: 商城的后端代码
- hmall-portal:商城用户端的前端代码
- hmall-admin:商城管理端的前端代码
部署的容器及端口说明:
| 项目 | 容器名 | 端口 | 备注 | |--------------|---------|--------|-------------| | hmall | hmall | 8080 | 黑马商城后端API入口 | | hmall-portal | nginx | 18080 | 黑马商城用户端入口 | | hmall-admin | nginx | 18081 | 黑马商城管理端入口 | | mysql | mysql | 3306 | 数据库 |
在正式部署前,我们先删除之前的nginx、dd两个容器:
|-----------|-------------------------------|
| 1
| docker rm -f nginx dd
|
mysql容器中已经准备好了商城的数据,所以就不再删除了。
部署SpringBoot项目 {#部署SpringBoot项目}
hamll项目是一个maven聚合项目, 打开项目结构如下
hamll
----->hm-common 通用工具模块
----->hm-service 业务模块
其中我们需要部署的是hm-service模块, 其中配置文件采用了多环境的方式
- application.yml
- application-dev.yml
- application-local.yml
其中的
application-dev.yaml
是部署到开发环境的配置,application-local.yaml
是本地运行时的配置
查看application.yaml,会发现其中的JDBC地址并未写死,而是读取变量:
|---------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13
| # 启动端口 server: port: 9000 spring: # 环境修改 profile: active: dev # 数据库相关 1. db.host 2. db.pw datasource: url: jdbc:mysql://${db.host}:3306/hmall?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=true username: root password: ${db.pw} driver-class-name: com.mysql.cj.jdbc.Driver
|
这两个变量在 application-dev.yml
和 application-local.yml
中并不相同:
|---------------------------|--------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9
| # application-dev.yml db: host: mysql pw: 123 # application-local.yml db: host: localhost pw: 123456
|
在dev开发环境(也就是Docker部署时)采用了mysql作为地址,刚好是我们的mysql容器名,只要两者在一个网络,就一定能互相访问
将 hm-service
目录下的 Dockerfile
和 hm-service/target
目录下的 hm-service.jar
一起上传到虚拟机的 root
目录
部署项目
|------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # 1.构建项目镜像,不指定tag,则默认为latest docker build -t hmall . # 2.查看镜像 docker images # 结果 REPOSITORY TAG IMAGE ID CREATED SIZE hmall latest 0bb07b2c34b9 43 seconds ago 362MB docker-demo 1.0 49743484da68 24 hours ago 327MB nginx latest 605c77e624dd 16 months ago 141MB mysql latest 3218b38490ce 17 months ago 516MB # 3.创建并运行容器,并通过--network将其加入hmall网络,这样才能通过容器名访问mysql docker run -d --name hmall --network hmall -p 8080:8080 hmall
|
测试,通过浏览器访问:http://你的虚拟机地址:8080/search/list。
部署前端 {#部署前端}
hmall-portal
和 hmall-admin
是前端代码,需要基于nginx部署。在黑马资料中已经提供了nginx的部署目录
其中:
html
是静态资源目录,我们需要把hmall-portal
以及hmall-admin
都复制进去nginx.conf
是nginx的配置文件,主要是完成对html
下的两个静态资源目录做代理
我们现在要做的就是把整个nginx目录上传到虚拟机的 /root
目录下:
然后创建nginx容器并完成两个挂载:
- 把
/root/nginx/nginx.conf
挂载到/etc/nginx/nginx.conf
- 把
/root/nginx/html
挂载到/usr/share/nginx/html
由于需要让nginx同时代理hmall-portal和hmall-admin两套前端资源,因此我们需要暴露两个端口:
- 18080:对应hmall-portal
- 18081:对应hmall-admin
命令如下:
|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8
| docker run -d \ --name nginx \ -p 18080:18080 \ -p 18081:18081 \ -v /root/nginx/html:/etc/nginx/html \ -v /root/nginx/nginx.conf:/etc/nginx/nginx.conf \ --network hmall \ nginx
|
测试,通过浏览器访问:http://你的虚拟机ip:18080
(新)项目部署 {#新-项目部署}
在Windows和Linux下部署其实是一样的,首先我们需要将 Dockerfile
和 project.jar
放在一个目录下面
例如 Dockerfile
示例如下
|------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12
| # 添加 Java 8 镜像来源 FROM registry.cn-beijing.aliyuncs.com/hub-mirrors/openjdk:8-jdk-alpine #WORKDIR指令用于指定容器的一个目录, 容器启动时执行的命令会在该目录下执行。 WORKDIR /opt/docker/images/calyeedatabases/ # 添加 Spring Boot 包 ADD chat-server-1.0-SNAPSHOT.jar /chat-server-1.0-SNAPSHOT.jar EXPOSE 8080 EXPOSE 8090 # 执行启动命令 /chat-server-1.0-SNAPSHOT.jar需要和上面的一样 ENTRYPOINT ["java","-jar","/chat-server-1.0-SNAPSHOT.jar"]
|
然后jar包也在当前目录,例如 chat-server-1.0-SNAPSHOT.jar
然后我们需要输入指令
|-----------|------------------------------------------------------------------|
| 1
| docker build -f Dockerfile -t calyee/calyeechat:1.0 .
|
然后就可以看到有镜像(calyee/calyeechat:1.0)了
我们需要将镜像跑起来
|-----------|-----------------------------------------------------------------------------------------|
| 1
| docker run -d -p 8080:8080 -p 8090:8090 --name calyeechat calyee/calyeechat:1.0
|
在当前项目我们开了两个端口 所以需要映射两个端口出去(当前我们没有用到网桥,如需使用网桥可以参考整合下面小结#FastDFS)
然后 docker start calyeechat
即可,如果我们没有运行成功,需要查看报错信息,可以使用 docker logs 容器id
.
DockerCompose {#DockerCompose}
在当前的项目部署示例中, 我们部署了 1)MySQL容器 2)Nginx容器 3) Java项目, 但是在以后复杂的项目中, 当然还要部署其他的中间件, 从而远远不止类似于当前的三个容器, 如果还像之前那样部署, 非常麻烦
而Docker Compose就可以帮助我们实现 多个相互关联的Docker容器的快速部署 。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器
基本语法 {#基本语法}
Docker Compose的YML语法详情见 Compose file version 3 reference | Docker Docs
在docker-compose文件中可以定义多个相互关联的应用容器,每一个应用容器被称为一个服务
在之前的MySQL部署时, 我们使用的命令示例是这样的
|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10
| docker run -d \ --name mysql \ -p 3306:3306 \ -e TZ=Asia/Shanghai \ -e MYSQL_ROOT_PASSWORD=123456 \ -v ./mysql/data:/var/lib/mysql \ -v ./mysql/conf:/etc/mysql/conf.d \ -v ./mysql/init:/docker-entrypoint-initdb.d \ --network hmall mysql
|
而使用Compose, 是这样的
|---------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| version: "3.8" services: mysql: image: mysql container_name: mysql ports: - "3306:3306" environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: 123 volumes: - "./mysql/conf:/etc/mysql/conf.d" - "./mysql/data:/var/lib/mysql" networks: - new networks: new: name: hmall
|
对比如下:
| docker run 参数 | docker compose 指令 | 说明 | |-------------------|-----------------------|--------| | --name | container_name | 容器名称 | | -p | ports | 端口映射 | | -e | environment | 环境变量 | | -v | volumes | 数据卷配置 | | --network | networks | 网络 |
那么对于刚刚项目部署的样例则可以修改为
|------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| version: "3.8" services: mysql: image: mysql container_name: mysql ports: - "3306:3306" environment: TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: 123456 volumes: - "./mysql/conf:/etc/mysql/conf.d" - "./mysql/data:/var/lib/mysql" - "./mysql/init:/docker-entrypoint-initdb.d" networks: - hm-net hmall: build: context: . dockerfile: Dockerfile container_name: hmall ports: - "8080:8080" networks: - hm-net depends_on: - mysql nginx: image: nginx container_name: nginx ports: - "18080:18080" - "18081:18081" volumes: - "./nginx/nginx.conf:/etc/nginx/nginx.conf" - "./nginx/html:/usr/share/nginx/html" depends_on: - hmall networks: - hm-net networks: hm-net: name: hmall
|
基本命令 {#基本命令}
编写好了Yaml文件, 就可以部署项目了
对于一些常见的命令 Overview of docker compose CLI | Docker Docs
语法如下
|-----------|--------------------------------------------|
| 1
| docker compose [OPTIONS] [COMMAND]
|
其中,OPTIONS和COMMAND都是可选参数,比较常见的有:
| 类型 | 参数或指令 | 说明 | |----------|-----------|--------------------------------------------------------| | Options | -f | 指定compose文件的路径和名称 | | Options | -p | 指定project名称。project就是当前compose文件中设置的多个service的集合,是逻辑概念 | | Commands | up | 创建并启动所有service容器 | | Commands | down | 停止并移除所有容器、网络 | | Commands | ps | 列出所有启动的容器 | | Commands | logs | 查看指定容器的日志 | | Commands | stop | 停止容器 | | Commands | start | 启动容器 | | Commands | restart | 重启容器 | | Commands | top | 查看运行的进程 | | Commands | exec | 在指定的运行中容器中执行命令 |
样例: Docker整合FastDFS {#样例-Docker整合FastDFS}
镜像
|-----------------|-----------------------------------------------------------------------------------|
| 1 2 3 4
| # 1. 查找FastDFS docker search fastdfs # 2. 拉取镜像 docker pull delron/fastdfs
|
tracker安装
|-----------|------------------------------------------------------------------------------------------------------------------------------------|
| 1
| docker run -d --name tracker --network=yournetwork -v E:\dockercontainers\fastdfs\tracker:/var/fdfs delron/fastdfs tracker
|
E:\dockercontainers\fastdfs\tracker
为挂载到本地的路径--network=yournetwork
加入的网桥
storage安装
|-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1
| docker run -d -p 8888:8888 --name storage --network=yournetwork -e TRACKER_SERVER=172.18.0.2:22122 -v E:\dockercontainers\fastdfs\storage:/var/fdfs -e GROUP_NAME=group1 delron/fastdfs storage
|
TRACKER_SERVER
为上面的tracker
连接到的网桥的地址GROUP_NAME
分组名
测试: 在storage容器中测试使用命令上传图片
|------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10
| # 进入容器内bash指令模式 docker exec -it storage bash # 进入/var/fdfs目录 cd /var/fdfs # 加载位于E:\dockercontainers\fastdfs\storage下的文件 3.png # E:\dockercontainers\fastdfs\storage为映射地址 # 加载完成会返回一串字符路径 group1/M00/00/00/rBIAA2VLaFSAXi66AABGbuqCV2g017.jpg /usr/bin/fdfs_upload_file /etc/fdfs/client.conf 3.png # 最后通过映射端口访问 http://localhost:8888/group1/M00/00/00/rBIAA2VLaFSAXi66AABGbuqCV2g017.jpg
|
应用: SpringBoot整合FastDFS {#应用-SpringBoot整合FastDFS}
导入第三方依赖
|---------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6
| <!--fastDFS--> < dependency > < groupId > com.luhuiguo </ groupId > < artifactId > fastdfs-spring-boot-starter </ artifactId > < version > 0.2.0 </ version > </ dependency >
|
配置SpringBoot Yaml
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5
| fdfs: # docker网桥分配的IP地址 tracker的地址 tracker-list: 172.18 .0 .4 :22122 so-timeout: 6000 # 设置读取时间 connect-timeout: 1000 # 设置连接时间
|
编写一个简单的UploadService
|---------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| // 注入Fast客户端 @Autowired private FastFileStorageClient fastFileStorageClient; public String uploadFile (MultipartFile multipartFile) { StorePath storePath = null ; try { storePath = fastFileStorageClient.uploadFile( "" , multipartFile.getInputStream() , multipartFile.getSize() , "jpg" ); log.info( "Group:{},Path:{},FullPath:{}" , storePath.getGroup(), storePath.getPath(), storePath.getFullPath()); } catch (IOException e) { log.error( "uploadFile发生了异常,{}" , e.getMessage()); return null ; } return storePath.getFullPath(); }
|
该starter源码参考: [luhuiguo]( luhuiguo/fastdfs-spring-boot-starter: Spring Boot FastDFS Starter (github.com) ), 关于此依赖版本, 参考 maven仓库 , 搜索fastdfs (当前github中的readme文件介绍指定的是0.1.0)
应用通信 {#应用通信}
环境: SpringBoot项目,Docker容器有: Redis, MySQL, FastDFS
当前项目的拓扑图示例如下:
-
对于Windows访问容器: Windows访问 暴露的端口 , 例如访问docker容器中的nginx暴露的8888端口, 从而访问FastDFS存储的照片
-
对于Docker容器内部通信: 容器之间可以通过网桥通信, 例如我的Application应用(SpringBoot), 需要访问MySQL和Redis等容器, 则可以访问 网桥 分配的ip地址(如图), 实现通信。查看如何查询网桥情况: docker network inspect your_bridge
关于线上环境: 在Docker内部则是通过网桥访问容器原生端口(例如MySQL:3306), SpringBoot的配置文件配置样例
|---------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| fdfs: # docker网桥分配的IP地址 tracker的地址 tracker-list: 172.18 .0 .4 :22122 so-timeout: 6000 # 设置读取时间 connect-timeout: 1000 # 设置连接时间 server: port: 9999 # 服务端口 spring: datasource: # docker网桥分配的IP地址 url: jdbc:mysql://172.18.0.2:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver #Redis相关配置 redis: host: 172.18 .0 .5 # docker网桥分配的IP地址 port: 6379 #password:123456 database: 0 #0是0号数据库,redis默认开启的16个数据库 timeout: 5000 #超时时间
|
例如Redis在网桥上的IP为172.18.0.5, 则需要在配置文件中配置网桥地址。 (结构图参考该小结首照片)