在23号刚刚学完新版本的docker还想说回去继续学习老版本的springcloud课程里面的docker 结果一看黑马首页新版本课程出了,绷不住了。以下是我学习新版本docker的笔记,记录了我学习过程遇到的各种bug和解决,也参考了黑马老师的笔记:Docsz
貌似我进入这个网站需要“魔法”,应该可能只是我吧。/狗头
先提前去防火墙开启好端口,项目中80,8080,3306都是需要开启的,80是nginx的端口,3306是mysql,8080是项目需要的端口。
systemctl status firewalld

- systemctl start firewalld
- systemctl stop firewalld
- firewall-cmd --reload
firewall-cmd --list-ports

这些端口我已经提前开启了。
命令含义: --zone #作用域 --add-port=80/tcp #添加端口,格式为:端口/通讯协议 --permanent #永久生效,没有此参数重启后失效
firewall-cmd --zone=public --add-port=80/tcp --permanent
注意:开启后重启防火墙才能生效!!!
firewall-cmd --reload
重启后可以再次查看开放的端口检验一下
firewall-cmd --list-ports
以此开启3306和8080端口
- firewall-cmd --zone=public --add-port=8080/tcp --permanent
- firewall-cmd --zone=public --add-port=3306/tcp --permanent
| 命令 | 说明 | 文档地址 |
|---|---|---|
| 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 images | 查看本地镜像 | |
| docker rmi | 删除本地镜像 |
| docker stop | 停止指定容器 | |
| docker start | 启动指定容器 | |
| docker restart | 重新启动容器 | |
| docker rm | 删除指定容器 | |
| docker ps | 查看容器 | |
| docker logs | 查看容器运行日志 | |
| docker exec | 进入容器 | |
| docker inspect | 查看容器详细信息 |
默认情况下,每次重启虚拟机我们都需要手动启动Docker和Docker中的容器。通过命令可以实现开机自启:
- # Docker开机自启
- systemctl enable docker
-
- # Docker容器开机自启
- docker update --restart=always [容器名/容器id]
下面这些是我目前创建的容器:
- # 查看运行中容器
- docker ps
- # 也可以加格式化方式访问,格式会更加清爽
- docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"

这里的dps是下面起别名后才有的指令。
为什么:给常用Docker命令起别名,方便我们访问
- # 1、通过命令页面去修改/root/.bashrc文件
- vi /root/.bashrc
-
-
- # 2、进入/root,去修改.bashrc文件

通过命令页面去修改,个人决定比较麻烦,下面是步骤:

这里我切换插入模式是点击右边键盘的Ins,我个人的电脑是数字的0,我禁用了数字键,所以点击0是开启插入模式。
输入完成后,执行接下来步骤。
正常保存并退出:按
Esc,然后输入:wq,再按Enter。不保存直接退出:按
Esc,然后输入:q!,再按Enter。

这个是直接用finalshell里面的编辑工具,这里我使用外部的NotePad++。
一般来说先设置外部编辑器,这里我设置了nodepad++,因为比较方便。

然后双击那个文件,正常修改,然后ctrl+s保存即可
设置号命令别名后极大方便使用命令。
- docker run -d \
- --name mysql \
- -p 3306:3306 \
- -e TZ=Asia/Shanghai \
- -e MYSQL_ROOT_PASSWORD=123 \
- mysql
这边建议直接在窗口里面输入不是用输入框。下面是黑马老师的结果,大差不差。

