You can build the image with the familiar `build` command:
```console
$ docker build --tag docker-gs-ping-roach .
```
### Run the application
Now, run your container. This time you'll need to set some environment variables so that your application knows how to access the database. For now, you’ll do this right in the `docker run` command. Later you'll see a more convenient method with Docker Compose.
> [!NOTE]
>
> Since you're running your CockroachDB cluster in insecure mode, the value for the password can be anything.
>
> In production, don't run in insecure mode.
```console
$ docker run -it --rm -d \
--network mynet \
--name rest-server \
-p 80:8080 \
-e PGUSER=totoro \
-e PGPASSWORD=myfriend \
-e PGHOST=db \
-e PGPORT=26257 \
-e PGDATABASE=mydb \
docker-gs-ping-roach
```
There are a few points to note about this command.
- You map container port `8080` to host port `80` this time. Thus, for `GET` requests you can get away with literally `curl localhost`:
```console
$ curl localhost
Hello, Docker! (0)
```
Or, if you prefer, a proper URL would work just as well:
```console
$ curl http://localhost/
Hello, Docker! (0)
```
- The total number of stored messages is `0` for now. This is fine, because you haven't posted anything to your application yet.
- You refer to the database container by its hostname, which is `db`. This is why you had `--hostname db` when you started the database container.
- The actual password doesn't matter, but it must be set to something to avoid confusing the example application.
- The container you've just run is named `rest-server`. These names are useful for managing the container lifecycle:
```console
# Don't do this just yet, it's only an example:
$ docker container rm --force rest-server
```
### Test the application
In the previous section, you've already tested querying your application with `GET` and it returned zero for the stored message counter. Now, post some messages to it:
```console
$ curl --request POST \
--url http://localhost/send \
--header 'content-type: application/json' \
--data '{"value": "Hello, Docker!"}'
```
The application responds with the contents of the message, which means it has been saved in the database:
```json
{ "value": "Hello, Docker!" }
```
Send another message:
```console
$ curl --request POST \
--url http://localhost/send \
--header 'content-type: application/json' \
--data '{"value": "Hello, Oliver!"}'
```
And again, you get the value of the message back:
```json
{ "value": "Hello, Oliver!" }
```
Run curl and see what the message counter says:
```console
$ curl localhost
Hello, Docker! (2)
```
In this example, you sent two messages and the database kept them. Or has it? Stop and remove all your containers, but not the volumes, and try again.
First, stop the containers:
```console
$ docker container stop rest-server roach
rest-server
roach
```
Then, remove them:
```console
$ docker container rm rest-server roach
rest-server
roach
```
Verify that they're gone:
```console
$ docker container list --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
```
And start them again, database first:
```console
$ docker run -d \
--name roach \
--hostname db \
--network mynet \
-p 26257:26257 \
-p 8080:8080 \
-v roach:/cockroach/cockroach-data \
cockroachdb/cockroach:latest-v20.1 start-single-node \
--insecure
```
And the service next:
```console
$ docker run -it --rm -d \
--network mynet \
--name rest-server \
-p 80:8080 \
-e PGUSER=totoro \
-e PGPASSWORD=myfriend \
-e PGHOST=db \
-e PGPORT=26257 \
-e PGDATABASE=mydb \
docker-gs-ping-roach
```
Lastly, query your service:
```console
$ curl localhost
Hello, Docker! (2)
```
Great! The count of records from the database is correct although you haven't only stopped the containers, but you've also removed them before starting new instances. The difference is in the managed volume for CockroachDB, which you reused. The new CockroachDB container has read the database files from the disk, just as it normally would if it were running outside the container.