前言
Docker
是当下使用最多的一种容器技术,想精通Docker
并不容易,在公司生产中会有专门的运维人员
负责。但是身为·开发人员·,适当的学习·Docker·是必要的。Docker的好处这里就不介绍了,网上一搜一大堆。本篇将用最简短的篇幅介绍开发人员需要学习的Docker干货
,你将学习到
- Docker的安装
- 第一个HelloWorld镜像
- 运行nginx并访问静态页面
- 运行mysql数据库
- 制作自己的镜像
概念
Docker最重要的3个概念:仓库
、镜像
、容器
,以springboot项目为例:
镜像(Image)
: 将jdk
+项目jar包
等文件以Docker的形式打包在一起就是镜像。这个概念跟重装系统时用的镜像是很相似的容器(Container)
: 将镜像实例化启动起来就是容器。容器是一个轻量级的linux系统
,root用户权限、进程空间、用户空间和网络空间容器都有。假设现在想要部署一个redis
,你得解压、安装、配置环境变量吧,但是docker
不一样,只要有人把redis
的镜像做好,运行起来成为一个小linux(也就是容器),这些环境跟做镜像的人的环境就会是一毛一样的,用户只需要run
就行了仓库(Repository)
: 这里的仓库用于存放镜像,github就是代码的仓库,而这里的docker hub也就是存放镜像的仓库,供用户pull
docker
跟git
是十分相识的,通常我们会进行一下操作
- 通过
pull
命令到docker hub
上拉取需要的镜像,比如mysql
、redis
等等 - 镜像已经拉取到本地了,通过
run
命令将镜像运行起来成为容器 - 以上两步是使用他人的镜像,而当自己要构建一个例如springboot的镜像时,使用
build
命令构建镜像
一、连接linux
本篇使用的服务器是ubuntu
,没有服务器的同学也可以使用虚拟机,效果是一样的
# ssh 用户名@ip地址
chaitous-Mac-mini:~ chaitou$ ssh ubuntu@148.70.139.121
ubuntu@148.70.139.121's password:
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-157-generic x86_64)
# 如果连接不上的,可能是你本机之前有其他服务的缓存和公钥信息
# 使用`ssh-keygen -R 148.70.139.121`清一下
如果是学生或者还没有接触过服务器的同学,笔者还是建议去买一个,现在面向新用户一年就几十块钱。能接触到公网,买个域名也能让项目真实的接触一下生产环境
这里推广一下阿里云小站,新老用户钜惠
二、安装docker
# 先切换到root用户下
sudo su
# 更新apt-get,保证apt-get最新版本
apt-get update
# 安装docker
apt-get install -y docker.io
# 查看docker版本
docker version
# 启动docker服务(有可能不需要这一步,多执行一遍也不会有错)
service docker start
# 再执行一次version,看到Client、Service说明启动成功了
docker version
Client:
Version: 18.09.7
API version: 1.39
Go version: go1.10.4
Git commit: 2d0083d
Built: Fri Aug 16 14:19:38 2019
OS/Arch: linux/amd64
Experimental: false
Server:
Engine:
Version: 18.09.7
API version: 1.39 (minimum version 1.12)
Go version: go1.10.4
Git commit: 2d0083d
Built: Thu Aug 15 15:12:41 2019
OS/Arch: linux/amd64
Experimental: false
三、第一个Docker镜像hello world
步骤:
- 先用
pull
命令从远端拉镜像
到本地 - 用
images
命令查看所有镜像 run
命令运行镜像
# pull: 从仓库拉取镜像
# docker pull [options] name[:tag]
# docker pull [可选参数] 镜像名[:版本号](如果不填默认为最新版本)
docker pull hello-world
# 默认从docker官方获取镜像,很可能因为网络原因需要多拉取几次
# 查看本机上的所有镜像
# docker images [可选参数]
docker images
# 看到hello-world说明拉取成功了
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest fce289e99eb9 15 months ago 1.84kB
# 运行镜像
# docker run [options] image[:tag] [command] [args]
# docker run [可选参数] 镜像名[:版本号] [镜像运行时要执行的命令] [命令参数]
docker run hello-world
Hello from Docker!
# 当你看到这条消息说明安装成功了
This message shows that your installation appears to be working correctly.
# 生成这条信息,docker做了以下几个步骤
To generate this message, Docker took the following steps:
# client端(也就是终端,命令行)连接到daemon端(指的是我们本地docker)
1. The Docker client contacted the Docker daemon.
# daemon端(本地docker)到Docker hub仓库中拉取了hello-world镜像
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
# daemon端(本地docker)从镜像中创建了一个容器,这个镜像运行了当前看到输出的代码
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
# daemon端(本地docker)将输出流给client端(命令行),显示到终端
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
配置加速器(已经科学上网的可以忽略)
docker hub
毕竟是境外网站,没有科学上网的情况下可能会网络超时,因此配置一下阿里镜像加速器
打开阿里云https://cr.console.aliyun.com/,登录一下aliyun
,按着下面的提示配置一遍
四、运行nginx
# 拉取nginx镜像
docker pull nginx
# 查看镜像
docker images
# REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest ed21b7a8aee9 12 days ago 127MB
hello-world latest fce289e99eb9 15 months ago 1.84kB
运行方式
刚刚run
命令运行了hello world
,这里详细将一下,运行方式有2种,前台运行
和后台运行
,前台运行则会占用终端,一般都会选择让容器在后台运行
- 前台运行,这种方式终端将不能进行其他操作,使用
Ctrl+C
停止
docker run nginx
- 后台运行,更常用的方式应该是这种
# 可以用docker run --help查看一下帮助文档,其中有这么一条
docker run --help
...
-d, --detach Run container in background and print container ID
...
# 使用-d后台运行nginx
docker run -d nginx
# 返回的是容器Id
7f7468b0d50ddea5bd258e78339d8c8a3681a7d601c82000bde1c6653e273c13
# docker ps 查看当前运行的容器
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7f7468b0d50d nginx "nginx -g 'daemon of…" 46 seconds ago Up 45 seconds 80/tcp dazzli
# 终止容器运行
docker stop 7f
7f
网络
刚刚提到docker
容器就是一个小linux
,也就是一个虚拟机。而容器行跟外界交互,只能先通过ubuntu
主机的网卡,才能跟外界交互。主机与docker容器
网络通讯的方式有为3种:
桥接(Bridge)
:也是最常用的方式,该模式下会将ubuntu
主机上的端口映射到docker容器
的端口上,例如8080:8081
则会将主机上的8080端口映射到docker容器的8081端口共享(Host)
:ubuntu主机与docker共享同一端口无网络(None)
:docker没有网络,外界无法访问
我们重点讲解一下最常用的桥接模式
桥接 Bridge
桥接模式需要使用-p
参数或者-P
参数,-p 主机端口:容器端口
,-P
则使用随机的主机端口映射到docker容器
1. -p 指定端口模式
# docker run -d -p 主机端口:容器端口 image[:tag]
docker run -d -p 8080:80 nginx
5e0cc45d89288faf9ba04b5e8b30548b8c14409a6d93e1abdd297676a7b7769a
docker stop 5e
此时我们就可以通过:8080
访问nginx了
-P 随机端口
可以看到docker自动将0.0.0.0:32768->80/tcp
随机端口32768映射到80上
# 随机开启一个端口映射到容器
# docker run -d -P image[:tag]
docker run -d -P nginx
docker ps
# 可以看到是32768端口映射到80端口
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
be30acaeb546 nginx "nginx -g 'daemon of…" 10 seconds ago Up 9 seconds 0.0.0.0:32768->80/tcp trusting_keller
docker stop be
五、运行mysql
使用docker
进行mysql
的部署比起在ubuntu
上部署简直不要太方便!打开阿里云https://cr.console.aliyun.com/
跳转到mysql的镜像地址查看mysql在docker下的使用。链接地址:https://hub.docker.com/_/mysql
使用步骤:
- 从远端仓库拉取mysql
- 通过
docker run
运行 -d
进行后台运行-p
指定端口映射-e
后面跟着的是mysql的参数,通过上方连接可以查询到通过MYSQL_ROOT_PASSWORD
设置数据库密码、MYSQL_DATABASE
设置数据库名
docker pull mysql
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=leilema -e MYSQL_DATABASE=leilema mysql:latest
通过数据库连接工具,例如Navicat等等进行数据连接,验证
是不是很简单,傻瓜式部署啊。特别是停止mysql容器
跟删除mysql
镜像,以前都是执行一大堆脚本还删不干净,现在就暴力多了,直接容器一停,镜像已删除,相当于整个虚拟linux
全部删掉,要多干净有多干净,关键还快!
# 停止容器
docker stop 容器ID
# 删除镜像
docker rmi image[:tag]
错误(*进入容器内部)
2059错误: Authentication plugin 'caching_sha2_password' cannot be loaded
这个错误不难,装mysql
时也遇到过,通过google 2059
错误,知道解决方案是要给进入到mysql,设置一下ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY 'leilema';
才能连接。
难面也是会有错误的发生,既然docker容器
就是一个虚拟linux
,我们偶尔也是要进入到docker容器
中查查日志啊,改改配置文件什么的。真好顺着这个错误,学习一下如何进入容器内部,也顺便看看容器内部是什么样子的:
- 通过
docker ps
查询容器id - 通过
docker exec -it 容器ID(可以只输入前缀) bash
进入容器,此时你会发现终端前方的用户从root@VM-0-12-ubuntu
改变成了root@9d71ee58f07c
,@后方跟着的正式我们的容器id - 进入容器后的操作就跟linux的操作是一样的,最后通过
exit
退出mysql
和容器
root@VM-0-12-ubuntu:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9d71ee58f07c mysql:latest "docker-entrypoint.s…" 8 minutes ago Up 8 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp hardcore_nash
root@VM-0-12-ubuntu:~# docker exec -it 9d bash
# 进入容器内部,ls可以看到这货就是一个linux
root@9d71ee58f07c:/# ls
bin docker-entrypoint-initdb.d home media proc sbin tmp
boot entrypoint.sh lib mnt root srv usr
dev etc lib64 opt run sys var
# 进入mysql
root@9d71ee58f07c:/# mysql --user=root --password
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
...
# 执行一下命令,修改下mysql密码
mysql> ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY 'leilema';
Query OK, 0 rows affected (0.01 sec)
mysql> exit
Bye
root@9d71ee58f07c:/# exit
exit
六、制作自己的镜像
想要制作自己的镜像需要有2步操作:
- 编写Dockerfile,说明镜像要如何进行创建,跟
makefile
有点像 - 通过
docker build
命令构建镜像
编写Dockerfile
这里以springboot项目
为例,手头有springboot项目
的同学可以直接使用手头的。我这里提供一个sringboot构建helloworld
的jar包,已经传到git上,因此
- 使用
git
拉取项目(或者自己通过rz
命令将jar
包传到服务器上) cd
到jar包
目录下,在同级目录开始编写Dockerfile
文件
get clone https://gitee.com/chaitou/hello-springboot
cd hello-springboot
vim Dockerfile
dockerfile文件如下(这只是简单用法,详细配置可以参考:dockerfile)
# 依赖的基础镜像
from java:8
# 创建者
MAINTAINER bugpool xxx@163.com
# 将当前目录下的jar复制到容器/目录下
COPY hello-springboot.jar /hello-springboot.jar
# 指定启动时运行java -jar 命令
ENTRYPOINT ["java", "-jar","/hello-springboot.jar"]
构建镜像
springboot项目
肯定是需要需要jdk
才能运行,dockerfile
上也写了from java:8
,因此
- 需要从仓库先
pull
一下java镜像
- 使用
docker build
构建镜像,-t
指定镜像名:版本号
,最后一个.
表示当前目录 - 启动镜像,如果使用的是上面我提供的
jar包
,我特意将其运行端口改为8081
来练习一下-p
桥接网络的使用。
# 拉取java8
docker pull java:8
# 构建镜像
docker build -t hello-springboot:1.0 .
# 启动镜像
docker run -p 80:8081 hello-springboot:1.0
我们将主机80端口映射成为了docker
容器的8081端口,因此我们需要访问ip:80/hello
,80端口可以省略,因此就是ip/hello
,如果看到一下界面,说明已经build
成功,并且成功部署了