推荐这里 阅读笔记 :Docker 笔记

〓 Docker - 一切在云端

B站视频地址:尚硅谷 Docker 阳哥

云原生Java 架构师的第一课K8s + Docker + KubeSphere + DevOps

Docker仓库:https://hub.docker.com/

编码开发微服务、上线部署容器化、时时刻刻要监控、devops。

01. Docker简介

Docker - 容器虚拟化技术,解决了运行环境和配置问题的软件容器。
环境配置相当麻烦,换一台机器,就要重来一次,费力费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。

一次镜像,处处运行。只需要一次配置好环境,换到别的机子上就可以一键部署好,大大简化了操作。

虚拟机与 Docker

1.1 Docker 安装

Docker 运行在CentOS 7 (64-bit)上,要求系统为64位、Linux系统内核版本为 3.8以上。

Linux 配置Docker
参考:https://blog.csdn.net/m0_63099094/article/details/121178929
systemctl status docker 查看docker 服务状态 or ps -ef | grep docker
systemctl start docker 启动 docker
docker version / docker -v 查看版本

测试是否成功 docker run hello-world (本地没有这个景象,是从仓库拉取的)

配置阿里云镜像加速,这个看脑图吧。配置完后,在执行 docker run hello-world 就会很快了,(上图虽然没配置上面等了一段时间才打出来。)

1.2 Docker 基本组成

镜像、容器、仓库。

先从本地拉镜像,本地没有,从仓库找。

1.2.1 镜像

Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。
它也相当于是一个root文件系统。比如官方镜像 centos:7 就包含了完整的一套 centos:7 最小系统的 root 文件系统。
相当于容器的“源代码”,docker镜像文件类似于Java的类模板,而docker容器实例类似于java中new出来的实例对象。

1.2.2 容器

