
有關(guān)docker的介紹啊,為什么 要使用docker啊這些就不說了,因?yàn)楫?dāng)你點(diǎn)開這篇作文的時(shí)候,你自己心里已經(jīng)有了答案。那么我們現(xiàn)在就打開電腦,擼起袖子開始docker入門吧。
相關(guān)名詞
鏡像(image):一個(gè)打包好的應(yīng)用,還有應(yīng)用運(yùn)行的系統(tǒng)、資源、配置文件等;
容器(container):鏡像的實(shí)例。你可以這么理解,我們使用對(duì)象(鏡像)可以alloc出來一個(gè)或者多個(gè)實(shí)例(容器);
倉庫:我們管理代碼有g(shù)ithub,每個(gè)項(xiàng)目創(chuàng)建一個(gè)repository,管理鏡像也是一樣的。
安裝docker
在這里下載相應(yīng)的docker安裝就好。
docker下載頁面
我們構(gòu)建自己的鏡像是需要基礎(chǔ)鏡像的,比如CentOS,獲取鏡像直接從Docker Hubpull就好,類似git clone操作。但是訪問國(guó)外網(wǎng)站速度慢,可以到阿里云下載,或者是配置阿里云加速器
常用命令
這尼瑪太多了,建議瞅瞅就直接略過吧。需要操作的時(shí)候回過來再查找相關(guān)命令就好。
搜索鏡像:docker search centos
獲取鏡像:docker pull registry.cn-hangzhou.aliyuncs.com/1hpc/centos
查看鏡像:
iMac:~ yetongxue$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.cn-hangzhou.aliyuncs.com/yetongxue/docker_test 1.2 f7d570f13f0a 7 days ago 515 MB
yetongxue/docker_test 1.2 f7d570f13f0a 7 days ago 515 MB
mysql 5.7 c73c7527c03a 3 weeks ago 412 MB
centos 7 3bee3060bfc8 2 months ago 193 MB
查看鏡像id:docker images -q
刪除鏡像:docker rmi image_id
刪除所有鏡像:docker rmi $(docker images -q)
創(chuàng)建容器:docker run --name <container_name> centos:7,container_name是自己定義的容器名
查看所有容器:docker ps -a
查看運(yùn)行容器:docker ps
查看容器id:docker ps -q
進(jìn)入容器:docker exec -it <container_id> bash
退出容器:exit
刪除容器:docker rm <container_id>
刪除所有容器:docker rm $(docker ps -aq)
端口映射:docker run -d -p 8080:80 hub.c.163.com/library/nginx,說明:-d 表示后臺(tái)運(yùn)行,-p 8080:80 表示將宿主機(jī)的8080端口映射到容器端口80。容器開放的端口在鏡像說明里面會(huì)有,nginx開放80,mysql開放3306,一般本來他們監(jiān)聽什么端口,容器就開放什么端口。
啟動(dòng)/停止/重啟容器:docker start/stop/restart <container_id>
獲取容器/鏡像的元數(shù)據(jù):docker inspect <container_id>
掛載數(shù)據(jù)卷:docker run -v host/machine/dir :container/path/dir --name volume_test_container centos:7,說明:數(shù)據(jù)卷的掛載相當(dāng)于在宿主機(jī)的目錄與容器目錄創(chuàng)建了一個(gè)鏈接,你修改任何一方的內(nèi)容,另一方的內(nèi)容也會(huì)同步修改。創(chuàng)建數(shù)據(jù)卷的作用:當(dāng)容器被刪除的時(shí)候,容器內(nèi)的數(shù)據(jù)也一起被刪除。像數(shù)據(jù)庫、媒體資源等文件我們通常都會(huì)使用 -v 將容器中的內(nèi)容鏈接到宿主機(jī),這樣我們重新創(chuàng)建容器的時(shí)候再次-v,數(shù)據(jù)又回來了。
啟動(dòng)mysql容器:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=qwerasdf -d mysql:5.7,默認(rèn)用戶為root,密碼qwerasdf
mysql容器啟動(dòng)后,其他容器就可以來連接使用了,方法如下:
容器連接:docker run --name some-app --link some-mysql:mysql -d application-that-uses-mysql
Dockerfile
以前上學(xué)的時(shí)候,好多課程學(xué)起來感覺沒勁,那是因?yàn)槲覀儾恢缹W(xué)習(xí)它除了考試之外還能做什么。一件事情,我們先有個(gè)宏觀的認(rèn)識(shí),然后再分解成很多步驟,那么在每一步的時(shí)候,我們才知道這一步我們?cè)谧鍪裁?,這一步對(duì)于整體所具有的意義是什么。那樣才會(huì)心里有數(shù),做起來也更帶感。
所以Dockerfile指令就不一一說明了,我們直接來整體感受下。
當(dāng)然,下面說的都是假設(shè)你已經(jīng)有了常規(guī)應(yīng)用部署的經(jīng)驗(yàn)了。本次demo采用的是django+uwsgi+nginx的一個(gè)搭配,數(shù)據(jù)庫使用mysql。
如果你還不太熟悉常規(guī)部署,請(qǐng)參照Django uwsgi nginx 應(yīng)用部署
獲取demo:git clone https://github.com/xander-ye/docker_test.git

