Docker 安装 MongoDB
MongoDB 是当下最流行的 NoSQL
数据库之一,Docker 安装 apache
的方式有两种
如果你是 Docker
初学者,如果你以后长期使用 mongodb
,我们建议你两种方法都试一试,为什么呢?
原因很简单,第一种方法,简单快捷,第二种方法,就是尝试自己编译安装
1. docker pull mongodb
如果想以最简单的方式安装 MongoDB
, 可以直接使用 docker pull mongo
命令
流程如下
-
查找
Docker Hub
上的mongodb
镜像[root@localhost ~]# docker search mongodb NAME ... OFFICIAL ... mongo ... [OK] ... mongo-express [OK] ...
列表很多,我们推荐你使用
OFFICIAL = OK
的那两条mongo
是官方数据库mongo-express
是官方使用Node.js
开发的MongoDB
管理后台
-
拉取官方最新的
MongoDB
镜像[root@localhost ~]# docker pull mongo Using default tag: latest ...
-
稍等片刻,下载完成后就可以在本地镜像列表里看到
mongo
的镜像了[root@localhost apache]# docker images mongodb REPOSITORY TAG IMAGE ID CREATED SIZE mongo latest f93ff881751f 5 days ago 367.6 MB
2. 通过 Dockerfile
文件构建
如果你是运维工程师,我们推荐你使用 Dockerfile
文件构建 mongodb
镜像
因为可以加深对安装 mongodb
的理解
现在,我们一步一步使用 Dockerfile
文件构建 mongodb
镜像吧
-
创建目录
mongo
用于存放后面的相关东西[root@localhost ~]# mkdir -p ~/mongo/db
目录 说明 mongo 该目录存放 Dockerfile
文件和db
数据库目录mongo/db 该目录将映射为 mongodb 容器的数据库目录 -
进入创建的
mongo
目录,创建docker-entrypoint.sh
脚本用于管理MongoDB
数据库[root@localhost ~]# cd mongo [root@localhost mongo] touch docker-entrypoint.sh [root@localhost mongo] chmod +x docker-entrypoint.sh [root@localhost mongo] vi docker-entrypoint.sh
然后输入以下内容
# !/bin/bash # 注意去掉上一行 # ! 之间的空格 set -Eeuo pipefail if [ "${1:0:1}" = '-' ]; then set -- mongod "$@" fi originalArgOne="$1" # allow the container to be started with `--user` # all mongo* commands should be dropped to the correct user if [[ "$originalArgOne" == mongo* ]] && [ "$(id -u)" = '0' ]; then if [ "$originalArgOne" = 'mongod' ]; then chown -R mongodb /data/configdb /data/db fi # make sure we can write to stdout and stderr as "mongodb" # (for our "initdb" code later; see "--logpath" below) chown --dereference mongodb "/proc/$$/fd/1" "/proc/$$/fd/2" || : # ignore errors thanks to https://github.com/docker-library/mongo/issues/149 exec gosu mongodb "$BASH_SOURCE" "$@" fi # you should use numactl to start your mongod instances, including the config servers, mongos instances, and any clients. # https://docs.mongodb.com/manual/administration/production-notes/#configuring-numa-on-linux if [[ "$originalArgOne" == mongo* ]]; then numa='numactl --interleave=all' if $numa true &> /dev/null; then set -- $numa "$@" fi fi # usage: file_env VAR [DEFAULT] # ie: file_env 'XYZ_DB_PASSWORD' 'example' # (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of # "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) file_env() { local var="$1" local fileVar="${var}_FILE" local def="${2:-}" if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then echo >&2 "error: both $var and $fileVar are set (but are exclusive)" exit 1 fi local val="$def" if [ "${!var:-}" ]; then val="${!var}" elif [ "${!fileVar:-}" ]; then val="$(< "${!fileVar}")" fi export "$var"="$val" unset "$fileVar" } # see https://github.com/docker-library/mongo/issues/147 (mongod is picky about duplicated arguments) _mongod_hack_have_arg() { local checkArg="$1"; shift local arg for arg; do case "$arg" in "$checkArg"|"$checkArg"=*) return 0 ;; esac done return 1 } # _mongod_hack_get_arg_val '--some-arg' "$@" _mongod_hack_get_arg_val() { local checkArg="$1"; shift while [ "$#" -gt 0 ]; do local arg="$1"; shift case "$arg" in "$checkArg") echo "$1" return 0 ;; "$checkArg"=*) echo "${arg#$checkArg=}" return 0 ;; esac done return 1 } declare -a mongodHackedArgs # _mongod_hack_ensure_arg '--some-arg' "$@" # set -- "${mongodHackedArgs[@]}" _mongod_hack_ensure_arg() { local ensureArg="$1"; shift mongodHackedArgs=( "$@" ) if ! _mongod_hack_have_arg "$ensureArg" "$@"; then mongodHackedArgs+=( "$ensureArg" ) fi } # _mongod_hack_ensure_no_arg '--some-unwanted-arg' "$@" # set -- "${mongodHackedArgs[@]}" _mongod_hack_ensure_no_arg() { local ensureNoArg="$1"; shift mongodHackedArgs=() while [ "$#" -gt 0 ]; do local arg="$1"; shift if [ "$arg" = "$ensureNoArg" ]; then continue fi mongodHackedArgs+=( "$arg" ) done } # _mongod_hack_ensure_no_arg '--some-unwanted-arg' "$@" # set -- "${mongodHackedArgs[@]}" _mongod_hack_ensure_no_arg_val() { local ensureNoArg="$1"; shift mongodHackedArgs=() while [ "$#" -gt 0 ]; do local arg="$1"; shift case "$arg" in "$ensureNoArg") shift # also skip the value continue ;; "$ensureNoArg"=*) # value is already included continue ;; esac mongodHackedArgs+=( "$arg" ) done } # _mongod_hack_ensure_arg_val '--some-arg' 'some-val' "$@" # set -- "${mongodHackedArgs[@]}" _mongod_hack_ensure_arg_val() { local ensureArg="$1"; shift local ensureVal="$1"; shift _mongod_hack_ensure_no_arg_val "$ensureArg" "$@" mongodHackedArgs+=( "$ensureArg" "$ensureVal" ) } # _js_escape 'some "string" value' _js_escape() { jq --null-input --arg 'str' "$1" '$str' } jsonConfigFile="${TMPDIR:-/tmp}/docker-entrypoint-config.json" tempConfigFile="${TMPDIR:-/tmp}/docker-entrypoint-temp-config.json" _parse_config() { if [ -s "$tempConfigFile" ]; then return 0 fi local configPath if configPath="$(_mongod_hack_get_arg_val --config "$@")"; then # if --config is specified, parse it into a JSON file so we can remove a few problematic keys (especially SSL-related keys) # see https://docs.mongodb.com/manual/reference/configuration-options/ mongo --norc --nodb --quiet --eval "load('/js-yaml.js'); printjson(jsyaml.load(cat($(_js_escape "$configPath"))))" > "$jsonConfigFile" jq 'del(.systemLog, .processManagement, .net, .security)' "$jsonConfigFile" > "$tempConfigFile" return 0 fi return 1 } dbPath= _dbPath() { if [ -n "$dbPath" ]; then echo "$dbPath" return fi if ! dbPath="$(_mongod_hack_get_arg_val --dbpath "$@")"; then if _parse_config "$@"; then dbPath="$(jq '.storage.dbPath' "$jsonConfigFile")" fi fi : "${dbPath:=/data/db}" echo "$dbPath" } if [ "$originalArgOne" = 'mongod' ]; then file_env 'MONGO_INITDB_ROOT_USERNAME' file_env 'MONGO_INITDB_ROOT_PASSWORD' # pre-check a few factors to see if it's even worth bothering with initdb shouldPerformInitdb= if [ "$MONGO_INITDB_ROOT_USERNAME" ] && [ "$MONGO_INITDB_ROOT_PASSWORD" ]; then # if we have a username/password, let's set "--auth" _mongod_hack_ensure_arg '--auth' "$@" set -- "${mongodHackedArgs[@]}" shouldPerformInitdb='true' elif [ "$MONGO_INITDB_ROOT_USERNAME" ] || [ "$MONGO_INITDB_ROOT_PASSWORD" ]; then cat >&2 <<-'EOF' error: missing 'MONGO_INITDB_ROOT_USERNAME' or 'MONGO_INITDB_ROOT_PASSWORD' both must be specified for a user to be created EOF exit 1 fi if [ -z "$shouldPerformInitdb" ]; then # if we've got any /docker-entrypoint-initdb.d/* files to parse later, we should initdb for f in /docker-entrypoint-initdb.d/*; do case "$f" in *.sh|*.js) # this should match the set of files we check for below shouldPerformInitdb="$f" break ;; esac done fi # check for a few known paths (to determine whether we've already initialized and should thus skip our initdb scripts) if [ -n "$shouldPerformInitdb" ]; then dbPath="$(_dbPath "$@")" for path in \ "$dbPath/WiredTiger" \ "$dbPath/journal" \ "$dbPath/local.0" \ "$dbPath/storage.bson" \ ; do if [ -e "$path" ]; then shouldPerformInitdb= break fi done fi if [ -n "$shouldPerformInitdb" ]; then mongodHackedArgs=( "$@" ) if _parse_config "$@"; then _mongod_hack_ensure_arg_val --config "$tempConfigFile" "${mongodHackedArgs[@]}" fi _mongod_hack_ensure_arg_val --bind_ip 127.0.0.1 "${mongodHackedArgs[@]}" _mongod_hack_ensure_arg_val --port 27017 "${mongodHackedArgs[@]}" _mongod_hack_ensure_no_arg --bind_ip_all "${mongodHackedArgs[@]}" # remove "--auth" and "--replSet" for our initial startup (see https://docs.mongodb.com/manual/tutorial/enable-authentication/#start-mongodb-without-access-control) # https://github.com/docker-library/mongo/issues/211 _mongod_hack_ensure_no_arg --auth "${mongodHackedArgs[@]}" if [ "$MONGO_INITDB_ROOT_USERNAME" ] && [ "$MONGO_INITDB_ROOT_PASSWORD" ]; then _mongod_hack_ensure_no_arg_val --replSet "${mongodHackedArgs[@]}" fi sslMode="$(_mongod_hack_have_arg '--sslPEMKeyFile' "$@" && echo 'allowSSL' || echo 'disabled')" # "BadValue: need sslPEMKeyFile when SSL is enabled" vs "BadValue: need to enable SSL via the sslMode flag when using SSL configuration parameters" _mongod_hack_ensure_arg_val --sslMode "$sslMode" "${mongodHackedArgs[@]}" if stat "/proc/$$/fd/1" > /dev/null && [ -w "/proc/$$/fd/1" ]; then # https://github.com/mongodb/mongo/blob/38c0eb538d0fd390c6cb9ce9ae9894153f6e8ef5/src/mongo/db/initialize_server_global_state.cpp#L237-L251 # https://github.com/docker-library/mongo/issues/164#issuecomment-293965668 _mongod_hack_ensure_arg_val --logpath "/proc/$$/fd/1" "${mongodHackedArgs[@]}" else initdbLogPath="$(_dbPath "$@")/docker-initdb.log" echo >&2 "warning: initdb logs cannot write to '/proc/$$/fd/1', so they are in '$initdbLogPath' instead" _mongod_hack_ensure_arg_val --logpath "$initdbLogPath" "${mongodHackedArgs[@]}" fi _mongod_hack_ensure_arg --logappend "${mongodHackedArgs[@]}" pidfile="${TMPDIR:-/tmp}/docker-entrypoint-temp-mongod.pid" rm -f "$pidfile" _mongod_hack_ensure_arg_val --pidfilepath "$pidfile" "${mongodHackedArgs[@]}" "${mongodHackedArgs[@]}" --fork mongo=( mongo --host 127.0.0.1 --port 27017 --quiet ) # check to see that our "mongod" actually did start up (catches "--help", "--version", MongoDB 3.2 being silly, slow prealloc, etc) # https://jira.mongodb.org/browse/SERVER-16292 tries=30 while true; do if ! { [ -s "$pidfile" ] && ps "$(< "$pidfile")" &> /dev/null; }; then # bail ASAP if "mongod" isn't even running echo >&2 echo >&2 "error: $originalArgOne does not appear to have stayed running -- perhaps it had an error?" echo >&2 exit 1 fi if "${mongo[@]}" 'admin' --eval 'quit(0)' &> /dev/null; then # success! break fi (( tries-- )) if [ "$tries" -le 0 ]; then echo >&2 echo >&2 "error: $originalArgOne does not appear to have accepted connections quickly enough -- perhaps it had an error?" echo >&2 exit 1 fi sleep 1 done if [ "$MONGO_INITDB_ROOT_USERNAME" ] && [ "$MONGO_INITDB_ROOT_PASSWORD" ]; then rootAuthDatabase='admin' "${mongo[@]}" "$rootAuthDatabase" <<-EOJS db.createUser({ user: $(_js_escape "$MONGO_INITDB_ROOT_USERNAME"), pwd: $(_js_escape "$MONGO_INITDB_ROOT_PASSWORD"), roles: [ { role: 'root', db: $(_js_escape "$rootAuthDatabase") } ] }) EOJS fi export MONGO_INITDB_DATABASE="${MONGO_INITDB_DATABASE:-test}" echo for f in /docker-entrypoint-initdb.d/*; do case "$f" in *.sh) echo "$0: running $f"; . "$f" ;; *.js) echo "$0: running $f"; "${mongo[@]}" "$MONGO_INITDB_DATABASE" "$f"; echo ;; *) echo "$0: ignoring $f" ;; esac echo done "$@" --pidfilepath="$pidfile" --shutdown rm -f "$pidfile" echo echo 'MongoDB init process complete; ready for start up.' echo fi # MongoDB 3.6+ defaults to localhost-only binding haveBindIp= if _mongod_hack_have_arg --bind_ip "$@" || _mongod_hack_have_arg --bind_ip_all "$@"; then haveBindIp=1 elif _parse_config "$@" && jq --exit-status '.net.bindIp // .net.bindIpAll' "$jsonConfigFile" > /dev/null; then haveBindIp=1 fi if [ -z "$haveBindIp" ]; then # so if no "--bind_ip" is specified, let's add "--bind_ip_all" set -- "$@" --bind_ip_all fi unset "${!MONGO_INITDB_@}" fi rm -f "$jsonConfigFile" "$tempConfigFile" exec "$@"
-
在
mongo
目录下创建Dockerfile
[root@localhost mongo]# vi Dockerfile
然后输入以下内容
FROM debian:jessie-slim # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added RUN groupadd -r mongodb && useradd -r -g mongodb mongodb RUN apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates \ jq \ numactl \ && rm -rf /var/lib/apt/lists/* # grab gosu for easy step-down from root (https://github.com/tianon/gosu/releases) ENV GOSU_VERSION 1.10 # grab "js-yaml" for parsing mongod's YAML config files (https://github.com/nodeca/js-yaml/releases) ENV JSYAML_VERSION 3.10.0 RUN set -ex; \ \ apt-get update; \ apt-get install -y --no-install-recommends \ wget \ ; \ rm -rf /var/lib/apt/lists/*; \ \ dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; \ wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; \ export GNUPGHOME="$(mktemp -d)"; \ gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; \ gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; \ rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc; \ chmod +x /usr/local/bin/gosu; \ gosu nobody true; \ \ wget -O /js-yaml.js "https://github.com/nodeca/js-yaml/raw/${JSYAML_VERSION}/dist/js-yaml.js"; \ # TODO some sort of download verification here \ apt-get purge -y --auto-remove wget RUN mkdir /docker-entrypoint-initdb.d ENV GPG_KEYS \ # pub rsa4096 2017-11-15 [SC] [expires: 2019-11-15] # BD8C 80D9 C729 D005 24E0 68E0 3DAB 7171 3396 F72B # uid [ unknown] MongoDB 3.8 Release Signing Key <packaging@mongodb.com> BD8C80D9C729D00524E068E03DAB71713396F72B # https://docs.mongodb.com/manual/tutorial/verify-mongodb-packages/#download-then-import-the-key-file RUN set -ex; \ export GNUPGHOME="$(mktemp -d)"; \ for key in $GPG_KEYS; do \ gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; \ done; \ gpg --export $GPG_KEYS > /etc/apt/trusted.gpg.d/mongodb.gpg; \ rm -r "$GNUPGHOME"; \ apt-key list # Allow build-time overrides (eg. to build image with MongoDB Enterprise version) # Options for MONGO_PACKAGE: mongodb-org OR mongodb-enterprise # Options for MONGO_REPO: repo.mongodb.org OR repo.mongodb.com # Example: docker build --build-arg MONGO_PACKAGE=mongodb-enterprise --build-arg MONGO_REPO=repo.mongodb.com . ARG MONGO_PACKAGE=mongodb-org-unstable ARG MONGO_REPO=repo.mongodb.org ENV MONGO_PACKAGE=${MONGO_PACKAGE} MONGO_REPO=${MONGO_REPO} ENV MONGO_MAJOR 3.7 ENV MONGO_VERSION 3.7.9 RUN echo "deb http://$MONGO_REPO/apt/debian jessie/${MONGO_PACKAGE%-unstable}/$MONGO_MAJOR main" | tee "/etc/apt/sources.list.d/${MONGO_PACKAGE%-unstable}.list" RUN set -x \ && apt-get update \ && apt-get install -y \ ${MONGO_PACKAGE}=$MONGO_VERSION \ ${MONGO_PACKAGE}-server=$MONGO_VERSION \ ${MONGO_PACKAGE}-shell=$MONGO_VERSION \ ${MONGO_PACKAGE}-mongos=$MONGO_VERSION \ ${MONGO_PACKAGE}-tools=$MONGO_VERSION \ && rm -rf /var/lib/apt/lists/* \ && rm -rf /var/lib/mongodb \ && mv /etc/mongod.conf /etc/mongod.conf.orig RUN mkdir -p /data/db /data/configdb \ && chown -R mongodb:mongodb /data/db /data/configdb VOLUME /data/db /data/configdb COPY docker-entrypoint.sh /usr/local/bin/ ENTRYPOINT ["docker-entrypoint.sh"] EXPOSE 27017 CMD ["mongod"]
这些内容,基本都是官方给的 Dockerfile
-
通过
Dockerfile
创建一个镜像ms-mongodb
,你可以替换成你自己的名字[root@localhost mongo]# docker build -t ms-mongo:3.7 .
-
稍等片刻,创建完成后,可以在本地的镜像列表里查找到刚刚创建的镜像
[root@localhost mongo]# docker images mongo:3.7 REPOSITORY TAG IMAGE ID CREATED SIZE ms-mongo 3.7 f0f3e4beccef 11 days ago 323 MB
这次自己编译的竟然比官方镜像小....
GitHub 下载加速
从 GitHub 下载文件非常慢,因为下载链接指向了 Amazon 的服务器
下载地址是 http://github-cloud.s3.amazonaws.com/,从国内访问 Amazon 非常慢,所以总是下载失败,解决方法时更改 hosts 文件,使该域名指向香港的服务器219.76.4.4 github-cloud.s3.amazonaws.com
运行 ms-mongo:3.7
容器
可以使用下面的命令运行我们刚刚创建的 ms-mongo:3.7
镜像
[root@localhost mongo]# docker run -d -p 27017:27017 -v $PWD/db:/data/db ms-mongo:3.7 dbe5d334e0063332633fe78fcc031c26851cbb1c5d589d50414e7bd37471671d
参数说明:
-
-p 27017:27017
将容器的
27017
端口映射到主机的27017
端口 -
-v $PWD/db:/data/db
将主机中当前目录下的
db
挂载到容器的/data/db
,作为 mongo 数据存储目录
查看容器启动情况
[root@localhost mongo]# docker ps -a CONTAINER ID IMAGE COMMAND ... dbe5d334e006 ms-mongo:3.7 "docker-entrypoint.sh" ...
查看容器的 IP
可以使用命令 docker inspect
查看容器的 IP
docker inspect --format '{{ .NetworkSettings.IPAddress }}' <container_id>
例如可以使用下面的命令查看刚刚创建的容器的 IP
[root@localhost mongo] docker inspect --format '{{ .NetworkSettings.IPAddress }}' dbe5d334e006 172.17.0.2
连接到 mongo 镜像
可以使用 mongo
镜像执行 mongo
命令连接到刚启动的容器, 主机 IP
为 172.17.0.2
[root@localhost mongo]# docker run -it ms-mongo:3.7 mongo --host 172.17.0.2 MongoDB shell version v3.6.5 connecting to: mongodb://172.17.0.2:27017/ MongoDB server version: 3.6.5 Welcome to the MongoDB shell. For interactive help, type "help". For more comprehensive documentation, see http://docs.mongodb.org/ Questions? Try the support group http://groups.google.com/group/mongodb-user 2018-05-18T14:01:20.078+0000 I STORAGE [main] In File::open(), ::open for '/home/mongodb/.mongorc.js' failed with No such file or directory Server has startup warnings: 2018-05-18T13:59:12.821+0000 I CONTROL [initandlisten] 2018-05-18T13:59:12.821+0000 I CONTROL [initandlisten] ** WARNING: Access control is not enabled for the database. 2018-05-18T13:59:12.821+0000 I CONTROL [initandlisten] ** Read and write access to data and configuration is unrestricted. 2018-05-18T13:59:12.821+0000 I CONTROL [initandlisten]