1 从面向对象角度
Docker 利用容器(Container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像是Java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台

2 从镜像容器角度
可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

1.2.3 仓库

仓库(Repository)是集中存放镜像文件的场所。

类似于
Maven仓库,存放各种jar包的地方;
github仓库,存放各种git项目的地方;
Docker公司提供的官方registry被称为Docker Hub,存放各种镜像模板的地方。

仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
最大的公开仓库是 Docker Hub(https://hub.docker.com/),
存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云、网易云等

02. Docker 命令

systemctl status docker or ps -ef | grep docker 查看docker 服务状态
systemctl start docker 启动 docker
docker version 查看版本
docker run hello-world 启动 hello-world 镜像
镜像命令
docker images 列出本地主机上的镜像
docker search 某个XXX镜像名字 查找镜像(在 docker hub上)
docker search --limit 5 redis 查找点赞数前5 的redis 镜像
docker pull 某个XXX镜像名字 拉取镜像(从 docker hub 上)
docker pull redis:6.0.8 拉取 redis 6.0.8 版本的镜像
docker system df 查看镜像/容器/数据卷所占的空间
docker rmi 某个XXX镜像名字ID 删除镜像
docker rmi feb5d9fea6a5 删除 hello-world 镜像
docker rmi -f feb5d9fea6a5 强制删除镜像,当镜像在使用时候会删除不了
docker rmi -f ${docker images -qa} 删除全部, docker images -qa 是查处所有的镜像id
docker image ls -f dangling=true 查看所有的虚悬镜像
docker image prune 删词所有的虚悬镜像 docker rmi -f 就行
容器命令(容器的创建等更加详细的参考脑图)
docker run -it ubuntu /bin/bash 启动容器(前台交互式启动)
docker run -it --name=myu1 ubuntu bash 启动 ubuntu 容器,并且重名为 myu1
exit run -it 进去,退出容器容器停止。
Ctrl + P + Q run -it 进去,退出容器容器不停止
docker run -d redis:6.0.8 启动容器(后台守护式启动)
docker logs 容器ID 查看容器日志
docker exec -it 容器ID /bin/bash 进入容器,exit 退出,不会停止。
docker ps 查看所有正在运行的容器
docker ps -a 查看所有正在运行的+ 历史运行的容器
docker ps -l 查看最近创建的容器(正在运行+ 历史运行)
docker ps -n 2 查看最近2个创建的容器(正在运行+ 历史运行)
docker ps -q 查看所有正在运行的容器 id。
docker start 容器ID 或容器名 启动已停止运行的容器(docker ps -n 10 查看容器ID)
docker restart容器ID 或容器名 重启容器
docker stop容器ID 或容器名 停止容器
docker kill容器ID 或容器名 强制停止容器
docker rm 容器ID 删除容器(正在运行的无法删除,需stop后才可以)
docker rm -f 容器ID 强制删除容器
docker rm -f $(docker ps -a -q) 强制删除所有容器
docker top 容器ID 查看容器内运行的进程,进程号、端口号等。
docker inspect 容器ID 查看容器内部细节
docker cp 容器ID:容器内路径目的主机路径 从容器内拷贝文件到主机上
docker export 927e21b06561 > /root/exportUbutun.tar 导出容器到主机上。
cat exportUbutun.tar | docker import - cg/ubuntu:1.0 导入导出的容器cg 随便写,1.0 版本号随便写
docker commit -m=“提交的描述信息” -a=“作者” 容器ID 要创建的目标镜像名:[标签名] docker commit -m=“vim cmd add ok” -a=“cg” 927e21b06561 cg/myubuntu:1.1
容器卷命令
docker inspect 803b5d9531c0 查看容器挂载

网络命令
docker network ls 查看 docker 网络列表
docker network create test_network 创建网络
docker network inspect test_network 查看网络源数据
docker network rm test_network 删除网络
docker inspect 容器名 | tail -n 20 查看容器网络
docker-compose
docker-compose --version 查看 docker-compose 版本

2.1 容器命令详解

2.1.1 docker run -it

docker run -it ubuntu /bin/bash

i:interactive,t:tyy(伪终端)
进入了 ubuntu 系统,并且以终端形式打开的。
ps -ef 可以看到 ubuntu 系统的/bin/bash 已运行。

docker ps 查看所有正在运行的容器

可以看到IMAGE ubuntu 镜像正在运行,CONTAINER ID 容器ID,和上面 root@778248e34084 是一样的。

docker run -it --name=myu1 ubuntu bash,又启动了一个容器,这次NAMES 为 myu1,前面返回了容器ID 就是正常启动了。新开一个终端查看 docker ps。

进入了 ubuntu 命令行模式后,输入exit 即可退出,或者关闭 xshell选项卡也可以退出,容器停止。
Ctrl + P + Q退出容器不停止。

2.2.1 docker run -d

上面 run -it 都是前台交互式启动, 后台守护式启动 run -d,比如 redis。

docker logs 容器ID,查看日志,比如redis

docker exec -it acb16932c06b /bin/bash 进入容器。 一般用 -d 后台启动,然后 exec 进入对应容器实例。

2.2.3 从容器内拷贝文件到主机上

docker cp 容器ID:容器内路径目的主机路径

docker export 927e21b06561 > /root/exportUbutun.tar 导出容器到主机上

cat exportUbutun.tar | docker import - cg/ubuntu:1.0 导入导出的容器,进入到这个容器 a.txt 还在。

2.2.4 复制容器生成一个新的镜像

docker commit 提交容器副本使之成为一个新的镜像
docker commit -m=“提交的描述信息” -a=“作者” 容器ID 要创建的目标镜像名:[标签名]
docker commit -m=“vim cmd add ok” -a=“cg” 927e21b06561 cg/myubuntu:1.1

03. 镜像发布

3.1 本地镜像发布到阿里云

https://cr.console.aliyun.com/cn-beijing/instances 阿里云容器镜像服务

3.1.1 镜像推送到阿里云

创建命令空间,创建镜像仓库。在从本地推送镜像到阿里云。

docker login --username=username registry.cn-beijing.aliyuncs.com
docker tag ImageId registry.cn-beijing.aliyuncs.com/cgxin/myubuntu:1.1
docker push registry.cn-beijing.aliyuncs.com/cgxin/myubuntu:1.1

3.1.2 从阿里云拉取镜像

docker pull registry.cn-beijing.aliyuncs.com/cgxin/myubuntu:1.1

3.2 本地镜像发布到私有库(详细的还可以在看脑图)

3.2.1 镜像推送到私服库

docker pull registry 拉取
docker run -d -p 5000:5000 -v /root/01Sofeware/10Docker/myregistry/:/tmp/registry --privileged=true registry 运行私有库 registry,这里-d 是后台守护运行,并且端口映射了。

原来什么也没有的 ubuntu,安装了 net-tools 在exit,下次进入就没有了。Ctrl + P + Q,然后将整个容器生成一个新的镜像,整个新的镜像是有 net-tools的。在 stop 原来的ubuntu,run -it 新的镜像即可。

docker commit -m=“ifconfig cmd add ok” -a=“cg” 4c6f298ddda8 cgubuntu:1.0

curl -XGET http://localhost:5000/v2/_catalog 验证私服库上有什么镜像。(localhost 是私服库的ip)

docker tag cgubuntu:1.0 localhost:5000/cgubuntu:1.0

docker 默认不允许 http 方式推送镜像,修改配置文件使之支持。
改完后如果不生效,重启 docker(systemctl restart docker)。

没配置成功啊,修改了配置,docker就起不来了。(docker 20.10.9 允许http 推送镜像…)

docker push localhost:5000/cgubuntu:1.0

3.2.2 从私服库拉取镜像

必须要记住版本号,没有版本号,没法拉取。

然后 run -it,ifconfig 测试可行。

04. Docker 容器数据卷★

容器数据卷的方式完成数据的持久化,重要资料backup(备份)
将容器内的数据 备份 + 持久化 到本地主机目录。

4.1 添加容器卷

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
docker run -it --privileged=true -v /root/01Sofeware/10Docker/host_data:/tmp/docker_data --name=u1 ubuntu

就会进入到 ubuntu 镜像创建的一个容器里,

有点 vue 中 v-model 双向绑定的意思。

docker inspect 803b5d9531c0 查看容器挂载信息。

4.2 读写规则

上面默认 不加 是可读可写的。
加个 ro(read only),容器里只能读,不能写。 touch/vim a.txt 会报错。
docker run -it --privileged=true -v /root/01Sofeware/10Docker/host_data:/tmp/docker_data:ro --name=u1 ubuntu

4.3 卷的继承和共享

docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
docker run -it --privileged=true --volumes-from u1 --name u2 ubuntu

这个 u1 和 u2 docker ps 最后一列 name 可以看到。

继承过来了。

05. Docker 常规安装★

5.1 安装 Tomcat

docker search tomcat
docker pull tomcat
docker images 查看 tomcat镜像是否下载成功

docker run -d -p 8081:8080 --name t1 tomcat

tomcat8 不需要修改上面的 webapps.dist 就可以访问猫首页。

5.2 安装Mysql ★

docker search mysql
ducker pull mysql:8.0

docker run -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:8.0
docker ps
docker exec -it 容器ID /bin/bash
mysql -uroot -p

上面这是简单版的,删除容器后数据就都没了。

实战版
docker run -d -p 3307:3306 --privileged=true
-v /cg/mysql/log:/var/log/mysql
-v /cg/mysql/data:/var/lib/mysql
-v /cg/mysql/conf:/etc/mysql/conf.d
-e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:8.0

上面3个 -v 挂了三个容器数据卷。
在主机上cd /cg/mysql/conf,vim my.cnf,加入下面
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8

重启 mysql容器:
docker ps
docker restart mysql

这时候在删除 mysql容器,
docker rm -f mysql
然后重新
docker run -d -p 3307:3306 --privileged=true
-v /cg/mysql/log:/var/log/mysql
-v /cg/mysql/data:/var/lib/mysql
-v /cg/mysql/conf:/etc/mysql/conf.d
-e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:8.0
可以看到,数据库、表、表数据等等都还在。

高级篇 Mysql主从复制★(亲测成功)

脑图用的 5.7,我这里用的8.0,版本这一个真是个大坑,因为你并没有去关注8.0 升级了什么。
主从复制:只会在连接成功后,从才会复制主的数据,从数据库不会去复制主之前的数据。

新建主服务器容器实例3307
docker run -p 3307:3306 --name mysql-master
-v /cg/mysql-master/log:/var/log/mysql
-v /cg/mysql-master/data:/var/lib/mysql
-v /cg/mysql-master/conf:/etc/mysql
-v /cg/mysql-master/mysql-files:/var/lib/mysql-files
-e MYSQL_ROOT_PASSWORD=root
-d mysql:8.0

cd /cg/mysql-master/conf
vim my.cnf 添加如下:
[mysqld]

server_id=101

binlog-ignore-db=mysql

log-bin=mall-mysql-bin

binlog_cache_size=1M

binlog_format=mixed

binlog_expire_logs_seconds=7

replica_skip_errors=1062

docker restart mysql-master
docker exec -it mysql-master /bin/bash docker ps
mysql -uroot -p (没有密码,如果有密码 mysql -uroot -proot,不知道为啥密码没生效)

CREATE USER ‘slave’@‘%’ IDENTIFIED BY ‘123456’;
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON . TO ‘slave’@‘%’;
ALTER USER ‘slave’@‘%’ IDENTIFIED WITH mysql_native_password BY ‘123456’; (8.0需要,5.7不用了)

新建从服务器容器实例3308
docker run -p 3308:3306 --name mysql-slave
-v /cg/mysql-slave/log:/var/log/mysql
-v /cg/mysql-slave/data:/var/lib/mysql
-v /cg/mysql-slave/conf:/etc/mysql
-v /cg/mysql-slave/mysql-files:/var/lib/mysql-files
-e MYSQL_ROOT_PASSWORD=root
-d mysql:8.0

cd /cg/mysql-slave/conf
vim my.cnf 添加如下:
[mysqld]

server_id=102

binlog-ignore-db=mysql

log-bin=mall-mysql-slave1-bin

binlog_cache_size=1M

binlog_format=mixed

expire_logs_days=7

slave_skip_errors=1062

relay_log=mall-mysql-relay-bin

log_slave_updates=1

read_only=1

docker restart mysql-master

然后在主数据库中 show master status;

出现如上。

进入到从数据库:
docker exec -it mysql-slave /bin/bash
mysql -uroot -proot

在从数据库中:(连接之前开放端口,别忘了安全组配置)
change master to master_host=‘ip’, master_user=‘slave’, master_password=‘123456’, master_port=3307, master_log_file=‘mall-mysql-bin.000002’, master_log_pos=156, master_connect_retry=30; (master_log_file 和master_log_pos 要跟上图对应)
STOP SLAVE IO_THREAD FOR CHANNEL ‘’; (停止主从)
从机重启slave配置"stop slave;",“start slave;”,“show slave status \G;”,问题解决

在从数据库中查看主从同步状态:
show slave status \G;

在从数据库中开启主从同步,在查看主从状态
start slave;
show slave status \G; 下面Slave_IO_Running: Connecting 说明没成,看下面Bug 解决。

主从测试:
在主数据库中使用库,新建表,插入数据。从数据库中查看记录。
主数据库:create database db01; use db01; create table t1 (id int, name varcahr(20)); insert into t1 value(1, ‘cg’);
从数据库:use db01; select * from t1;

Bug:Mysql 8.0 采用新的身份验证插件。(caching_sha2_password), 原来的身份验证插件为(mysql_native_password)

从数据库使用 slave 这个用户。
在 主数据库修改:
ALTER USER ‘slave’@‘%’ IDENTIFIED WITH mysql_native_password BY ‘123456’;

终于连接成功了!

5.3 安装Redis ★

实战版
docker images
docker run -d -p 6380:6379 redis:6.0.8 (我已经装过redis了,这里端口用6380)
docker exec -it 容器ID /bin/bash
redis-cli
set k1 v1
get k1

一套丝滑走完。 但是删了也就凉凉了。

在主机配置好 redis.conf (redis 配置文件,假如在/app/redis/,具体配置可以看脑图)
docker run -p 6380:6379 --name myr3 --privileged=true
-v /app/redis/redis.conf:/etc/redis/redis.conf
-v /app/redis/data:/data
-d redis:6.0.8 redis-server /etc/redis/redis.conf (以自己配置的 redis.conf 启动)

docker exec -it myr3 /bin/bash
redis-cli
set k1 v1
get k1

测试文件生效,在 redis.conf 的 databases 16 是16个库(015),改成10个库(09)
docker restart myr3
docker exec -it myr3 /bin/bash
redis-cli
然后在 select 15 时候就会报错了(因为并没有16库了。)

高级篇★Redis 集群(3主3从)

大厂面试题:
1~2 亿条数据需要缓存,请问如何设计这个存储案例
单机单台100%不可能,肯定是分布式存储,用redis如何落地?

● 哈希取余分区,hash(key)/ 集群数量。缺点:集群扩缩,hash 取余会全部重新洗牌。
● 一致性哈希算法:hash环,节点映射。缺点:一致性哈希算法的数据倾斜问题。(服务器少不要用)
● 哈希槽分区:0 ~ 16383(2`14 - 1). (大厂都用)

搭建Redis 集群3主3从

启动6个redis 容器:
docker run -d --name redis-node-1 --net host --privileged=true -v /cg/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381

docker run -d --name redis-node-2 --net host --privileged=true -v /cg/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382

docker run -d --name redis-node-3 --net host --privileged=true -v /cg/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383

docker run -d --name redis-node-4 --net host --privileged=true -v /cg/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384

docker run -d --name redis-node-5 --net host --privileged=true -v /cg/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385

docker run -d --name redis-node-6 --net host --privileged=true -v /cg/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386

构建主从关系:(如果不是一个主机的话,注意开放端口)
docker exec -it redis-node-1 /bin/bash
redis-cli --cluster create ip:6381 ip:6382 ip:6383 ip:6384 ip:6385 ip:6386 --cluster-replicas 1

hash slot 哈希槽,3个槽;0:0 - 5640、1:5461 - 10922、2:10923 - 16383

查看集群状态:
连接进入6381 作为切入点,查看集群状态、集群节点
docker exec -it redis-node-1 /bin/bash
redis-cli -p 6381
cluster info
cluster nodes

可以看到6381、6382、6383 是 master,6381的 slave 是6384,和下图一样。

向Redis 集群 set 值
docker exec -it redis-node-1 /bin/bash
redis-cli -p 6381
在 redis里 set 值,集群环境不要用单机进入,如下进入了 node 1(0-5640),超过了哈希槽位,就报错。

docker exec -it redis-node-1 /bin/bash
redis-cli -p 6381 -c 集群环境连接 redis

查看集群状态:
redis-cli --cluster check ip:6381

主从切换
6381 宕机后(被kill),6384 上位。

查看主从节点关系:

stop 6381,6384上位:

依旧可以 get 值。

6381 恢复后,6381 是 slave,想让6381 当 master的话,需要 stop 6384,然后在 start 6384

再查看集群状态:redis-cli --cluster check ip:6381

主从扩容(更详细看脑图)
3主3从变成4主4从。
新增主机:6387,新增从机:6388

3台master + 1台 = 4 台
分配的槽位:16384 / 4 = 4096

docker run -d --name redis-node-7 --net host --privileged=true -v /cg/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
docker run -d --name redis-node-8 --net host --privileged=true -v /cg/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388

将6387 作为 master 加入集群中:
redis-cli --cluster add-node ip:6387 ip:6381

检查集群
redis-cli --cluster check ip:6381

重新分派槽位
redis-cli --cluster reshard ip:6381
3台master + 1台 = 4 台,分配的槽位:16384 / 4 = 4096
6387的master id,all,yes。

在检查集群情况:
redis-cli --cluster check ip:6381

为主节点6387分配从节点6388
redis-cli --cluster add-node ip:6388 ip:6387 --cluster-slave --cluster-master-id d6e9e3b11b1fe8fc5f41f43e51f61d6bf32e3d60

检查集群
redis-cli --cluster check ip:6381

查看 key的存储情况:

主从缩容
4主4从 -> 3主3从,减少 6387 master 6388 slave
思路:先删除 6388 slave,清出来的槽号重新分配,在删除 6387 master,恢复3主3从。

检查集群
redis-cli --cluster check ip:6381

删除从机6388
redis-cli --cluster del-node ip:6388 b46cd3c1e82a3faff5a8ebc990d5cf2ecab67987

将6387的槽号清空,重新分配,本例将清出来的槽号都给6381。
重新分配槽号,全分给 6381了, 6382和 6383 还是 4096个槽位,6381 8192个槽位了。这里并没有匀分给之前的。
redis-cli --cluster reshard ip:6381

检查集群
redis-cli --cluster check ip:6381

删除主机6387
redis-cli --cluster del-node ip:6387 d6e9e3b11b1fe8fc5f41f43e51f61d6bf32e3d60

5.4 安装Nginx

查看 9.3 Portainer 操作配置 nginx

06. Dockerfile ★

总结:
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
● Dockerfile是软件的原材料
● Docker镜像是软件的交付品
● Docker容器则可以认为是软件镜像的运行态,也即依照镜像运行的容器实例

Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

● Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
● Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;
● Docker容器,容器是直接提供服务的。

6.1 Dockerfile 简介

Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。

之前是拉取镜像ubuntu ,不含有 vim/ifconfig … 这些命令,安装后, docker commit 构建功能更加强大的 ubuntu++ 镜像。每次增加功能,随时变化都需要 docker commit 构建新的镜像。这样很不方便。

DockerFile 一次性给搞定。
某种镜像的增强,给个list清单,后续 需要加入任何功能,直接在list单子里面写好,相当于多次提交。 解决上面说的麻烦。 vim/ifconfig/tomcat/java8…

Dockerfile 构建镜像3步骤:编写 Dockerfile文件,docker build 构建镜像,docker run 镜像运行容器实例。

6.2 Dockerfile 文件

Dockerfile 底层就解析为 docker 命令。
例如 pig-ui的 Dockerfile:

6.2.1 保留字

● 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
● 指令按照从上到下,顺序执行。 # 表示注释
● 每条指令都会创建一个新的镜像层并对镜像进行提交

FROM 基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是FROM
MAINTAINER 镜像维护者的姓名和邮箱地址
RUN 容器构建时需要运行的命令,RUN是在 docker build时运行。用 shell的命令即可。
EXPOSE 当前容器对外暴露出的端口
WORKDIR 指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
USER 指定该镜像以什么样的用户去执行,如果都不指定,默认是root
ENV 用来在构建镜像过程中设置环境变量
ADD 将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
COPY

(docker cp) 类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置
COPY src dest
COPY [“src”, “dest”]
<src源路径>:源文件或者源目录
<dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
VOLUME (-v) 容器数据卷,用于数据保存和持久化工作
CMD 指定容器启动后的要干的事情,CMD是在 docker run时运行,命令和 RUN 一样。Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
ENTRYPOINT 也是用来指定一个容器启动时要运行的命令,类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

更多详细的,看脑图吧。特别是 ENTRYPOINT 和 CMD。

6.2.2 Tomcat8 的 Dockerfile

例如 Tomcat8的 Dockerfile,
https://github.com/docker-library/tomcat/blob/master/Dockerfile.template

6.2.2.1 WOEKDIR 落脚点

上面命令写错了, -p 8081:8080
docker run -it -p 8081:8080 tomcat bash;

上面这样子访问猫网是进不去的。
删除上面这个容器。
docker run -it -p 8081:8080 tomcat
Ctrl + P +Q
docker ps
docker exec -it dfb736f73c4e bash
rm -r webapps
mv webapps.dist/ webapps/
即可成功访问。

6.2.2.2 EXPOSE 和 CMD

docker run -it -p:8081:8080 tomcat
相当于
EXPOSE 8080
CMD [“catalina.sh”, “run”]

docker run -it -p:8081:8080 tomcat /bin/bash
相当于
EXPOSE 8080
CMD [“/bin/bash”, “run”]
这样子访问猫, localhost:8081 是进不去的。替换了 CMD。(亲测,真的进不去。)

docker 构建 nginx 镜像
nginx 一般要指定一个配置文件,
ENTRYPOINT [“nginx”, “-c”] 定参
CMD[“/etc/nginx/nginx.conf”] 变参 脑图下面的表格

6.2.3 Dockerfile 案例 - centos7

Centos7拉取下来是什么也没有,现在让Centos7镜像具备vim + ifconfig + jdk8。

注意:用centos7,docker pull centos:7,centos8 会报错的。

首先 Docker pull centos; Dockerfile 如下:
#镜像(本地没有则拉取)
FROM centos:7
MAINTAINER cgxincgxin7@163.com

ENV MYPATH /usr/local
WORKDIR $MYPATH

#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk-8u11-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u11-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_11
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH JAVAHOME/lib/dt.jar:JAVA_HOME/lib/dt.jar:JAVAH​OME/lib/dt.jar:JAVA_HOME/lib/tools.jar:JREHOME/lib:JRE_HOME/lib:JREH​OME/lib:CLASSPATH
ENV PATH JAVAHOME/bin:JAVA_HOME/bin:JAVAH​OME/bin:PATH

EXPOSE 80

CMD echo $MYPATH
CMD echo “success--------------ok”
CMD /bin/bash

Dockerfile 构建镜像(需要在当前目录下)

docker build -t 新镜像名字:TAG . (注意,TAG 后面是空格 + .)
docker build -t centosjava8:1.5 .

出现 Successfully 即是成功,本地镜像没有centos:7,FROM centos:7 会从远程拉取了。

Run 且测试 vim、ifconfig、java环境
docker run -it centosjava8:1.5 bash

再加一个 lsof 命令
yum install lsof

Dockerfile 改成如下:
#镜像(本地没有则拉取)
FROM centos:7
MAINTAINER cgxincgxin7@163.com

ENV MYPATH /usr/local
WORKDIR $MYPATH

#安装lsof
RUN yum -y install lsof
#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk-8u11-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u11-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_11
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH JAVAHOME/lib/dt.jar:JAVA_HOME/lib/dt.jar:JAVAH​OME/lib/dt.jar:JAVA_HOME/lib/tools.jar:JREHOME/lib:JRE_HOME/lib:JREH​OME/lib:CLASSPATH
ENV PATH JAVAHOME/bin:JAVA_HOME/bin:JAVAH​OME/bin:PATH

EXPOSE 80

CMD echo $MYPATH
CMD echo “success--------------ok”
CMD /bin/bash

再次构建镜像,测试 lsof
docker build -t centosjava8:1.5 .

总结:
只要有Dockerfile 就可以一行命令,无限构建镜像。之前那种 docker commit 方式简直不行。

6.3 虚悬镜像 dangling iamges

仓库名、标签都是的镜像,俗称dangling image
虚悬镜像没有任何价值,直接删了就行。

查看虚悬镜像:
docker image ls -f dangling=true

删除虚悬镜像:
docker image prune
它有镜像id,用docker rmi -f 镜像ID,也可以删除

6.4 Dockerfile 构建微服务镜像

01. 建项目

随便建一个项目,打成一个 jar包。(可以看脑图建一个)

02. 写 Dockerfile

FROM java:8

MAINTAINER cgxincgxin7@163.com

VOLUME /tmp

ADD docker_boot.jar cgxin_docker.jar

RUN bash -c ‘touch /cgxin_docker.jar’
ENTRYPOINT [“java”,“-jar”,“/cgxin_docker.jar”]
#暴露8080 端口作为微服务, jar包中 yml写的端口
EXPOSE 8080

将 Dockerfile 和 jar包放在同一目录下:

03. 构建镜像

docker build -t cgxin_docker:1.0 .

04. 运行镜像

docker run -d -p 8080:8080 cgxin_docker:1.0

访问成功!

07. Docker 网络

容器间的互联和通信以及端口映射,容器IP变动时候可以通过服务名直接网络通信而不受到影响。

7.1 Docker 网络简介

启动docker后,产生一个 docker0 的虚拟网桥。

安装完 docker 默认创建3个网络模式:
docker network ls

创建网络:docker network create test_network
查看网络源数据:docker network inspect test_network
删除网络:docker network rm test_network

7.2 网络模式

Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

docker run 的时候没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址

网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。
● 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
● 每个容器实例内部也有一块网卡,每个接口叫eth0;
● docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。

7.2.1 bridge

查看 bridge 网络的详细信息,可以通过 grep 获取名称项
docker network inspect bridge
docker network inspect bridge | grep name

两两匹配验证:
docker run -d -p 8081:8080 --name tomcat81 billygoo/tomcat8-jdk8
docker run -d -p 8082:8080 --name tomcat82 billygoo/tomcat8-jdk8

启动两个容器后,在主机 ip address,可以看到多了个2个ip

在启动一个 u1 容器,查看 ip address,发现也增加了一个 ip。 (网络模式用 bridge 时)

7.2.2 host

直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。
容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。

docker run -d -p 8083:8080 --network host --name tomcat83 billygoo/tomcat8-jdk8

docker启动时指定–network=host或-net=host,如果还指定了-p映射端口,那这个时候就会有此警告,
并且通过-p设置的参数将不会起到任何作用,端口号会以主机端口号为主,重复时则递增。
解决的办法就是使用docker的其他网络模式,例如–network=bridge,这样就可以解决问题,或者直接无视。

docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8

可以看到并没有增加新的 ip,而是和主机共用一个。

没有设置-p的端口映射了,如何访问启动的tomcat83?
http://宿主机IP:8080/
此时容器的IP借用主机的,所以容器共享宿主机网络IP,这样的好处是外部主机与容器可以直接通信。

真的牛,亲测可以访问的, 8080 8081 8082 都可以进猫网。

7.2.3 none

在none模式下,并不为Docker容器进行任何网络配置。
也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo
需要我们自己为Docker容器添加网卡、配置IP等。

禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)

docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8
docker inpsect tomcat84 | tail -n 20 (进入到容器外查看)
docker exec -it tomcat84 bash (进入到容器里查看)
ip addr

7.2.4 container

这个不看了,有需要看脑图吧。演示案例没用 tomcat,说是很坑。用的其他镜像。
在阿里云上并没有 Driver 是 container 的。

7.2.5 自定义网络★

自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)

还是用的 bridge 的 tomcat81 和 tomcat82
分别看一下 ip:

进入容器实例,互相 ping ip 和服务名。

自定义网络
自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)

docker network create cgxin_network
docker network ls

docker run -d -p 8083:8080 --network cgxin_network --name tomcat83 billygoo/tomcat8-jdk8
docker run -d -p 8084:8080 --network cgxin_network --name tomcat84 billygoo/tomcat8-jdk8

分别进去,再 ping 域名试试。
查看ip:

结论:自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)

pig中的 network查看
可以看到项目中都会自己的 network,用来 ping 域名实现网络通信,而不是 ip。

7.3 容器实例内默认网络IP生产规则

启动2个ubuntu 容器(之前创建的没删,docker run -it --name u1 ubuntu bash)
docker start u1
docker start u2

查看容器网络:docker inspect u1 | tail -n 20

关闭 u2,新建一个 u3,查看网络IP变化
docker stop u2
docker run -it --name u3 ubuntu bash
docker inspect u3 | tail -n 20

总结:
这说明 docker 容器内部的 Ip 是有可能改变的。使用自定义网络,可以 ping 域名。

08. Docker-compose 容器编排★

8.1 简介

Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器。 容器启动需要有加载顺序,比如 jar包,需要先启动mysql + redis容器。

对 docker 容器集群的快速编排 (容器调用关系,一键启动,一键stop)
就像容器 aplicaitonContext.xml 对bean对象统计集中管理起来
java里有对象, docker 里有容器, docker-compose 就是管理容器。

下载官网:https://docs.docker.com/compose/install/ 选择 Linux,翻译成中文照着操作。
查看 docker-compose 版本:docker-compose --version

三步走:
● 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
● 使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
● 最后,执行docker-compose up命令来启动并运行整个应用程序,完成一键部署上线

8.2 compose 命令

docker-compose -h 查看帮助
docker-compose up 启动所有docker-compose服务
docker-compose up -d 启动所有docker-compose服务并后台运行
docker-compose down 停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id 进入容器实例内部 docker-compose exec
docker-compose yml文件中写的服务id /bin/bash
docker-compose ps 展示当前docker-compose编排过的运行的所有容器
docker-compose top 展示当前docker-compose编排过的容器进程
docker-compose logs yml里面的服务id 查看容器输出日志
docker-compose config 检查配置
docker-compose config -q 检查配置,有问题才有输出
docker-compose restart 重启服务
docker-compose start 启动服务
docker-compose stop 停止服务

8.3 compose 编排微服务★

改造 6.4 写的项目,添加上 mysql 和 redis,这就需要mysql 和 redis 环境。

8.3.1 改造项目

8.3.2 构建镜像

Dockerfile 还是原来,没有改动。

docker build -t cgxin_docker:1.1 .

8.3.3 编排容器

8.3.3.1 不使用compose

● 单独的mysql实例
● 单独的redis实例
● 单独的jar包

上面3个实例依次顺序启动成功。
缺点:
● 先后顺序要去固定,先 mysql + redis 才能再 jar 包;需要多个 run
● 容器间的启停或者宕机,有可能导致 ip地址对应的容器实例变化,映射出错,要么生产ip写死(可以但不推荐),要么通过微服务调用。

8.3.3.2 使用 compose 编排项目★

想了很久很久啊。还是不编排了,阿里云服务器上本来就装了redis 和 mysql 环境了,下面还要在搭一个镜像。需要先 stop 原来的,然后其这个容器,测试完了后,在 start 原来的那些。mysql 还好说, redis 那个配置文件都在另一份笔记上了。嗯,这里不测试了,就写写吧。

编写 docker-compose.yml

version: “3”

services:
microService:
image: cgxin_docker:1.1
container_name: cgxin_docker02
ports:

  • “8080:8080”
    volumes:
  • /01exec/01docker/02docker_boot/microService:/data
    networks:
  • cgxin_net
    depends_on:
  • redis
  • mysql

redis:
image: redis:6.0.8
ports:

  • “6379:6379”
    volumes:
  • /cg/redis/docker_boot/redis.conf:/etc/redis/redis.conf
  • /cg/redis/docker_boot/redis/data:/data
    networks:
  • cgxin_net
    command: redis-server /etc/redis/redis.conf

mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: ‘123456’
MYSQL_ALLOW_EMPTY_PASSWORD: ‘no’
MYSQL_DATABASE: ‘db2021’
MYSQL_USER: ‘zzyy’
MYSQL_PASSWORD: ‘zzyy123’
ports:

  • “3306:3306”
    volumes:
  • /cg/redis/docker_boot/mysql/db:/var/lib/mysql
  • /cg/redis/docker_boot/mysql/conf/my.cnf:/etc/my.cnf
  • /cg/redis/docker_boot/mysql/init:/docker-entrypoint-initdb.d
    networks:
  • cgxin_net
    command: --default-authentication-plugin=mysql_native_password #解决外部无法访问

networks:
cgxin_net:

修改docker_boot 项目中的 yml
mysql 的密码, mysql 和 redis 域名是在 docker-compose.yml 中编排的。

构建镜像

进入到这个目录,用 Dockerfile构建镜像。(Dockerfile 还是之前,没有改,基础镜像java8 和 java -jar)
docker build -t cgxin_docker:1.2 .

编排项目
先docker-compose config -q检查配置,如果有错误就会输出。
docker compose up或者docker compose up -d

docker netword ls,可以看到自己创建了新的网络。

测试
先进入mysql 实例,建库建表
docker exec -it 容器实例id /bin/bash
mysql -uroot -p
create database db2021;
use db2021;
CREATE TABLE t_user (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
username VARCHAR(50) NOT NULL DEFAULT ‘’ COMMENT ‘用户名’,
password VARCHAR(50) NOT NULL DEFAULT ‘’ COMMENT ‘密码’,
sex TINYINT(4) NOT NULL DEFAULT ‘0’ COMMENT '性别 0=女 1=男 ',
deleted TINYINT(4) UNSIGNED NOT NULL DEFAULT ‘0’ COMMENT ‘删除标志,默认0不删除,1删除’,
update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT ‘更新时间’,
create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT ‘创建时间’,
PRIMARY KEY (id)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT=‘用户表’;

浏览器调用写的那些接口, redis 和 mysql 正常使用,即可成功。
要注意是用镜像创建的 redis 和 mysql,需要把自己之前安装的stop。

关停

09. Portainer - Docker轻量级可视化工具★

Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。

9.1 安装

官网:https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux

docker命令安装:–restart=always (docker 重启后,这个依旧运行着。)
docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest

http://ip:9000/

第一次登录需要创建admin。

9.2 使用

可以手动启动容器。

9.3 Portainer 操作配置 nginx

9.3.1 拉取镜像

Pull the Image

9.3.2 部署容器

Deploy the container:部署容器。下面可以进行一个更多的设置。

部署后,浏览器访问 nginx,可以看到成功了。 Docker 是真牛啊!

10. CIG - Docker重量级监控系统

CAdvisor监控收集 + InfluxDB存储数据 + Granfana展示图表

10.1 介绍

docker ps
docker stats
通过docker stats命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,
一般小公司够用了。
但是,docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能。

10.1.1 CAdvisor

10.1.2 InfluxDB

10.1.3 Granfana

10.2 操作 CIG

编写 docker-compose.yml
version: ‘3.1’

volumes:
grafana_data: {}

services:
influxdb:
image: tutum/influxdb:0.9
restart: always
environment:

  • PRE_CREATE_DB=cadvisor
    ports:
  • “8083:8083”
  • “8086:8086”
    volumes:
  • ./data/influxdb:/data

cadvisor:
image: google/cadvisor
links:

  • influxdb:influxsrv
    command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
    restart: always
    ports:
  • “8080:8080”
    volumes:
  • /:/rootfs:ro
  • /var/run:/var/run:rw
  • /sys:/sys:ro
  • /var/lib/docker/:/var/lib/docker:ro

grafana:
user: “104”
image: grafana/grafana
user: “104”
restart: always
links:

  • influxdb:influxsrv
    ports:
  • “3000:3000”
    volumes:
  • grafana_data:/var/lib/grafana
    environment:
  • HTTP_USER=admin
  • HTTP_PASS=admin
  • INFLUXDB_HOST=influxsrv
  • INFLUXDB_PORT=8086
  • INFLUXDB_NAME=cadvisor
  • INFLUXDB_USER=root
  • INFLUXDB_PASS=root

部署容器:
docker-compose config -q
docker-compose up

出现上面这个,才是正常的。
查看网络:

所以下面配置 Granfana 中的 panel 时,写的数据库用的域名InfluxDB。

CAdvisor:http://ip:8080/

往下拉动,有很多图形化监控。
cadvisor也有基础的图形展现功能,这里主要用它来作数据采集。

InfluxDB:http://ip:8083/

Granfana:http://ip:3000/

默认账号密码:admin / admin

配置数据源:

出现上面 Data Souce is working 即是成功。

配置面板 panel:

这样子,就配置完成了。

学习笔记:Docker相关推荐

  1. homeassistant mysql_HomeAssistant学习笔记docker安装的ha更换数据库

    HomeAssistant学习笔记docker安装的ha更换数据库 用了一段时间之后发现日志和历史打开的速度越来越慢,在论坛里查了半天发现是因为HA官方所用数据库导致,官方也给出了相关文档,https ...

  2. homeassistant mysql_学习笔记 篇三:HomeAssistant学习笔记docker安装的ha更换数据库

    学习笔记 篇三:HomeAssistant学习笔记docker安装的ha更换数据库 2018-11-15 12:06:58 4点赞 18收藏 3评论 是返乡过年?还是就地过年?最新一届#双面过节指南# ...

  3. 阿龙的学习笔记--- Docker 的一些概念总结

    借鉴这些文章: https://zhuanlan.zhihu.com/p/57024225 https://wangguoping.blog.csdn.net/article/details/8104 ...

  4. 狂神说--docker学习笔记-docker安装,常用命令,以及使用

    狂神说bilibili视频地址:https://www.bilibili.com/video/BV1og4y1q7M4?p=1 1. Docker概述 1.1 Docker为什么出现? 大家经常做一款 ...

  5. Docker学习笔记 — Docker私有仓库搭建

    2019独角兽企业重金招聘Python工程师标准>>> 和Mavan的管理一样,Dockers不仅提供了一个中央仓库,同时也允许我们使用registry搭建本地私有仓库. 使用私有仓 ...

  6. Docker学习笔记 - Docker Compose

    一.概念 Docker Compose 用于定义运行使用多个容器的应用,可以一条命令启动应用(多个容器). 使用Docker Compose 的步骤: 定义容器 Dockerfile 定义应用的各个服 ...

  7. Docker学习笔记 - Docker容器的日志

    docker logs  [-f]  [-t]  [--tail]  容器名 -f -t --tail="all" 无参数:返回所有日志 -f 一直跟踪变化并返回 -t 带时间戳返 ...

  8. 学习笔记---Docker

    Docker简介 Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余 项目.它基于 Google 公司推出的 Go 语言实现. 项目后来加入了 Linu ...

  9. 狂神 Docker学习笔记 从基础到进阶 一步到位

    Docker 学习笔记 感谢狂神的分享.附上B站视频链接. https://www.bilibili.com/video/BV1og4y1q7M4?from=search&seid=92256 ...

  10. Docker基础03--Dockerfile详解与镜像发布--(狂神说docker学习笔记)

    文章目录 1. Dockerfile介绍 2. Dockerfile指令说明 3. 制作Centos镜像 3.1 编写Dockerfile的文件 3.2 通过这个文件构建镜像(注意最后加个点!!!) ...

最新文章

  1. 徐科:做IC不外乎PPA,但需要成百上千的专家合作 投入数千万
  2. 理想汽车事故,智能短板暴露
  3. VS2015+MySql+EF6采坑经验总结
  4. MySQL WHERE:条件查询
  5. mysql中的count函数和sum函数如果条件不符合返回什么
  6. python中的装饰器(以及多个装饰器详细执行过程)
  7. SQLite学习-临时文件
  8. 线程自动退出_什么是Java的守护线程?
  9. 新发现一款监控Linux集群sinfo
  10. 后台使用orm多还是直接sql_Django应用app创建及ORM
  11. Chrome 好玩的插件
  12. android 模仿uc标签页,android模仿UC首页天气效果
  13. Ubuntus安装vmware tools工具
  14. unknown type name err_status_t; did you mean srtp_err_status_t/err_status_ok/err_status_replay_fail
  15. LumaQQ.NET 试用
  16. 那些年用过的机械键盘--游戏人生键盘风云#入坑keychron#
  17. (蓝图)虚幻4重制俄罗斯方块(四)移动方块
  18. RT-Thread Env工具下 scons命令构建工程 SConscript和Kconfig修改示例
  19. 月入万元的乞丐谈营销
  20. 理解JavaScript设计模式

热门文章

  1. 鸿蒙系统如何恢复安卓系统
  2. 福建省计算机二级登录入口,福建省教育考试院官网登录入口
  3. 面对不喜欢的工作,只有跳槽一条路吗?
  4. 上班人员必读:“五险一金”详解!
  5. 基于Java的师生交流系统
  6. 第二十三章:面向对象(3)
  7. 工具栏的打印图标不见了_我的电脑右下角任务栏上打印机小图标不见了, – 手机爱问...
  8. Java 新手笔记(一)
  9. win7计算机收藏夹位置,win7中收藏夹在哪里 win7找到IE收藏夹的两种方法[多图]
  10. User-Agent 大全