试水docker布置

899 阅读7分钟

一、前置学习

1 虚拟机 vs 容器

容器少了hypervisor层(把物理资源虚拟化的层)和操作系统,更小巧。而每个虚拟机都是一个完整的操作系统,要给其分配资源。

2 容器能做什么

简化配置(常用)、代码流水线管理、提高开发效率、隔离应用、整合服务器、调试能力、多租户、快速部署。

3 热门的容器

docker、k8s(容器编排工具,应用场景:比如有上千个容器)

二、ubuntu 20.04 配置docker

官网地址:

docs.docker.com/engine/inst…

先用sudo apt-get update更新包索引,再允许apt使用https上的仓库:

添加docker的gpg密钥:

添加仓库:

再次更新索引并下载:

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io

查看docker安装的版本:

测试一下:

至此,docker安装完成。之后,是关于docker其他内容的学习。

三、docker基础指令

方括号表可选。

0.文件传输
# 主机拷贝文件到docker
docker cp 源文件 docker_id:要保存的文件路径
# docker拷贝文件到主机
docker cp docker_id:源文件 要保存的文件路径

1.保存修改
# 改动不会默认保存,如果你需要保存修改,保存后会产生一个新image而不是新docker
docker commit -m"备注" docker_id [new_image_name]
然后可以通过docker ps -a查看新生成的image

2.删除
docker rmi image_id	# 删除images
docker rm docker_id	# 删除docker

3.展示镜像或容器
docker ps	# 正在运行的docker
docker ps -a	# 所有docker
docker images	# 所有镜像

4.docker的启动和停止
docker run image_name	# 启动
docker stop docker_id|docker_name	# 停止

5.进入已启动的docker
docker exec -it docker_id|docker_name sh

四、Dockfile入门

首先要确定docker、容器和镜像的关系。docker是容器的一种,因为广泛使用,有些地方直接把docker和容器混用。容器由镜像实例化而来,也可以说,容器是进程。镜像是只读的,可以理解为静态文件,相对而言容器是动态的。

通过编写dockerfile创建docker镜像。

至此,可以开始学习dockerfile的编写,先看语法。

1 dockerfile语法

dockerfile的语法很简单,也不区分大小写,但还是约定为大写,常用的如下:

FROM		基于哪个镜像来实现
MAINTAINER	镜像的创建者
ENV		声明环境变量
RUN		执行的命令
ADD		添加宿主机文件到容器里,有需要解压的文件会自动解压
COPY		添加宿主机文件到容器中
WORKDIR		工作目录
EXPOSE		声明容器打算使用的端口,但并不会因为有这条命令就自动做端口映射。实际作用是帮助使用者配置映射,或者是当运行时使用随机端口映射,即docker run -p时,会自动映射到EXPOSE端口。
CMD		容器启动后所执行的程序,如果执行docker run后面跟启动命令会被覆盖掉
ENTRYPOINT	与CMD功能相同,区别在于:没有指定ENTRYPOINT时,按CMD运行;如果指定了ENTRYPOINT,CMD指定的内容会变成ENTRYPOINT的参数。
VOLUME		将宿主机的目录挂载到容器中

2 第一个dockfile

找一个你想放docker文件的地方,新建一个文件,通常直接命名为Dockerfile(用其他也可以但是不推荐),内容为:

FROM alpine:latest
MAINTAINER Winszheng
CMD echo 'hello docker'

其中,alpine是一个专门为docker做的linux镜像。写好文件后,在文件所在目录打开终端,使用命令生成镜像:

docker build -t hello_docker .

其中-t表示tag为hello_docker,‘.’表示使用当前目录的所有文件来生成这个镜像。运行完毕之后查看是否产生了这个镜像:

可见产生成功,试着运行一下:

可见正常运行。至此,我们用dockerfile产生了第一个镜像并成功运行。

3 第二个dockerfile

创建一个文件夹,新建一个Dockfile文件和index.html文件,这个dockerfile会安装nginx并把本机中的index.html复制到容器当中: Dockfile:

from ubuntu
maintainer Winszheng
run sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
run apt-get update
run apt-get install -y nginx
copy index.html /var/www/html
ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]
EXPOSE 80

这里值得注意的是,当docker镜像启动后,我们往往希望docker自动运行特定的程序,此时需要用CMD或者ENTRYPOINT显式指定具体命令。

index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>我的测试站点</title>
  </head>
  <body>
    <p>这是我的页面</p>
  </body>
</html>

然后生成镜像:

docker build -t winszheng/docker_nginx .

尝试运行镜像:

其中-d表示后台运行镜像并返回容器id;-p指定要映射的ip和端口,可以接收的映射格式有: host_port:docker_port ip:host_pot:docker_port ip::docker_port 打开相应页面,可见第二个镜像也成功运行:

3 镜像分层

dockerfile中的每一行都会产生一个新层。镜像是静态的,所以镜像中的层只读,但是当镜像运行时,会产生容器层,容器层可读可写——因此,镜像静态只读,但是运行成容器之后,却又能修改能容并保存成新的镜像。

分层的其他好处:不同docker之间可能会有共享的内容,比如几个docker之间有几层是共享的,那么分层就能减小存储压力。

五、关于Volume

1 把容器的指定目录挂载到本地

运行一个nginx程序,通过-v挂载一个卷:

sudo docker run -d --name nginx -v /usr/share/nginx/html docker_nginx
# -d: 后台运行并返回容器id
# /usr/share/nginx/html: 容器内的路径
# --name: 自定义docker名

可见挂载成功:

那么如何查看挂载信息呢? 执行:

docker inspect nginx	# inspect是查看的意思

结果会出现docker的所有信息:

然而我们并不需要读懂所有内容,暂时只需关心“Mounts”部分:

可见,我们把主机的source路径挂载到了docker的destination路径,接下来为了方便操作,使用sudo su切换到root用户,然后查看挂载文件夹,可见docker的文件index.html已经共享到本地:

为了验证本地和docker之间能否方便地共享文件,在本地文件夹随便创建一个文件:

然后到docker找到这个文件,可见共享成功:

2 把本地的指定目录挂载到容器的指定目录

其中,$PWD是一个始终指向当前目录的环境变量,这条指令在启动docker的同时把当前目录下的html文件夹挂载到docker的/usr/share/nginx/html,此时查看访问效果:

显然本地文件夹确实挂载到docker了!不用在docker里修改东西却还能用docker的环境,舒服!

3 数据卷容器

即,从容器挂载到容器。

详细点说,就是从另一个容器中挂载容器中已经创建好的数据卷。

如果我们存在一些需要持续更新,并需要在容器中共享的数据卷,那么最好创建数据卷容器。目前来看,docker需要持久化的数据都应该放在数据卷上。

本质上,数据卷容器也就是个普通的容器,只是专门用来提供数据卷供其他容器挂载罢了。

3.1 创建数据卷容器

在你喜欢的目录下创建data文件夹,并打开终端,输入命令:

sudo docker create -v $PWD/data:/var/mydata --name db ubuntu

以上意思是把$PWD/data挂载到docker的/var/mydata,基础镜像选ubuntu,docker名字为db。

3.2 挂载数据卷容器

sudo docker run -it --volumes-from db ubuntu sh

--volumes-from: 表示从容器db挂载

结果:

可见docker中确实产生了/var/mydata,但是是空的,所以我随便创建了一个文件并退出。然后直接查看本地,发现文件共享成功:

至此,完成了把本地文件夹挂载到数据卷容器,再在其他容器中成功挂载数据卷容器。也即,以后用docker完成容器见数据共享也可以在本地操作了。

六、docker部署mysql

拉取官方最新镜像:

sudo docker pull mysql/mysql-server:latest

创建mysql文件夹用于挂载数据库文件,生成mysql容器: 进入mysql容器并连接:

可见能够连接。

七、golang容器化

使用docker部署一个golang应用。照例随便选一个你喜欢的目录,创建两个文件:main.go和Dockerfile,其中main.go表你的golang程序,是什么都可以,现在先用个简单的。

Dockerfile的内容:

FROM golang:alpine

ENV GO111MODULE=auto \
    CGO_ENABLED=0 \
    GOOS=linux \
    GOARCH=amd64

WORKDIR /build

COPY . .

RUN go build -o main .


WORKDIR /main


RUN cp /build/main .

EXPOSE 9090

CMD ["/main/main"]

main.go:

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", hello)
	server := &http.Server{
		Addr: ":9090",
	}
    fmt.Println("server startup...")
	server.ListenAndServe()
}

func hello(w http.ResponseWriter, _ *http.Request) {
	w.Write([]byte("hello docker!"))
}

然后sudo docker build . -t go_demo构建镜像并运行:

可见部署成功:

八、杂七杂八的问题

1 docker build的速度很慢

那就是遇到喜闻乐见的外国源问题,如果你的系统是ubuntu,那么:

cd /etc/docker
sudo gedit daemon.json

在打开文件中写入:

{
    "registry-mirrors":["https://almtd3fa.mirror.aliyuncs.com"] 
}

然后重启docker即可:

service docker restart