Dockerfile內(nèi)容詳解
#當(dāng)你寫下FROM centos:7的時(shí)候,你就要想著,在這以后的每一步操作都是在centos 7系統(tǒng)鏡像中進(jìn)行的操作,
#你以前是怎么部署應(yīng)用的,那么請(qǐng)按照你以前的步驟一步一步來就好。
FROM centos:7
#聲明鏡像制作者
MAINTAINER yetongxue <yeli.studio@qq.com>
#設(shè)置時(shí)區(qū)
ENV TZ "Asia/Shanghai"
# 設(shè)置系統(tǒng)環(huán)境變量DOCKER_SRC
ENV DOCKER_SRC=mysite
# 設(shè)置系統(tǒng)環(huán)境變量DOCKER_HOME
ENV DOCKER_HOME=/root
# 設(shè)置系統(tǒng)環(huán)境變量DOCKER_PROJECT
ENV DOCKER_PROJECT=/root/project
#這句指令相當(dāng)與:cd /root
WORKDIR $DOCKER_HOME
#緊接著在root目錄下面創(chuàng)建了兩個(gè)文件夾
RUN mkdir media static
#安裝應(yīng)用運(yùn)行所需要的工具依賴pip,git好像沒用上,mysql客戶端,
#nc是一個(gè)網(wǎng)絡(luò)工具,端口檢測(cè)腳本wait-for-it.sh里面有使用這個(gè)軟件
RUN yum -y install epel-release && \
yum -y install python-pip && \
yum -y install git nginx gcc gcc-c++ python-devel && yum -y install mysql && \
yum -y install mysql-devel && yum install nc -y && yum clean all && \
pip install --upgrade pip
# cd $DOCKER_PROJECT
WORKDIR $DOCKER_PROJECT
# . 表示當(dāng)前目錄,一是Dockerfile所在的目錄,二是剛剛設(shè)置的DOCKER_PROJECT目錄,
#這一步操作將會(huì)把項(xiàng)目中application目錄下的所有文件拷貝到鏡像目錄DOCKER_PROJECT=/root/project下面
COPY ./ ./
#這一步安裝python依賴軟件django、Pillow、mysql-python、uwsgi、django-ckeditor。
#補(bǔ)充,-i 是修改pip源,默認(rèn)的源速度很慢,經(jīng)??ㄔ谶@里。
RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt
#暴露端口8000,到時(shí)候執(zhí)行docker run 的時(shí)候才好把宿主機(jī)端口映射到8000
EXPOSE 8000
#賦予start_script執(zhí)行權(quán)限
RUN chmod u+x start_script
#容器啟動(dòng)后要執(zhí)行的命令
ENTRYPOINT ["./start_script"]
以上就是我們構(gòu)建一個(gè)鏡像所要進(jìn)行的操作,有了這個(gè)Dockerfile,我們就可以進(jìn)入Dockerfile所在的目錄了,執(zhí)行:docker build -t yetongxue/docker_test:1.2 ./ 構(gòu)建我們的鏡像了。
我知道,現(xiàn)在你心里已經(jīng)有很多疑問了:
這個(gè)容器啟動(dòng)后能工作嗎?
我數(shù)據(jù)庫上哪兒連???
還有nginx配置,python manage.py migrate 刷新數(shù)據(jù)庫都還沒有做,uwsgi還沒啟動(dòng)咧!
是的是的,咋們繼續(xù)分解分解...
啟動(dòng)腳本start_script
我們剛剛忽略了容器啟動(dòng)后還有執(zhí)行的命令了。咋們一起來看看start_script里面在做什么。
#!/bin/bash
#sed是一個(gè)Linux編輯器吧,此命令的作用是查找文件/etc/nginx/nginx.conf中包含user的行,并將此行的nginx替換成root
sed -i '/user/{s/nginx/root/}' /etc/nginx/nginx.conf
#將項(xiàng)目nginx配置連接到nginx配置
ln -s /root/project/mysite_nginx.conf /etc/nginx/conf.d/
#啟動(dòng)nginx
nginx
#賦予wait-for-it.sh可執(zhí)行權(quán)限
chmod u+x wait-for-it.sh
#判斷數(shù)據(jù)庫端口是否可用,因?yàn)閿?shù)據(jù)庫未準(zhǔn)備好的話接下來的數(shù)據(jù)庫刷新操作將失敗。
#其實(shí),假如我們事先啟動(dòng)好了一個(gè)數(shù)據(jù)庫容器的話,此操作也可以省略。
#這樣做是因?yàn)樽詈笪覀儠?huì)使用docker-compose來一起管理兩個(gè)或者多個(gè)容器,
#docker-compose里面三個(gè)關(guān)鍵字:link、depends_on、volume_from是可以確定容器的啟動(dòng)順序的,
#但是,容器里面的mysql是否啟動(dòng)那就不一定了,所以我們檢測(cè)下端口比較穩(wěn)妥。
#沒有好我們等幾秒也無妨
#另外,這里的兩個(gè)環(huán)境變量DB_PORT_3306_TCP_ADDR和DB_PORT_3306_TCP_PORT是mysql容器中的,
#不用猜也知道,一個(gè)是host,一個(gè)是port
#如果我們通過link將一個(gè)容器連接到mysql容器,mysql容器中的一些環(huán)境變量會(huì)共享出來的。
./wait-for-it.sh $DB_PORT_3306_TCP_ADDR:$DB_PORT_3306_TCP_PORT &
wait
#設(shè)置manage.py中使用的setting
export DJANGO_SETTINGS_MODULE=mysite.settings.server
#進(jìn)入mysite目錄(application下一級(jí)目錄,不是mysite目錄下的mysite)
#剛開始也許你有點(diǎn)困惑,不知道現(xiàn)在操作的目錄到底在哪里,不像通常操作Linux,我可以pwd一下。
#其實(shí)是這樣的,你以此腳本所在的位置為參照,你看項(xiàng)目目錄結(jié)構(gòu)發(fā)現(xiàn),
#start_script與目錄mysite是同一級(jí)的,manage.py在mysite之下,對(duì)吧
cd mysite
#刷新數(shù)據(jù)庫
./manage.py migrate --noinput
#加載管理員用戶到數(shù)據(jù)庫,以便容器啟動(dòng)之后不必再進(jìn)入容器執(zhí)行python manage.py createsuperuser操作
./manage.py loaddata ./fixtures/superuser.json
#收集靜態(tài)文件
./manage.py collectstatic --noinput
#返回上級(jí)目錄,mysite_uwsgi.ini所在的目錄
cd ..
#啟動(dòng)uwsgi
uwsgi --ini mysite_uwsgi.ini
附一:鏈接過mysql容器的容器的環(huán)境變量
[root@d9f25c4909bb project]# env
HOSTNAME=d9f25c4909bb
DB_NAME=/web/db
DOCKER_HOME=/root
TERM=xterm
DB_PORT=tcp://172.17.0.2:3306
DB_PORT_3306_TCP_PORT=3306
DB_ENV_GOSU_VERSION=1.7
DB_PORT_3306_TCP_PROTO=tcp
DB_ENV_MYSQL_ROOT_PASSWORD=qwerasdf
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
DOCKER_PROJECT=/root/project
PWD=/root/project
TZ=Asia/Shanghai
DB_PORT_3306_TCP_ADDR=172.17.0.2
SHLVL=1
HOME=/root
DB_PORT_3306_TCP=tcp://172.17.0.2:3306
DB_ENV_MYSQL_VERSION=5.7.19-1debian8
LESSOPEN=||/usr/bin/lesspipe.sh %s
DB_ENV_MYSQL_MAJOR=5.7
DOCKER_SRC=mysite
_=/usr/bin/env
附二:server.py 設(shè)置中的數(shù)據(jù)庫連接配置
DATABASES = {
#mysql database setting:
#when the container link a mysql container,this container will has the env variable of "DB_PORT_3306_TCP_ADDR", the mysql host.
'default':{
'ENGINE': 'django.db.backends.mysql',
'NAME':'docker_db',
'USER':'root',
'PASSWORD': os.environ.get('DB_ENV_MYSQL_ROOT_PASSWORD'),
'HOST':os.environ.get('DB_PORT_3306_TCP_ADDR'),
'PORT':3306,
'OPTIONS':{
}
}
}
附三:Django初始化數(shù)據(jù)
針對(duì)腳本里面的命令./manage.py loaddata ./fixtures/superuser.json,請(qǐng)參見Providing initial data for models
執(zhí)行命令后數(shù)據(jù)庫相應(yīng)的表中會(huì)添加一條記錄。
./fixtures/superuser.json內(nèi)容如下:
[
{ "model": "auth.user",
"pk": 1,
"fields": {
"username": "root",
"password": "pbkdf2_sha256$30000$IdlNbZkEbkO3$4sqwI5SnLPDN2bhelVCE+Hu1rzspQU20OuYfQbW0G+c=",
"is_superuser": true,
"is_staff": true,
"is_active": true
}
}
]
因?yàn)閐jango的密碼是經(jīng)過的哈希的,所以這里填寫的密碼是你想要設(shè)置密碼的哈希字符串。
生成django密碼:
In [1]: from django.contrib.auth.hashers import make_password
In [2]: make_password('qwerasdf')
Out[2]: u'pbkdf2_sha256$30000$IdlNbZkEbkO3$4sqwI5SnLPDN2bhelVCE+Hu1rzspQU20OuYfQbW0G+c=‘
附四:nginx配置
# mysite_nginx.conf
# configuration of the server
server {
# the port your site will be served on, default_server indicates that this server block
# is the block to use if no blocks match the server_name
listen 8000 default_server;
# the domain name it will serve for
server_name localhost; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
location /media {
alias /root/media; # your Django project's media files - amend as required
}
location /static {
alias /root/static; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass unix:///root/project/mysite/docker_app.sock; # for a file socket
include /root/project/uwsgi_params; # the uwsgi_params file you installed
}
}
這下了然了噻。
運(yùn)行容器
我們剛剛在Dockerfile所在的目錄下執(zhí)行docker build -t yetongxue/docker_test:1.2 ./得到了鏡像yetongxue/docker_test:1.2。此容器運(yùn)行是需要依賴mysql容器的。所以我們首先啟動(dòng)一個(gè)mysql容器:
docker run --name db -d -e MYSQL_ROOT_PASSWORD=qwerasdf -e MYSQL_DATABASE=docker_db -v Users/yetongxue/Desktop/volumes/docker_test/db:/var/lib/mysql mysql:5.7
說明:
- --name給容器取個(gè)好聽的名字;
- -d 后臺(tái)運(yùn)行;
- -e你要傳遞給容器的參數(shù),你還可以指定用戶名,不傳默認(rèn)root用戶
- -v 容器中的數(shù)據(jù)庫同步到宿主機(jī)以防不測(cè)。如果你創(chuàng)建了一個(gè)數(shù)據(jù)卷容器的話,你這里也可以使用參數(shù) volume_from
- 最后是要采用的鏡像及版本號(hào)
補(bǔ)充:
mysql的鏡像其實(shí)跟我們剛剛構(gòu)建的鏡像一樣,Dockerfile的最后會(huì)有一句ENTRYPOINT ["docker-entrypoint.sh"],我們來看看這個(gè)腳本吧。
[root@iZ94l43yka9Z docker_test]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
70d1d4b59e06 registry.cn-hangzhou.aliyuncs.com/yetongxue/docker_test:1.2 "./start_script" 30 hours ago Up 12 seconds 0.0.0.0:8100->8000/tcp dockertest_web_1
6b5881e8c4b2 mysql:5.7 "docker-entrypoint.sh" 30 hours ago Up 12 seconds 3306/tcp dockertest_db_1
[root@iZ94l43yka9Z docker_test]# docker exec -it 6b5881e8c4b2 bash
root@6b5881e8c4b2:/# ls
bin dev entrypoint.sh home lib64 mnt proc run srv tmp var
boot docker-entrypoint-initdb.d etc lib media opt root sbin sys usr
root@6b5881e8c4b2:/# nl entrypoint.sh
1 #!/bin/bash
2 set -eo pipefail
3 shopt -s nullglob
4 # if command starts with an option, prepend mysqld
5 if [ "${1:0:1}" = '-' ]; then
6 set -- mysqld "$@"
7 fi
8 # skip setup if they want an option that stops mysqld
9 wantHelp=
10 for arg; do
11 case "$arg" in
12 -'?'|--help|--print-defaults|-V|--version)
13 wantHelp=1
14 break
15 ;;
16 esac
17 done
18 # usage: file_env VAR [DEFAULT]
19 # ie: file_env 'XYZ_DB_PASSWORD' 'example'
20 # (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of
21 # "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature)
22 file_env() {
23 local var="$1"
24 local fileVar="${var}_FILE"
25 local def="${2:-}"
26 if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
27 echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
28 exit 1
29 fi
30 local val="$def"
31 if [ "${!var:-}" ]; then
32 val="${!var}"
33 elif [ "${!fileVar:-}" ]; then
34 val="$(< "${!fileVar}")"
35 fi
36 export "$var"="$val"
37 unset "$fileVar"
38 }
39 _check_config() {
40 toRun=( "$@" --verbose --help )
41 if ! errors="$("${toRun[@]}" 2>&1 >/dev/null)"; then
42 cat >&2 <<-EOM
43 ERROR: mysqld failed while attempting to check config
44 command was: "${toRun[*]}"
45 $errors
46 EOM
47 exit 1
48 fi
49 }
50 # Fetch value from server config
51 # We use mysqld --verbose --help instead of my_print_defaults because the
52 # latter only show values present in config files, and not server defaults
53 _get_config() {
54 local conf="$1"; shift
55 "$@" --verbose --help --log-bin-index="$(mktemp -u)" 2>/dev/null | awk '$1 == "'"$conf"'" { print $2; exit }'
56 }
57 # allow the container to be started with `--user`
58 if [ "$1" = 'mysqld' -a -z "$wantHelp" -a "$(id -u)" = '0' ]; then
59 _check_config "$@"
60 DATADIR="$(_get_config 'datadir' "$@")"
61 mkdir -p "$DATADIR"
62 chown -R mysql:mysql "$DATADIR"
63 exec gosu mysql "$BASH_SOURCE" "$@"
64 fi
65 if [ "$1" = 'mysqld' -a -z "$wantHelp" ]; then
66 # still need to check config, container may have started with --user
67 _check_config "$@"
68 # Get config
69 DATADIR="$(_get_config 'datadir' "$@")"
70 if [ ! -d "$DATADIR/mysql" ]; then
71 file_env 'MYSQL_ROOT_PASSWORD'
72 if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" -a -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
73 echo >&2 'error: database is uninitialized and password option is not specified '
74 echo >&2 ' You need to specify one of MYSQL_ROOT_PASSWORD, MYSQL_ALLOW_EMPTY_PASSWORD and MYSQL_RANDOM_ROOT_PASSWORD'
75 exit 1
76 fi
77 mkdir -p "$DATADIR"
78 echo 'Initializing database'
79 "$@" --initialize-insecure
80 echo 'Database initialized'
81 if command -v mysql_ssl_rsa_setup > /dev/null && [ ! -e "$DATADIR/server-key.pem" ]; then
82 # https://github.com/mysql/mysql-server/blob/23032807537d8dd8ee4ec1c4d40f0633cd4e12f9/packaging/deb-in/extra/mysql-systemd-start#L81-L84
83 echo 'Initializing certificates'
84 mysql_ssl_rsa_setup --datadir="$DATADIR"
85 echo 'Certificates initialized'
86 fi
87 SOCKET="$(_get_config 'socket' "$@")"
88 "$@" --skip-networking --socket="${SOCKET}" &
89 pid="$!"
90 mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" )
91 for i in {30..0}; do
92 if echo 'SELECT 1' | "${mysql[@]}" &> /dev/null; then
93 break
94 fi
95 echo 'MySQL init process in progress...'
96 sleep 1
97 done
98 if [ "$i" = 0 ]; then
99 echo >&2 'MySQL init process failed.'
100 exit 1
101 fi
102 if [ -z "$MYSQL_INITDB_SKIP_TZINFO" ]; then
103 # sed is for https://bugs.mysql.com/bug.php?id=20545
104 mysql_tzinfo_to_sql /usr/share/zoneinfo | sed 's/Local time zone must be set--see zic manual page/FCTY/' | "${mysql[@]}" mysql
105 fi
106 if [ ! -z "$MYSQL_RANDOM_ROOT_PASSWORD" ]; then
107 export MYSQL_ROOT_PASSWORD="$(pwgen -1 32)"
108 echo "GENERATED ROOT PASSWORD: $MYSQL_ROOT_PASSWORD"
109 fi
110 rootCreate=
111 # default root to listen for connections from anywhere
112 file_env 'MYSQL_ROOT_HOST' '%'
113 if [ ! -z "$MYSQL_ROOT_HOST" -a "$MYSQL_ROOT_HOST" != 'localhost' ]; then
114 # no, we don't care if read finds a terminating character in this heredoc
115 # https://unix.stackexchange.com/questions/265149/why-is-set-o-errexit-breaking-this-read-heredoc-expression/265151#265151
116 read -r -d '' rootCreate <<-EOSQL || true
117 CREATE USER 'root'@'${MYSQL_ROOT_HOST}' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
118 GRANT ALL ON *.* TO 'root'@'${MYSQL_ROOT_HOST}' WITH GRANT OPTION ;
119 EOSQL
120 fi
121 "${mysql[@]}" <<-EOSQL
122 -- What's done in this file shouldn't be replicated
123 -- or products like mysql-fabric won't work
124 SET @@SESSION.SQL_LOG_BIN=0;
125 DELETE FROM mysql.user WHERE user NOT IN ('mysql.sys', 'mysqlxsys', 'root') OR host NOT IN ('localhost') ;
126 SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${MYSQL_ROOT_PASSWORD}') ;
127 GRANT ALL ON *.* TO 'root'@'localhost' WITH GRANT OPTION ;
128 ${rootCreate}
129 DROP DATABASE IF EXISTS test ;
130 FLUSH PRIVILEGES ;
131 EOSQL
132 if [ ! -z "$MYSQL_ROOT_PASSWORD" ]; then
133 mysql+=( -p"${MYSQL_ROOT_PASSWORD}" )
134 fi
135 file_env 'MYSQL_DATABASE'
136 if [ "$MYSQL_DATABASE" ]; then
137 echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ;" | "${mysql[@]}"
138 mysql+=( "$MYSQL_DATABASE" )
139 fi
140 file_env 'MYSQL_USER'
141 file_env 'MYSQL_PASSWORD'
142 if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then
143 echo "CREATE USER '$MYSQL_USER'@'%' IDENTIFIED BY '$MYSQL_PASSWORD' ;" | "${mysql[@]}"
144 if [ "$MYSQL_DATABASE" ]; then
145 echo "GRANT ALL ON \`$MYSQL_DATABASE\`.* TO '$MYSQL_USER'@'%' ;" | "${mysql[@]}"
146 fi
147 echo 'FLUSH PRIVILEGES ;' | "${mysql[@]}"
148 fi
149 echo
150 for f in /docker-entrypoint-initdb.d/*; do
151 case "$f" in
152 *.sh) echo "$0: running $f"; . "$f" ;;
153 *.sql) echo "$0: running $f"; "${mysql[@]}" < "$f"; echo ;;
154 *.sql.gz) echo "$0: running $f"; gunzip -c "$f" | "${mysql[@]}"; echo ;;
155 *) echo "$0: ignoring $f" ;;
156 esac
157 echo
158 done
159 if [ ! -z "$MYSQL_ONETIME_PASSWORD" ]; then
160 "${mysql[@]}" <<-EOSQL
161 ALTER USER 'root'@'%' PASSWORD EXPIRE;
162 EOSQL
163 fi
164 if ! kill -s TERM "$pid" || ! wait "$pid"; then
165 echo >&2 'MySQL init process failed.'
166 exit 1
167 fi
168 echo
169 echo 'MySQL init process done. Ready for start up.'
170 echo
171 fi
172 fi
173 exec "$@"
哎呀臥槽,將近兩百行,終于滾完了!
好吧,咋們抓重點(diǎn)看。
在第72行的時(shí)候,進(jìn)行了一個(gè)判斷,判斷MYSQL_ROOT_PASSWORD、MYSQL_ALLOW_EMPTY_PASSWORD、MYSQL_RANDOM_ROOT_PASSWORD是否為空,不為空的話就進(jìn)行Database initialize。
在第135行的時(shí)候判斷MYSQL_DATABASE是否為空,不為空的話執(zhí)行echo "CREATE DATABASE IF NOT EXISTS `{mysql[@]}"
緊接著在第140-148行進(jìn)行了一個(gè)數(shù)據(jù)庫權(quán)限的授予操作。
所以,我們啟動(dòng)mysql容器之后就可以開開心心的去使用了。
數(shù)據(jù)庫容器啟動(dòng)了,接下來就是啟動(dòng)我們的應(yīng)用容器,并與數(shù)據(jù)庫容器鏈接。執(zhí)行docker run --name web -v Users/yetongxue/Desktop/volumes/docker_test/media:/root/media --link db docker_test:1.2
It works!
現(xiàn)在呢,我們就基本上就把整個(gè)的過程走了一遍。
但是呢,我們現(xiàn)在有兩個(gè)容器,我們就執(zhí)行了兩條啟動(dòng)命令,假如我們有三個(gè)四個(gè)呢?而且現(xiàn)在流行的微服務(wù)架構(gòu),很多服務(wù)唉……
不要擔(dān)心,還有docker-compose!
docker-compose
docker-compose是一個(gè)服務(wù)編排工具,簡(jiǎn)化復(fù)雜應(yīng)用的利器,使用yaml語法。
對(duì)于yaml這里有個(gè)專門針對(duì)容器編排的教程docker-compose.yml 語法說明可以瞅瞅。
好啦,現(xiàn)在針對(duì)現(xiàn)在的兩個(gè)容器,一個(gè)應(yīng)用容器,一個(gè)數(shù)據(jù)庫容器,我們來看看這個(gè)docker-compose.yml長(zhǎng)啥樣吧。
web:
image: yetongxue/docker_test:1.2
links:
- "db"
ports:
- "8100:8000"
volumes:
- "${DOCKER_VOLUME_PATH}/docker_test/media:/root/media"
restart: always
db:
image: mysql:5.7
environment:
TZ: 'Asia/Shanghai'
MYSQL_ROOT_PASSWORD: qwerasdf
MYSQL_DATABASE: docker_db
restart: always
command: ['mysqld', '--character-set-server=utf8']
volumes:
- "${DOCKER_VOLUME_PATH}/docker_test/db:/var/lib/mysql"
docker-compose命令
- 啟動(dòng):docker-compose up (注意需要在docker-compose.yml文件目錄下執(zhí)行)
- 停止:docker-compose stop
-
還有:docker-compose start
其他的就自己--help吧。
應(yīng)用的部署
好了,我們?cè)谧约旱臋C(jī)器上已經(jīng)大功告成了。是時(shí)候放到另外一臺(tái)機(jī)器跑跑看了。
開始的時(shí)候就說到,git 有g(shù)ithub,docker 有dockerhub。但是呢,這個(gè)dockerhub離我們太遠(yuǎn)了,網(wǎng)速慢。所以我們用國(guó)內(nèi)的阿里云或者網(wǎng)易蜂巢。
我用的是阿里云。
登錄》控制臺(tái)》產(chǎn)品與服務(wù)》容器服務(wù)》新建鏡像》新建鏡像倉庫。如下圖:



創(chuàng)建鏡像的時(shí)候,你可以設(shè)置代碼源。我這里選擇的是本地倉庫。倉庫創(chuàng)建好之后,我會(huì)獲得一個(gè)倉庫地址,拿到這個(gè)地址在本機(jī)執(zhí)行:
docker tag yetongxue/docker_test:1.2 registry.cn-hangzhou.aliyuncs.com/yetongxue/docker_test:1.2之后,
docker push registry.cn-hangzhou.aliyuncs.com/yetongxue/docker_test:1.2
mysql鏡像因?yàn)槭褂玫木褪蔷W(wǎng)上的公開鏡像,所以不用管。
在我們要部署的機(jī)器上面,創(chuàng)建好相關(guān)將要-v 的數(shù)據(jù)卷目錄。
再將剛剛的docker-compose.yml修改web所使用的鏡像就好。
web:
image: registry.cn-hangzhou.aliyuncs.com/yetongxue/docker_test:1.2
links:
- "db"
ports:
- "8100:8000"
volumes:
- "${DOCKER_VOLUME_PATH}/docker_test/media:/root/media"
restart: always
db:
image: mysql:5.7
environment:
TZ: 'Asia/Shanghai'
MYSQL_ROOT_PASSWORD: qwerasdf
MYSQL_DATABASE: docker_db
restart: always
command: ['mysqld', '--character-set-server=utf8']
volumes:
- "${DOCKER_VOLUME_PATH}/docker_test/db:/var/lib/mysql"
見證奇跡的時(shí)刻到了,docker-compose up
It works!
寫在后面
其實(shí)我也是個(gè)docker初學(xué)者,這個(gè)教程算是最近一兩個(gè)月斷斷續(xù)續(xù)學(xué)習(xí)的一個(gè)總結(jié)吧。寫得比較啰嗦,但我的本意是希望盡可能的把我覺得比較重要的點(diǎn)記錄下來。程序員是熱愛分享的一群人,作為程序員,我們都有看過別人寫的教程。作為一個(gè)初學(xué)者,教程中任何重要信息的遺漏都有可能給我們?cè)斐衫Щ?。所以我在每一處都進(jìn)行了詳細(xì)的說明。
希望能夠幫到你。