SQL Server 真是越来越有看头。当我们还在为 Linux 上运行 SQL Server 而兴奋的时候,SQL Server 已经开启了 容器化之路,至此才能看清微软的胸怀,开始拥抱更大的世界。当我越来越深入去阅读有关 Docker 容器的文档,已然发现曾经部署上千台 Linux MySQL 的场景,如今在 Docker 的帮助下,SQL Server 也是手到擒来。如果 SQL Server 再匹配一个分布式计算引擎,那也是分分钟即可打造一个计算怪兽,和小象 Hadoop 分庭抗礼。届时玩 SQL 的朋友们不用分心去折腾 Hadoop/Spark, 仅用 T-SQL 依然可以笑傲江湖。因为人工智能,机器学习算法本就是数据集合操作,天生和 SQL 结合紧密。不信看我的这篇:
机器学习算法之 KNN 的 SQL 实现
当然,理想是要有的,目前还是将心放一放,回归这次的主题, Docker.
接触容器化实践,始于团队 2017 的 CRM 产品发布流程改革,微服务化。
现将整个过程梳理一下,对 SQL Server 容器化进程做一个总结。
- Docker 概念以及作用
- Docker 用来发布 SQL Server 部署的方法和优势
Docker 的概念以及作用
Docker 的安装
安装的必备条件:
- 64位 CPU
- Linux 3.8 以上版本
- 内核必须支持一种合适的存储驱动(storage driver),如:
代码语言:javascript复制
Device Manager
AUFS
vfs
btrfs
默认存储驱动是 Device Mapper
- 内核必须支持并开启 cgroup 和命名空间功能
检查 Centos 版本:
代码语言:javascript复制[root@centos00 log]# uname -a
Linux centos00 3.10.0-514.el7.x86_64 #1 SMP Tue Nov 22 16:42:41 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
检查存储驱动:
代码语言:javascript复制[root@centos00 log]# ls -l /sys/class/misc/device-mapper
lrwxrwxrwx. 1 root root 0 Aug 22 18:33 /sys/class/misc/device-mapper -> ../../devices/virtual/misc/device-mapper
或者直接查当前运行的设备
代码语言:javascript复制[root@centos00 log]# grep device-mapper /proc/devices
253 device-mapper
若没有则运行下面脚本安装
代码语言:javascript复制yum install -y device-mapper
modprobe dm_mod
安装 EPEL 软件包仓库
此仓库只是在 centos 上安装 Docker 的时候需要,当然 RedHat 也是同门。而 Fedora 则不需要,因为 EPEL 是 Fedora 出品,已经包含了此库。
https://fedoraproject.org/wiki/EPEL
EPEL: Extra Packages For Enterprise Linux
顾名思义,这是专门为企业版 Linux 打造的扩展功能库。
CentOS 6/7 安装路径各不相同:
代码语言:javascript复制yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
而正式的安装则简单的多:
代码语言:javascript复制yum install -y docker
Docker 运行时检查:
代码语言:javascript复制[root@centos00 log]# docker info
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
以上脚本可用来检查 Docker 运行时信息,亦可用来检查 Docker 是否运行
启动 Docker 进程以及配置开机运行 Docker :
代码语言:javascript复制systemctl start docker
systemctl enable docker
代码语言:javascript复制[root@centos00 log]# systemctl start docker
Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.
代码语言:javascript复制[root@centos00 log]# systemctl status docker.service -l
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Thu 2018-08-30 07:45:41 CST; 2min 19s ago
Docs: http://docs.docker.com
Process: 31489 ExecStart=/usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json $OPTIONS $DOCKER_STORAGE_OPTIONS $DOCKER_NETWORK_OPTIONS $ADD_REGISTRY $BLOCK_REGISTRY $INSECURE_REGISTRY $REGISTRIES (code=exited, status=1/FAILURE)
Main PID: 31489 (code=exited, status=1/FAILURE)
Aug 30 07:45:38 centos00 systemd[1]: Starting Docker Application Container Engine...
Aug 30 07:45:38 centos00 dockerd-current[31489]: time="2018-08-30T07:45:38.949026762 08:00" level=warning msg="could not change group /var/run/docker.sock to docker: group docker not found"
Aug 30 07:45:38 centos00 dockerd-current[31489]: time="2018-08-30T07:45:38.954488551 08:00" level=info msg="libcontainerd: new containerd process, pid: 31496"
Aug 30 07:45:41 centos00 dockerd-current[31489]: Error starting daemon: SELinux is not supported with the overlay2 graph driver on this kernel. Either boot into a newer kernel or disable selinux in docker (--selinux-enabled=false)
Aug 30 07:45:41 centos00 systemd[1]: docker.service: main process exited, code=exited, status=1/FAILURE
Aug 30 07:45:41 centos00 systemd[1]: Failed to start Docker Application Container Engine.
Aug 30 07:45:41 centos00 systemd[1]: Unit docker.service entered failed state.
Aug 30 07:45:41 centos00 systemd[1]: docker.service failed.
参考这篇文章:
https://stackoverflow.com/questions/45461307/selinux-is-not-supported-with-the-overlay-graph-driver
执行命令:
代码语言:javascript复制[root@centos00 log]# cat /etc/sysconfig/docker-storage
DOCKER_STORAGE_OPTIONS="--storage-driver overlay2 "
修改其 storage driver,使其应用 devicemapper :
代码语言:javascript复制[root@centos00 log]# cat /etc/sysconfig/docker-storage
DOCKER_STORAGE_OPTIONS="--storage-driver devicemapper "
再次启动 docker, 并检查 Docker 的状态
代码语言:javascript复制[root@centos00 log]# docker info
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 1.13.1
Storage Driver: devicemapper
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
Registries: docker.io (secure)
创建一个容器:
代码语言:javascript复制[root@centos00 log]# docker run -i -t ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
Trying to pull repository docker.io/library/ubuntu ...
latest: Pulling from docker.io/library/ubuntu
124c757242f8: Downloading [===============================> ] 19.84 MB/31.76 MB
2ebc019eb4e2: Download complete
dac0825f7ffb: Download complete
82b0bb65d1bf: Download complete
ef3b655c7f88: Download complete
这是简易版本的创建新容器的方式。如果容器不是远程服务器维护的,而在本地局域网(为了安全,放在本地局域网缓存),创立新容器的方法又有稍微不同。
当命令执行完毕,此时我们已经在 Docker 新建的容器里面:
代码语言:javascript复制root@ecb9d7b74b07:~# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 ecb9d7b74b07
另起一个窗口,检查开启的容器
代码语言:javascript复制[root@centos00 huangyun]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ecb9d7b74b07 ubuntu "/bin/bash" 9 minutes ago Up 9 minutes vibrant_thompson
这是一个临时起的容器,一旦退出执行了 docker run -i -t ubuntu /bin/bash 的窗口,容器就随之关闭了。
如果要建立一个长久不关闭的容器,就需要执行面的命令来安装守护容器:
代码语言:javascript复制docker run --name daemon_dave -d ubuntu /bin/sh -c "while true ;
do echo hello world; sleep 1 ; done"
-d 标识了此容器运行在后台,命令执行完之后,返回主机。
可以执行下面的命令,连接后台执行的容器:
代码语言:javascript复制[root@centos00 huangyun]# docker exec -i -t daemon_dave /bin/bash
root@eb6cb2a3b7b6:/# top
top - 14:19:01 up 16:17, 0 users, load average: 0.29, 0.21, 0.20
Tasks: 4 total, 1 running, 3 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.6 us, 1.2 sy, 0.0 ni, 98.2 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 3878288 total, 114852 free, 2647828 used, 1115608 buff/cache
KiB Swap: 2097148 total, 2092540 free, 4608 used. 831552 avail Mem
关闭一个容器:
执行下面命令即可关闭一个正在运行的容器:
代码语言:javascript复制[root@centos00 website]# docker stop nginx_server_1
nginx_server_1
[root@centos00 website]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@centos00 website]#
docker ps 可以用来检查当前运行着的容器。
以特定名字运行一个容器之后,这名字就一直保存着,下次运行,如果再以这份名字执行相应的运行程序,会报如下的错误:
代码语言:javascript复制[root@centos00 website]# docker run -d -p 80 --name nginx_server_1 -v /var/www/html/website:/var/www/html/website:rw ubuntu/nginx3
/usr/bin/docker-current: Error response from daemon: Conflict. The container name "/nginx_server_1" is already in use by container f40d10674908782758915399d3f16f1c5207e2907cb90e25f3689bccb9449d34. You have to remove (or rename) that container to be able to reuse that name..
See '/usr/bin/docker-current run --help'.
不知道为什么 Docker 主程会一直保存着运行过的 docker 名字:
代码语言:javascript复制[root@centos00 website]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
17f8ba709f49 ubuntu/nginx3 "nginx" 4 minutes ago Exited (0) 3 minutes ago hardcore_pare
f40d10674908 ubuntu/nginx3 "nginx" 10 hours ago Exited (0) 6 minutes ago nginx_server_1
当再一次使用其中之一运行容器时,名字会因为重复而被拒绝运行。
针对这种需要使用同一个名字重启容器的情况,一般的解决方法有3种:
- 在每次运行容器时,指定关闭容器之后,销毁
# docker run -d -p 80 --rm --name nginx_server_1 -v /var/www/html/website:/var/www/html/website:rw ubuntu/nginx3
- 先关闭容器,再移除容器名字
# docker stop nginx_server_1
# docker rm nginx_server_1
- 重启容器而不用先销毁
# docker restart nginx_server_1
Docker 的镜像与仓库
Docker 公司出版了自己维护和运营的一些镜像,官方网站维护了这份列表: https://hub.docker.com/
注册一个 Docker 官网的账户 , dblenis, l*w*6.
每个仓库中都存放着各种镜像,执行命令,可以将这些镜像都拉到本地存储:
代码语言:javascript复制[root@centos00 containers]# docker pull centos
Using default tag: latest
Trying to pull repository docker.io/library/centos ...
latest: Pulling from docker.io/library/centos
256b176beaff: Pull complete
Digest: sha256:6f6d986d425aeabdc3a02cb61c02abb2e78e57357e92417d6d58332856024faf
Status: Downloaded newer image for docker.io/centos:latest
[root@centos00 containers]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/ubuntu latest 16508e5c265d 9 days ago 84.1 MB
docker.io/centos latest 5182e96772bf 3 weeks ago 200 MB
[root@centos00 containers]#
每个镜像都会带有自己的标签,在建立新容器的时候带上这份标签,会让我们更明白操作的对象是什么,会有什么异常:
代码语言:javascript复制[root@centos00 containers]# docker run --name centos7 -d centos:centos7.4.1708 /bin/sh
如果不指定特定标签,在拉取官网镜像时,则拉取的是最新的。
构建镜像
两种方法:
使用 Docker Commit 命令 使用 Docker build 命令和 Dockerfile 文件
通过前面新建的 ubuntu 没有 ping 的功能,我希望可以将 ping 功能安装进去,然后打包一个新的镜像,放在 Docker 上分享。
代码语言:javascript复制# apt-get install iputils-ping
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
libcap2 libcap2-bin libidn11 libpam-cap
The following NEW packages will be installed:
iputils-ping libcap2 libcap2-bin libidn11 libpam-cap
0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded.
Need to get 140 kB of archives.
After this operation, 537 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
apt-get 安装一些其他软件,方便以后使用,提交这些更改,将其完整的做成一个容器镜像。以后若要新建容器,只需要在此镜像基础上新建便可。
代码语言:javascript复制[root@centos00 huangyun]# docker commit daemon_dave ubuntu/ping
若此时查看镜像库:
代码语言:javascript复制[root@centos00 huangyun]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu/ping latest 2eb12722cb2f 2 minutes ago 186 MB
docker.io/ubuntu latest 16508e5c265d 9 days ago 84.1 MB
docker.io/centos 7.4.1708 d3949e34634c 3 weeks ago 197 MB
docker.io/centos centos7.4.1708 d3949e34634c 3 weeks ago 197 MB
docker.io/centos latest 5182e96772bf 3 weeks ago 200 MB
发现 repository 里面多了一个 ubuntu/ping 的镜像。
就像是虚拟机多保存了一个 snapshot 一样,更方便的是我们居然可以依据这份 snapshot 来构建一个新的虚拟机。
官方更推荐使用 Dockerfile 和 Docker build 来构建新容器镜像
Dockerfile 是一种特殊的文件,用来编写 DSL 指令,这些指令可以被 Docker 进程识别,并根据这些指令进行处理,最终完成一个可用的镜像制作。每一个镜像都是从基础镜像之上,一点点添加其他镜像组成的。一开始的基础镜像只是符合最低运行库的内核,比如 ubuntu 的基础镜像,居然连 ping, vi 都没有。如果需要这些功能作为新镜像的一部分,那么就要在 Dockerfile 里面新加。
更多的 Dockerfile 支持的指令: http://docs.docker.com/reference/builder
Docker build 就是基于 Dockerfile ,将其中的指令发送给 Docker 进程,使其进行构建新镜像。Docker 进程可以看做是服务进程,提供一系列的后台服务,docker build 就是客户端,发送请求给 Docker ,Docker 统一调度工作完成 build 的请求。
代码语言:javascript复制[root@centos00 DockerWeb]# cat Dockerfile
# version : 0.0.1
FROM ubuntu:14.04
MAINTAINER Lenis Huang "huangyun_122@163.com"
RUN apt-get update
RUN apt-get install -y nginx
RUN echo "Hello, World!" > /usr/share/nginx/html/index.html
EXPOSE 80
上面的脚本安装了 nginx 服务,并且创建了一个简单的静态网页,最后允许 80 开放给外界访问。
构建开始:
代码语言:javascript复制[root@centos00 DockerWeb]# docker build -t="ubuntu/nginx" .
Sending build context to Docker daemon 2.048 kB
Step 1/6 : FROM ubuntu:14.04
Trying to pull repository docker.io/library/ubuntu ...
14.04: Pulling from docker.io/library/ubuntu
72c01b436656: Extracting [=====> ] 7.799 MB/67.13 MB
944f9cf63457: Download complete
6856614e8780: Download complete
9d0e4b6507f2: Download complete
c00913272b9b: Download complete
正在 build 之中的镜像,这一步步看的更详细:
代码语言:javascript复制[root@centos00 DockerWeb]# docker build -t="ubuntu/nginx" .
Sending build context to Docker daemon 2.048 kB
Step 1/6 : FROM ubuntu:14.04
Trying to pull repository docker.io/library/ubuntu ...
14.04: Pulling from docker.io/library/ubuntu
---> e7cab50d7846
Removing intermediate container 7478088422e9
Step 6/6 : EXPOSE 80
---> Running in fadc982b2846
---> a99888e05c01
Removing intermediate container fadc982b2846
Successfully built a99888e05c01
似乎中间也出现了一些异常:
代码语言:javascript复制debconf: unable to initialize frontend: Dialog
debconf: (TERM is not set, so the dialog frontend is not usable.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (This frontend requires a controlling tty.)
debconf: falling back to frontend: Teletype
似乎也没有影响继续 build 的进程。
代码语言:javascript复制Setting up nginx (1.4.6-1ubuntu3.8) ...
Processing triggers for libc-bin (2.19-0ubuntu6.14) ...
Processing triggers for sgml-base (1.26 nmu4ubuntu1) ...
---> 3e46f256a08d
Removing intermediate container 7199f88e91ef
Step 5/6 : RUN echo "Hello, World!" > /usr/share/nginx/html/index.html
---> Running in 7478088422e9
---> e7cab50d7846
Removing intermediate container 7478088422e9
Step 6/6 : EXPOSE 80
---> Running in fadc982b2846
---> a99888e05c01
Removing intermediate container fadc982b2846
Successfully built a99888e05c01
中间层的镜像,在顺利 build 完之后,被移除,而只保留了最后一个顺利完成 build 的镜像,而这正是我们需要的。
查看刚才 Build 完之后的镜像,基于这份镜像再新建一个新的容器:
代码语言:javascript复制[root@centos00 DockerWeb]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu/nginx latest a99888e05c01 6 minutes ago 230 MB
docker.io/centos latest 5182e96772bf 3 weeks ago 200 MB
Docker 测试网站
先按照书上的代码敲一遍,看看效果如何。但在 Linux 下安装配置 nginx 是必知必会的东西。我觉得有必要另开一篇好好说道。
新建一份 Dockerfile :
代码语言:javascript复制[root@centos00 DockerNginx]# cat Dockerfile
FROM ubuntu
MAINTAINER Lenis Huang "huangyun_122@163.com"
ENV REFRESHED_AT 2018-09-01
RUN apt-get update
RUN apt-get install -y -q nginx
RUN mkdir -p /var/www/html
ADD nginx/global.conf /etc/nginx/conf.d/
ADD nginx/nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
Nginx 的两个配置文件:
代码语言:javascript复制# global.conf
server {
listen 0.0.0.0:80;
server_name _;
root /var/www/html/website;
index index.html index.htm
access_log /var/log/nginx/default_access.log;
error_log /var/log/nginx/default_error.log;
}
代码语言:javascript复制# nginx.conf
user www-data;
worker_processes 4;
pid /run/nginx.pid;
daemon off;
events {}
http {
sendfile on ;
tcp_nopush on ;
tcp_nodelay on ;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_disable "msie6";
include /etc/nginx/conf.d/*.conf;
}
Dockerfile 和 nginx 目录是平级的,docker build 在构建的时候,会依据相对路径找到对应的文件进行操作。docker build 命令会在指定的路径下寻找 dockerfile ,所以最简单的方式便是指定当前目录为 Build 起始路径:
代码语言:javascript复制[root@centos00 DockerNginx]# docker build -t ubuntu/nginx2 .
很不幸的是遇到一些问题:
代码语言:javascript复制E: Failed to fetch http://archive.ubuntu.com/ubuntu/pool/main/libx/libxau/libxau6_1.0.8-1_amd64.deb Connection failed [IP: 91.189.88.152 80]
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
The command '/bin/sh -c apt-get install -y -q nginx' returned a non-zero code: 100
再一次运行 build 命令这个错误消失,我认为这是一次简单的链接失效问题。
虽然安装了 nginx,但是在主机访问容器中的 web 服务,却是访问不了的。要登录 docker 虚拟机,开启 Nginx.
还记得配置 Nginx 的时候,指定了 root 文件吧:
代码语言:javascript复制# global.conf
server {
listen 0.0.0.0:80;
server_name _;
root /var/www/html/website;
index index.html index.htm
access_log /var/log/nginx/default_access.log;
error_log /var/log/nginx/default_error.log;
}
在这里,只要简单的编写 html 文件,放在 /var/www/html/website/目录下,以 index.html 命名即可。
在本地建立一个文件夹 website,专门放置需要在容器 nginx 服务下托管的网页。再指定容器开启时直接运行 nginx ,保持后台运行的容器可以一直处于运行状态而不退出。
代码语言:javascript复制[root@centos00 html]# docker run -d -p 80 --name website -v $PWD/website:/var/www/html/website ubuntu/nginx2 nginx
498f38dab68d3f5bc7166b2f92aeb344a795af7462081b68ca1cbeaa2f433b7d
但是亲测, Nginx 命令写在 docker run 之后不管用,还是要写在 dockerfile 之中:
代码语言:javascript复制FROM ubuntu
MAINTAINER Lenis Huang "huangyun_122@163.com"
ENV REFRESHED_AT 2018-09-01
RUN apt-get update
RUN apt-get install -y -q nginx
RUN mkdir -p /var/www/html
ADD nginx/global.conf /etc/nginx/conf.d/
ADD nginx/nginx.conf /etc/nginx/nginx.conf
CMD ["nginx"]
EXPOSE 80
在本地的文件夹 $PWD/website 下面编写简单的 index.html 文件:
代码语言:javascript复制[root@centos00 html]# cat index.html
This web page is built up outside of docker nginx.
But it is hosted by docer nginx.
It's amazing, like shared folder in vmware!
访问虚拟机,即可看到 index.html 中所写的内容。
非常利索的一个借壳托管网页的 docker 程序就那么完成了!
Docker 构建 Web 应用程序
代码语言:javascript复制# Dockerfile
FROM ubuntu
MAINTAINER Lenis Huang huangyun_122@163.com
RUN apt-get update
RUN apt-get -y install ruby ruby-dev build-essential redis-tools
RUN gem install --no-rdoc --no-ri sinatra json redis
RUN mkdir -p /opt/webapp
ADD webapp/bin /opt/webapp/bin
ADD webapp/lib /opt/webapp/lib
EXPOSE 4567
CMD ["/opt/webapp/bin/webapp"]
代码语言:javascript复制# webapp
#!/usr/bin/ruby
$:.unshift(FIle.expand_path(File.join(File.dirname(__FILE__),"..","lib")))
require 'app'
App.run!
代码语言:javascript复制# app.rb
require "rubygems"
require "sinatra"
require "json"
class App < Sinatra::Application
set :bind, '0.0.0.0'
get '/' do
"<h1>DockerBook TEst Sinatra app</h1>"
end
post '/json/?' do
params.to_json
end
end
新建容器,打开服务:
代码语言:javascript复制# docker run -i -t -p 4567 --rm --name sinatrapp ubuntu/sinatra3 /bin/sh
传入参数,返回 json:
代码语言:javascript复制# curl -i -H 'Accept:application/json' -d 'name=Foo&status=Bar' http://127.0.0.1:32781/json
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 29
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Server: WEBrick/1.4.2 (Ruby/2.5.1/2018-03-29)
Date: Sun, 02 Sep 2018 07:27:23 GMT
Connection: Keep-Alive
{"name":"Foo","status":"Bar"}
Redis on Docker
有意义的应用离不开数据库,用 Redis 为 Sinatra 应用来提供存储。
新建一台 Redis 数据库容器
代码语言:javascript复制# Dockerfile
FROM ubuntu
MAINTAINER Lenis Huang huangyun_122@163.com
RUN apt-get update
RUN apt-get -y install redis-server redis-tools
EXPOSE 6379
ENTRYPOINT ["/usr/bin/redis-server"]
CMD []
开启 Redis 容器之后,验证 Redis 是否可用:
代码语言:javascript复制# redis-cli -h 127.0.0.1 -p 32783
这里的端口 32783 是通过 docker ps 看来的:
代码语言:javascript复制[root@centos00 Redis]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e324f0fd3d31 ubuntu/redis "/usr/bin/redis-se..." 9 minutes ago Up 9 minutes 0.0.0.0:32783->6379/tcp redis
9ccf74ce181d ubuntu/sinatra3 "/bin/sh" 25 minutes ago Up 25 minutes 0.0.0.0:32781->4567/tcp sinatrapp
bbef28a8db2b ubuntu/nginx3 "nginx" 7 hours ago Up 7 hours 0.0.0.0:32775->80/tcp nginx_server_1
[root@centos00 Redis]#
0.0.0.0:32783->6379/tcp 就是宿主机端口与容器端口的映射。
Web App Sinatra 与 Redis 的连接
连接 Redis 有多种方法:
基于宿主机与容器之间端口映射
在运行容器的时候,通常会暴露一个端口 (docker run -p 80), 此时容器端口默认会映射到宿主机中的随机一个端口,比如33728. 外部计算机通过访问宿主机的映射端口(33728)就可以访问容器所提供的(80)服务了。
基于 Docker 栈的连接
Docker 在安装完毕之后,分配一个 172.16.X.X - 172.30.X.X IP 地址,也 就是所有宿主机可分配给新建容器的 IP 地址范围。Docker 服务进程自占一个 IP 作为路由,与宿主机进行通信的 IP,比如 172.17.0.1.
通过 docker 命令 inspect 来查看 redis 分配的 IP 地址
代码语言:javascript复制# docker inspect redis
"NetworkSettings": {
"Bridge": "",
"SandboxID": "2f679e6d9361654ec54f0e2c4c26cf358e008394580920921e106a66bb619c77",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"6379/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "32783"
}
]
},
"SandboxKey": "/var/run/docker/netns/2f679e6d9361",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "5d4467ebd24ce1ab75ec0f8c7df7411cd157c8f1305b6ea9fa08363d6d7781fc",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.4",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:04",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "6416f1f801bd82855cc4ffaf4c8086a61d5b56a3311b900ebfc12b70c9bd0775",
"EndpointID": "5d4467ebd24ce1ab75ec0f8c7df7411cd157c8f1305b6ea9fa08363d6d7781fc",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.4",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:04"
}
}
}
分配的 IP 可能下一次启动的时候会变,所以通过 IP 来连接 redis 不是很稳定。
这时候就需要 docker link 了
Docker Link 连接两个容器
这是一个令人兴奋的功能。不仅仅是省去了暴露端口的步骤,更赞的是绝对的安全。只要使用 link 连接了两个容器,不需要将端口暴露给宿主机,而两台容器之间依然可以相互通信。
代码语言:javascript复制# docker run -p 4567 --name webapp --link redis:db -t -i ubuntu/sinatra3 /bin/bash
root@3e140f12028b:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 db b078287c5cb9 redis
172.17.0.3 3e140f12028b
--link redis:db : redis 容器名,db 是别名,反应在父容器(指定--link的容器)的 hosts 文件中。
有了这个别名也就彻底解决了 Redis 服务器 IP 硬编码和 IP 地址不稳定的因素。
Docker 的网络,我简单手绘了下示意图:
Docker 应用在 SQL Server 上,包括这些主题:
- 在 Docker 上制作 SQL Server 镜像
- Docker 发布 SQL Server
参考:https://docs.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker?view=sql-server-2017
1. 在 Docker 上制作 SQL Server 镜像
制作 SQL Server On Docker 的镜像:
代码语言:javascript复制[root@centos00 Redis]# docker pull microsoft/mssql-server-linux
Using default tag: latest
Trying to pull repository docker.io/microsoft/mssql-server-linux ...
latest: Pulling from docker.io/microsoft/mssql-server-linux
f6fa9a861b90: Extracting [======================> ] 21.14 MB/46.41 MB
da7318603015: Download complete
6a8bd10c9278: Download complete
d5a40291440f: Download complete
bbdd8a83c0f1: Download complete
3a52205d40a6: Downloading [====================================> ] 21.27 MB/28.98 MB
6192691706e8: Downloading [=====================================> ] 28.7 MB/38.7 MB
1a658a9035fb: Download complete
25c716e804a1: Waiting
28fea03ad20e: Waiting
运行新建的 SQL Server On Docker 镜像:
代码语言:javascript复制# 官方实例
sudo docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=<YourStrong!Passw0rd>'
-p 1433:1433 --name sql1
-d microsoft/mssql-server-linux:2017-latest
代码语言:javascript复制[root@centos00 Redis]# docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=1QAZ2WSX' -e 'MSSQL_PID=Developer' -p 1433 --rm --name=sqlserver microsoft/mssql-server-linux
2018-09-02 23:52:48.67 Server Setup step is copying system data file 'C:templatedatamaster.mdf' to '/var/opt/mssql/data/master.mdf'.
2018-09-02 23:52:48.83 Server Did not find an existing master data file /var/opt/mssql/data/master.mdf, copying the missing default master and other system database files. If you have moved the database location, but not moved the database files, startup may fail. To repair: shutdown SQL Server, move the master database to configured location, and restart.
2018-09-02 23:52:48.84 Server Setup step is copying system data file 'C:templatedatamastlog.ldf' to '/var/opt/mssql/data/mastlog.ldf'.
2018-09-02 23:52:48.85 Server Setup step is copying system data file 'C:templatedatamodel.mdf' to '/var/opt/mssql/data/model.mdf'.
2018-09-02 23:52:48.90 Server Setup step is copying system data file 'C:templatedatamodellog.ldf' to '/var/opt/mssql/data/modellog.ldf'.
2018-09-02 23:52:48.94 Server Setup step is copying system data file 'C:templatedatamsdbdata.mdf' to '/var/opt/mssql/data/msdbdata.mdf'.
2018-09-02 23:52:48.97 Server Setup step is copying system data file 'C:templatedatamsdblog.ldf' to '/var/opt/mssql/data/msdblog.ldf'.
2018-09-02 23:52:49.16 Server Microsoft SQL Server 2017 (RTM-CU10) (KB4342123) - 14.0.3037.1 (X64)
Jul 27 2018 09:40:27
Copyright (C) 2017 Microsoft Corporation
Developer Edition (64-bit) on Linux (Ubuntu 16.04.5 LTS)
2018-09-02 23:52:55.40 spid20s The default language (LCID 0) has been set for engine and full-text services.
2018-09-02 23:57:57.72 spid54 Using 'dbghelp.dll' version '4.0.5'
连接在 Docker 中运行的 SQL Server:
代码语言:javascript复制# 官方实例
sudo docker exec -it sql1 /opt/mssql-tools/bin/sqlcmd
-S localhost -U SA -P '<YourStrong!Passw0rd>'
-Q 'ALTER LOGIN SA WITH PASSWORD="<YourNewStrong!Passw0rd>"'
代码语言:javascript复制[root@centos00 Sinatra]# docker exec -it sqlserver /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P '1QAZ2WSX'
这是阶段性的摸索成果,简单的演示在 Docker 上安装 SQL Server. 看到这里大家肯定不过瘾,重要的是 Docker 并不保存数据,一旦重启 Docker 容器,数据全丢,所以集成化部署 SQL Server Docker 的文章,还在路上,请稍后。