上面这个方式是创建容器及其镜像,及其方便。下面是解读:
- docker run -d :创建并运行一个容器,-d则是让容器以后台进程运行
- --name mysql : 给容器起个名字叫mysql,你可以叫别的
- -p 3306:3306 : 设置端口映射
- 容器是隔离环境,外界不可访问。但是可以将宿主机端口映射容器内到端口,当访问宿主机指定端口 时,就是在访问容器内的端口了。
- 容器内端口往往是由容器内的进程决定,例如MySQL进程默认端口是3306,因此容器内端口一定是3306;而宿主机端口则可以任意指定,一般与容器内保持一致。
- 格式: -p 宿主机端口:容器内端口,示例中就是将宿主机的3306映射到容器内的3306端口
- -e TZ=Asia/Shanghai : 配置容器内进程运行时的一些参数
- 格式:-e KEY=VALUE,KEY和VALUE都由容器内进程决定
- 案例中,TZ=Asia/Shanghai是设置时区;MYSQL_ROOT_PASSWORD=123是设置MySQL默认密码
- mysql : 设置镜像名称,Docker会根据这个名字搜索并下载镜像
- 格式:REPOSITORY:TAG,例如mysql:8.0,其中REPOSITORY可以理解为镜像名,TAG是版本号
- 在未指定TAG的情况下,默认是最新版本,也就是mysql:latest
镜像的名称不是随意的,而是要到DockerRegistry中寻找,镜像运行时的配置也不是随意的,要参考镜像的帮助文档,这些在DockerHub网站或者软件的官方网站中都能找到。
分步来部署容器和镜像
- # 拉取Nginx镜像
- docker pull nginx
执行后查看镜像:
- # 查看镜像
- docker images

- # 创建并允许Nginx容器
- docker run -d --name nginx -p 80:80 nginx
下面可以几个指令测试:
- # 停止容器
- docker stop nginx
-
- # 启动nginx容器
- docker start nginx
-
- # 格式化方式访问,格式会更加清爽
- docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"
-
- # 查看容器详细信息
- docker inspect nginx
目的:容器提供程序的运行环境,但是程序运行产生的数据、程序运行依赖的配置都应该与容器解耦。
数据卷(volume)是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁。

如上,将Nginx容器里面的conf和html文件映射到宿主机里面。
步骤:创建两个数据卷:conf、html,Nginx容器内部的conf目录和html目录分别与两个数据卷关联。而数据卷conf和html分别指向了宿主机的/var/lib/docker/volumes/conf/_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 | 清除数据卷 |
注意:容器与数据卷的挂载要在创建容器时配置,对于创建好的容器,是不能设置数据卷的。而且创建容器的过程中,数据卷会自动创建。所以接下来nginx和mysql容器都先删除后再挂载!!!
参考官方文档:https://hub.docker.com/_/nginx

- # 1.首先创建容器并指定数据卷,注意通过 -v 参数来指定数据卷
- docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx
-
- # 2.然后查看数据卷
- docker volume ls
-
- # 3.查看数据卷详情
- docker volume inspect html

采用挂载本地目录或文件的方式--缘由:数据卷的目录结构较深,如果我们去操作数据卷目录会不太方便
注意:本地目录或文件必须以 / 或 ./开头,如果直接以名字开头,会被识别为数据卷名而非本地目录名。
- # 挂载本地目录
- -v 本地目录:容器内目录
- # 挂载本地文件
- -v 本地文件:容器内文件
-
- -v mysql:/var/lib/mysql # 会被识别为一个数据卷叫mysql,运行时会自动创建这个数据卷
- -v ./mysql:/var/lib/mysql # 会被识别为当前目录下的mysql目录,运行时如果不存在会创建目录
先提前在虚拟机里面root目录下准备好mysql文件,里面有conf和init,在里面放自己的配置初始化SQL脚本和配置文件



其中,hm.cnf主要是配置了MySQL的默认编码,改为utf8mb4;而hmall.sql则是后面我们要用到的黑马商城项目的初始化SQL脚本。(这里是黑马老师的资料)
实现本地目录挂载:
- # 1.删除原来的MySQL容器
- docker rm -f mysql
-
- # 2.进入root目录
- cd ~
-
- # 3.创建并运行新mysql容器,挂载本地目录
- docker run -d \
- --name mysql \
- -p 3306:3306 \
- -e TZ=Asia/Shanghai \
- -e MYSQL_ROOT_PASSWORD=123 \
- -v ./mysql/data:/var/lib/mysql \
- -v ./mysql/conf:/etc/mysql/conf.d \
- -v ./mysql/init:/docker-entrypoint-initdb.d \
- mysql
可以通过下面命令测试:
- # 1.查看root目录,可以发现~/mysql/data目录已经自动创建好了
- ls -l mysql
-
- # 2.查看data目录,会发现里面有大量数据库数据,说明数据库完成了初始化
- ls -l data
镜像中包含了程序运行需要的系统函数库、环境、配置、依赖,能让我们快速跨操作系统部署应用而忽略其运行环境、配置。
打包镜像也是分成这么几步:
- 准备Linux运行环境(java项目并不需要完整的操作系统,仅仅是基础运行环境即可)
- 安装并配置JDK
- 拷贝jar包
- 配置启动脚本

