一.问题提出
软件的运行依赖操作系统的设置,各种库和组件的安装(环境配置问题)。在不同的机器上,可能由于环境不同,软件能否运行,运行结果都会有差别。为了软件的正确运行,必须进行麻烦的环境配置。能否让软件带环境安装呢?
二.问题的解决
解决方法一:虚拟机
虚拟机(virtual machine)就是带环境安装的一种解决方案.可以在一种操作系统中运行另一种操作系统.如在windows中运行Linux系统.虚拟机对于底层系统而言就是一个文件.
用户可以通过虚拟机恢复软件运行环境,但也有不足:
1.资源占用多.
虚拟机占用的内存和硬盘资源在虚拟机运行时,不论它实际占用多少,其他机器都不能使用.
2.冗余步骤多
虚拟机要安装完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录。
3.启动慢
软件必须等待系统启动后,才能开始运行.
解决方法二:Linux容器
由于虚拟机存在这些缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)
Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离
或者说,在正常进程的外面套了一个保护层对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。
由于容器是进程级别的,相比虚拟机,基本克服了虚拟机的不足:
容器启动相当于启动一个进程,启动快。只占用必要的资源。只包含需要的组件。所以,容器类似轻量级的进程。
三.Docker是什么?
Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。它是目前最流行的 Linux 容器解决方案。
Docker工作原理:将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。
Docker 的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
四.Docker的用途
(1)提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。
(2)提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
(3)组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。
五.Docker的安装
1.安装docker
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun #安装。若提示无法连接到服务器,重试即可。
docker version #检测安装是否成功。若成功,则会显示与版本有关的信息。
2.Docker 是服务器---客户端架构。命令行运行docker
命令的时候,需要本机有 Docker 服务
启动docker服务如下:
sudo systemctl start docker #启动docker服务
sudo systemctl status docker#查看docker服务状态
3.为避免命令执行加sudo,执行以下命令将用户加入docker用户组
sudo usermod -aG docker username #username是用户名
!!!!注意:将用户加入docker组后,一定要重新登录,操作才会生效。
六.image 文件
Docker 把应用程序及其依赖,打包在 image 文件里面。只有通过这个文件,才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。
image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。
docker image ls #列出本机所有的image文件
docker image rm [imageName] #删除imageName这个image文件
image 文件是通用的,一台机器的 image 文件拷贝到另一台机器,照样可以使用。一般来说,为了节省时间,我们应该尽量使用别人制作好的 image 文件,而不是自己制作。即使要定制,也应该基于别人的 image 文件进行加工,而不是从零开始制作。
为了方便共享,image 文件制作完成后,可以上传到网上的仓库。Docker 的官方仓库 Docker Hub是最重要、最常用的 image 仓库。此外,出售自己制作的 image 文件也是可以的。
七.运行一个Docker示例
docker image pull library/hello-world#从远端库中将image文件抓取到本地。docker image pull是抓取命令。library是image文件所在的组,hello-world是文件名。
#docker官方image文件都放在library里,且library是默认组,故可以省略为:docker image pull hello-world
#可以查看本机是否有image文件:docker image ls
docker container run hello-world # docker container run 命令会从 image 文件,生成一个正在运行的容器实例,由于本地仓库没有image文件时,它可以自动抓取文件,则上一条抓取命令不是必须的。(每执行一次该命令,就新建一个容器)
命令执行成功结果如下:
输出结果后,hello-world就会停止。有些容器由于提供服务,所有不会停止。可用以下命令手动停止:
docker container kill [containID] #containID是容器ID。查阅方法见下
八.容器文件
image 文件生成的容器实例,本身也是一个文件,称为容器文件。即一旦容器生成,就会同时存在两个文件: image 文件和容器文件。而且关闭容器并不会删除容器文件,只是容器停止运行而已。
#列出本机正在运行的容器
docker container ls #终止容器运行时用到 ==docker ps
#列出本机所有容器,包括终止运行的容器
docker container ls -a ==docker ps -a
#终止运行的容器文件,依然会占据硬盘空间,用以下命令删除
docker container rm [containerID]
九.Dockerfile文件
Dockerfile文件是一个文本文件,用来配置image,Docker根据该文件生成二进制的image文件。
十.其他命令
docker container start containerID #启动一个已有的,停止运行的容器
docker container stop containerID #不一定会立即终止。docker container kill会立即终止。
docker container logs containerDI #查看容器输出(容器里面shell的标准输出),当docker run 没用-it命令时,就要用此命令查看。 ==docker logs containerName
docker container exec -it [containerID] /bin/bash #进入正运行的容器,当docker run 没用-it命令时,就要用此命令进入容器,进入后就可以用容器的shell执行命令了。
docker container cp [containID]:[/path/to/file] . #在正运行的容器里,拷贝文件到本地机器。此命令拷贝到当前目录。
十一.mysql容器
一.启动
启动错误:
1.
docker run --name=test mysql:5.7#直接启动一个名为test,版本5.7的容器。
error: database is uninitialized and password option is not specified
You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD`
原因:没有指定MYSQL_ROOT_PASSWORD参数。
2.
docker run --name=test --env``="MYSQL_ROOT_PASSWORD=mypassword" mysql:5.7 #添加MYSQL_ROOT_PASSWORD这个环境变量
#此时若未删除启动失败的容器。则需删除原来的容器(--name重复)。否则出现以下错误:
Error response from daemon: Conflict. The name "test" is already in use by container 80b4914976a2. You have to delete (or rename) that container to be able to reuse that name.
#此时,正确启动后,发现,容器执行在前台(attach mode),导致命令行无法输入命令,以及执行命令。
#若用powershell连接的,则退出登录,重新登录即可。
3.正确启动
docker run --detach --name=test --env="MYSQL_ROOT_PASSWORD=123456" mysql:5.7
#长格式时,name,env前两个-。少一个出错。
#运行在后台,只有本机应用可以通过3306端口可以访问。
二.docker容器的连接
正确启动后,可以查看容器信息:
docker inspect test #test是容器命令。
从输出中,可以看到"IPAddress":"172.17.0.20"。可以称为容器ip
上述方式启动,只有本机应用(如本机上的mysql客户端,本机上的容器)可以通过容器ip访问。
验证方法如下:
sudo apt-get install mysql-client #安装客户端
mysql -uroot -pmypassword -h 172.17.0.20 -P 3306 #P是大写。-u跟root用户,-p跟启动时设置的密码。-h是docker inspect命令查看到的ip。
容器ip是动态的,每次容器重启,都会重新分配一个ip。那么,两个相连的容器,如何避免由于容器重启,使得连接失效呢?
#若有一个wordpress应用想要连接上已经存在的mysql容器
docker run --detach --name test-wordpress --link test-mysql:mysql wordpress#名叫test-wordpress容器连上已经存在的容器test-mysql
docker exec -it test-wordpress bash #进入容器
cat /etc/hosts #查看此文件。可以看到改容器连接上了一个mysql容器(重启mysql容器连接会保持,删除mysql容器,则进入test-wordpress从前会出错)。结果如下:
将mysql容器端口映射到本地机器端口,实现从其他机器也可以连接上此容器
docker rm -f test #删除容器test
docker run --detach --name=test --env="MYSQL_ROOT_PASSWORD=123456" --publish 6603:3306 mysql #--publish将容器端口3306映射到本地机器端口6603
#用docker ps命令查看结果如下,注意PROTS列对应的结果变化。
三.docker容器的配置文件
1.启动一个mysql 5.7容器,未挂载额外的配置文件时。其内置的配置文件可以在/etc/mysql这个目录里找到。此目录下的my.cnf包含了两个目录:/etc/mysql/conf.d和/etc/mysql/mysql.conf.d。若需要添加额外的配置,最好的方法是启动时挂载一个目录,这个目录是容器外的目录(主机目录),而额外的配置文件放在这个目录下即可。格式:--volume=主机目录:/etc/mysql/conf.d 。
例如下面的启动方式:
$ docker run \
--detach \
--name=test-mysql \
--env="MYSQL_ROOT_PASSWORD=mypassword"\
--publish 6603:3306 \
--volume=/root/docker/test-mysql/conf.d:/etc/mysql/conf.d\
mysql:5.7
#注意:\是命令行的换行符,若启动命令在脚本中,则需要删除。--volume这项就是把主机目录/root/docker/test-mysql/conf.d(手动创建)下的配置文件挂载到/etc/mysql/conf.d目录下。所以启动时,配置文件为:/etc/mysql/my.cnf和/etc/mysql/conf.d/my-custom.cnf。
#使用docker exec -it containerID /bin/bash进入容器,执行相应mysql命令可以看到配置是否生效。
#很多配置参数都可以在启动时指定。所以可以较少的配置修改可以直接在执行docker run命令启动容器时指明。如下面指定最大连接数等设置的的启动方式:
$ docker run \
--detach \
--name=test-mysql \
--env="MYSQL_ROOT_PASSWORD=mypassword"\
--publish 6603:3306 \
--volume=/root/docker/test-mysql/conf.d:/etc/mysql/conf.d\
mysql:5.7\
--max-connections=200\
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci \
2.数据存储
使用docker inspect containerID |grep -A 4 'Volumes' 命令可以看到数据存储的位置。默认的(启动没挂载数据卷),mysql容器里面的数据存储目录:/var/lib/mysql(前述命令可以查看)。这很简单直观。但宿主机器(容器所在的机器)访问这个位置的数据很不方便。
因此,较好的方法是在容器外挂载一个目录(可手动创建:注意目录权限问题)。作为数据存储的位置。使得/var/lib/mysql映射到挂载的目录。启动方式如下:
$ docker run
--detach
--name=test-mysql
--env="MYSQL_ROOT_PASSWORD=mypassword"
--publish 6603:3306
--volume=/root/docker/test-mysql/conf.d:/etc/mysql/conf.d
--volume=/storage/docker/mysql-datadir:/var/lib/mysql
mysql
这种方式重启和删除容器,并不会删除数据卷。多个mysql容器使用同一个数据卷时,同一时刻只能有一个对象访问数据库的数据。
参考文章
四.自定义dockerfile