Docker就提供了自动打包镜像的功能,提供的一种记录镜像结构的文件就称为Dockerfile。
官方文档:Dockerfile reference | Docker Docs
语法比较多,比较常用的有:
| 指令 | 说明 | 示例 |
|---|---|---|
| FROM | 指定基础镜像 |
|
| ENV | 设置环境变量,可在后面指令使用 |
|
| COPY | 拷贝本地文件到镜像的指定目录 |
|
| RUN | 执行Linux的shell命令,一般是安装过程的命令 |
|
| EXPOSE | 指定容器运行时监听的端口,是给镜像使用者看的 | EXPOSE 8080 |
| ENTRYPOINT | 镜像中应用的启动命令,容器运行时调用 | ENTRYPOINT java -jar xx.jar |
有人提供了基础的系统加JDK环境,在此基础上制作java镜像,就可以省去JDK的配置了。
- # 基础镜像
- FROM openjdk:11.0-jre-buster
- # 设定时区
- 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"]


这个文件一般在写项目的时候准备。
将课前资料提供的docker-demo.jar包以及Dockerfile拷贝到虚拟机的/root/demo目录:

执行命令,构建镜像:
- # 进入镜像目录
- cd /root/demo
-
-
- # 开始构建
- # 1、在当前目录下指定
- docker build -t docker-demo:1.0 .
-
- # 2、直接指定Dockerfile目录
- docker build -t docker-demo:1.0 /root/demo
介绍:
docker build : 就是构建一个docker镜像
-t docker-demo:1.0 :-t参数是指定镜像的名称(repository和tag)
. : 最后的点是指构建时Dockerfile所在路径,由于我们进入了demo目录,所以指定的是.代表当前目录,也可以直接指定Dockerfile目录:
测试:(下面都用黑马的笔记)
- # 查看镜像列表:
- docker images
- # 结果
- REPOSITORY TAG IMAGE ID CREATED SIZE
- docker-demo 1.0 d6ab0b9e64b9 27 minutes ago 327MB
- nginx latest 605c77e624dd 16 months ago 141MB
- mysql latest 3218b38490ce 17 months ago 516MB
-
-
- # 尝试运行该镜像
-
- # 1.创建并运行容器
- docker run -d --name dd -p 8080:8080 docker-demo:1.0
- # 2.查看容器
- dps
- # 结果
- CONTAINER ID IMAGE PORTS STATUS NAMES
- 78a000447b49 docker-demo:1.0 0.0.0.0:8080->8080/tcp, :::8090->8090/tcp Up 2 seconds dd
- f63cfead8502 mysql 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp Up 2 hours mysql
-
- # 3.访问
- curl localhost:8080/hello/count
- # 结果:
- <h5>欢迎访问黑马商城, 这是您第1次访问<h5>
容器的网络IP其实是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP会发生变化,连接会失败。可借助于docker的网络功能来解决这个问题。官方文档:docker network | Docker Docs
| 命令 | 说明 | 文档地址 |
|---|---|---|
| docker network create | 创建一个网络 | |
| docker network ls | 查看所有网络 | |
| docker network rm | 删除指定网络 | |
| docker network prune | 清除未使用的网络 | |
| docker network connect | 使指定容器连接加入某网络 | |
| docker network disconnect | 使指定容器连接离开某网络 | |
| docker network inspect | 查看网络详细信息 |
说简单一点就是:一个ip地址里面容器可能位置会变,但是容器的名字是不会变的,所以可以构建一个干净的网络,网络是联桥模式才能实现同一个网络ip内容器互相访问。
- # 1.首先通过命令创建一个网络
- docker network create hmall
-
- # 2.然后查看网络
- docker network ls
-
- # 除了hmall和heima以外,其它都是默认的网络

- # 让dd,mysql,nginx都加入该网络,注意,在加入网络时可以通过--alias给容器起别名
- # 这样该网络内的其它容器可以用别名互相访问!
- # 1.mysql容器,指定别名为db,另外每一个容器都有一个别名是容器名
- docker network connect hmall mysql --alias db
- # 2.nginx容器,指定别名为ng,另外每一个容器都有一个别名是容器名
- docker network connect hmall mysql --alias ng
- # 3.dd容器,也就是我们的java项目
- docker network connect hmall dd
查看网络里面指定容器
- # docker network inspect [OPTIONS] NETWORK [NETWORK...]
- docker network inspect nginx NETWORK hmall

下面是之前我自己写的一个项目,打包步骤差不多:



在黑马的项目中打包后还有一个配置文件Dockerfile,到时候讲打包好的jar包和配置文件一起上传到虚拟机的root目录,当然这个目录也是自定义的。

- # 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部署。

其中:
- html是静态资源目录,我们需要把hmall-portal以及hmall-admin都复制进去
- nginx.conf是nginx的配置文件,主要是完成对html下的两个静态资源目录做代理
把整个nginx目录上传到虚拟机的/root目录下:

通过指定目录挂载的方式,之前我们已经把nginx放在指定目录下,接下来挂载就行。
然后创建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

- docker run -d \
- --name nginx \
- -p 18080:18080 \
- -p 18081:18081 \
- -v /root/nginx/html:/usr/share/nginx/html \
- -v /root/nginx/nginx.conf:/etc/nginx/nginx.conf \
- --network hmall \
- nginx
测试,通过浏览器访问:http://你的虚拟机ip:18080
Docker Compose可以帮助我们实现多个相互关联的Docker容器的快速部署。它允许用户通过一个单独的 docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器。官方文档:Compose file version 3 reference | Docker Docs
| docker run 参数 | docker compose 指令 | 说明 |
|---|---|---|
| --name | container_name | 容器名称 |
| -p | ports | 端口映射 |
| -e | environment | 环境变量 |
| -v | volumes | 数据卷配置 |
| --network | networks | 网络 |
docker-compose文件- 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"
- - "./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
将编写好的yml文件放在root下

官方文档:Overview of docker compose CLI | Docker Docs
- # 基础语法:
- docker compose [OPTIONS] [COMMAND]
| 类型 | 参数或指令 | 说明 |
|---|---|---|
| Options | -f | 指定compose文件的路径和名称 |
| -p | 指定project名称。project就是当前compose文件中设置的多个service的集合,是逻辑概念 | |
| Commands | up | 创建并启动所有service容器 |
| down | 停止并移除所有容器、网络 | |
| ps | 列出所有启动的容器 | |
| logs | 查看指定容器的日志 | |
| stop | 停止容器 | |
| start | 启动容器 | |
| restart | 重启容器 | |
| top | 查看运行的进程 | |
| exec | 在指定的运行中容器中执行命令 |
- # 1.进入root目录
- cd /root
-
- # 2.删除旧容器
- docker rm -f $(docker ps -qa)
-
- # 3.删除hmall镜像
- docker rmi hmall
-
- # 4.清空MySQL数据
- rm -rf mysql/data
-
- # 5.启动所有, -d 参数是后台启动
- docker compose up -d
-
- # 6.查看镜像
- docker compose images
-
- # 7.查看容器
- docker compose ps
-
- # 8.关闭所有容器
- docker-compose down
查看springboot的日志,容器是hmall
docker logs -f hmall
打开浏览器,访问:http://yourIp:8080
在我第二天登录访问http://yourIp:8080的时候发现,进不去,我看了一下springboot的日志。

我觉得应该是没有登录访问被拦截的问题。
下面是解决办法:
访问这个网站:http://192.168.147.130:18080/cart.html或者http://192.168.147.130:18080/
第一个个是前端的登录页面网址,然后用黑马提供的 jack 123 这个账号密码登录,第二个是首页的页面,再去登录就可以了。
